> ## Documentation Index
> Fetch the complete documentation index at: https://docs.beta.b3os.org/llms.txt
> Use this file to discover all available pages before exploring further.

# 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:

1. The fetch gets the credential in that one command's environment, as `GIT_CONFIG_COUNT`, `GIT_CONFIG_KEY_0` and
   `GIT_CONFIG_VALUE_0`. git reads them as runtime config: the value is not written to `.git/config` and, unlike
   `git -c`, is in no process's argv. The recipe sends a random canary in place of a token, then looks for it.
2. `POST /v1/sandboxes/{id}/egress` narrows the sandbox to `registry.npmjs.org`, and `npm ci --ignore-scripts`
   installs the lockfile's packages without running their install scripts. github.com is now refused, by name and by
   address.
3. The same call narrows egress to `deny`, and the PR's tests run with no network at all.
4. Outside the sandbox, the `io.b3os/deps-dev/get-version` action 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

**curl**

```bash
API=https://beta-api.b3os.org
AUTH="Authorization: Bearer $B3OS_API_KEY"
HEAD=f1d76f52b68f9161cc2b6d3093f151e774c6748b
run() { 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_code

curl -s "$API/v1/sandboxes/$SBX/egress" -H "$AUTH" -H "Content-Type: application/json" \
  -d '{"mode": "allowlist", "allow": ["registry.npmjs.org"]}' | jq .egress
run "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 .egress
run "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
```
**TypeScript**

```ts
const 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}`);
}
```
**Python**

```python
import json
import os
import requests

API = "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']}")
```
**MCP**

The remote [B3OS MCP server](/sdks/mcp) 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:

```text
In 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 any
advisory 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

**Command**

```bash
$ node run.mjs
# exit 0
```
**Outputs**

```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`.