Skip to content

feat: pluggable sandbox backends: bwrap, Landlock, macOS sandbox-exec - #4

Merged
clhodapp merged 1 commit into
mainfrom
feat/sandbox-backends
Sep 28, 2026
Merged

clhodapp merged 1 commit into
mainfrom
feat/sandbox-backends

Conversation

@clhodapp

Copy link
Copy Markdown
Owner

The :sandbox spec (paths, environment, network) stays as it is; what enforces it is now chosen by parenting-sandbox-backend:

  • bwrap, the default on GNU/Linux, unchanged.
  • landlock, Landlock through the landrun launcher (parenting-sandbox-landlock-program). No namespaces, so it works where unprivileged user namespaces are disabled.
  • sandbox-exec, the default on macOS: a deny-by-default Seatbelt profile, with parenting-sandbox-exec-extra-rules for rules a child turns out to need.
  • a function, called with the spec, the socket directory and the library directory, returning the command prefix.

Landlock and Seatbelt grant paths in place, so a (SRC . DEST) remapping stays bwrap only (an error on the others), and an ungranted path can still be probed for existence (stat, access) but not read, listed or written. Both clear the environment to HOME, the baseline, and the named pass-through variables. parenting-spawn now creates HOME and TMPDIR under the socket directory for every backend. Landlock restricts TCP, not UDP.

Tests: the dispatch, both new command builders, and a live Landlock child that answers over the socket, has a writable HOME, does not see an unpassed variable, and is refused a file outside its grants. Locally, with landrun 0.1.15 on Linux 7.2, all 62 tests pass, both live sandbox tests included; in CI the live Landlock test skips when landrun is absent. The sandbox-exec backend is tested as generated text only and has not been run on macOS.

🤖 Generated with Claude Code

The :sandbox spec (paths, environment, network) stays as it is; what
enforces it is now chosen by parenting-sandbox-backend: bwrap (the
default on GNU/Linux, unchanged), landlock through the landrun
launcher, sandbox-exec (the default on macOS) with a deny-by-default
Seatbelt profile, or a function returning the command prefix.

Landlock and Seatbelt grant paths in place, so a (SRC . DEST)
remapping stays bwrap only and is an error there, and an ungranted
path can still be probed for existence but not read, listed or
written. Both clear the environment to HOME, the baseline, and the
named pass-through variables; parenting-spawn now creates HOME and
TMPDIR under the socket directory for every backend. Landlock
restricts TCP, not UDP.

Tests cover the dispatch, both new command builders, and a live
Landlock child that answers over the socket, has a writable HOME,
does not see an unpassed variable, and is refused a file outside its
grants. The sandbox-exec backend is tested as generated text only; it
has not been run on macOS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@clhodapp clhodapp self-assigned this Sep 28, 2026
@clhodapp
clhodapp merged commit 5195c39 into main Sep 28, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant