Files
captoys/toybox/README.md
T
dckcandClaude Opus 5.5 2820c015ee capsite/toybox: a grant is an object in env, not the vat's global fetch
A vat's globalOutbound is now always null. A granted host arrives as
env.egress, an Egress the app can hand to whichever of its parts should
have it; as globalOutbound it was ambient to every module in the vat.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 21:44:29 -05:00

3.2 KiB

toybox

Vats whose code is installed at runtime: each vat is a Durable Object whose app runs as a facet on code loaded through workerd's Worker Loader. Think vatAdmin.createVat(bundle), with a supervisor per vat.

  • supervisor.js: Vat stores code by SHA-256 and runs the app on it; Public and Admin are the two entrypoints; Egress is a grant of one host.
  • switchboard.js: a separate workerd process, the vats' only way out: a forward proxy for HTTP and WebSockets.
  • config.capnp: the sockets have no addresses; whoever starts workerd hands them in, so holding a socket is the authority it grants.
socket reaches what its holder can do
http Public GET /<vat>/…: talk to a vat's app
admin Admin PUT /<vat> with an ES module body: install it and (re)start the app; its storage carries over. ?egress=<host> grants the app that one host.

An app must export class App extends DurableObject (see apps/). Its global fetch always throws: nothing in a vat is ambient. A granted host arrives as env.egress, an Egress with the host in ctx.props: its fetch forwards matching requests, WebSocket upgrades included, to the switchboard and refuses the rest with a 403. It is an object, so the app can pass it to whichever of its parts should have it.

toybox reaches the switchboard over a unix socket (-e switchboard=unix:…), in HTTP proxy style so the full URL, scheme included, survives the hop.

Run it

pnpm install
pnpm test         # real workerds: install, upgrade, isolation, egress grants, fetch and WebSocket out, crash and restart
pnpm switchboard  # systemd-socket-activate on ./switchboard.sock
pnpm start        # likewise on 127.0.0.1:8787 and ./admin.sock; state in ./state

Then, in a third terminal:

curl -X PUT --unix-socket admin.sock --data-binary @apps/counter-v1.js http://toybox/alice
curl localhost:8787/alice                # v1 count 1
curl -X PUT --unix-socket admin.sock --data-binary @apps/counter-v2.js http://toybox/alice
curl localhost:8787/alice                # v2 count 2

curl -X PUT --unix-socket admin.sock --data-binary @apps/egress-probe.js 'http://toybox/erin?egress=example.com'
curl 'localhost:8787/erin?url=https://example.com/'   # got: <!doctype html>…
curl 'localhost:8787/erin?url=https://example.org/'   # got: egress to example.org not granted

Under systemd

systemd/ has socket and service pairs for toybox and its switchboard, assuming this directory is installed at /opt/toybox. toybox gets no network of its own (PrivateNetwork=yes): only the two sockets it is handed and the switchboard's socket, which only members of the toybox group can open. The switchboard has the network, fenced by IPAddressDeny=; switchboard.capnp allows local addresses only so the tests can reach a local echo server.

Neither unit has been run under the system manager yet.

PrivateNetwork= needs the system manager; as a systemd-run --user unit, systemd logs "lack privileges for network namespace, proceeding without".