docs: consolidate egress + gVisor docs into a worked Manifest section
test / run tests/run_tests.py (push) Successful in 17s

Replaces the standalone Egress section with a Manifest section that
shows a complete bottle + agent example, with the egress and gVisor
explanations folded into JSONC comments above the relevant keys. The
gVisor paragraph in Security model is trimmed to a one-line pointer
at the manifest example.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-10 01:47:52 -04:00
parent c8a35beb12
commit e7cfc91ca5
+59 -39
View File
@@ -37,24 +37,9 @@ the host: a misbehaving Claude Code session can't read files outside
the bottle, can't reach the host's network without going through the bottle, can't reach the host's network without going through
pipelock, and can't see other bottles. By default it is not a hardened pipelock, and can't see other bottles. By default it is not a hardened
boundary against a determined attacker with kernel-level escape boundary against a determined attacker with kernel-level escape
capability — see `docs/research/stronger-isolation-alternatives.md` capability — Linux hosts can opt into [gVisor](https://gvisor.dev/)
for the broader v2 discussion. per bottle (see `runtime` in the manifest below); the broader v2
discussion lives in `docs/research/stronger-isolation-alternatives.md`.
Linux hosts can opt into [gVisor](https://gvisor.dev/) per bottle for
a userspace syscall barrier between the agent and the host kernel:
```jsonc
{
"bottles": {
"default": { "runtime": "runsc" }
}
}
```
When `runtime` is set to `"runsc"`, claude-bottle verifies the runtime
is registered with Docker before launch and passes `--runtime=runsc`
to the agent container. Default is `"runc"` (Docker's default). gVisor
is not available on macOS.
The egress proxy and OAuth-token handling below are the load-bearing The egress proxy and OAuth-token handling below are the load-bearing
pieces of v1. pieces of v1.
@@ -72,37 +57,72 @@ The container is removed automatically when the session ends. If the script
is killed with SIGKILL the exit trap won't fire and the container may be is killed with SIGKILL the exit trap won't fire and the container may be
left running; remove it with `docker rm -f <container-name>`. left running; remove it with `docker rm -f <container-name>`.
## Egress ## Manifest
Agent containers route HTTP / HTTPS traffic through a per-agent Agents and the bottles they run in are declared in `claude-bottle.json`
[pipelock](https://github.com/luckyPipewrench/pipelock) sidecar in your project root or `$HOME` (both files merge if present, with
attached to a Docker `--internal` network. The sidecar enforces a project entries overriding home entries on key conflict).
hostname allowlist, runs DLP scanning (48 default credential
patterns), and detects URL-embedded high-entropy secret leaks. Without
the proxy the agent has no route off-box at all — the internal network
has no default gateway. The sidecar and network are torn down with the
agent on session exit.
The effective allowlist is the union of a baked-in default for Claude
Code's required hosts (`api.anthropic.com`, `claude.ai`, ...) and the
optional `bottles.<name>.egress.allowlist` field in
`claude-bottle.json`:
```jsonc ```jsonc
{ {
"bottles": { "bottles": {
"default": { "gitea-dev": {
"env": { }, // Container runtime for the agent. Default "runc"; set to
"ssh": [ ], // "runsc" on Linux hosts to launch the agent under gVisor for
"egress": { "allowlist": ["github.com"] } // a userspace syscall barrier between the agent and the host
// kernel. claude-bottle verifies the runtime is registered with
// Docker before launch; gVisor is not available on macOS.
"runtime": "runsc",
"env": {
"GITEA_TOKEN": "?paste your Gitea API token",
"GITHUB_TOKEN": "${GH_PAT}",
"GIT_AUTHOR_NAME": "Eric Diderich"
},
"ssh": [
{
"Host": "gitea",
"Hostname": "gitea.dideric.is",
"User": "git",
"Port": 30009,
"IdentityFile": "/Users/didericis/.ssh/id_ed25519_gitea",
"KnownHostKey": "gitea.dideric.is ssh-ed25519 AAAA..."
}
],
// Egress is forced through a per-agent
// [pipelock](https://github.com/luckyPipewrench/pipelock) sidecar
// on a Docker `--internal` network — without the proxy the agent
// has no route off-box. The effective allowlist is the union of
// baked-in defaults (api.anthropic.com, claude.ai, ...) and the
// hostnames listed here. Pipelock also runs DLP scanning and
// detects URL-embedded high-entropy secrets. The resolved
// allowlist is shown in the y/N preflight before launch.
"egress": {
"allowlist": [
"github.com",
"registry.npmjs.org",
"pypi.org"
]
}
}
},
"agents": {
"gitea-helper": {
"bottle": "gitea-dev",
"skills": ["init-prd"],
"prompt": "You help maintain Gitea-hosted projects."
} }
} }
} }
``` ```
The resolved allowlist is shown in the y/N preflight before launch. Comments are illustrative; the file itself must be valid JSON. See
See `docs/prds/0001-per-agent-egress-proxy-via-pipelock.md` for the `claude-bottle.example.json` for a working starting point. Pipelock's
design and `docs/research/pipelock-assessment.md` for the rationale. design lives in `docs/prds/0001-per-agent-egress-proxy-via-pipelock.md`
and the rationale in `docs/research/pipelock-assessment.md`.
## Auth: OAuth token, not API key ## Auth: OAuth token, not API key