Repository navigation
Sandbox fixes: launch status, shared denies, CA trust, copies - #5
Merged
Merged
Conversation
The override decides every launch, but `sandbox <name>` and `list` only read the .sandbox marker, so with it set they could report a microVM for a profile that launches on the host. Both now say when the override is set and what it does, and `sandbox --on/--off` says so when the override contradicts the new setting. They also read the marker the way the launch does: a dangling marker link counts as sandboxed. `sandbox --on` replaces a linked marker instead of touching, and so creating, the file the link points at.
The sandbox's copy of the profile's settings.json drops deny rules such as Bash(sudo *), which would otherwise block the VM's own scoped sudo (deny wins even under --dangerously-skip-permissions). Shared settings from shared-settings.json reach claude through --settings and kept them, so a shared sudo deny still blocked sudo dnf and sudo podman in the VM. Sandbox launches now drop the same denies from the shared settings; host launches keep them.
Both were mounted straight from the host with :z, which relabels the user's own files for containers (known_hosts loses its ssh_home_t label) out from under the host's tools and restorecon. The VM now gets copies in the profile's state dir, refreshed every launch, and :z relabels those, as the launcher already does for the claude binary.
When the host has custom CA anchors, the entrypoint ran update-ca-trust extract on every boot, which takes about 7 s in the VM. The host's own update-ca-trust has already merged those anchors with its system roots into /etc/pki/ca-trust/extracted, so the launcher now mounts that directory read-only at the same path, alongside the anchors, and the entrypoint no longer extracts. Boot to exit fell from 13.7 s to 4.6 s on a host with six anchors, with every anchor still trusted. Anchors without an extracted directory warn and mount neither.
Each host update of claude copied the 244 MiB native binary into the data dir for the sandbox. On Python 3.13, shutil.copy writes every block of it, and snapshots then keep each old version pinned. The copy now asks the kernel to share the binary's blocks (FICLONE), which is instant and takes no space on btrfs or XFS, and falls back to a plain copy elsewhere or across filesystems.
podman run passes the host's http_proxy, https_proxy, no_proxy and the like into the container by default, so a proxy URL's credentials reached the VM although the launcher forwards nothing else from the host environment. Sandbox launches now pass --http-proxy=false; a proxy the VM needs can be forwarded with CLAUDE_PROFILE_SANDBOX_FORWARD_ENV.
The digest-pinned FROM line and the printf that writes storage.conf ran past 100 characters. The digest moves into an ARG ahead of FROM, and printf takes one argument per line as the sudoers step does. The build resolves the same base digest and writes a byte-identical storage.conf.
The security section described what the VM can change but not which credentials it can read or use. It now lists what every launch hands the VM (the profile's Claude login, .env values, MCP tokens in .claude.json and ancestor .mcp.json files, a copy of ~/.gitconfig), what each opt-in setting adds, and what is not mounted.
3 of 5 tasks
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.
Stacked on #4: merge #3 and #4 first. GitHub retargets this pull request as their branches are deleted.
Smaller sandbox fixes, one commit each.
What it does
claude-profile sandbox <name>andlistsay whenCLAUDE_PROFILE_SANDBOXoverrides the profile's own setting, andsandbox --on/--offsays so when the override contradicts the change. Both read a dangling marker link as the launch does (sandboxed), and--onreplaces a linked marker instead of creating the file it points at.Bash(sudo,Read(~/.ssh, …) fromshared-settings.jsonas they already do from the profile'ssettings.json, so a shared sudo deny no longer blocks the VM's scopedsudo dnfandsudo podman. Host launches keep them.~/.gitconfigand~/.ssh/known_hostsfrom the profile's state dir, refreshed each launch, instead of:zrelabelling the user's own files./etc/pki/ca-trust/extracted) read-only, and the entrypoint no longer runsupdate-ca-trust extract, which took about 7 s per launch. Boot to exit went from 13.7 s to 4.6 s on a host with six anchors, every anchor still trusted.FICLONEwhere the filesystem supports it (btrfs, XFS) and a plain copy elsewhere, so a claude update no longer writes another 244 MiB.--http-proxy=falsekeeps the host's*_proxyvariables, and any credentials in them, out of the VM;CLAUDE_PROFILE_SANDBOX_FORWARD_ENVforwards them when a proxy is needed.ARG), and the README lists the credentials each launch, and each opt-in setting, gives the VM.The sandbox image needs a rebuild: the entrypoint and Containerfile changed.
Test plan
prek run --all-filespasses (390 tests)https_proxystays out, all six host anchors trusted, the gitconfig and known_hosts copies readable, git config read-onlystorage.confshutil.copyshared none