Run an outside PR's tests with no network
Fetch an outside PR into a sandbox, install from npm only, run its tests with egress denied, check its dependencies with deps.dev and get a note.
Code from someone else's pull request should not see your credentials or your network. This recipe runs an outside contributor's PR (jshttp/cookie #289, pinned to its head commit) in a sandbox and narrows what the sandbox can reach before any of that code runs:
- The fetch gets the credential in that one command's environment, as
GIT_CONFIG_COUNT,GIT_CONFIG_KEY_0andGIT_CONFIG_VALUE_0. git reads them as runtime config: the value is not written to.git/configand, unlikegit -c, is in no process's argv. The recipe sends a random canary in place of a token, then looks for it. POST /v1/sandboxes/{id}/egressnarrows the sandbox toregistry.npmjs.org, andnpm ci --ignore-scriptsinstalls the lockfile's packages without running their install scripts. github.com is now refused, by name and by address.- The same call narrows egress to
deny, and the PR's tests run with no network at all. - Outside the sandbox, the
io.b3os/deps-dev/get-versionaction looks up each direct dependency at the version the lockfile pins, and the model turns the test result and the dependency facts into a three-sentence note. The recipe reads the lockfile right after the install, before the tests: the PR's code could rewrite it.
The sandbox has no api grant, so code inside it cannot call B3OS. The sandbox starts with public egress for the
fetch: fetching runs no code from the PR, and git runs no hooks from the repository it fetches.
Verified 2026-11-01: this recipe's last run passed against https://beta-api.b3os.org, label live-recorded (recorded from production), from commit cebfa5fc. The recipe harness runs it again, and a failed run takes this page out of the cookbook.
Run it
bashAPI=https://beta-api.b3os.orgAUTH="Authorization: Bearer $B3OS_API_KEY"HEAD=f1d76f52b68f9161cc2b6d3093f151e774c6748brun() { jq -n --arg cmd "$1" '{cmd: $cmd, timeout_ms: 60000}' \ | curl -s "$API/v1/sandboxes/$SBX/exec" -H "$AUTH" -H "Content-Type: application/json" -d @- \ | jq -r '.stdout, "exit \(.exit_code)"'; }SBX=$(curl -s "$API/v1/sandboxes" -H "$AUTH" -H "Content-Type: application/json" \ -d '{"template": "base", "vcpu": 2, "memory_mib": 2048, "timeout_s": 600}' | jq -r .id)# The credential only in this command's env (a token would go where the canary is).jq -n --arg cmd "git init -q pr && cd pr && git remote add origin https://github.com/jshttp/cookie.git && git fetch -q --depth 1 origin $HEAD && git checkout -q --detach FETCH_HEAD" \ '{cmd: $cmd, timeout_ms: 60000, env: {GIT_CONFIG_COUNT: "1", GIT_CONFIG_KEY_0: "http.extraHeader", GIT_CONFIG_VALUE_0: "X-Canary: replace-me"}}' \ | curl -s "$API/v1/sandboxes/$SBX/exec" -H "$AUTH" -H "Content-Type: application/json" -d @- | jq .exit_codecurl -s "$API/v1/sandboxes/$SBX/egress" -H "$AUTH" -H "Content-Type: application/json" \ -d '{"mode": "allowlist", "allow": ["registry.npmjs.org"]}' | jq .egressrun "cd pr && npm_config_cache=/tmp/npm npm ci --ignore-scripts --no-audit --no-fund 2>&1 | grep '^added'"curl -s "$API/v1/sandboxes/$SBX/egress" -H "$AUTH" -H "Content-Type: application/json" \ -d '{"mode": "deny"}' | jq .egressrun "cd pr && NO_COLOR=1 npm_config_cache=/tmp/npm npx --no-install vitest run 2>&1 | grep -E 'Test Files|Tests '"run "cd pr && git config --get-all http.extraheader || echo 'no http.extraheader in the clone'"curl -s "$API/v1/actions/call" -H "$AUTH" -H "Content-Type: application/json" \ -d '{"ref": "io.b3os/deps-dev/get-version@1", "input": {"system": "npm", "name": "vitest", "version": "4.1.9"}}' \ | jq '.output | {licenses, advisories}'curl -s -X DELETE "$API/v1/sandboxes/$SBX" -H "$AUTH" | jq .status
tsconst API = "https://beta-api.b3os.org";const headers = { authorization: `Bearer ${process.env.B3OS_API_KEY}`, "content-type": "application/json" };const call = async (method: string, path: string, body?: unknown): Promise<any> => (await fetch(`${API}${path}`, { method, headers, body: body === undefined ? undefined : JSON.stringify(body) })).json();const head = "f1d76f52b68f9161cc2b6d3093f151e774c6748b";const sbx = await call("POST", "/v1/sandboxes", { template: "base", vcpu: 2, memory_mib: 2048, timeout_s: 600 });const run = (cmd: string, env?: Record<string, string>) => call("POST", `/v1/sandboxes/${sbx.id}/exec`, { cmd, env, timeout_ms: 60000 });try { await run( `git init -q pr && cd pr && git remote add origin https://github.com/jshttp/cookie.git && git fetch -q --depth 1 origin ${head} && git checkout -q --detach FETCH_HEAD`, // The credential only in this command's env; a token would go where the canary is. { GIT_CONFIG_COUNT: "1", GIT_CONFIG_KEY_0: "http.extraHeader", GIT_CONFIG_VALUE_0: "X-Canary: replace-me" }, ); await call("POST", `/v1/sandboxes/${sbx.id}/egress`, { mode: "allowlist", allow: ["registry.npmjs.org"] }); await run("cd pr && npm ci --ignore-scripts --no-audit --no-fund", { npm_config_cache: "/tmp/npm" }); await call("POST", `/v1/sandboxes/${sbx.id}/egress`, { mode: "deny" }); const tests = await run("cd pr && npx --no-install vitest run", { npm_config_cache: "/tmp/npm" }); const deps = await call("POST", "/v1/actions/call", { ref: "io.b3os/deps-dev/get-version@1", input: { system: "npm", name: "vitest", version: "4.1.9" }, }); const note = await call("POST", "/v1/infer/chat/completions", { model: "b3os/qwen3.5-9b", temperature: 0, chat_template_kwargs: { enable_thinking: false }, messages: [ { role: "system", content: "Write a three-sentence note for the maintainer from these facts only." }, { role: "user", content: JSON.stringify({ tests: tests.stdout.slice(-400), vitest: deps.output }) }, ], }); console.log(note.choices[0].message.content);} finally { await call("DELETE", `/v1/sandboxes/${sbx.id}`);}
pythonimport jsonimport osimport requestsAPI = "https://beta-api.b3os.org"s = requests.Session()s.headers["Authorization"] = f"Bearer {os.environ['B3OS_API_KEY']}"HEAD = "f1d76f52b68f9161cc2b6d3093f151e774c6748b"sbx = s.post(f"{API}/v1/sandboxes", json={"template": "base", "vcpu": 2, "memory_mib": 2048, "timeout_s": 600}).json()run = lambda cmd, env=None: s.post(f"{API}/v1/sandboxes/{sbx['id']}/exec", json={"cmd": cmd, "env": env or {}, "timeout_ms": 60000}).json()try: # The credential only in this command's env; a token would go where the canary is. run(f"git init -q pr && cd pr && git remote add origin https://github.com/jshttp/cookie.git && " f"git fetch -q --depth 1 origin {HEAD} && git checkout -q --detach FETCH_HEAD", {"GIT_CONFIG_COUNT": "1", "GIT_CONFIG_KEY_0": "http.extraHeader", "GIT_CONFIG_VALUE_0": "X-Canary: replace-me"}) s.post(f"{API}/v1/sandboxes/{sbx['id']}/egress", json={"mode": "allowlist", "allow": ["registry.npmjs.org"]}) run("cd pr && npm ci --ignore-scripts --no-audit --no-fund", {"npm_config_cache": "/tmp/npm"}) s.post(f"{API}/v1/sandboxes/{sbx['id']}/egress", json={"mode": "deny"}) tests = run("cd pr && npx --no-install vitest run", {"npm_config_cache": "/tmp/npm"}) deps = s.post(f"{API}/v1/actions/call", json={ "ref": "io.b3os/deps-dev/get-version@1", "input": {"system": "npm", "name": "vitest", "version": "4.1.9"}, }).json() note = s.post(f"{API}/v1/infer/chat/completions", json={ "model": "b3os/qwen3.5-9b", "temperature": 0, "chat_template_kwargs": {"enable_thinking": False}, "messages": [ {"role": "system", "content": "Write a three-sentence note for the maintainer from these facts only."}, {"role": "user", "content": json.dumps({"tests": tests["stdout"][-400:], "vitest": deps["output"]})}, ], }).json() print(note["choices"][0]["message"]["content"])finally: s.delete(f"{API}/v1/sandboxes/{sbx['id']}")
The remote B3OS MCP server creates the sandbox, runs commands and calls the action, but it has no tool
that changes a running sandbox's egress yet, so make the two POST /v1/sandboxes/{id}/egress calls with the API
(the curl tab) and ask your agent for the rest:
textIn sandbox <id>, run `npm ci --ignore-scripts` in /workspace/pr. When I say egress is denied, run the tests with`npx --no-install vitest run`.Look up vitest 4.1.9 on npm with the deps-dev get-version action. Tell me whether the tests passed and whether anyadvisory applies, then delete the sandbox.
The agent calls sandbox_exec, actions_call and sandbox_delete.
What the run checks, besides the tests passing: the canary is in neither the clone's git config, nor any file in the
guest (a search of the whole filesystem as root), nor the next command's environment, nor the API's answers about the
sandbox (GET /v1/sandboxes/{id}, its logs and its request log). A canary is not a token: a real token stays valid
until it expires, whoever fetched with it, so give the fetch the narrowest token there is, for one repository and
read only.
Owner: Docs. Products: Docs, Sandboxes, Actions and triggers, Infer.
Output of the last green run
bash$ node run.mjs# exit 0
json{ "repo": "jshttp/cookie", "pr": 289, "head": "f1d76f52b68f9161cc2b6d3093f151e774c6748b", "fetched": true, "egress_install": "allowlist", "packages_installed": 225, "github_refused_after_narrowing": true, "github_by_address_refused": true, "egress_tests": "deny", "tests_exit": 0, "test_files": 4, "tests_passed": 63743, "tests_failed": 0, "canary_in_git_config": false, "extraheader_in_git_config": false, "canary_files_count": 0, "canary_in_next_exec_env": false, "canary_in_api_answers": false, "deps_checked": 8, "deps_with_advisories": 1, "deps_deprecated": 0, "advisories": [ "GHSA-82fw-gwwq-j7x9" ], "licenses": [ "Apache-2.0", "MIT" ], "model": "b3os/qwen3.5-9b", "note": "All 63743 tests passed in 4 test files with no network. The repository includes one dependency with an advisory: vitest@4.1.9 (GHSA-82fw-gwwq-j7x9). There are no deprecated dependencies.", "create_ms": 245.9, "fetch_ms": 499.8, "install_ms": 1852.1, "tests_ms": 4100.3, "search_ms": 1049.9, "deps_ms": 1131.2, "note_ms": 335.4, "total_ms": 19654.4, "deleted": true}
The outputs this recipe publishes (its recipe.json publish.outputs), with workspace identifiers redacted. The run's stdout, stderr and other outputs are not published.
Captured 2026-11-01 from commit
cebfa5fc
, label
live-recorded
(recorded from production). Case
recipes/untrusted-pr-tests
.