capsite/toybox: vats have ids, not names; ingress by mount
createVat (POST / on the admin socket) makes a vat with newUniqueId and returns its id, which addresses it only there. A vat is reachable only where it is mounted: ?mount=<labels> on each start, as ?egress= is granted; absent means none. The ingress reads a request's labels from its query string, plus a Toybox-Labels header for secret ones (a URL ends up in logs and Referers). It routes to the vat whose mount labels the request carries, every one: stricter than Flower's no-conflict match, since an ingress client holds no constrained handle and a label it omits must not match. Registration keeps Flower's rule, so a mount must conflict with every other and no request can carry two. The app keeps the whole path and sees its connection labels in Toybox-Connection-Labels. A vat from before ids lives at idFromName(name). PUT /by-name/<name> reaches it on the admin socket; it stays unreachable from outside until mounted. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
f0557d29d6
commit
8d8900d84d
6 files changed
+307
-69
No files matched your search
@@ -50,3 +50,24 @@ export const checkUrl = (labels, url) => {
|
||||
if (k in labels && labels[k] !== v) throw new Error(`egress to ${actual.host} not granted`);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Do `a` and `b` give some key different values? Flower refuses to register
|
||||
* a target that doesn't conflict with every other: lookups stay unambiguous.
|
||||
*
|
||||
* @param {Record<string, string>} a
|
||||
* @param {Record<string, string>} b
|
||||
*/
|
||||
export const conflict = (a, b) => Object.entries(a).some(([k, v]) => k in b && b[k] !== v);
|
||||
|
||||
/**
|
||||
* Does `request` carry every label of `mount`, with the same values?
|
||||
*
|
||||
* Stricter than Flower's match (no conflict): an ingress client holds no
|
||||
* constrained handle, so a label it omits must not match, or a secret
|
||||
* label would protect nothing.
|
||||
*
|
||||
* @param {Record<string, string>} mount
|
||||
* @param {Record<string, string>} request
|
||||
*/
|
||||
export const carries = (mount, request) => Object.entries(mount).every(([k, v]) => request[k] === v);
|
||||
Reference in new issue
Block a user