5.8 Sandboxing
bazel build //app:binary --sandbox_debug --verbose_failures can leave you
staring at a missing file inside a directory that looks almost like Bazel's
normal execroot. The tempting explanation is simply “the sandbox blocked it.”
That phrase hides every useful question: Was the file absent from the action
contract? Did the input view omit it? Could the process still reach it through
the host? Which sandbox backend actually ran?
The consultant's model is a boundary stack. Start with what the action declared. Then ask how Bazel presented those declared inputs to the process, what the operating system prevented beyond that view, and what the failed spawn or profile actually proves. The layers reinforce one another, but none can stand in for the others. A complete declaration does not describe the strength of the OS boundary. A strict backend does not repair a missing input. A green sandboxed build does not prove that no ambient dependency remains.
Follow the boundary from contract to evidence
See the filesystem Bazel gives one action
Begin with 5.8.1 Symlink Forests. It distinguishes Bazel's shared execroot from the execroot-shaped tree prepared for one sandboxed spawn, then separates that input presentation from the stronger restrictions supplied by a concrete backend. This is the foundation for the rest of the section: without the two execroots and two jobs straight, both missing-file diagnosis and setup-cost analysis become guesswork.
The historical sandboxfs subsection in 5.8.1 Symlink Forests is the
counterexample to the ordinary symlink-tree design. Read that subsection after
the current mechanism when the question is whether filesystem virtualization
can remove sandbox setup cost. Its lesson is about cost placement: changing how
a view is materialized can trade host filesystem mutations for manifest and
per-access work. It is safe to skip on a first pass because sandboxfs is not a
current Bazel strategy.
The mental shift is from treating “sandboxed” as a binary property to asking four ordered questions:
- What inputs, tools, outputs, environment, and command did the action declare?
- How were those declarations presented at their exec paths?
- What could the concrete backend prevent outside that prepared view?
- What runtime or profile evidence shows where behavior diverged?
Skipping a question encourages category errors. An undeclared input is a contract defect, not a slow filesystem. A host-policy denial is not evidence that a relative input was unstaged. A larger input set suggests more potential staging work, but does not by itself prove where the elapsed time went.
Turn a failure into a contract repair
5.8.2 Diagnosing Sandbox Issues turns the stack into an investigation. It
starts with one retained failing spawn, uses the printed working directory
rather than a guessed sandbox path, and reconciles the attempted access with
the post-analysis action shown by aquery. It also keeps a local-strategy
comparison in its proper role: useful evidence for an ambient-dependency
hypothesis, not a production fix.
This is the section's operational center. Read it immediately after the symlink-forest foundation if you arrived with a failure or a performance incident. Return to the backend-specific article only when the evidence points at platform enforcement, and to the historical subsection only when evaluating a filesystem-presentation design or an old recommendation.
Add the platform branch when macOS is in scope
5.8.3 macOS Sandboxing Challenges follows the core diagnostic path as a recommended
platform branch. It separates the sandboxed selector from the concrete
darwin-sandbox and processwrapper-sandbox backends, including fallback and
the limits of the host policy. Its transferable habit is to record the backend
that actually ran, then state precisely what its prepared input view and OS
mechanism do.
Classify: A sandboxed action reports a missing file. Which four layers must you separate before choosing a repair?
Reveal
Check the declared action contract, the prepared filesystem view, the concrete sandbox backend and policy, and the observed access mismatch or measured cost. An undeclared input requires a contract repair. A missing staged path implicates presentation. A host-policy denial implicates enforcement. An unknown layer is the next evidence to collect, not a blank to fill from another layer.
Scale the same questions without copying a local design
Remote workers split this boundary stack across distinct owners. Use
6.3.9 Remote Executor Environments and Isolation for process, container, or VM isolation,
executor lifecycle, cleanup, and cross-action residue. Use
6.3.10 Remote Input Presentation for eager or lazy input-root materialization,
filesystem presentation, and CAS GetTree traversal. At production scale
those components can have separate bottlenecks and evidence, so continue with
the reference that matches the layer implicated by the incident.
The local symlink forest is therefore a useful first mechanism, not a universal architecture. What survives across environments is the sequence of questions: establish the declared action, identify how its input root appears, name the enforcement boundary, and measure the layer implicated by the symptom.
Choose the shortest useful path
For a general consulting toolkit, read 5.8.1 Symlink Forests and 5.8.2 Diagnosing Sandbox Issues first. They provide the filesystem model and the evidence-first workflow. Add 5.8.3 macOS Sandboxing Challenges whenever macOS is in scope or silent backend fallback would change the required boundary.
Skim the historical sandboxfs subsection in 5.8.1 Symlink Forests for its
performance-design lesson, not for a flag to enable. Save
6.3.9 Remote Executor Environments and Isolation and 6.3.10 Remote Input Presentation until the incident
crosses from a local spawn into remote-worker architecture, then select between
them by the isolation/lifecycle versus input-presentation boundary. Avoid
beginning with a blanket strategy change or a favorite sandbox technology:
first locate the failed or slow layer, then choose the evidence and remedy that
address it directly.
Sandboxing is a boundary stack, not one switch: the action contract names the intended inputs and outputs, the filesystem view presents them, the concrete backend adds a platform-specific enforcement boundary, and runtime evidence shows where reality diverged. Learn the symlinked view and diagnostic workflow first. Use the platform article, historical lesson, and production references when the incident reaches those layers.
Sections in this chapter · 3
How symlinked per-action sandboxes map declared exec paths to backing files, where setup cost comes from, and how Bazel reuses directories.
Preserving one failed sandbox, reconciling runtime access with the action contract, and testing ambient-dependency and performance hypotheses.
How macOS selects and enforces darwin-sandbox, where it falls back, and how to choose local and CI strategy from evidence.