fix(delivery): the on_green_tests gate ran the suite in the live checkout

Fourth instance of the same defect, and the last of the three commands that run
as root against a mission tree.

`verify_tests` execs the project's test command with `workdir = repo` — the live
checkout — inside a container running as ROOT. `cargo test` writes `target/`, so
the checkout ends up owned by two uids and the next phase's cargo hits
permission-denied. The harness reported `uids=0,65532` the first time this gate
ever ran end to end.

It survived because it had never run. Every one of the ten harness fixtures used
`commit_policy: "always"`; `on_green_tests` and `on_reviewer_approval` were
parsed, implemented, and never exercised — and `Gate`'s own doc already records
that three recipes carried this policy while it "did precisely nothing" for want
of a reader. A policy that is never exercised is indistinguishable from one that
is ignored.

Consolidated rather than fixed a third time. `root_copy` now owns the pattern —
copy through `mission_fs::pack_dir` into a SIBLING of the mission dir, run there,
and purge FROM INSIDE THE CONTAINER, because the copy's `target/` is root-owned
and the server (uid 65532) cannot delete it. `benchmark_runner` moved onto it;
`evaluator_tools::Sandbox` keeps its own copy logic for now (it carries an
allow-list and a judge-facing API, so folding it in is a larger change than this
moment warrants — noted, not done).

The gate fails CLOSED if the copy cannot be made: an unverifiable suite must not
license a push.

Also adds the `refactor` scenario, which is what found this. I had written it off
as "structurally identical to four existing scenarios" — wrong: it is the only
recipe carrying `on_green_tests`, and that made it the only one testing this
code path at all.

245 lib tests, 20 test binaries.
This commit is contained in:
Omar Sobh
2026-08-07 17:48:29 -07:00
parent a4b4d05b8d
commit a8b8efba6a
5 changed files with 219 additions and 75 deletions
+23 -1
View File
@@ -345,7 +345,29 @@ pub async fn capture_phase_diff_at(
if gate == Gate::OnGreenTests {
let container = std::env::var("CLAWMATES_RUNTIME_CONTAINER")
.unwrap_or_else(|_| "clawmates-runtime".to_string());
let o = verify_tests(&repo, &container).await;
// Against a COPY, never the checkout. `verify_tests` execs
// `cargo test` in a container running as ROOT, which writes
// `target/` — in the live tree that leaves root-owned build
// output in a checkout owned by uid 65532 and breaks the
// single-writer invariant. Measured the first time this gate
// ever ran end to end: `uids=0,65532`.
//
// The gate had been implemented but never exercised (every
// harness fixture used `commit_policy: "always"`), which is why
// a bug this mechanical survived in it.
let gate_root = crate::root_copy::copy_root("_gate", mission_id);
crate::root_copy::purge(&container, &gate_root).await;
let o = match crate::root_copy::RootCopy::of(&repo, &gate_root) {
Ok(copy) => {
let r = verify_tests(copy.workdir(), &container).await;
crate::root_copy::purge(&container, &gate_root).await;
r
}
// Fail-closed: an unverifiable suite must not license a push.
Err(e) => TestOutcome::CouldNotRun(format!(
"could not copy the checkout to test it: {e}"
)),
};
// An infrastructure fault must be loud. The gate degrades
// safely either way, but "we could not run the suite" is a
// problem with the platform and needs to look like one.