Some checks failed
ci / validate (push) Has been cancelled
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0726e-5232-73f2-aaca-2c05ceb62efb
206 lines
9.5 KiB
Markdown
206 lines
9.5 KiB
Markdown
---
|
|
id: GLAS-WP-0005
|
|
type: workplan
|
|
title: "Sandbox-boundary correction and runtime hardening"
|
|
domain: infotech
|
|
repo: glas-harness
|
|
status: finished
|
|
owner: codex
|
|
topic_slug: sandbox-boundary-runtime-hardening
|
|
created: "2026-08-21"
|
|
updated: "2026-09-05"
|
|
state_hub_workstream_id: "c8049700-73ca-549a-b250-1020de1cddc5"
|
|
---
|
|
|
|
# Sandbox-boundary correction and runtime hardening
|
|
|
|
## Context
|
|
|
|
The versioned profile path provisions and tears down sand-boxer instances, but
|
|
the concrete rein adapters currently prefer the caller's original repository
|
|
path and invoke their CLIs as ordinary local subprocesses. They do not enter a
|
|
same-host bwrap namespace or cross the SSH reachability boundary for a remote
|
|
sandbox. As a result, the existing lifecycle evidence does not prove that the
|
|
agent process executed inside the selected sandbox, and the enabled remote
|
|
profile is not executable through its declared transport.
|
|
|
|
The review also found persistent task-spec files in `/tmp`, no outer subprocess
|
|
timeout, an undeclared direct `httpx` dependency, and a Forgejo workflow that
|
|
only prints routing probes rather than running tests or catalog validation.
|
|
|
|
## Goal
|
|
|
|
Make every governed execution use the workspace and execution transport
|
|
declared by the resolved sand-boxer reachability descriptor, fail closed when
|
|
that descriptor is unsupported, and close the adjacent runtime/CI gaps without
|
|
changing scheduling, rein credential ownership, or sand-boxer provisioning
|
|
ownership.
|
|
|
|
## Task: Correct workspace and execution transport selection
|
|
|
|
```task
|
|
id: GLAS-WP-0005-T01
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "fc29c99f-6938-5450-868e-1a94123995f4"
|
|
```
|
|
|
|
Introduce one validated execution transport derived from `SandboxHandle`:
|
|
|
|
- same-host bwrap uses `workspace_dir` and enters the namespace identified by
|
|
`pid` for the rein subprocess;
|
|
- remote sandboxes use `remote_dir` and the declared SSH endpoint;
|
|
- the caller's source checkout is never passed to the rein as its execution
|
|
workspace after sandbox creation; and
|
|
- missing, ambiguous, or unsupported reachability fails closed before the rein
|
|
subprocess starts.
|
|
|
|
Add tests proving the original checkout is not selected, the expected transport
|
|
argv is used, remote execution is represented honestly, and teardown still
|
|
runs on every failure.
|
|
|
|
**Completed 2026-08-21:** added strict reachability-derived execution
|
|
transports. Local descriptors require `pid` + `workspace_dir` and wrap commands
|
|
with `nsenter`; remote descriptors require `ssh` + `remote_dir` and wrap
|
|
commands over SSH. Mixed/incomplete descriptors fail closed. The gateway no
|
|
longer passes the source checkout to a rein after provisioning, and tests cover
|
|
transport argv, workspace selection, refusal, cleanup, and teardown.
|
|
|
|
## Task: Bound subprocesses and remove temporary task material
|
|
|
|
```task
|
|
id: GLAS-WP-0005-T02
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "219ecaeb-c576-5b93-b65c-6445ebd3d139"
|
|
```
|
|
|
|
Enforce the profile timeout on the outer rein subprocess, normalize timeout
|
|
failures, and remove generated task-spec files on success, ordinary failure,
|
|
timeout, and interruption. Caller-supplied task files must not be deleted.
|
|
Record and safely remove already-orphaned `glas-harness-task-*.json` files after
|
|
their exact scope is verified.
|
|
|
|
**Completed 2026-08-21:** the profile timeout now bounds the outer transport
|
|
subprocess. Generated task specs are mode-0600 files inside the sandbox
|
|
workspace and the gateway calls rein cleanup before sandbox teardown on every
|
|
terminal path; caller-owned task files are preserved. Verified all 22 legacy
|
|
`/tmp/glas-harness-task-*.json` files were owned by the current user, mode 0600,
|
|
and valid Glas task specs with no active rein process, then securely removed
|
|
those exact files.
|
|
|
|
## Task: Repair package dependency metadata
|
|
|
|
```task
|
|
id: GLAS-WP-0005-T03
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "0c57d3a4-40d4-5764-a0df-7c03c58fa23e"
|
|
```
|
|
|
|
Declare direct runtime dependencies directly, build the wheel, install it in an
|
|
isolated environment with the sandbox extra, and validate that packaged profile
|
|
and rein data resolve without relying on the source checkout.
|
|
|
|
**Completed 2026-08-21:** declared `httpx>=0.27` directly. Built the wheel with
|
|
uv, installed it outside the checkout, resolved all three profiles from packaged
|
|
data, verified both rein descriptors are present, and inspected wheel metadata
|
|
for direct and optional dependencies.
|
|
|
|
## Task: Replace routing-only CI with executable validation
|
|
|
|
```task
|
|
id: GLAS-WP-0005-T04
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "222d9df6-5361-5b5e-8236-8fa3a1fbe3bf"
|
|
```
|
|
|
|
Make Forgejo CI check out the repository, install the project and its test
|
|
dependencies, run the full unit suite, and run `glas-harness profiles`. Retain
|
|
only routing probes that still provide operational value.
|
|
|
|
**Completed 2026-08-21:** replaced the two echo-only jobs with the estate's
|
|
archive-checkout pattern, explicit Python/sand-boxer/project installation, the
|
|
full test suite, and packaged catalog validation. Run `#45` was superseded and
|
|
canceled; run `#46` exposed five tests that incorrectly relied on the host's
|
|
global Git author identity. The same job reproduced this cleanly in the runner's
|
|
`node:20-bookworm` image, and the test repositories now configure a local,
|
|
non-deliverable test identity. Forgejo Actions run `#47` passed on published
|
|
commit `994b2da`.
|
|
|
|
## Task: Re-prove the sandbox boundary and close evidence
|
|
|
|
```task
|
|
id: GLAS-WP-0005-T05
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "a4be4d68-b0af-5273-978a-367bba414f0c"
|
|
```
|
|
|
|
Run offline boundary tests and, where the already-approved local runtime permits
|
|
it, a bounded non-secret bwrap proof showing that execution targets the sandbox
|
|
copy and cannot mutate the source checkout. Correct prior evidence claims rather
|
|
than silently treating lifecycle-only proof as isolation proof. Run the full
|
|
suite and catalog validation, synchronize work records, and hand off any live
|
|
residual before finishing the workplan.
|
|
|
|
**2026-08-21 boundary recheck:** offline transport/package tests pass and the
|
|
prior GLAS-WP-0004 evidence now explicitly withdraws its isolation implication.
|
|
A real managed-agent bwrap probe failed closed: direct `nsenter` was denied on
|
|
the reported namespace and neither rein command is mounted inside the bwrap
|
|
root. The source checkout is no longer used as a fallback. Runtime mounting,
|
|
owner-exec, network, and credential delivery are handed off as residual
|
|
`GLAS-IN-0002`; live positive proof waits on that owner contract.
|
|
|
|
**2026-08-22 coordination:** primary registrar reconciliation assigned the
|
|
workplan, all tasks, and `GLAS-IN-0002` authoritative State Hub identities. A
|
|
fresh owner check found no sand-boxer implementation or returned contract, so
|
|
the registered residual was re-sent to sand-boxer in message
|
|
`2e203700-6a2c-4d86-8eed-5dea72e69994`. T05 remains `wait`; no unsafe host
|
|
fallback was introduced.
|
|
|
|
**2026-08-23 production evidence:** rein-aharness deployed the corrected
|
|
`worker_id`/`actor` mapping and ran ops run
|
|
`ededc939-266f-473c-8386-ffd3f027f5f0` with governed actor `agt`. Glas resolved
|
|
the local profile, created sandbox `d750cd5c`, and failed closed at
|
|
`session_start` before dispatch or commit because consumer `nsenter` could not
|
|
join the bwrap namespaces. The sandbox reached `destroyed` and its workspace is
|
|
absent. Loading Ubuntu's bwrap user-namespace AppArmor profile kept bwrap alive
|
|
with child `CapEff=0`, but did not make direct namespace entry permissible.
|
|
This confirms that T05 needs sand-boxer-owned execution rather than another
|
|
consumer-side namespace workaround.
|
|
|
|
**Completed 2026-09-05:** reviewed sand-boxer `b6655d8` and replaced the stale
|
|
T01 direct-nsenter implementation with sandbox-owner execution. Create and exec
|
|
now preserve exact actor/project and resolved request id as `consumer.run_id`;
|
|
every command carries the profile's value-free credential route references and
|
|
a timeout capped by its limit. Task writes and removal both execute inside the
|
|
sandbox, with prompt content supplied only over bounded stdin. Unbound local
|
|
descriptors, owner refusals, timeouts, and truncated output fail closed.
|
|
|
|
The real non-secret gateway proof passed in sandbox `e3907e55`: source checkout
|
|
absent and mutation refused, a new commit only in the sandbox copy, exact child
|
|
identity, mode-0600 task removed before teardown, loopback-only networking,
|
|
unchanged host source, and destroyed/absent sandbox workspace. Full suite:
|
|
**81 passed**; catalog validation passes. Reproduction and limitations:
|
|
[owner boundary evidence](../docs/evidence/GLAS-WP-0005-owner-boundary-2026-09-05.md).
|
|
|
|
The production runtime/credential/explicit-egress requirements remain live in
|
|
registered residual `GLAS-IN-0002` (`01a02b76-f020-7d60-a3ce-12a34c13ebce`),
|
|
refreshed before closure with owner responsibilities and real-rein acceptance.
|
|
Both local profiles remain blocked and the remote profile unverified. This
|
|
closes T05's bounded boundary proof and residual handoff; it does not certify
|
|
production rein readiness. Decision: `6d927f9f-d37d-4234-ad97-bad562b31eaf`.
|
|
|
|
## Overall acceptance
|
|
|
|
1. No governed rein invocation operates on the caller's original checkout.
|
|
2. The selected process crosses the declared local namespace or remote SSH
|
|
boundary, or fails closed without execution.
|
|
3. Profile timeouts bound the outer subprocess and generated task files do not
|
|
survive any terminal path.
|
|
4. Package metadata names every direct dependency and the built artifact carries
|
|
the executable profile/rein catalog.
|
|
5. Forgejo CI executes tests plus catalog validation.
|
|
6. Evidence distinguishes sandbox lifecycle from verified sandbox execution.
|