9  Recipe: gate lab-mode and exp-classified tools

Tool: kailash (safety classes, lab gate) · Section: Administrator · Level: medium · Time: ~20 min · Layer/Category: admin (cross-layer) · Tags: admin, safety, lab-mode, exp

9.1 Problem

Tools whose manifest row reads safety.level: exp — experimental code-execution surfaces like mlflow-bypass — ship in the catalogue but must be unreachable by default. You want to demonstrate the gate actually works on your host: a bare run refuses, a half-opened gate refuses, and only the deliberate double opt-in fires the tool.

9.2 Solution

The gate is double-keyed by construction: a host key (a NixOS option, baked into the gate wrapper at build time) plus a shell key (an env var on the individual invocation). Neither key alone ever suffices:

# 1. Who is exp-gated on this host? (the gate's state record)
cat /etc/kailash/safety/wrapped-exp-tools.json
#    -> per wrapped id: {id, program, gate package}

# 2. Key 1 alone is NOT sufficient — lab host default is labMode=false:
#    the wrapper refuses (exit 126) even WITH the shell key set
KAILASH_LAB_MODE=1 mlflow-bypass --help
#    expected: refused; message names BOTH keys + cites
#    docs/responsible-use.md

# 3. Open the HOST key (deliberate, reviewable config change) and rebuild:
#    kailash.labMode = true;      # in configuration.nix / your host module
sudo nixos-rebuild switch

# 4. Still gated: the shell key is the second, in-the-moment opt-in
mlflow-bypass --help
#    expected: refused — the invocation did not set the shell key

# 5. BOTH keys on the same invocation -> the tool runs
KAILASH_LAB_MODE=1 mlflow-bypass --help
#    expected: the tool's real help output

What success looks like:

  • step 2 fails (host lab-off: the shell key alone is refused)
  • step 4 fails (host lab-on: the missing shell key is refused)
  • step 5 succeeds, and every refusal cites the responsible-use doc
  • step 1’s state file lists the wrapped tools your closure carries, consumed by the parity validator, which independently re-parses the manifest to prove the wrapper set matches the exp row set

9.3 Discussion

  • Why double-key: a single knob is a single mistake. The host key is a deliberate configuration act (reviewable in the system declaration); the shell key is an in-the-moment, per-invocation decision. Gate state commits to the closure — a rebuild without the host key removes the gate’s open path entirely.
  • Gate data flows from the manifest, never a hand-copy: the exp-id list is scanned at eval from the declared manifest surfaces; the packaging-side generator emits the wrapper for every safety.level: exp row — the manifest row IS the routing record. The parity validator re-parses the manifest with an independent implementation and proves coverage; a deliberately broken fixture is refused (proven in CI by construction).
  • There is no separate lab-mode distro: the same image carries both postures — the gate, not the package set, is what differs. A lab-off host is the default; opening the posture is the configuration change, and the per-invocation key stays the second.
  • Legitimate lab enablement: with authorisation (see responsible-use), open the host key on lab machines, keep the shell key per-invocation, and prefer scoped invocations over standing open shells.
  • Requires-target is a different, lighter gate: most ATTACK tools are requires-target, not exp — they refuse to self-fire, run freely when given an explicit target. Attack the platform, then verify walks an exp-gated tool through this exact gate in a full pair run.

9.4 See also


Recipe provenance. The double-key mechanics (host option kailash.labMode, shell KAILASH_LAB_MODE=1, exit 126 wrappers, wrapped-exp-tools.json, refusal text citing responsible-use), the generator-parity contract and the manifest-routing statements are the landed gate contract per spec §9.2/§4.3 and the safety-exp-wrap validator, verified 2026-10-14 at master. behavioural transcript of each refusal/output: PENDING — the mechanism above is the verified contract; the worked host demonstration is the upkeep lane’s obligation.