-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Summary
Investigate replacing the custom Docker-based egg sandbox with Claude Code's built-in sandboxing (@anthropic-ai/sandbox-runtime), while keeping the gateway sidecar for policy enforcement, credential isolation, and network filtering.
Motivation
The current sandbox uses a full Docker container with custom Squid proxy, dual Docker networks, and binary relocation tricks. Claude Code now ships with OS-native sandboxing (bubblewrap + seccomp on Linux, Seatbelt on macOS) that provides filesystem and network isolation out of the box. Moving to it would simplify deployment and eliminate container build/orchestration overhead.
Key Finding: httpProxyPort / socksProxyPort
The sandbox-runtime supports replacing its built-in proxy with an external one. When httpProxyPort is set, SRT skips starting its own HTTP proxy and bridges all sandboxed traffic to the specified port. This means we can route everything through the gateway sidecar:
Bubblewrap sandbox (no network namespace)
→ socat bridge (Unix socket)
→ Gateway sidecar (HTTP proxy + REST API)
→ Internet (filtered by mode)
Architecture Changes Required
| Component | Current (Docker) | Proposed (Claude Code sandbox) |
|---|---|---|
| Network isolation | Docker network namespace + Squid | Bubblewrap network namespace + socat bridge |
| Proxy | Squid (SNI filtering) | Gateway as HTTP CONNECT proxy |
| Git/GH interception | Binary relocation to /opt/.egg-internal/ |
PATH-based wrappers + NO_PROXY=localhost |
| Credentials | Not in container at all | denyRead on credential paths |
| Public/private mode | Docker network assignment | Gateway domain allowlist config |
| Binary availability | Only what Dockerfile installs | Host binaries available (deny what you can) |
| Anthropic API proxy | ANTHROPIC_BASE_URL → gateway |
Same, unchanged |
Gotchas and Open Questions
1. Gateway must become an HTTP CONNECT proxy
The gateway currently exposes a REST API. It needs to also handle CONNECT tunnel requests to act as a forward proxy. Recommended approach: two ports — REST API on 9848 (for git/gh wrappers via NO_PROXY=localhost), HTTP proxy on 3129 (for general traffic via httpProxyPort).
2. Host binary contamination (gcloud, aws, docker, etc.)
Docker gives default-deny: nothing exists unless installed. Claude Code sandbox gives default-allow with deny rules. Binaries like gcloud are present on the host and functional if their domains are allowed and credentials are readable.
Mitigations:
denyReadon~/.config/gcloud/,~/.aws/,~/.ssh/,~/.kube/,~/.docker/,~/.gnupg/- Domain blocking at the gateway level
- Linux
denyReaddoes not support glob patterns — paths must be enumerated literally
3. Programs ignoring HTTP_PROXY silently fail
Bubblewrap removes the network namespace entirely. Programs respecting HTTP_PROXY/HTTPS_PROXY work; others get "network unreachable". This is actually stronger than Docker (hard block vs soft), but may break tools with custom network stacks.
4. Public/private mode switching
Currently per-container via Docker network assignment. New approach: configure gateway domain allowlist at startup. SRT supports dynamic config updates via --control-fd (JSON-lines), enabling runtime mode switching without restart.
5. excludedCommands interaction
docker is explicitly incompatible with the sandbox and must be in excludedCommands. Known bug: when allowUnsandboxedCommands: false, excluded commands still attempt sandboxed execution first and fail (anthropics/claude-code#19135).
6. Linux-specific limitations
- No glob patterns in filesystem paths (only literal paths)
- Bind-mount deny rules only affect files existing at sandbox creation time
- Requires
bubblewrapandsocatpackages on host
7. Credential isolation is weaker
Docker: zero credentials in container. Claude Code sandbox: credentials exist on host, blocked via denyRead. Environment variables are inherited unless scrubbed before launch. Need explicit env scrubbing for GITHUB_TOKEN, cloud credentials, etc.
8. Nested sandbox concerns
If running Claude Code inside Docker (e.g., CI), enableWeakerNestedSandbox: true is required, which substantially weakens namespace isolation. The outer container provides the boundary in that case.
Proposed Settings
{
"sandbox": {
"network": {
"httpProxyPort": 3129,
"socksProxyPort": 1080,
"allowedDomains": ["*"]
},
"filesystem": {
"denyRead": ["~/.ssh", "~/.aws", "~/.config/gcloud", "~/.kube", "~/.docker", "~/.gnupg"],
"allowWrite": ["."],
"denyWrite": [".env", "secrets.env"]
}
}
}Tasks
- Add HTTP CONNECT proxy capability to the gateway sidecar
- Convert git/gh wrappers from binary-relocation to PATH-based approach
- Implement credential path deny list for host environments
- Add environment variable scrubbing at launch
- Implement public/private mode via gateway domain allowlist config
- Test
gcloud,aws,dockerbehavior under sandbox restrictions - Validate git/gh wrapper behavior with
NO_PROXY=localhostbypass - Evaluate
--control-fdfor runtime mode switching
— Authored by egg