Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Sandboxing tiers

Hermeticity is enforced, not trusted. Every action runs inside a sandbox that makes its declared inputs available and undeclared ones unreachable — so a forgotten dependency fails the build instead of silently working on your machine and breaking on someone else’s.

zut picks the strongest tier the host supports by default. Override with --sandbox=<tier> or sandbox = <tier> in .zutrc.

The tiers (a capability ladder)

namespace — the hermetic-leaning tier (Linux)

Runs the action inside fresh user + mount + pid + net + ipc + uts namespaces:

  • user ns — your uid/gid map to root inside, so zut can mount without real privileges (works wherever unprivileged user namespaces are allowed);
  • mount ns — the host / is bind-mounted recursively read-only (so /home, /run, /dev/shm can’t be written either); the execroot is an overlayfs (materialized inputs as the read-only lower, a writable upper for the action’s outputs); pivot_root then makes the contained tree the root;
  • pid ns — the action runs as PID 1 under a thin reaper that also enforces timeout_ns;
  • net ns — no network (builds can’t fetch);
  • ipc/uts ns — isolated SysV IPC and hostname.

Result: the action can read the toolchain, its inputs are tamper-proof, and it can only write to its overlay upper and a private /tmp.

landlock — write-containment (Linux 5.13+)

Uses the Landlock LSM to confine writes to the work directory while allowing reads, without namespaces. A good fit where unprivileged user namespaces are disabled but Landlock is available.

prep — preparation only (portable, non-hermetic)

Materializes the action’s declared inputs into a clean work directory (so the inputs are right) but does not isolate the action from the rest of the filesystem. This is the fallback on non-Linux hosts and the weakest tier — use it only when the stronger tiers are unavailable.

Choosing a tier

$ zut build //:app                      # strongest available (recommended)
$ zut build //:app --sandbox=namespace  # force the namespace tier
$ zut build //:app --sandbox=prep       # opt out of isolation (debugging)

The chosen tier is printed in the build header:

  sandbox: namespace (recursive ro host, net+pid isolated)

Known limitations

Full input hermeticity still reads the host toolchain (it isn’t a declared, content-addressed input yet); recursive read-only makes that tamper-proof but not yet reproducible across hosts. This — plus seccomp hardening and the Landlock setup-status pipe — is tracked on the roadmap.

The full design, including the threat model and the syscall-level details, is in docs/ARCHITECTURE.md §7.