feat: the sandbox's network grant (NETWORK slice 10) #167
Loading…
Reference in a new issue
No description provided.
Delete branch "loop/7-sandbox-network-grant"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #7
Implements NETWORK.md slice 10: a host grants a sandboxed receiver script the network with
network connect: "host:port", listen: "address:port", and inside a sandbox the runtime holds every network native to those patterns.What
feat(runtime): hold the network natives to a sandbox's network grantruntime/sandbox.cparsesconnect/listenlines of the grant into endpoints (exact name,*.suffix,*, IPv4,[IPv6], port or*). It keeps the addresses a granted name resolved to until the sandbox closes, and exposestorb_sandbox_check_resolve/_connect/_listen/_name_servers. A refusal isTORB_SANDBOX_REFUSED, a stop, never aNetworkError. A line it cannot read grants nothing.runtime/io.c: listen and UDP bind ask the listen side; TCP connect, UDP connect andsend(to:)ask the connect side; resolve asks before the resolver; a finished resolution feeds the connectable set (torb_io_socketkeeps the host it resolved);torb_network_name_serversalways refuses inside a sandbox. accept, receive, send, shutdown, close and addresses are not checked again.runtime/sandbox.cis the single list of guarded natives. It says that a new entry point (#119, #129) calls one of the checks or refuses while a sandbox is open.runtime/tests/sandbox_test.c: 12 tests covering parsing and matching (exact name with case and trailing dot, suffix,*host,*port, IPv6, localhost, malformed), the connectable set after a resolution and its reset on close,unrestricted, and the refusal messages.feat(std/sandbox): grant the network to a scriptSandboxCapabilities.network(connect:, listen:)appends one pattern per side per call.Sandbox.loadfails with aSandboxErrorat line 0 for a pattern outside the grammar.tests/conformance/vm-only/sandbox-network.trb:modules "std/network"fail the load.tests/conformance/vm-only/sandbox-network-refused.trb(with a.leaksfile): a refused connect, resolve and datagramsend to, which run in tasks, andsystemNameServersstop the script with the expected text and line, and the program goes on.tests/conformance/sandbox-crossing.trbgets the same grant through the native script host: granted echo, a refused listen, the missing module, and a malformed pattern.unrestrictedrules, and slice 10 is Done.docs/standard-library/sandbox.mdanddocs/language/configuration/the-sandbox.mdare updated, andskills/is regenerated.Choices worth a look in review
testthat waited for that task, not the line of theconnect/resolvecall.TcpStream.connectandresolverun in a task, and per VM.md section 10 the stop waits for the operation that ran the scheduler. The refusal itself is instd/network, so no script frame sits below it. Synchronous calls (listen, bind,systemNameServers) stop at the line of the call. This is written into NETWORK.md section 10, SCRIPTS.md section 6 and the test.std/networktask strands the waiting tasks' frames: 4 blocks for a connect, 1 for a resolve, 5 for a send.systemNameServersstrands the list it allocated before the native: 1 block. The first CI run failed tier B's leak gate on exactly these. So those refusals moved tosandbox-network-refused.trb, whose.leaksfile states that reason, and the crossing keeps only refusals that hold nothing. Everything else is still held to zero live blocks, in the VM and natively. Freeing a stopped task's frames would change gap 9, so it is not part of this PR.Resolver/lookupneed a listen pattern for their ephemeral bind (0.0.0.0:0, or[::]:0for an IPv6 server) plus a connect pattern forserver:53.systemNameServersstops. Both fail closed.localhostin a pattern. It also names127.0.0.1and::1, becausestd/networkanswerslocalhostwithout the resolver.*orlocalhost, never another name. Port 0 must be named (:0) or*.Gates
aandb(runtime change) run in forge CI only. The worker ran no gate, bootstrap or LTO build locally.runtime/tests/sandbox_test.cbuilt withzig cc -std=c11 -Wall -Wextra -Wpedantic -Werror: 18 sandbox tests, 0 failed.torb format --checkandtorb checkon every touched.trb.torbof the first push:TORB_REPORT_LEAKS=1 torb run --vmofsandbox-network.trbandsandbox-crossing.trbreports 0 live blocks, and the output matches.expectedfor both of those and forsandbox-network-refused.trb.torb docs skill docs skills --checkis clean.tools/check-commits.shis clean.4f79322c6daf21560c68Checklist (head
af21560):runtime/tests/sandbox_test.ccovers parsing/matching (exact, suffix,*, port*, IPv6, malformed) and the connectable set; vm-only conformance programs cover grant/refusal over loopback, the program-task exemption and zero live blocks; crossing test covers the native host. CI is green on this head (tier A/B, gates, pdisc, commit messages).io.cthat opens or addresses a socket asks a check (listen, bind, connect, UDP connect,send(to:), resolve, name servers). Refusal frees its socket reference before the stop jumps. The resolved-host copy moves from operation to resolution and is freed on both paths. Fail-closed parsing: an unreadable line grants nothing, a numeric host is an address or nothing, and a listen pattern cannot be a name. The load-time pattern check instd/sandboxmatches the runtime grammar.Non-blocking:
test, not of the call) and the stranded frames on a refusal inside a task are documented trade-offs tied to gap 9; good that they are written into the docs and the.leaksfile.