--- id: SAND-WP-0014 type: workplan title: "Owner-mediated governed bwrap execution" domain: infotech repo: sand-boxer status: active flavor: implementation owner: codex topic_slug: owner-mediated-execution created: "2026-09-04" updated: "2026-09-05" state_hub_workstream_id: "b616d1cd-208f-5ecf-a4a0-a028396422c4" --- # Owner-mediated governed bwrap execution Promote intake `GLAS-IN-0002` into sand-boxer ownership. Replace the unusable consumer-side `nsenter` hint with an owner-executed command boundary that remains bound to the sandbox and its governed consumer identity. A refused execution must never fall back to a host checkout or another extension. ## Define the governed execution contract ```task id: SAND-WP-0014-T01 status: done priority: high state_hub_task_id: "1b4349de-7027-5f01-8deb-122772e1404d" ``` Define request/result schemas and evidence for exact actor/project/session/run binding, ready/active lifecycle, workspace confinement, declared network posture, value-free credential route references, bounded command duration, and bounded output. ## Implement owner-mediated bwrap execution ```task id: SAND-WP-0014-T02 status: done priority: high state_hub_task_id: "59f9af7c-7cd7-5e86-849f-5dfc7a3a06ee" ``` Add manager, extension, CLI, and authenticated HTTP surfaces. Only `ext.bwrap` may execute in this slice. The extension launches an owner broker inside bwrap, uses the sandbox workspace as its working directory, starts commands with a sanitized environment, and fails closed if the recorded workspace is not the exact owner-managed sandbox directory. ## Remove direct namespace-entry guidance ```task id: SAND-WP-0014-T03 status: done priority: high state_hub_task_id: "4fc7d747-13d5-58e7-b89e-b72e845515aa" ``` Stop publishing raw consumer-side `nsenter` commands. Reachability describes owner-mediated execution without exposing a misleading direct-attach route. ## Verify unit and local namespace behavior ```task id: SAND-WP-0014-T04 status: done priority: high state_hub_task_id: "c7ada937-4430-59d7-b3a6-9f3f36e9a907" ``` Cover identity/state/TTL refusal, unsupported-extension refusal, exact workspace validation, sanitized environment, credential route references, timeout/output bounds, API authentication, lifecycle restoration, and teardown. Run the full repository check and, when host user namespaces permit it, a non-secret live bwrap command proof. Implemented and verified 2026-09-04. `make check` passes with 119 tests. The first live attempt proved that even the bwrap owner cannot reliably `setns` from the host on this kernel (`IPC: Operation not permitted`), so execution was moved to a small read-only broker launched inside the namespace and reached via an owner-only Unix socket. `make smoke-bwrap-exec` then passed: actor `agt`, project/session/run binding reached the command; cwd was the copied sandbox; the host-source sentinel was absent; the command created an artifact; the net namespace exposed only `lo` under declared `default: deny`, `egress: []`; no credential routes or values were present; and teardown reported `destroyed` with the workspace removed. The authenticated HTTP smoke subsequently exposed and fixed a lifecycle defect: `--die-with-parent` tied bwrap to the process handling `create`, so the namespace could disappear before a later API `exec`. Owner sandboxes now persist across requests and remain bounded by explicit destroy, TTL expiry, and stale reaping. The consumer-contract audit also found that Glas needs to create a private task file without writing through the host mirror or putting prompt content in argv. Owner exec now supports bounded `stdin_text` (1,000,000 UTF-8 bytes), delivers it only to the child process, and excludes it from results and lifecycle evidence. ## Prove one governed rein and coordinate consumers ```task id: SAND-WP-0014-T05 status: wait priority: high state_hub_task_id: "c6812fd4-bb7b-5be0-8344-a122496fe5bc" ``` With Glas and rein-aharness, run one real selected rein command through the owner API using an explicitly declared egress profile and catalog credential route. Prove that the source checkout is absent, retain value-free evidence, destroy the workspace, then update Glas readiness and Activity Core `ACTIVITY-WP-0032-T05`. Do not trigger the production pilot before readiness changes. This task depends on a reviewed Glas profile revision and its matching credential/egress/runtime contract. Glas selected the Claude route first in GLAS-WP-0012; the earlier OpenRouter AppRole dependency applies only to the separate open-weight profile and does not establish Claude authentication. 2026-09-05: SAND-WP-0015 implements pinned Python runtime mounts and private namespace state, with a real rein CLI startup proof. Claude workload credential routing, enforced provider egress, pinning/deploying the Claude executable, and the real-model acceptance remain open in SAND-WP-0015-T04. No credential value belongs in this workplan or State Hub. ## Acceptance criteria - Execution requires the recorded actor, project, session, and run identity. - Only a live, unexpired, ready sandbox can start a command; concurrent commands are refused. - Command execution is argument-vector based, starts inside the copied sandbox workspace, and has no host/source-checkout fallback. - `ext.bwrap` supplies its declared read-only runtime paths and enforces the profile's network namespace. Evidence reports default policy and egress list. - Credential inputs are non-secret catalog route references only. - Duration and captured output are bounded, lifecycle state is restored, and teardown remains idempotent. - Consumer-facing reachability no longer recommends direct `nsenter`.