noether-isolation 0.7.3

Stage-execution sandbox policy + bubblewrap command builder. Extracted from noether-engine for consumers that want isolation without the full composition engine.
Documentation

Stage execution isolation — the sandbox primitive extracted from [noether_engine::executor::isolation] for consumers that want isolation without pulling in the composition engine.

The noether-engine crate re-exports this module verbatim, so existing callers see no API change. Downstream consumers (agentspec, the standalone noether-sandbox binary) depend on this crate directly.

Wraps subprocess execution in a sandbox that restricts what the stage can read, write, and call. Closes the gap documented in SECURITY.md: a user-authored Python stage has host-user privileges by default; with isolation it runs in a bounded filesystem + network namespace.

Phase 1 (v0.7) backends:

  • [IsolationBackend::None] — legacy pass-through. Emits a warning unless the user opts in with --unsafe-no-isolation / NOETHER_ISOLATION=none.
  • [IsolationBackend::Bwrap] — bubblewrap wrapper. Linux-only. Requires the bwrap binary in PATH.

Phase 2 (v0.8) will add IsolationBackend::Native — direct unshare(2) + Landlock + seccomp syscalls, no external binary. See docs/roadmap/2026-04-18-stage-isolation.md.

Policy derivation

An [IsolationPolicy] is derived from a stage's declared EffectSet. Phase 1 surfaces exactly one axis from the effect vocabulary — Effect::Network toggles whether the sandbox inherits the host's network namespace. Every other effect variant (Pure, Fallible, Llm, NonDeterministic, Process, Cost, Unknown) produces the same baseline policy: RO /nix/store bind, a sandbox-private /work tmpfs, --cap-drop ALL, UID/GID mapped to nobody, --clearenv with a short allowlist.

TLS trust store — dual path

When network=true, the sandbox binds /etc/ssl/certs (via --ro-bind-try) for non-Nix-aware clients that expect the system trust store (curl, openssl). Nix-built code uses NIX_SSL_CERT_FILE / SSL_CERT_FILE (both in the env allowlist) pointing into /nix/store, which is always bound. So TLS works whether the stage resolves certs through the filesystem path or the env-pointer path; NixOS hosts without /etc/ssl/certs fall through to the env path automatically.

Filesystem effects — not yet expressible

The v0.6 Effect enum has no FsRead(path) / FsWrite(path) variants, so there is no way for a stage to declare "I need to read /etc/ssl but nothing else." The sandbox compensates by allowing nothing outside /nix/store, the executor's cache dir, and the nix binary. That is the strictest sane default — but it means stages that legitimately need a specific host path cannot run under isolation today. Planned for v0.8: extend Effect with FsRead / FsWrite path variants, then expand from_effects to translate them into bind mounts. Tracked in docs/roadmap/2026-04-18-stage-isolation.md.