Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0726e-5232-73f2-aaca-2c05ceb62efb
124 lines
5.8 KiB
Markdown
124 lines
5.8 KiB
Markdown
# Bwrap runtime and private state
|
|
|
|
`ext.bwrap` can mount a standalone Python runtime selected by the owner's
|
|
extension configuration. A create/exec caller cannot select host paths or
|
|
replace the sanitized child environment.
|
|
|
|
```yaml
|
|
config:
|
|
runtime:
|
|
path: /srv/sandboxer/runtimes/rein-aharness-example
|
|
sha256: <reviewed-complete-artifact-digest>
|
|
```
|
|
|
|
The path must be a canonical absolute directory with `pyvenv.cfg` and
|
|
`bin/python3`. Its complete tree digest includes file contents, modes, directory
|
|
entries, and internal symlinks. Absolute/escaping symlinks and special files
|
|
are refused. Missing files, added files, changed permissions, or changed
|
|
content invalidate the pin. The runtime must not overlap the source checkout
|
|
or writable sandbox workspace.
|
|
|
|
The owner mounts the artifact read-only at `/opt/sandboxer/runtime` and prepends
|
|
its `bin` directory to the child PATH. Console entrypoints must use that fixed
|
|
mount prefix. Artifacts remain an owner trust boundary: publish them in a
|
|
protected location and do not mutate them while sandboxes use them. Digest
|
|
validation occurs at creation; it is not a mechanism for making a mutable host
|
|
directory immutable to its owner.
|
|
|
|
## Building and testing the Python rein bundle
|
|
|
|
From this repository, with committed rein/llm-connect source checkouts:
|
|
|
|
```bash
|
|
uv run python scripts/build-rein-runtime.py \
|
|
--output /tmp/rein-runtime-candidate \
|
|
--rein-source ../rein-aharness \
|
|
--llm-source ../llm-connect
|
|
```
|
|
|
|
The builder creates a standalone system-Python venv, installs both packages
|
|
non-editably with their dependencies, rewrites Python console entrypoint
|
|
shebangs to the fixed mount path, and records source revisions plus resolved
|
|
package versions in `build-info.json`. It prints the resulting path/digest.
|
|
Dependency versions are resolved during this candidate build; the digest pins
|
|
the produced artifact, not a promise that another build will be bit-identical.
|
|
No interactive home, credentials, or provider login is copied into the bundle.
|
|
|
|
Prove the artifact using the returned values:
|
|
|
|
```bash
|
|
uv run python scripts/smoke-bwrap-runtime.py \
|
|
--runtime-path /tmp/rein-runtime-candidate \
|
|
--runtime-sha256 <returned-digest>
|
|
```
|
|
|
|
The smoke uses an isolated owner extension configuration and the real broker.
|
|
It imports the rein's Claude adapter and llm-connect, runs `rein-aharness
|
|
--help`, proves the runtime rejects writes, writes private state outside the
|
|
worktree, verifies source absence and a clean Git tree, checks loopback-only
|
|
networking, and tears down. This is real CLI startup, not a model task.
|
|
|
|
The Python bundle does not package or pin the separate Claude executable.
|
|
That executable's release, startup behavior, and authentication still require
|
|
review in the eventual production runtime. No committed profile selects a
|
|
temporary `/tmp` build as its production runtime.
|
|
|
|
## Private writable state
|
|
|
|
The broker creates mode-0700 directories in the namespace's temporary root:
|
|
|
|
| Environment variable | Location |
|
|
|---|---|
|
|
| `HOME` | `/run/sandboxer/state/home` |
|
|
| `XDG_CONFIG_HOME` | `/run/sandboxer/state/config` |
|
|
| `XDG_CACHE_HOME` | `/run/sandboxer/state/cache` |
|
|
| `XDG_STATE_HOME` | `/run/sandboxer/state/data` |
|
|
| `TMPDIR` | `/run/sandboxer/state/tmp` |
|
|
|
|
These directories persist between exec requests in the same sandbox, remain
|
|
outside the Git worktree, and disappear with namespace teardown. Python user
|
|
site packages and bytecode writes are disabled. The owner's child environment
|
|
continues to carry exact consumer identity and value-free route references.
|
|
|
|
## Network and credentials remain separate gates
|
|
|
|
Bwrap refuses `network.default: allow` and setup secret references. Network
|
|
egress is opt-in through the owner allowlist described in bwrap-egress.md;
|
|
empty-egress profiles retain loopback-only networking. There is still no
|
|
credential-delivery mechanism. Returning a
|
|
declared egress list as evidence would not make that list enforced or usable.
|
|
Exec credential route references continue to be labels, not credential values
|
|
or delivery grants.
|
|
|
|
On 2026-09-05, `warden route find anthropic --json` and `warden route find
|
|
claude-code --json` returned no matching workload routes. The generic OpenBao
|
|
entry is explicitly a routing template, not an executable credential lane.
|
|
The OpenRouter AppRole route belongs to the other rein and is not a substitute
|
|
for Claude authentication.
|
|
|
|
`SAND-WP-0015-T04` / `SAND-WP-0014-T05` and `GLAS-WP-0012-T02` retain the
|
|
production requirements: a concrete owner-approved Claude credential route,
|
|
delivery and revocation semantics, a pinned Claude runtime, and explicitly
|
|
enforced provider egress with negative tests. Glas local profiles remain
|
|
blocked until those requirements and the real-model acceptance pass.
|
|
|
|
## 2026-09-05 candidate evidence
|
|
|
|
Runtime SHA-256:
|
|
`4c316737ec2715936a12c4f49621a5e4be3d1f4fe4739130393f28cdda66fbd9`.
|
|
Candidate path: `/tmp/sandboxer-rein-aharness-runtime-20260905-v2`.
|
|
Source revisions: rein-aharness `1429db5ad4c83331b6375349ffde1eb13af9575b`,
|
|
llm-connect `00560945f81ba6ff1f5cacd9fe99c7fe756cc4b1`; Python 3.12.3.
|
|
|
|
Sandbox `f333fb66` passed the real CLI/import/read-only/private-state smoke.
|
|
`sys.prefix` was `/opt/sandboxer/runtime`, HOME was outside the worktree with
|
|
mode 0700, Git stayed clean, source was absent, only `lo` existed, credential
|
|
references were empty, and the workspace was removed. No model request or
|
|
credential acquisition occurred.
|
|
|
|
Final validation: `make check` passed lint and 132 tests. Authenticated owner
|
|
API smoke `223db65b` returned HTTP 200 with exact identity/stdin and complete
|
|
teardown. Follow-up runtime smoke `d4de9531` repeated the real CLI/startup
|
|
checks and proved private state survives a second exec in the same namespace.
|
|
The default unconfigured `profile.bwrap-local` still has no selected rein
|
|
bundle; candidate startup does not constitute production deployment.
|