Skip to content

Build sandbox

Draft Defined in RFC 0001 §9 Mechanism unshare(2)

A reproducible description is only half of a reproducible build. The build itself must not be able to reach anything the description does not mention, such as a library that happens to be installed on the host, a file in a home directory, or a server on the network. Lattice prevents this by running every build in a fresh set of Linux namespaces that it creates itself through the unshare(2) system call. No Docker, Podman or Bubblewrap is involved.

Isolation

Namespace What the build sees
User It runs as root inside the sandbox, but only as the unprivileged Lattice user on the host.
Mount Its own filesystem tree, which the host never sees and which disappears when the build ends.
Network A loopback interface and nothing else. There is no route to any other machine.
PID Its own process tree, in which the builder is PID 1. Host processes are invisible.

Filesystem

The root of the sandbox is an empty tmpfs. Lattice creates two writable directories in it, /build for the build to work in and /out for what it produces. The store paths of the build's declared inputs are mounted read-only at their usual locations, and a fresh /proc is mounted for the sandbox's own processes. Nothing else from the host is present, so a write anywhere outside /build, /out and the temporary root fails.

One build, start to finish

---
config:
  themeVariables:
    fontSize: 16px
  flowchart:
    useMaxWidth: false
  sequence:
    useMaxWidth: false
---
sequenceDiagram
    participant L as Lattice
    participant S as Sandbox
    L->>S: create namespaces
    S->>S: build root, mount inputs read-only
    S->>S: run builder in /build
    S-->>L: exit status
    L->>L: check every declared output exists
    L->>L: copy outputs to staging, tear down

When the builder exits, the kernel ends every process it started, because they all belong to the sandbox's PID namespace. Lattice checks that each output the derivation declared is present in /out. If one is missing or the builder failed, nothing is published.

Host requirements

The sandbox needs unprivileged user namespaces, which most current Linux kernels provide. Some distributions restrict them by default, for example Ubuntu through the kernel.apparmor_restrict_unprivileged_userns setting. In that case Lattice reports the problem and refuses to build, rather than falling back to a build without isolation.

The full specification, including the order of system calls and why the builder needs a second fork, is in RFC 0001 §9.