feat: a :sandbox keyword for parenting-spawn - #1
Merged
Merged
Conversation
Turn a bwrap-jail spec into the command-wrapper, child-socket-path and child-library-directory for the caller, so a child can be launched under bubblewrap without hand-assembling any of that. The jail runs with --die-with-parent, a minimal read-only root, a private /tmp, /proc and /dev, and a cleared environment. The control socket's directory is bound read-write at its own path so the socket crosses the mount namespace, and the parenting sources read-only at their own path so the child loads them and the parent can still verify they are readable. :sandbox is mutually exclusive with the three keywords it derives. The bwrap line is built by parenting--sandbox-command-wrapper, a pure function unit-tested without spawning. A guarded integration test spawns a real child under the jail and skips cleanly where unprivileged user namespaces are unavailable. Co-Authored-By: Claude Opus 4.8 <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.
What
Adds a
:sandboxkeyword toparenting-spawn. When non-nil it is a plist describing a bubblewrap jail;parenting-spawnderives thecommand-wrapper, and the socket and library-directory crossing, from it, so a caller gets an isolated child without hand-assembling a bwrap line.Spec fields, all optional:
:ro-binds— extra read-only binds (paths or(SRC . DEST)), also the field for project directories the child may read.:rw-binds— extra read-write binds, same shape.:environment— a list of env var NAMES to carry into the otherwise-cleared jail; unset names are dropped.:network— non-nil to share the host network (default: none).:sandboxis mutually exclusive with:command-wrapper,:child-socket-path, and:child-library-directory, since it sets all three; passing any alongside it signals an error. Every other spawn keyword still applies.How the socket and sources cross the namespace
The socket's private directory is bound read-write at the same path, so the in-jail socket path equals the parent's and
child-socket-pathkeeps its default. The parenting sources are bound read-only at the same path, sochild-library-directorystays nil and the bootstrap's readability check stays on. Under:sandboxonlycommand-wrapperis actually rebound; the rest falls out of existing defaults.New symbols
parenting--sandbox-command-wrapper (spec socket-directory library-directory)— the pure bwrap-line builder (--die-with-parent --unshare-all,--share-netonly with:network, ro-binds of the existing system dirs,--ro-bind /nix/store /nix/storewhen present,--tmpfs /tmp --proc /proc --dev /dev,--clearenvthen baseline env, HOME on the tmpfs, pass-through vars).parenting--sandbox-bind-args (flag binds)— bind-list helper.parenting-sandbox-program,parenting-sandbox-system-directories,parenting-sandbox-default-environment.Tests
Five pure unit tests over the generated bwrap argument list (core flags, network toggle, nix-store bind, environment pass-through, extra binds), a negative test for the mutual-exclusion error, and a guarded integration test that spawns a real child under the jail and evals in it, skipping via
ert-skipwhen bwrap cannot create a user namespace.Run locally with emacs and bubblewrap present:
Ran 54 tests, 51 as expected. The three failures areparenting-remote-daemon-child,parenting-spawn-daemon-child-is-interactive, andparenting-spawned-interactive-child-exits-on-close, which fail identically on cleanmain(44/47) in a headless environment with no display; all eight new sandbox tests pass and the integration test ran rather than skipped. Byte-compiles clean underbyte-compile-error-on-warn.🤖 Generated with Claude Code