Files
harness-tools/docs/adr/0003-trusted-nono-policy-composition-27AUG2026.md
T

2.9 KiB

Materialize trusted Nono policy composition before launch

Nono 0.74 accepts multiple extends parents, merges additive grants and environment allowlists across them, and preserves restrictive network decisions such as block: true. The trusted Slice 3 generator will therefore treat the Slice 1 core and provider profiles as reviewed policy inputs, select exactly one core and one provider, materialize one canonical launch profile, and validate that result rather than launching a multiple-inheritance profile directly. This keeps the reusable core fail-closed when validated alone while allowing the trusted generator to make the selected provider route explicit.

Consequences

The managed LM Studio extension uses exact URL http://127.0.0.1:1234/v1, while Nono's Linux policy grants outbound TCP port 1234. Nono 0.74 Landlock mediation is port-only and cannot constrain that grant to loopback, so compromised sandbox code could connect to another address on port 1234. The adjacent-port behavioral proof and exact extension endpoint make this narrower than broad networking without overstating host enforcement.

Cloud provider fragments enable Nono networking with an explicit empty direct-domain allowlist and exactly one phantom credential route. The route's reviewed upstream is the only proxy destination; raw provider keys remain denied to the sandbox. Live secret-backed verification stays behind a separate explicit approval gate.

The active unmanaged LM Studio source remains in place during Slice 1 by explicit approval because quarantining it before an immutable managed installation would disable the current provider. Its reviewed legacy digest and both blockers are recorded in config/pi-package-lock.json; Slice 3 must perform hash-guarded quarantine atomically with immutable promotion before activation.

Provider fragments are not standalone launch profiles despite passing strict schema validation. They exclude the inherited Linux and macOS system runtime-read groups, so direct execution cannot read its executable; the trusted generator extracts only the reviewed provider route into a core that owns runtime reads. Untrusted repositories cannot compose or override fragments, and every generated profile must prove that it contains one state namespace, one worktree grant, one temporary directory, and exactly one provider route before nono run. Slice 1 isolated settings expose only Pi's read, edit, and write built-ins; model-visible bash, package tools, notification commands, background-job extensions, and project resources are absent. Core profiles intentionally define no command_policies; later broker slices must bind each controlled command to an exact executable and declare every permitted caller under commands.<name>.from, because inherited denials and caller edges are not safely loosened by child profiles. Slice 3 must invoke the exact Pi entrypoint and must not expose arbitrary caller-selected Nono commands as a launch interface.