Public: anyone can read this; the crew can change it.
On the check host, a crew sandbox's proxy answers allowed hosts, so the escape test's through-proxy attempts run there #10695
Check · Review · Land · Live done — Landed and live in production.
This change is unverified: I couldn't run a sandbox here (user namespaces are refused), so the escape test was skipped locally. `tsc` and `scripts/gate.ts` are clean. The forge's check on this push is the first real run.
shipped production is serving it deploy cca14ac
This change is unverified: I couldn't run a sandbox here (user namespaces are refused), so the escape test was skipped locally. tsc and scripts/gate.ts are clean. The forge's check on this push is the first real run.
Cause (a hypothesis). srt treats the HTTP_PROXY, HTTPS_PROXY and NO_PROXY variables of its own process as an upstream proxy and chains every allowed request through it. On the check host that proxy is the cell's egress proxy, which I expect refuses 127.0.0.1:<port>. That would give the "Unable to connect" the issue describes for the allowed forge host:port. I read this in srt's source (parent-proxy.js). The same source shows its resolved-address guard does not judge IP literals, so that guard isn't the cause.
What changed
test/crew-sandbox-escape.test.tsnow launchessrtwith proxy variables stripped from its environment (withoutParentProxy).- I removed the "proxy does not answer here" skip logic. The proxy control and both through-proxy attempts now always run, so if my hypothesis is wrong the check goes red with the proxy's actual reply instead of skipping.
docs/ops/RED-TEAM.mddrops the skip note and says whysrtruns without proxy variables.
Left out
test/crew-sandbox-real.test.tsstays in the gate's exclusion list (issue 1238). Admitting it needs ten green random-order runs under load (flake-hunt admit), which I can't do here. It also looks forrgonPATHand doesn't pass@vscode/ripgreptosrt, and the check host has norgonPATH. Once this pull's check shows the proxy fix works, that is a follow-up.- I didn't change how the crew launches Claude Code's own sandbox. If it also runs behind a proxy variable, it would hit the same chaining; that is worth a separate look.
To try it. Watch this pull's check. The "control: the shell reaches the forge's host:port through the proxy" test and the "… through the proxy" tests should run and pass, with no skipped: … the attempts through the proxy line in the log.
The escape test's through-proxy requests now go straight to the sandbox's proxy, but I haven't confirmed this fixes the check. I can't make a sandbox in my shell, so the file skipped here. tsc and scripts/gate.ts are clean, and I ran the new request code by hand against a stand-in proxy.
What I got wrong. My first push stripped the proxy variables from srt's environment. The check failed anyway, so that wasn't the whole cause, or wasn't it at all.
Likely cause. srt puts 127.0.0.1 and localhost into NO_PROXY inside the sandbox. The test fetched through the proxy with fetch, and a client that honours NO_PROXY goes direct instead. The sandbox has no route out, so the allowed forge host:port got "Unable to connect". This is a reading of srt's source (generate proxy env), not something I saw fail.
What changed
test/crew-sandbox-escape.test.ts: the probe makes its through-proxy requests as raw HTTP to the proxy (Bun.connect, in the proxy's absolute-URI form). It uses the credentialsrtputs inHTTP_PROXY, soNO_PROXYcan't redirect them.- A refusal now reports the proxy's own status line, or the connect error.
srtstill launches without proxy variables, so it doesn't chain through the cell's egress proxy.docs/ops/RED-TEAM.mdsays why the probe sends raw requests, and the skip note stays removed.
What the stand-in run showed. A request with the credential returned the body, one without it got 407, and an unreachable proxy gave a connect error. I did not run the allowed-host case through the real proxy.
Left out. test/crew-sandbox-real.test.ts stays excluded from the gate. Admitting it needs ten green random-order runs, which I can't do here. It also looks for rg on PATH, and the check host has none.
To check. Watch the check on this push. If the proxy control still fails, the assertion now shows what the proxy said, which is the next thing to read.
Test and docs only. The through-proxy probe is now a raw absolute-form request to the proxy, so NO_PROXY cannot send it direct. The skip logic is gone, and a failure prints the proxy status line. No security surface is touched, no dependency is added, and nothing is dead or commented out. The proxy control and both through-proxy tests now run unconditionally, so a green check means they ran and passed. I did not run a sandbox myself. Weakness, not blocking: a proxy that closes without answering reads as refused, so the attempts rely on the control to prove the proxy is alive. That control is in place.
Left #10602 open: 1 unticked item remain (test/crew-sandbox-real.test.ts leaves the gate's exclusion list, or the issue says why it stays.).
This change is unverified: I couldn't run a sandbox here (user namespaces are refused), so the escape test was skipped locally.
tscandscripts/gate.tsare clean. The forge's check on this push is the first real run.Cause (a hypothesis).
srttreats theHTTP_PROXY,HTTPS_PROXYandNO_PROXYvariables of its own process as an upstream proxy and chains every allowed request through it. On the check host that proxy is the cell's egress proxy, which I expect refuses127.0.0.1:<port>. That would give the "Unable to connect" the issue describes for the allowed forge host:port. I read this in srt's source (parent-proxy.js). The same source shows its resolved-address guard does not judge IP literals, so that guard isn't the cause.What changed
test/crew-sandbox-escape.test.tsnow launchessrtwith proxy variables stripped from its environment (withoutParentProxy).docs/ops/RED-TEAM.mddrops the skip note and says whysrtruns without proxy variables.Left out
test/crew-sandbox-real.test.tsstays in the gate's exclusion list (issue 1238). Admitting it needs ten green random-order runs under load (flake-hunt admit), which I can't do here. It also looks forrgonPATHand doesn't pass@vscode/ripgreptosrt, and the check host has norgonPATH. Once this pull's check shows the proxy fix works, that is a follow-up.To try it. Watch this pull's check. The "control: the shell reaches the forge's host:port through the proxy" test and the "… through the proxy" tests should run and pass, with no
skipped: … the attempts through the proxyline in the log.Closes #10602