share the host ~/.agents read-only, so skills come along

A sandboxed harness found none of your skills, prompt templates or
standing AGENTS.md, because those live in ~/.agents and only the project
was mounted. It is now bind-mounted at /home/sandbox/.agents by default
-- bound, never copied -- with --no-agents to opt out and --agents-dir
for a curated set, reported by --print-policy and by doctor.

Read-only is the load-bearing part and has no escape hatch: a skill is an
instruction the model follows later, on the host, so a sandbox that could
write ~/.agents had a persistence path out of itself, planted as a
helpful-looking SKILL.md. It holds even under --insecure-keep-root, the
mount lands after /home/sandbox itself so it cannot be shadowed by the
home volume or tmpfs, and an explicit --mount on the same destination
wins because podman refuses duplicates. A missing or unreadable directory
is a silent skip like the pi bridge's; an explicit --agents-dir that
resolves to nothing is a hard error.

The exposure is stated in docs/threat-model.md: the tree, its .git history
and anything pasted into a skill are readable by whatever runs in there.

tests/unit/09_agents.sh covers resolution, precedence and the
bind-never-copy canary; tests/e2e/12_sandbox.sh mounts it in a real
container, checks the host tree survives a run byte for byte and that
even root inside the sandbox cannot write it.

LLM-Generated: true
This commit is contained in:
2026-10-27 20:30:53 -04:00
parent 8ee535f6ae
commit ed2eb462d6
10 changed files with 437 additions and 18 deletions
+7 -1
View File
@@ -6,10 +6,16 @@ Working notes for anyone (human or agent) changing this repository.
One bash script, `bin/ai-sandbox`, that runs another program — usually an LLM
coding harness — inside a rootless podman container with a strict, explicit policy:
only the current directory mounted, no inherited environment, no root or
the current directory as the only writable mount plus the host `~/.agents` read-only
(so the harness still has its skills), no inherited environment, no root or
capabilities inside the container, resource caps, and egress limited to an
allowlist that the sandboxed process cannot lift.
The `.agents` share is the one exception to "nothing but the project directory", so it is
read-only with no escape hatch (`agents`/`--agents`/`--agents-dir`, and `--no-agents`):
a sandbox that could write your skills could write instructions you follow later on the
host. See `agents_src_of()` and the tests in `tests/unit/09_agents.sh` / `tests/e2e/12_sandbox.sh`.
## Non-negotiables
1. **Single script.** The Containerfile, the container entrypoint, the squid