Skip to content

openenvd 5/5: unit assembly, daemon, enforcement check and live tests - #1387

Draft
zkwentz wants to merge 5 commits into
zkwentz/openenvd-k4-relaysfrom
zkwentz/openenvd-k5-unit
Draft

zkwentz wants to merge 5 commits into
zkwentz/openenvd-k4-relaysfrom
zkwentz/openenvd-k5-unit

Conversation

@zkwentz

@zkwentz zkwentz commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

This puts it together. openenvd starts as PID 1 of every image, runs the preflight, and either isolates or steps aside.

One environment unit: openenvd in the parent namespaces, with the agent zone, hidden services and privileged observers in child namespaces

Each container's only way out is one socket that openenvd hands it. Nothing in a zone can address openenvd or another zone directly.

  • daemon.py:
    • If the preflight passes: it adopts the cgroup root, builds the unit and serves its listener on the manifest's port.
    • If it fails: it logs isolation disabled: <reasons> and execs the environment's own uvicorn app on the same port, exactly as the image ran before.
    • --require-isolation (or OPENENVD_REQUIRE_ISOLATION=1) turns that fallback into a refusal, for production launchers.
  • unit.py:
    • builds per-episode overlays and one socket directory per container (each container's only way out);
    • starts the relays, then services, the env server, an optional harness and observers in the phases they list;
    • inspect/resume freeze and thaw zones/agent;
    • at done it kills the agent zone and waits for the kernel to report it empty;
    • grading runs a runner (no assets) before the verdict (assets read-only and nosymfollow), with custody copies between them;
    • failures are blamed by subtree: agent_misbehavior versus infrastructure_error;
    • results are served at GET /verdict.
  • runtime.py. The crun driver and mount helpers.
  • CLI:
    • openenv check preflight says whether isolation would be on here;
    • openenv check enforcement starts throwaway probe containers in every zone and tries what each zone must not be able to do.

Grading

Grading: the agent zone is emptied, the runner works without assets, custody copies its report, the verdict reads assets

Agent code runs only where answers aren't, and answers exist only where agent code doesn't run. Each step starts only after the previous container's cgroup reports empty.

Test plan

  • Unit tests: 122 passed and 5 skipped.
  • tests/core/test_openenvd/integration/run.sh runs the live tests in Docker twice:
    • Privileged:
      • the cgroup tests from openenvd 2/5: cgroups and the isolation preflight #1385 run against the real kernel;
      • the enforcement check passes;
      • a full episode runs with masked state and assets, no egress, the hidden service reached only through its relay, and the harness model proxy keeping the real key out of the zone;
      • runner/verdict grading is reported at /verdict.
    • Plain container: openenvd logs isolation disabled and the echo env serves /mcp unchanged.
  • The privileged live tests also pass in a Firecracker microVM (a Novita sandbox; guest kernel 6.1): preflight reports isolation on, and the enforcement check and full episode pass. That run found two fixes in this PR:
    • openenvd creates missing mountpoints, because the VM mounts a fresh tmpfs on /run;
    • every bind it makes is private, because systemd marks / as shared and unmounting the bind of / would otherwise unmount the VM's /tmp.
  • The manifest has no isolation policy: Landlock and the socket filter were removed, so zones can read anything in the image that isn't masked (assets, control-plane state and secrets are masked).

Stack

Part of openenvd on kernel primitives (#1053). Review bottom-up; each PR shows only its own layer.

  1. openenvd 1/5: manifest contract and unit phases #1383: Contract and phases
  2. openenvd 2/5: cgroups and the isolation preflight #1385: cgroups and the isolation preflight
  3. openenvd 3/5: confinement (seccomp, OCI, shim, forwarders, custody) #1416: Confinement: seccomp, OCI, shim, forwarders, custody
  4. openenvd 4/5: relays and the external surfaces #1386: Relays and surfaces
  5. openenvd 5/5: unit assembly, daemon, enforcement check and live tests #1387: Unit, daemon, check, live tests ← this PR

Deployment assumption: openenvd ships in every image. Run privileged (a microVM in production, or docker run --privileged in development) and it isolates. Run any other way and it logs isolation disabled and serves the environment exactly as before.

The trace machinery (hash-chained trace, seal, harness self-report cross-check, /observe) is parked on zkwentz/openenvd-with-trace and is out of this stack's scope.

🤖 Generated with Claude Code

@zkwentz
zkwentz force-pushed the zkwentz/openenvd-k5-unit branch from 7eccfe5 to 32ab710 Compare October 12, 2026 17:35
@zkwentz zkwentz changed the title openenvd 5/5: unit assembly, daemon, enforcement check and live tests openenvd 4/4: unit assembly, daemon, enforcement check and live tests Oct 12, 2026
@zkwentz
zkwentz added this pull request to stack #1415 October 12, 2026 18:38
Comment thread src/openenv/core/openenvd/unit.py Resolved
Comment thread src/openenv/core/openenvd/unit.py Resolved
Comment thread src/openenv/core/openenvd/unit.py Resolved
Comment thread src/openenv/core/openenvd/runtime.py Resolved
@zkwentz
zkwentz force-pushed the zkwentz/openenvd-k5-unit branch from 32ab710 to a276605 Compare October 13, 2026 00:31
@zkwentz
zkwentz removed this pull request from stack #1415 October 13, 2026 00:32
@zkwentz
zkwentz added this pull request to stack #1417 October 13, 2026 00:32
@zkwentz zkwentz changed the title openenvd 4/4: unit assembly, daemon, enforcement check and live tests openenvd 5/5: unit assembly, daemon, enforcement check and live tests Oct 13, 2026
@zkwentz
zkwentz force-pushed the zkwentz/openenvd-k5-unit branch from a276605 to 28c1e9b Compare October 13, 2026 01:09
@zkwentz
zkwentz force-pushed the zkwentz/openenvd-k5-unit branch from 28c1e9b to c8cf4f6 Compare October 13, 2026 01:29
Comment thread src/openenv/core/openenvd/runtime.py Resolved
Comment thread src/openenv/core/openenvd/runtime.py Resolved
Comment thread src/openenv/core/openenvd/runtime.py Resolved
@zkwentz
zkwentz force-pushed the zkwentz/openenvd-k5-unit branch from 2e24d20 to 2848aa7 Compare October 13, 2026 14:24
zkwentz and others added 5 commits October 13, 2026 13:32
Part 5 of 5 of openenvd on kernel primitives (#1053).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In a Novita Firecracker microVM, /run is a fresh tmpfs, so the image's
/run/openenvd is gone and crun can't create it through the read-only bind
of /. openenvd now creates missing mount destinations before starting a
container on the root bind.

systemd also makes / shared, so the bind of / joined its peer group and
the lazy unmount at shutdown detached the VM's own /tmp. Binds now leave
the peer group right after they are made.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The shim spec carries only argv, env, forwarders and workdir. The
enforcement check drops the AF_INET probe, which only a strict zone failed;
connecting outside the unit is still probed in every zone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zkwentz
zkwentz force-pushed the zkwentz/openenvd-k5-unit branch from 2848aa7 to f01034d Compare October 13, 2026 17:35

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants