Repository navigation
egress: write the host's lane verdict into every NIC-bearing guest - #171
Merged
Merged
Conversation
CMGS
force-pushed
the
feat/egress-rule-ports
branch
from
September 14, 2026 06:54
5e163a3 to
e8176f8
Compare
The desktop image's guest-proxy-setup decided from NIC presence, so on a guarded bridge lane the GNOME session and osworld-server got neither a route nor the relay, and silkd's marker only said "locked", which left a guest with a NIC no way to tell "the host has not decided yet" from "the host says direct". sandboxd now writes /etc/silkd-lane with the verdict, relay on a locked bridge lane and direct on a CNI lane, at the same three sites the marker used (golden build, cold provision, late reconcile lock); the golden sidecar records the word so a golden built under another verdict is rebuilt. silkd routes directly only when the file does not read relay, one 8-byte read per exec on a NIC-bearing guest, nothing on the none lane. guest-proxy-setup waits up to 30 s for the file on a NIC-bearing guest, follows relay, and treats direct or a silent host as routing. desktopsmoke gains -net egress with a fetch through the session's proxy environment in place of the checkpoint leg, which the lane refuses. The old marker shipped in no release, so it is renamed rather than kept. Closes #167
CMGS
force-pushed
the
feat/egress-lane-file
branch
from
September 14, 2026 06:56
11e2fcb to
fe3416d
Compare
CMGS
added a commit
that referenced
this pull request
Sep 14, 2026
…te (#173) Batch-end round on the state with #169, #170 and #171 merged, scoped by the hygiene ledger (0 files due after) plus an ownership pass over all of silkd. Fixed with tests: hostPort defaulted the port it could not parse and serveConnect dialed the raw authority, so a path-form CONNECT with Host: example.com:+22 was judged as 443, allowed by a ports rule and dialed to port 22; every malformed authority (out-of-range port, two ports, stray or unclosed brackets, empty host) is now a deny with a no-port audit line, the dial and the intercept authority come from the parsed pair, and serveSocks refuses port 0. The SOCKS5 door becomes the pool policy's call (the tenant's rules already gate every tunnel), ServesSocks trusts Validate, the desktop unit's wait outlives the host's probe and write timeouts and fails visibly on timeout, silkd latches a relay verdict and serves base_env from a static slice, deploy docs gain the daemon/image lockstep and the strict-config rollback. Round net prod +34 / test +88, comment lines +5 / -8; every gate green on both platforms, hardware suites and the desktop lane PASS on cocoon-test1; Codex converged after five rounds.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #170 (base
feat/egress-rule-ports); merge order #169 → #170 → this → the review PR that follows. One commit of its own. Closes #167.The desktop image's
guest-proxy-setupdecided from NIC presence, so on a guarded bridge lane the GNOME session andosworld-servergot neither a route nor the relay; and the boolean marker #165 introduced only said "locked", which left a NIC-bearing guest no way to tell "the host has not decided yet" from "the host says direct".Change
sandboxd/engine/lane.goreplacesnicmark.go:Lane(relay|direct) andEngine.MarkLanewrite/etc/silkd-lanethrough the existingfs_writepath.sandboxd/pool:laneOf(key)is empty on the none lane (no NIC to route through),relaywhen the lane is locked (bridge), elsedirect(CNI);markLanewrites it at the same three sites the marker used (golden build after the readiness probe, cold provision, the late reconcile lock). The.nicgolden sidecar stores the word, so a golden built under another verdict — including one built by the marker version — is rebuilt, not adopted; none-lane goldens keep matching.Engine.MarkLanereplacesMarkNICLocked; fake engines follow.silkd/src/net.rs:routes_directly()is true only for a NIC whose lane file does not readrelay; an absent or unreadable file routes directly, so an old sandboxd that writes nothing leaves the guest as it was. Unit test covers absent / direct / relay.os-image/desktop/24.04/Dockerfile:guest-proxy-setupstill configures the relay at once when there is no NIC; with a NIC it waits for/etc/silkd-lane, followsrelay, and exits ondirect. The unit already ranAfter=silkd.serviceandBefore=desktop-session.service osworld-server.service, so the session andosworld-serverstart after the verdict.e2e/cmd/desktopsmokegains-net none|egressand-probe: on the egress lane the checkpoint/branch leg (refused on the lane) gives way to a/executeleg that requireshttp_proxyin the session's environment and a 200 from the allowed origin through the relay; the/executeparsing moved into oneexecutehelper used by both legs.docs/silkd.md,docs/egress.md(lane paragraph),docs/desktop.md(lane bullet, unit bullet); desktop pools may use the egress lane again.Decisions
directwritten explicitly, a timeout fires only for an old sandboxd.deploy.mdmakes draining claims part of upgrading, and silkd's execs follow the file at once.Codex's review of this branch raised one MAJOR: a 30 s guest wait is shorter than the host's own worst case (90 s probe plus a 2-minute write timeout), so a late
relaycould land after the desktop had configured itself and been snapshotted. That is resolved in the review PR stacked on this one, the way the previous batch's round fixes rode #168 on #165: the wait is 300 s (longer than the host's success window, so a guest still waiting belongs to a boot the host already failed), the timeout exits non-zero so a mis-timed build is visible, the NIC test matches silkd's device-backed probe, and desktopsmoke asserts the unit is active. Merge this PR together with the review PR.Hot path
None on the claim path: the write happens at golden build, cold provision and the late reconcile lock. silkd's per-exec cost on a NIC-bearing guest is one small read (the marker was one stat; measured below noise: 750 vs 745 µs exec RTT); the review PR latches a
relayverdict so the bridge lane pays it once. Nothing on the none lane.Tests and evidence
TestLaneVerdictReachesGuestOnColdBoots(locked / unlocked egress lane and none lane, golden and cold),TestGoldenNICSidecarGatesAdoption; silkdlane_file_decides_relay.make go-lint10 ×0 issues.;asl -forwarder=falseclean on both GOOS;go testengine/pool;go vet ./...e2e; silkdcargo fmt --check, clippy-D warnings, 111 tests on macOS and 111 in arust:1.98.0linux/arm64 container.rt-lane4,desktop-lane4=desktop:24.04+ this silkd + thisguest-proxy-setup):scripts/egress-e2e.shNET=none PASS and NET=egress BRIDGE=sbxbr0 PASS (direct egress blocked by the lock, allowed origin reached with and without-xwith the injected credential, denied host 403);scripts/sandboxd-e2e.shBRIDGE=sbxbr0 PASS including restart re-adoption;desktopsmoke -net egressPASS on a 2xlarge egress-lane desktop pool with a policy (screenshot, AT-SPI tree, PyAutoGUI click, then: the session's environment carries the relay and the allowed origin answers 200 through it, audited as a GET on port 80);desktopsmoke -net nonePASS with the checkpoint/branch leg.