✅ test(audit): pin the AUD2 remediations behind a PR-visible exit gate (AUD2-S05) - #82
Merged
Conversation
REQ-AUD2-S05-01..05. hack/audit/aud2_exitgate_test.sh asserts, per 2026-08-18
audit finding, that all four AUD2 remediations are still present:
REL-01/02/07 (S01) CallExec bounds stdout at MaxResponseBytes, sets
cmd.WaitDelay, and folds a bounded stderr into its error;
REL-03 (S02) resolveRunFacts skips only on forge.ErrNotFound;
SEC-03 (S03) hack/install.sh pins the cosign identity + OIDC issuer,
byte-identically with SECURITY.md;
TEST-02 (S04) isStricterInterventionEffect keeps EffectChallenge and
the named unit case defends it.
Three of the four have a decoy occurrence in the very same file (CallHTTP's
MaxResponseBytes, loadResourceOwnerRegistry's D-130 errors.Is guard, the
compare tests' EffectChallenge), so every assertion reads a function body
extracted by name, with a positive control on a known-present anchor and a
scoping control refusing the neighbouring decoy function. 14 mutation
controls on temp copies prove each assertion goes red, and red for its own
stated reason (REQ-AUD2-S05-02); the REL-03 mutant deliberately leaves the
D-130 guard intact, so a file-level grep stays green on it.
Wiring, in this same commit because the AUD-S18 pin exists to force exactly
that: `- task: audit-aud2-exitgate-test` in Taskfile check: (19th stage) and
the matching CHECK_STAGES entry in hack/audit/exitgate_test.sh. A stale pin
here is the AUD-S18/RELSE-08 incident that reddened main for four merges.
REQ-AUD2-S05-05: the gate runs as an early step of verify.yaml's `verify`
job, which fires on pull_request — not only in release-exitgate, whose
`if: github.event_name != 'pull_request'` is RELSE-08 itself. The gate
asserts that placement and reds if the step is deleted or the job grows a
push-only condition. What stays out of tree is recorded in the spec: making
`verify` a required check is branch protection, and the `task check` stage
still does not run on PRs. Also corrects verify.yaml's stale "all 14 task
check stages" comment (19 now).
Spec hygiene surfaced by AUD2-S03's re-review, all in the AUD2 spec:
REQ-AUD2-S03-06 promotes the real-SAN fixture assertion (D-153's "assertion
that would have caught the defect") from a Definition-of-done bullet to an
annotated requirement pinning install_cosign_pin_test.sh §4c/§4d; the Paths
owned table now records S03's SECURITY.md and CHECK_STAGES writes and S05's
actual footprint; and the Problem section's line numbers are dated to
b4f5054 with the SECURITY.md range corrected to that same era.
REQ-AUD2-S05-05. check_pr_wiring proved the `verify` job carries no job-level `if:`, but nothing read the workflow's own `on:` block — so deleting the `pull_request:` trigger removed the gate's entire pull-request reach for every job at once while every assertion stayed green. That is the same class of hole the REQ exists to close (RELSE-08 by another route), so it is now asserted, with a mutation control that keeps the step wired and only drops the trigger. Mutation-control floor raised 12 -> 15 to match. Verified identically green under GNU coreutils (debian:stable-slim), not only macOS BSD sed/awk/grep — this gate now runs on every PR on ubuntu-latest, and awk -v escape handling already bit once here.
Independent review, P1. check_notfound_discrimination's second assertion grepped the whole resolveRunFacts body for `^\s*return nil, nil, fmt.Errorf(`. That function has THREE such returns — the guard's own, the LoadProviderConfig path and the provider-call path — so the pattern was satisfied on every possible tree, including a broken one. The reviewer proved it with a compiling, gofmt-clean half-revert (guard kept, its body downgraded to `continue`, i.e. REL-03 fully restored) that this gate passed. An assertion that cannot fail is the exact defect class this epic exists to close, and its presence made the gate's own "every assertion can fail" banner untrue. The assertion now reads only the guard BLOCK — from `if !errors.Is(err, forge.ErrNotFound)` to the `}` at the same indentation, brace-matched on gofmt's indentation guarantee — over a comment-stripped view, because the guard's own prose names both LoadProviderConfig and the `continue` it replaced. Three controls keep the isolation honest: the region must start with the guard line, must not contain the LoadProviderConfig statement, and must be strictly smaller than the body. Adds the missing mutation control (16th): guard kept, first `return nil, nil, fmt.Errorf(` downgraded to `continue` at the same indentation. It asserts the guard line survives AND that two sibling returns survive, so the mutant is one a body-wide grep stays green on — that survival is the proof the assertion is scoped. Verified end-to-end: the mutated file is gofmt-clean, `go build ./cmd/assent` succeeds, and the gate reds naming REL-03. Also (F3) widens the REL-02 wait-forever defence: `[[ "$rhs" == "0" ]]` accepted `time.Duration(0)` and `0 * time.Second`, both of which are Go's wait forever. The rule is now "digits present and all of them zero", with a control for the typed spelling and a reverse control proving `30 * time.Second` is still accepted. MUTATIONS_PROVED 15 -> 17; the floor moves with it. Same file, same review round: - F2: the wiring section ran its mutants BEFORE its real-tree greens, so a genuine revert of the `check:` line / CHECK_STAGES entry / verify.yaml step surfaced as the harness's own "mutation did not land" instead of a REQ-named message. Green now runs first, as in sections 1-4. - F5: two of the three body_of over-extraction guards named a function ABOVE their target, and extract_func only reads downward, so they could never fire — the same species as F1. CallExec's now names execFailure (the function below it); isStricterInterventionEffect is the last function in its file and passes none. A direction-independent `^func ` count is the live backstop in every case.
…F4, F6) F4 — hack/audit/README.md had no entry for the 800-line AUD2 exit gate, and its exitgate_test.sh table still read "all 14 pinned stages", the identical stale number already corrected at verify.yaml:156. Both fixed: the count is 19, and aud2_exitgate_test.sh now has its own section covering what it asserts, why every assertion is scoped to a function body (three of the four remediations have a same-file decoy), why the REL-03 branch assertion reads only the guard block, the anti-vacuity discipline and mutation-control floor, the GNU/BSD portability recipe with the awk -v escaping trap, and — stated plainly — what it does NOT certify: the Later wave, WG-S01, branch protection, and the fact that the `task check` stage still does not run on PRs. F6 — the spec cited `provider_host.go:281-285` for loadResourceOwnerRegistry's D-130 guard in three places; at b4f5054 it is 282-286. Pre-existing, but this lane's new blanket "every line number in this section is as of b4f5054" now vouches for it. Also corrects the Reuse list's second `SECURITY.md:80-98` to 80-93 (the same overshoot into the SBOM section already fixed in Problem) and dates that list's line numbers to the same commit. Spot-checked the remaining citations in that list against b4f5054: transport.go:100-116, run.go:465-474 and provider_host.go:82-86 are all correct as written.
… appears"
Independent review round 2, P1 (finding A). The guard-scoped assertion still
asked "does a `return … fmt.Errorf(` appear anywhere in the region". The
reviewer built two mutants — both gofmt-clean, both compiling, both leaving
REL-03 fully restored — that the gate exited 0 on:
1. block-comment camouflage: the half-revert plus the return quoted inside a
`/* … */` span. code_only stripped `//` lines only, so the script's own
claim that a commented return cannot satisfy the assertion was false as
written.
2. nested fail-open, no comments at all: the return survives only under
`if errors.Is(err, context.Canceled) { … }`, followed by `continue`. Every
real forge error — 503, 401, 403, throttle — is skipped. This is the one
that needs no trick.
Mutant 2 is caught today by `go test -race` in the same PR-visible verify job,
so nothing merges through right now; it stays P1 because that only holds for a
revert that keeps the behavioural tests, and a revert that nests the return AND
drops the 401/403 cases would be invisible to both layers. That is TEST-02's
own failure mode reproduced inside the gate built to prevent it.
Two fixes, both required:
* TERMINAL PATH. The return must sit at exactly the guard's body indent — one
level deeper than the `if`, and no deeper — so a return reachable only under
a further condition does not count. gofmt (check stage 1) is what makes that
indentation load-bearing rather than cosmetic.
* code_only strips BLOCK comments too, via a state machine rather than a grep,
since `/* … */` spans cross lines. It does not model Go string literals;
that direction is fail-CLOSED (the assertion sees less code, never more) and
is documented rather than left implicit. The claim is now one the code backs.
Both reviewer mutants added as controls, each asserting the mutant is one the
PREVIOUS version accepted: the block-comment mutant still contains the required
return text, and the nested-if mutant's guard block still contains a real,
uncommented return. Verified outside the gate as well — spliced into the real
provider_host.go, both compile (`go build ./cmd/assent`), the nested one is
gofmt-clean as written and the commented one after `gofmt -w`, and the gate
reds naming REL-03 on each.
Finding B (P2): the PASS banner claimed the controls "proved every assertion can
fail". This script emits roughly forty distinct findings; twenty-two carry a
control. An exit gate whose banner overstates its own coverage is the D-124
failure mode this epic exists to close, so both were addressed:
* the two uncontrolled REQ-bearing sites now have controls — the CI step
present but DISARMED (`continue-on-error: true` and `if: false`, both
spellings, REQ-AUD2-S05-05's core property) and the check: stage still wired
and named but its body no longer invoking this script (REQ-AUD2-S05-03's
second half, the AUD-S18 gutted-stage-body lesson applied to this gate);
* the banner now states what is actually proved: N controls ran
(floor-asserted), each red for its own stated reason, covering every
REQ-bearing assertion here — NOT every finding the script can emit.
MUTATIONS_PROVED 17 -> 22; floor and README updated with it. Re-verified
byte-identical output under Debian/mawk (ubuntu-latest's awk), since this round
adds three awk programs.
Independent review round 3, P1. `de30e4f`'s subject — "measure the REL-03
guard's terminal path" — OVERSTATED what that commit achieved, and this one
says so on the record: an indent rule measures where a return SITS, not whether
the guard's path can be taken without stopping the run. The reviewer's
polarity-swapped revert
if !errors.Is(err, context.Canceled) {
continue
}
return nil, nil, fmt.Errorf(...)
puts a real return at exactly the guard's body indent and skips every forge
error except context.Canceled. Reproduced here on the real tree: gofmt -l
silent, go vet clean, go build OK, golangci-lint clean — and the previous gate
exited 0 printing "REL-03 ... CLOSED", while `go test ./cmd/assent` fails
TestProviderDeclarationForgeErrorAbortsResolveRunFacts and the 401/403 cases.
It is also the more idiomatic of the two guard-clause spellings.
And it was a CLASS, not a call site. REL-07's fold assertion was body-wide and
unscoped, so the same idiom reverted it too: nest the fold under
`errors.Is(err, context.DeadlineExceeded)`, `return nil, err` otherwise, and
every real provider failure loses its diagnostic while one matching line
survives. Verified the same way (clean toolchain, TestExecStderrFoldedIntoError
fails, old gate exit 0).
The discriminating property, for both:
REL-03 — no `continue` / `break` / `goto` anywhere inside the ErrNotFound
guard, at any depth. The remediated guard has none in code; every revert
shape needs one, because skipping the provider IS the defect. One assertion
kills all four mutants: plain half-revert, block-comment camouflage,
nested errors.Is fail-open, and the polarity swap.
REL-07 — no `return` inside the `cmd.Run()` failure branch may omit the
stderr sink. A path that does hands the operator a bare "exit status 1"
however the condition around it is spelled.
The terminal-path checks stay as necessary conditions — they name the defect
precisely when the absence check fires — but they are now documented as
insufficient rather than as the property.
THE FILTER INVERSION, which is the part that could have traded one unfailable
assertion for another. code_only is tuned for PRESENCE: over-stripping hides a
return and causes a false RED (safe). An ABSENCE assertion inverts that —
over-stripping hides the token being hunted and goes falsely GREEN — so
code_only is NOT reused. Absence assertions read a second filter,
code_conservative, which can only ever keep too much: it strips a line only
when its first non-blank characters are `//`, and a block span only when the
opening line's first non-blank characters are `/*`. A trailing `//` comment and
a mid-line `/*` are deliberately not recognised, because deciding whether the
marker sits inside a string literal is exactly the guess that produces the false
green. Its one residual — a multi-line raw string literal — is refused outright
by a backtick check (assert_no_raw_string) rather than assumed away.
Also audits REL-01 as asked: rhs_of reads the FIRST assignment and Go runs the
LAST, so appending `cmd.Stdout = &bytes.Buffer{}` after the bounded capture
reverted REL-01 with every existing check still reading the good statement.
cmd.Stdout, cmd.Stderr, cmd.WaitDelay and both sink variables must now be
assigned exactly once.
Four new controls (MUTATIONS_PROVED 22 -> 26): the REL-03 polarity swap, the
REL-07 nested fold, the REL-07 polarity swap, and the REL-01 reassignment. Each
asserts a precondition proving it is a mutant the PREVIOUS version accepted —
the polarity mutants put their return at the right indent, the REL-07 nested
mutant keeps a stderr-carrying return, the REL-01 mutant keeps the bounded
capture — so each control grades the new assertion and not the old one.
Corrects the three places that claimed the invariant the gate did not have:
hack/audit/README.md's "Scoping is the whole gate" (rewritten to five items,
with item 2 now explicitly labelled necessary-but-not-sufficient), the script
comment above the terminal-path check, and this commit body for de30e4f's
subject. Re-verified byte-identical under Debian/mawk.
… shape
Independent review round 4, two P1s — and this commit stops patching shapes.
What broke round 4's version, both compiling, gofmt/vet clean, both failing the
real tests, both passing the gate at exit 0:
* REL-03, condition NARROWING, one line, no camouflage:
if !errors.Is(err, forge.ErrNotFound) && errors.Is(err, context.Canceled) {
No fall-through, return at the correct body indent, every source-shape
heuristic green.
* REL-07, a bare return whose MESSAGE contains the identifier:
return nil, fmt.Errorf("provider exec failed (stderr suppressed): %w", err)
Both halves of the fold assertion are substring tests, not data flow, so
both accept it. It is a plain double-quoted string literal, which is why no
comment filter and no filter polarity can fix it — and it invalidates the
"keeping too much is fail-closed" argument for that assertion specifically,
since a NEGATED match makes extra kept text fail-OPEN.
And the demonstration that settles it: revert REL-03 *and* delete its two
behavioural tests — `go test ./cmd/assent/` green, gate green.
Anything that re-derives these two remediations from unparsed Go source text has
unbounded surface. So they are now pinned the way TEST-02 already was — BY TEST
NAME — and the shape checks are demoted to a documented secondary heuristic.
REL-03 -> TestProviderDeclarationForgeErrorAbortsResolveRunFacts,
TestProviderDeclarationUnauthorizedAbortsResolveRunFacts, and the
[]int{401, 403} case table, in cmd/assent/provider_host_test.go
REL-07 -> TestExecStderrFoldedIntoError and its three t.Run cases, in
internal/provider/transport_test.go
THE COMPOSITION, written into the script and the README so nobody simplifies one
half away: a revert that KEEPS the tests reds via `go test` — check stage 4,
before this gate's stage 19, and a step of the same PR-visible verify job; a
revert that DELETES or RENAMES them reds here, because `go test` reports a
deleted test as success. Neither half can be defeated by restructuring
production source, which is what every mutant that beat the shape checks does.
Verified end to end: with the narrowing applied and the tests renamed away, the
gate reds naming both missing tests.
The shape checks are kept, not deleted — they name the defect precisely on the
shapes they do recognise, and their controls are strong. They are just no longer
treated as the property. Both blind spots are now recorded as EXECUTABLE
controls that assert the heuristic still accepts them, so a future change that
drops the name pins turns them red instead of passing quietly.
Doc truth (F4). Removed every claim the gate cannot back: README item 3's "every
revert shape needs one, because skipping the provider IS the defect", the
REL-07 "however the condition around it is spelled" in both the README and the
script message, and item 4's "its ONE residual" (an ordinary string literal is a
second, and the fail-closed argument does not hold for REL-07's negated match at
all). Added a "What actually holds each remediation closed" table — the four are
not held by the same mechanism and the README said otherwise. The PASS banner
now states the composition per finding instead of implying uniform source pins.
Notes fixed, not chased (F5, F6): the rel07nested/rel07polarity mutants inject
errors.Is into transport.go, which does not import `errors`, so they do not
compile as spliced — the comment claiming "gofmt/vet/lint/build clean" was wrong
and now says the controls grade TEXT, with the compile-clean equivalent verified
separately on the real tree. And the rel07fold control's witness was
`return nil, err`, which already occurs twice in CallExec, so a no-op sed
reddened with "mutation harness: sed did not change" instead of naming REL-07;
the witness is now the CallExec-scoped absence of the execFailure call.
Four new controls (MUTATIONS_PROVED 26 -> 30): test rename and dropped case for
each of REL-03 and REL-07. Plus two non-counting blind-spot controls. Re-verified
byte-identical under Debian/mawk.
Independent review round 5, P1: a name is not a behaviour. Keep the pinned test
names, empty the bodies —
func TestProviderDeclarationForgeErrorAbortsResolveRunFacts(t *testing.T) {
t.Skip("temporarily disabled")
}
— add the one-line condition narrowing, drop the orphaned imports, and the
result is gofmt silent, go build OK, go vet OK, `go test ./cmd/assent/` ok, and
this gate GREEN with REL-03 fully reverted. `t.Skip("flaky")` is a routine
event, not a contrivance. Round five's "keeps the tests / deletes the tests"
was presented as a partition and is not one: gutting is a third case that both
halves missed. There is no third backstop either — cmd/ is outside
./internal/..., so the coverage floor does not move when those tests are gutted.
The decisive argument was from this script itself: it already builds
Taskfile.gutted.yml to control for body-gutting against the Taskfile stage,
citing the AUD-S18 gutted-coverage-body lesson, and did not apply that same
reasoning to its own primary pin.
THE FIX, and it terminates the class because it measures behaviour instead of
reading text or names: copy the working tree's tracked files to $WORK, apply the
revert TO THE COPY, run the pinned tests against the copy, and require them to
FAIL. Indifferent to how the production revert is spelled (condition narrowing,
polarity swap, string-literal return) AND to how a test might be hollowed out
(t.Skip, a no-op body, a deleted assertion), because it reports what the tests
DO. Nothing is written to the real tree.
Three ways it could pass for the wrong reason are refused explicitly:
* the pinned tests must first `--- PASS:` BY NAME on an unmutated copy —
`go test` exits 0 both when a -run pattern matches nothing and when a test
calls t.Skip, so an exit code would treat a disabled test as passing;
* a `[build failed]` transcript on the reverted copy is refused — "the mutant
does not compile" is not evidence about behaviour (controlled: a mutant that
does not build reds with its own message);
* the reverted run must fail AND name a pinned test in a `--- FAIL:` line.
Verified end to end on the real tree with EVERY text pin satisfied in live code
(names kept, `[]int{401, 403}` kept as a real statement, not a comment):
gofmt/build/vet clean, `go test ./cmd/assent/` ok — and the gate exits 1 with
"the pinned tests still PASS with … REVERTED in a copy of the tree".
Cost, measured: the tracked-file copy is ~1,200 files / 8.6 MB and is effectively
instant; the two `go test -run <pinned>` runs take ~2s each. Whole gate ~40s at
check stage 19, after `task test` has already built the packages. The behavioural
runs are top-level checks, NOT inlined into the per-file check functions — a
dozen mutation controls re-invoke those against mutant files, and inlining took
the gate from 4s to 65s.
--text-only added (the AUD-S18 idiom): pattern layer plus its full mutation
harness, skipping the behavioural runs, for exercising the patterns under
Linux/GNU grep + mawk in a container with no Go. Its PASS banner says plainly
that it certifies NOTHING about REL-03/REL-07. Both the Taskfile stage and the
verify.yaml step are now asserted to invoke the script with NO arguments, with a
control for each, so the flag cannot disarm the gate where it counts. The
control floor is mode-aware (36 full, 32 text-only) so neither mode can shrink.
F4: case pins now read a comment-stripped view. `[]int{401, 403}` was being
satisfied out of a Go comment left behind by a gutted body, while every
production-source assertion in this script already filtered comments.
F3: dropped check_named_tests' corpus control. `grep -cE '^func Test' >= 1`
cannot independently fail — any file satisfying a `func <pinned>(` pin
necessarily contains a `^func Test` line — which is the D-124 species this epic
exists to close.
Doc truth: hack/audit/README.md's "a revert that keeps the tests is caught by
`go test`" bullet and the keeps/deletes partition are removed and replaced by an
explicit correction recording what was false and why, plus what replaced it. The
"What actually holds each remediation closed" table row for REL-03/REL-07 and
the gate's own assert-table rows now name the mutation run. The PASS banner
states the same.
Also made the REL-03 revert program indent-anchored so it lands on the
provider-declaration guard only — the identical D-130 guard in
loadResourceOwnerRegistry sits at one tab, this one at three, and an unanchored
program reverted both.
Four new controls (MUTATIONS_PROVED 30 -> 36): t.Skip bodies, no-op bodies for
each finding, a non-compiling revert, and the two --text-only disarm controls.
Re-verified byte-identical under Debian/mawk in --text-only mode.
Independent review round 6, two P1s.
F1 — THE QUORUM WAS WEAKER THAN THE CLAIM. The behavioural run was satisfied
when AT LEAST ONE pinned test landed in a `--- FAIL:` line, while the banner and
README claimed indifference to hollowing "including a deleted assertion". Two
escapes, both executed by the reviewer and both now controls here:
* gut only TestProviderDeclarationUnauthorizedAbortsResolveRunFacts (`_ = t`
plus `_ = []int{401, 403}` in LIVE code so the case pin stays green),
production source untouched -> go test ok, gate exit 0. Its sibling still
failed under the revert and satisfied the quorum; the entire 401/403 auth
branch was left undefended.
* empty the body of t.Run("nonzero_exit_reports_stderr", …) — the canary that
IS REL-07's behavioural defence — keeping the name. The function-level FAIL
line still appeared (the sibling subtest fails), so the gate exited 0.
Fixed with an explicit must-fail list per finding, and the asymmetry is
deliberate and measured, not generalised:
REL03_MUSTFAIL = ForgeError, Unauthorized/401, Unauthorized/403
REL07_MUSTFAIL = nonzero_exit_reports_stderr,
runaway_stderr_is_bounded_and_truncated
REL-07's third subtest, stderr_never_merged_into_facts, is deliberately NOT
required: under the fold-dropping revert it LEGITIMATELY PASSES — it asserts
stderr does not leak into the fact map, which stays true when the fold is
removed — so demanding it would be an assertion no correct tree can satisfy. It
is still held by the case pin in check_named_tests. Transcript names measured,
not assumed:
--- FAIL: TestExecStderrFoldedIntoError/nonzero_exit_reports_stderr
--- PASS: TestExecStderrFoldedIntoError/stderr_never_merged_into_facts
--- FAIL: TestExecStderrFoldedIntoError/runaway_stderr_is_bounded_and_truncated
REL-03 pins subtests too, which is stronger than the review asked for and
verified safe by the same measurement: dropping just the 401 case is now caught
at case granularity. Match uses a trailing space (`--- FAIL: X `) so a
function-level pin cannot be satisfied by one of its own subtests.
F2 — THE GATE EXITED 0 ON BASH 3.2. Under stock macOS /bin/bash the script died
at the first `local -n` nameref after one section header and exited 0. Confirmed
against the previous commit in place: EXIT=0, with "local: -n: invalid option"
and "fns[@]: unbound variable" on stderr. CI is ubuntu/bash 5 so nothing merges
through, but AGENTS.md rule 4 makes a green LOCAL `task check` a per-commit
precondition, and this is the anti-vacuity gate certifying nothing on a
maintainer's machine. Now asserted first, before anything can partially run;
observed EXIT=1 with a named message under /bin/bash 3.2.57.
F3 — "pure text over the source, needs no toolchain, fails in seconds" survived
at four sites and has been untrue since the behavioural runs landed. All four
corrected: .github/workflows/verify.yaml, Taskfile.yml, this script's header,
and hack/audit/README.md — the last was worst, because it DERIVED the PR-reach
argument from a property the gate no longer has and contradicted its own runtime
figure sixty lines below. The reach argument is now made on its own terms (the
verify job is the one that fires on pull_request; release-exitgate does not),
and --text-only is named as the mode that is still toolchain-free.
F4 — the gate step sat ABOVE actions/setup-go in verify.yaml. With
`toolchain go1.26.6` in go.mod the first `go test` would have had to download a
toolchain with no Go cache present, and this branch has no PR and no CI run, so
the placement had never executed. Moved below setup-go, with the reason recorded
in the step so it is not "tidied" back up.
MUTATIONS_PROVED 36 -> 38; full-mode floor raised with it (text-only floor
unchanged at 32). Runtime measured here at 52s (38.6s for the reviewer); the
figure is now stated as a range in all three places rather than as one machine's
number. Re-verified --text-only byte-identical under Debian/mawk, and re-ran the
three other verify.yaml readers after moving the step.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
AUD2-S05 — the P5-AUD2 epic exit gate
Closes the P5-AUD2 epic. Adds
hack/audit/aud2_exitgate_test.sh(2121 lines), whichasserts the four 2026-08-18 audit remediations landed by S01–S04 are still present, and
wires it PR-visibly as the 19th
task checkstage.The four remediations it pins
CallExec(bounded stdout atMaxResponseBytes,cmd.WaitDelay)TestExecStderrFoldedIntoErrormust FAIL against itresolveRunFactstestshack/install.sh+ no drift fromSECURITY.mdTestClassifyStricterInterventionAddedChallengeEffectThe mutation runs are indifferent both to how a production revert is spelled and to how a
test might be hollowed out (
t.Skip, a no-op body, a deleted assertion all redden it).38 mutation controls run, floor-asserted, each red for its own stated reason.
Why it is in
verify, not onlyrelease-exitgaterelease-exitgatecarriesif: github.event_name != 'pull_request'(RELSE-08), so a gatewired only there is invisible to every PR — exactly how AUD-S18's stale
CHECK_STAGESpinsurvived four merges. This gate is a
task checkstage and the same commit adds it toCHECK_STAGES(now 19).Step position in
verify.yamlis load-bearing: it sits belowactions/setup-go,because the gate runs
go build/go testagainst reverted tree copies andgo.modpinstoolchain go1.26.6.Verification on this head
task checkexit 0; 19/19 unique stage banners observed in the transcript.bash hack/audit/aud2_exitgate_test.shexit 0 (full mode);--text-onlyexit 0.bash hack/audit/exitgate_test.sh --text-onlyexit 0 — the AUD-S18 grader confirms"Taskfile check: runs exactly the 19 pinned stages".
task ci-audit-testexit 0.git diff origin/main...HEADoverinternal/provider/transport.go,cmd/assent/provider_host.go,internal/compare/,hack/install.sh,SECURITY.mdisempty — this lane modifies none of the remediations it grades.
agent-context/committed.Integrator-owned commits
CHANGELOG.mdregenerated withtask changelog-writeafter the rebase (a no-op — thelane was already based on
07b44db) and amended into the tip, alongsideopenspec/specs/backlog.md's AUD2 status line (AUTONOMOUS COMPLETE,AUD2-F01leftexplicitly OPEN as a follow-up, not an AUD2 story, per D-152).
Branch note
The changelog amend rewrote SHAs already published on
lane/aud2-s05, and force-push is notauthorized (AGENTS.md rule 2) — so this PR comes from a new branch.
lane/aud2-s05stays onorigin at
d1c8096as the pre-rebase review record.Independent review: APPROVE after seven implementation rounds and eight reviews; no P0/P1
outstanding. This branch has never had a CI run (lane branches get no Actions here), so this
PR is the first time the gate executes on a real runner.