docs: consolidate egress + gVisor docs into a worked Manifest section
test / run tests/run_tests.py (push) Successful in 17s
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:
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user