feat(sandbox): integrate @anthropic-ai/sandbox-runtime as outer sandbox layer#7
Merged
linuxdevel merged 13 commits intomainfrom Mar 20, 2026
Merged
Conversation
…dboxRuntimeConfig
Replace linuxCheck with platformCheck (passes on linux and darwin). Replace unshareCheck with bwrapCheck (bubblewrap is now the outer isolation layer). Add socatCheck and ripgrepCheck for sandbox-runtime network proxy and search tool dependencies. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rop inside bwrap When the native helper binary is found, Sandbox.execute() now writes the policy (filesystem + syscalls) to a mode-0600 temp file and runs: helper --policy-file <tmp> -- command [args] as the inner command inside the bwrap container. This re-enables the Landlock filesystem restrictions and capability-drop layer (Phase 2). enforcement.landlock and enforcement.capDrop are now true when the helper is present. The temp file is cleaned up in both close and error handlers. If the helper is in a non-system directory, its parent is added to rtConfig.filesystem.allowWrite so bwrap bind-mounts it into the container. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…p failure PolicyBuilder.toRuntimeConfig() used to include all sensitive home dirs (~/.ssh, ~/.aws, etc.) in denyRead unconditionally. bwrap cannot mount tmpfs over non-existent paths or symlinks to external filesystems (e.g. WSL2 symlinks pointing to /mnt/c/...), causing the sandbox command to fail with "Can't mount tmpfs on /newroot/home/...". Fix: use lstatSync to filter denyRead to only include paths that are real directories (not symlinks, not missing). Symlinks to Windows paths on WSL2 are excluded. Update sandbox.test.ts and policy-builder.test.ts mocks to cover the new lstatSync import. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- README: add macOS to platform requirements; add bubblewrap/socat prerequisites; update sandbox description and @safeclaw/sandbox blurb; mark Feature 5 (sandbox-runtime integration) as Done - AGENTS.md: update platform note (Linux + macOS); rewrite Sandbox section to reflect SandboxManager/wrapWithSandbox outer layer and --policy-file inner protocol; add SandboxManager.initialize() to bootstrap flow - docs/getting-started.md: add bubblewrap/socat to prerequisites; replace kernel-only verification with bwrap/socat checks; update doctor command category description - docs/sandboxing.md: rewrite architecture diagram to show two-layer model (sandbox-runtime outer + C helper inner); update Layer 1 from unshare to sandbox-runtime/bwrap; document PolicyBuilder.toRuntimeConfig and WSL2 symlink handling; update policy delivery from fd 3 to --policy-file; add pivotRoot/bindMounts to EnforcementLayers; update graceful degradation table; update platform requirements section - docs/security-model.md: rewrite sandboxing architecture intro for two-layer model; update namespaces section to reference bwrap; fix development policy (remove ~/.safeclaw from readwrite — it was never included; home dir is read-only) - docs/architecture.md: update @safeclaw/sandbox description; update Linux-only design decision to Linux + macOS; update doctor description Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
bootstrap.ts imports SandboxManager directly from @anthropic-ai/sandbox-runtime but the package was only declared as a dependency of @safeclaw/sandbox, not @safeclaw/cli, causing a TS2307 build error. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GitHub's device flow returns 'slow_down' when the client polls too frequently. The previous code threw 'Token poll error: slow_down', which looked like an immediate failure during onboarding. - Handle slow_down by increasing the interval by 5 s (as required by the GitHub Device Flow spec) and continuing to poll - Add AbortSignal.timeout(30s) to requestDeviceCode and pollForToken fetch calls (consistent with CopilotClient.REQUEST_TIMEOUT_MS) - Update existing fetch call assertions to expect AbortSignal - Add test: slow_down increases interval and retries successfully Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
getCopilotToken had no AbortSignal, causing an indefinite hang after the GitHub device flow poll succeeded but the Copilot API token exchange stalled. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
@anthropic-ai/sandbox-runtimeas the outer sandbox layer (bubblewrap on Linux, sandbox-exec on macOS), replacing the previous unshare-based approachSandboxPolicytoSandboxRuntimeConfigviaPolicyBuilder.toRuntimeConfig(), with a denylist for credential dirs (.ssh,.aws, etc.) usinglstatSyncto skip symlinks (avoids bwrap failure on WSL2 paths)safeclaw-sandbox-helper) as the inner process via--policy-file <tmp>when available, enabling Landlock + seccomp + cap-drop inside the bwrap containerdoctorchecks: replaceslinuxCheck/unshareCheckwithplatformCheck(Linux+macOS) andbwrapCheck, addssocatCheckandripgrepCheckfor sandbox-runtime dependenciesCommits
9e92639@anthropic-ai/sandbox-runtimegit dependencyeff4215NetworkPolicytype andEnforcementLayers/KernelCapabilities00753c8PolicyBuilder.toRuntimeConfig()c25704119d12a9Sandbox.execute()to useSandboxManager.wrapWithSandbox()86766b2SandboxManagernetwork proxy before constructingSandbox4bfacad67aa8dc--policy-filefor Landlock + cap-drop inside bwrap2414d0fdenyReadpaths by real directories to avoid bwrap failure on WSL2 symlinksTest Plan
pnpm test— 693 tests pass (63 test files)pnpm lint— zero diagnosticspnpm typecheck— zero errors~/.aws → /mnt/c/...) are excluded from bwrap denyRead config🤖 Generated with Claude Code