You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit af8f3c2
Browse filesBrowse the repository at this point in the historyBrowse files
D5: Add the combined real-Docker isolation gate (#50)
* D5: Add the combined real-Docker isolation gate
- Probe scripts asserted forbidden actions with `! command` under
`set -e`, which never fails, so the metadata, read-only isolation and
capacity probes reported success even when isolation broke. Replace
every negated check with a `deny` helper that exits and names the
breach.
- Add agent-gate breach self-tests: each negative production probe runs
in a container missing one protection and must report that breach.
- Add probes and real-profile tests for scratch byte and inode ceilings
(both vendors), metadata link/alias/truncation/replacement attempts
with an unchanged digest, and hostile repository symlinks; an oversized
repository fails closed without leaving storage.
- Live vendor probes read the mounted schema and return its value through
each adapter's documented channel.
- Run the gate in the Agent isolation workflow, keep it out of the
parallel main CI run, and document the T9 matrix and F/G handoff.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Make scratch and hostile-repository probes fail closed
- scratch-capacity required only that fills fail, so an unwritable area
or a Codex container missing CODEX_HOME passed vacuously. Each fill now
must write before hitting its limit, and a Codex container must have
its Codex scratch areas.
- hostile-repo searched with grep -R, which follows symlinks, so a
hostile link to / or a loop could walk the whole container. Search
without following links and check the link targets separately.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Require exact live vendor values and widen gate breach coverage
- The container-level Codex live probe now reads the mounted schema
instead of echoing a fixed marker, and the Claude container probe and
both live adapter probes compare the trimmed value exactly, with no
allowance for wrapping quotes or backticks.
- Add gate breach cases for an unbounded HOME and for a repository link
that resolves inside the container, so the hostile-repository link
target checks can fail.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Cover Codex scratch areas and read-only phases in the gate self-tests
- Run scratch breach cases in a Codex environment with an unbounded
CODEX_HOME and an unbounded output directory, so removing or breaking
the Codex-only scratch checks fails the gate.
- Run the phase write-denial breach case in planning, questions and
review, and the metadata alias breach case in planning.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Discard forbidden command output in probe denials
deny suppressed only stderr, so a forbidden read that unexpectedly
succeeded (such as cat through a repository link) copied its data into
the invocation output before the breach was reported. Discard both
streams of the attempted command; the gate now requires empty stdout for
a resolvable repository link.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Refuse repository links that leave the checkout
The seeder copies repository symlinks as links, so an absolute link such
as root-link -> / let a path-restricted agent tool read container files
outside the checkout, including process environments that hold vendor
credentials. prepareTaskFilesystems now refuses, before creating
storage, any link with an absolute target or one that leaves the
checkout lexically or through a chain of links (checked with the POSIX
native realpath; the JavaScript realpath cancels .. before following
links and misses chained escapes). Links inside the checkout, loops and
not-yet-existing targets still work.
The hostile-repo probe now checks every link in /work, and the gate adds
breach cases for absolute and escaping links, a writable control
directory, and inode-only limit removal for task and scratch areas.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Allow contained link cycles and resolve link targets explicitly
- realpathSync.native reports ELOOP for an in-checkout cycle such as
a -> b, b -> a, and seeding rethrew it, refusing a repository whose
links all stay inside. A cycle never resolves, so treat it like a
missing target; direct escapes are still refused lexically.
- The hostile-repo probe resolves each link's target from the link's
directory rather than canonicalizing the link path, and treats an
unresolvable cycle as contained.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Prove each metadata-alias operation is detected on its own
The metadata-alias probe exits at its first breach, so the gate only
proved detection of the first succeeding operation. For each documented
operation (hard links, alias writes, config overwrite and truncation,
removal and both moves), the gate now checks the production script
denies it and that its deny line reports it when the operation succeeds
against plain writable metadata.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Refuse links in cloned Git metadata and bound the link scan per entry
- The link scan skipped .git, but the seeder copies it and it is mounted
at /work/.git, where the read-only mount stops writes but not reads
through a link. Git never needs links in its own metadata, so any
link there is now refused before allocation.
- Check the deadline and the entry limit before each directory entry is
queued, as the clone object audit does, so one huge directory cannot
defer either bound.
- Add Codex gate cases that remove only the inode limit of CODEX_HOME or
the output directory.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Resolve repository links as the container kernel does
Link containment treated a link whose target was missing on the host as
harmless, so a chain such as deep/er/top -> ../.. plus
chained -> deep/er/top/../run/codeboost-auth/codex/auth.json passed:
the host lacks that path, but in the container /work/.. is / and the
credential mount exists. Replace the host realpath check with a resolver
that follows each existing link component by component from the link's
directory, applies missing components textually, and requires the path
to stay inside the checkout after every step. More than 40 hops is a
cycle, which cannot resolve and is contained.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Compare live vendor probe values without trimming
The live probes trimmed responses, so surrounding whitespace passed. They
now accept the exact value, optionally followed by the single trailing
newline a CLI adds; the Codex container probe requires the value as an
exact, untrimmed output line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The `Agent isolation` workflow runs the same command. The main `CI` workflow skips
17
+
the Docker suites so that they never run in parallel.
18
+
19
+
The live vendor probes need real credentials, so CI does not run them. To run them,
20
+
set `CODEBOOST_RUN_AUTH_PROBES=1`, `CODEBOOST_CODEX_AUTH_FILE` (a Codex `auth.json`
21
+
path) and `CLAUDE_CODE_OAUTH_TOKEN`. Do not put credentials in an issue, a pull
22
+
request or chat.
23
+
24
+
## What the gate proves
25
+
26
+
Each row is a T9 requirement for the Docker suite. The suite fails if any row fails.
27
+
28
+
| Requirement | Tests |
29
+
| --- | --- |
30
+
| Isolation holds: non-root, no capabilities, read-only root, no host paths or secrets, vendor-only egress |`agent-container`: read-only isolation, lockdown and mount validation; `agent-network`: egress and DNS |
31
+
| A read-only phase cannot write `/work`|`agent-container`: phase worktree for all five phases |
32
+
| Planning and questions cannot run a process |`agent-policy`: tool sets exclude the command tool, and command dispatch refuses these phases |
33
+
| Task and scratch byte and inode limits hold |`agent-container`: task capacity; scratch capacity for Codex and Claude (`/tmp`, `HOME`, `CODEX_HOME`, output directory) |
34
+
| Hard links and alias writes from `.git/config` and objects fail, and metadata stays unchanged |`agent-container`: metadata alias probe in planning, review and execute, with a digest of `.git` before and after |
35
+
| Mountpoint replacement fails |`agent-container`: metadata and metadata alias probes (`mv` and `rm -rf` of `.git`) |
36
+
| Both vendor startup probes read the schema and return bounded valid output through their documented channel |`agent-supervisor` live probes: Codex through its output file, Claude through its stdout envelope (credentials required) |
37
+
| Hostile input stays inside the boundary |`agent-container`: repositories with links that leave the checkout are refused, links inside the checkout still work, oversized repositories fail closed; `agent-policy`: option-like prompts; `agent-proxy`: hostile CONNECT traffic; `agent-supervisor`: hostile output |
38
+
39
+
## Why the gate can fail
40
+
41
+
A test that cannot fail proves nothing. `agent-gate` runs each negative probe from
42
+
production in a container that is missing one protection. It then checks that the
43
+
probe reports that exact breach. The cases include writable Git metadata, a writable
44
+
worktree in each read-only phase, task and scratch areas without a byte or an inode
45
+
limit, the Codex-only scratch areas, a writable control directory, and repository
46
+
links or secret content in the worktree.
47
+
48
+
A probe also discards the output of any forbidden command it tries. So a breach that
49
+
succeeds, such as reading a file through a link, cannot copy data into the output.
50
+
51
+
Probe scripts must use the `deny` helper for actions that must fail. Do not write
52
+
`! command` in a probe: `set -e` ignores a negated command, so the probe would
53
+
continue and report success even when the forbidden action worked. Before D5, the
54
+
metadata, read-only isolation and capacity probes had this defect.
55
+
56
+
## Handoff to lanes F and G
57
+
58
+
Use only these entry points to run an agent:
59
+
60
+
1.`createTaskClone` creates a committed, standalone staging clone.
61
+
2.`prepareTaskFilesystems` copies that clone into bounded task storage. Call
62
+
`removeTaskFilesystems` when the task ends. It refuses a repository that has a
63
+
symbolic link with an absolute target or a target outside the checkout, before it
64
+
creates any storage. Report this to the user as a repository the agent cannot run
65
+
on; do not retry it.
66
+
3.`captureInvocation` freezes the request. Capture each attempt ID once. A new
67
+
attempt needs a new attempt ID.
68
+
4.`startCodexInvocation` or `startClaudeInvocation` runs the agent and returns a
69
+
handle. Pass the vendor credential only as the function argument.
70
+
71
+
The boundary guarantees the following:
72
+
73
+
- The profile is immutable, and every launch revalidates it against Docker.
74
+
- Tools are limited by phase. Planning and questions can only read, list and search.
75
+
- Web search and MCP are off, stdin is closed, and network traffic reaches only the
76
+
vendor hosts.
77
+
- Output is bounded and decoded as strict UTF-8. Invalid output fails as
78
+
`capture-failure`.
79
+
- The invocation deadline bounds every launch. Cleanup still runs after the deadline.
80
+
81
+
The caller must do the following:
82
+
83
+
- Keep ownership until `settled` resolves. It resolves only after the container has
84
+
stopped and its cleanup has finished. The supervisor retries cleanup until then.
85
+
- Call `cancel` to stop an invocation. The first stop reason is kept.
86
+
- Treat `stopReason` as the result of the invocation. A missing `stopReason` means
87
+
the agent finished normally.
88
+
89
+
## Limits of this gate
90
+
91
+
- CI does not run the live vendor probes. Run them locally with credentials before
92
+
a release that changes the image, the adapters or the prompts.
93
+
- T9 as a whole is complete only when lane F runs every suite in required CI (F6).
0 commit comments