fix: execute local reins through the sandbox owner
Some checks failed
ci / validate (push) Has been cancelled

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0726e-5232-73f2-aaca-2c05ceb62efb
This commit is contained in:
tegwick 2026-09-05 19:16:22 +02:00
parent 92392f75f1
commit 63a7f9f160
14 changed files with 463 additions and 81 deletions

View file

@ -0,0 +1,68 @@
# GLAS-WP-0005 sandbox owner boundary proof
Date: 2026-09-05. Sand-boxer revision:
`b6655d88590e03820675719d6dd574e5f5a9f82e`.
The Glas gateway now binds same-host execution to the creating manager's
`execute` operation. Each request repeats the exact actor/project identity and
resolved request id as `consumer.run_id`, forwards the selected profile's
value-free credential route references, and caps execution at the profile
timeout. Local descriptors without that process-local binding fail closed.
There is no direct `nsenter` or host task-file write path.
Generated task files travel through bounded stdin to an exclusive mode-0600
writer inside the sandbox's `.git` directory. Removal uses owner execution.
Timeouts, owner refusals, and truncated output fail closed; gateway teardown
still runs when session initialization fails.
## Live non-secret proof
Command: `.venv/bin/python scripts/prove-owner-boundary.py`.
This reproducible fixture exercises the real gateway, real sand-boxer manager,
real bwrap owner broker, and the rein-aharness adapter's session setup, commit
verification, and cleanup. Its dispatch is a deterministic Python/Git probe,
not an installed agent CLI or model call. Only the fixture's in-memory profile
is made unverified; the committed profile catalog is unchanged.
Successful sandbox: `e3907e55`, workspace `/tmp/sandboxer-bwrap/e3907e55`.
- Source checkout was absent inside the sandbox; a source write was refused.
- The sandbox copy was readable and accepted a new committed file.
- Host source sentinel and Git HEAD remained unchanged; no proof file appeared
in the source checkout.
- Actor `agt`, project `glas-boundary-proof`, and run id
`glas-wp-0005-boundary-proof` matched inside the child environment.
- Task content arrived through stdin and its file mode was `0600`.
- Only `lo` appeared in the network namespace.
- The generated task was removed before teardown. Final state was `destroyed`
and the workspace was absent.
An initial fixture run (`78be8886`) encountered a Python quoting error in the
probe itself. It failed during dispatch, removed its generated task, preserved
the source, and destroyed the workspace. The fixture quoting was corrected
before the successful run above.
## Validation and limits
`.venv/bin/python -m pytest tests/ -q`: **81 passed**. Coverage includes exact
create/exec identity with supplied and generated request ids, unchanged route
references, timeout caps, stdin-only task content, no local subprocess or host
file fallback, and teardown on owner refusal, timeout, truncation, and writer
failure. Both concrete adapters' session and cleanup tests pass.
`.venv/bin/glas-harness profiles`: catalog validation passed. Both local
profiles remain **blocked**; the remote profile remains **unverified**.
This closes the boundary-hardening acceptance in GLAS-WP-0005. It does not
prove an installed production rein runtime, credential delivery, required
outbound connectivity, or the remote SSH runtime. Registered residual
`GLAS-IN-0002` (`01a02b76-f020-7d60-a3ce-12a34c13ebce`) remains live for the
local production requirements and was refreshed before workplan closure.
Sand-boxer owns runtime/credential/egress provision; Glas owns the subsequent
real-rein acceptance and profile readiness review. The prior GLAS-WP-0004
lifecycle-only evidence remains explicitly withdrawn as an isolation proof.
Earlier T03 package and T04 Forgejo CI evidence remains historical; this
session validates the changed code locally and does not claim a new published
Forgejo run.

View file

@ -72,13 +72,27 @@ publish compact ExecutionEvidence
After sandbox creation, the caller's source checkout is no longer an execution
path. A same-host descriptor must contain `pid` plus `workspace_dir` and every
rein command is wrapped with `nsenter`; a remote descriptor must contain `ssh`
rein command uses the creating managers `execute` operation; a remote descriptor must contain `ssh`
plus `remote_dir` and every command crosses SSH. Incomplete, mixed, or unknown
reachability refuses at session start. The transport also bounds the outer rein
subprocess with the profile timeout. A host must make the selected rein command
and its dependencies available inside that transport; host-only installation is
not treated as sandbox availability.
The gateway binds local execution to the exact create-time consumer: actor,
project, and resolved request id as `run_id`. Every owner command forwards the
selected profile's value-free `credential_route_refs` and a timeout capped by
its limit. The binding is process-local and excluded from serialized handles.
An unbound local descriptor refuses execution; no consumer namespace entry or
host execution fallback exists. Owner timeouts and truncated output fail closed.
Generated task specs travel over stdin to an exclusive mode-0600 writer inside
`.git`; removal also crosses the owner boundary. Sand-boxer revision `b6655d8`
or a compatible implementation with bounded `stdin_text` is required.
Run `.venv/bin/python scripts/prove-owner-boundary.py` for a non-secret gateway
boundary proof. It injects deterministic dispatch in place of the agent loop
and does not establish production rein, credential, or egress readiness.
SSH reachability accepts only one non-option host or `user@host` target whose
components begin with an alphanumeric character. Glas also terminates SSH
option parsing with `--`; a reachability descriptor cannot reinterpret its

View file

@ -77,6 +77,22 @@ description: |
consumer namespace-entry authority. This strengthens the owner-exec need; it
does not justify widening host execution.
2026-09-05 handoff refresh: sand-boxer b6655d8 now supplies owner-mediated
execution and bounded stdin. Glas replaced direct nsenter and host task-file
writes with that operation, preserving exact actor/project/request run_id,
profile credential_route_refs, and timeout. The non-secret gateway proof
passed in sandbox e3907e55: source absent and mutation refused, sandbox-only
commit, loopback-only network, mode-0600 task removed before teardown, and
destroyed workspace. Evidence: docs/evidence/GLAS-WP-0005-owner-boundary-2026-09-05.md.
Remaining owner work: supply the declared rein runtimes and dependencies,
governed credential delivery and explicit required egress, then prove a real
rein command through the Glas adapter before changing either local profile
from blocked. Glas owns the final profile review and acceptance run once the
sand-boxer runtime contract is available. The deterministic non-secret proof
does not satisfy this production acceptance. GLAS-WP-0005 can close its
boundary-hardening scope with this registered live residual still open.
Done when a non-secret probe and one real rein command execute inside the
namespace, the source checkout is not visible/mutable, required egress is
explicit, and teardown removes the sandbox workspace.