Heimdall and Build Thing
Heimdall is a defensive sandbox. This document says where it sits next to Build Thing (edda's nornir-build-thing): what lives in this repository, what Build Thing drives, and how the same probe run also feeds the measured kernel trim.
The split: Heimdall is its own repository, Build Thing drives it
| Part | Where it lives | Why |
|---|---|---|
| The sandbox runtime: container, broker, wasm host, signed results | This repository, its own crates | It runs in production inside Holger, Gunnar and pods; Build Thing is never in production. |
The probe and profile generator (heimdall-probe) | This repository, as a library | Generic: every product uses the same one. |
| Running it: build, probe, generate, review, drift check | A Build Thing pipeline step that calls heimdall-probe as a library | Build Thing already knows every row, payload, arch and test suite. Runtime code calls Rust libraries, never xtask. |
| The review | The Build Thing UI shows the profile diff and the near-miss calls; a person approves | Spec §3.1 step 5: never auto-merged into a release branch. |
| The drift check | A Build Thing gate, beside the kernel canary | The build fails when a program makes a new system call, naming the call and the test that made it. |
One "measure" step, two outputs
The measured kernel trim (tunnr 1.1) and Heimdall's profile generator share one idea: run the full check suite and watch what is really used. Build Thing runs that suite once, on a probe kernel, and gets two results:
- Kernel coverage → candidate kernel-option vetoes for the row, explained through edda's Kconfig graph (
kconfig_graph.rs,kernel.why.toml). Each veto is kept only after a full rerun, with a receipt. - System calls per payload → Heimdall seccomp profiles (spec §3), one per program, arch and libc.
They feed each other. When no payload on a row ever calls io_uring_setup, the kernel trim knows IO_URING can go on that row; the syscall profile is the proof.
build row ─► probe kernel (coverage on) ─► full check suite
│
┌─────────────────────────────────┴────────────────┐
▼ ▼
kernel code executed system calls per payload
│ │
Kconfig graph: unused symbols heimdall-probe: merge + minimise
│ │
veto candidates (one at a time, profiles/<workload>/<arch>-<libc>
full rerun, receipt) (.rs + .json)
└──────────────► review in the Build Thing UI ◄────┘
│
checked in; drift gate in CI
Coverage risk
A path the suite never ran looks unused. Both halves therefore:
- run the FULL failure suite (HA failover, rolling upgrade, drive move, power cut, error injection), not only the happy path;
- keep a protect list (block-layer errors, watchdog, NVMe reset; for profiles, the near-miss report of calls seen only in error paths);
- fail closed: a missing system call kills the worker, a wrongly vetoed kernel option fails the rerun before it is kept.
tunnr / rusternetes
- First step, easy: the generated profile is also written as a standard OCI seccomp JSON. A pod uses it through the normal
securityContext.seccompProfile: Localhost, with no RuntimeClass needed. - Later: the
heimdallRuntimeClass (broker, Landlock, signed results) for pods that handle untrusted input (spec §9).
Milestones
Milestone 1 (heimdall-core, heimdall-wasm, the verify-bundle guest, heimdall-run and heimdall-cli for wasm jobs) needs none of this. The Build Thing step arrives with milestone 3 (heimdall-probe); the kernel-trim half is planned in tunnr 1.1.