.github/workflows at 895208db30, reviewed by claude-code, verified by codex.
deploy.yml gates the generated-documentation drift checks (cost-model table, before/after page) on `steps.filter.outputs.code == 'true'`, so a Markdown-only pull request — the only change class that can hand-edit those generated .md pages — is exactly the pull request on which the checks never run, and hand-edited drift ships.
#!/bin/sh
set -u
fail() { echo "NOT DEMONSTRATED: $1"; exit 1; }
echo "== A. deploy.yml gates the cost-table drift check on the docs-only filter =="
step=$(grep -n -A2 "name: Check the cost-model page's table" .github/workflows/deploy.yml) || fail "cost-table step not found in deploy.yml"
printf '%s\n' "$step"
printf '%s\n' "$step" | grep -q "if: steps.filter.outputs.code == 'true'" || fail "the cost-table step is not gated on the docs-only filter"
echo
echo "== B. deploy.yml's OWN filter logic, run verbatim on a .md-only change =="
files="docs/design/cost-model.md"
if printf '%s\n' "$files" | grep -qvE '(^$|\.md$)'; then code=true; else code=false; fi
echo "changed files: $files"
echo "filter verdict: code=$code -> the step in A does NOT run on this pull request"
[ "$code" = "false" ] || fail "the filter did not classify a .md-only change as docs-only"
echo
echo "== C. the skipped check is what stands between a hand-edit and published drift =="
bash scripts/gen-cost-table.sh --check >/dev/null 2>&1 || fail "baseline: the committed page is already drifted, or gen-cost-table.sh cannot run here"
echo "baseline: gen-cost-table.sh --check PASSES on the committed page"
awk '{print} /<!-- cost-table:start -->/{print "| tampered | 999s | 999s |"}' docs/design/cost-model.md > docs/design/cost-model.md.tampered || fail "could not edit the page"
mv docs/design/cost-model.md.tampered docs/design/cost-model.md
echo "hand-edited docs/design/cost-model.md (a Markdown-only change):"
sed -n '43,46p' docs/design/cost-model.md
out=$(bash scripts/gen-cost-table.sh --check 2>&1); rc=$?
[ "$rc" -ne 0 ] || fail "the drift checker passed on a tampered page"
echo "gen-cost-table.sh --check now exits $rc:"
printf '%s\n' "$out" | head -6
echo
echo "== D. nothing always-on covers it =="
echo "invocations of the generator checks anywhere in .github/workflows:"
grep -rn 'gen-cost-table.sh\|gen-before-after.py' .github/workflows || true
echo
echo "DEMONSTRATED: a Markdown-only PR can hand-edit the generated cost table (and, by the same"
echo "gating at deploy.yml:206, docs/design/before-and-after.md); the only check that catches it"
echo "is gated on code=='true', which a Markdown-only PR is not."
exit 0== A. deploy.yml gates the cost-table drift check on the docs-only filter == 199: - name: Check the cost-model page's table hasn't drifted from its ledger fixture 200- if: steps.filter.outputs.code == 'true' 201- # Same reasoning as the CLI reference above: docs/design/cost-model.md's == B. deploy.yml's OWN filter logic, run verbatim on a .md-only change == changed files: docs/design/cost-model.md filter verdict: code=false -> the step in A does NOT run on this pull request == C. the skipped check is what stands between a hand-edit and published drift == baseline: gen-cost-table.sh --check PASSES on the committed page hand-edited docs/design/cost-model.md (a Markdown-only change): <!-- cost-table:start --> | tampered | 999s | 999s | | Phase | `src/flask/cli.py` (scan 1, pallets/flask, 2026-08-30, N=6 trees) | `src/requests/adapters.py` (scan 2, psf/requests, 2026-08-30, N=6 trees) | |---|---|---| gen-cost-table.sh --check now exits 1: FAIL: docs/design/cost-model.md's generated table has drifted from the recorded fixtures in docs/design/fixtures/: --- docs/design/cost-model.md 2026-09-08 12:36:30.995530082 -0400 +++ /tmp/tmp.4hj6jx3Cxt/spliced.md 2026-09-08 12:36:31.033530584 -0400 @@ -41,7 +41,6 @@ reproduce the `time:`/`cost:` lines below exactly. == D. nothing always-on covers it == invocations of the generator checks anywhere in .github/workflows: .github/workflows/deploy.yml:203: # and cost-model-requests.json by scripts/gen-cost-table.sh, never hand-edited. .github/workflows/deploy.yml:204: run: bash scripts/gen-cost-table.sh --check .github/workflows/deploy.yml:209: # scripts/gen-before-after.py, never hand-edited. .github/workflows/deploy.yml:210: run: python3 scripts/gen-before-after.py --check DEMONSTRATED: a Markdown-only PR can hand-edit the generated cost table (and, by the same gating at deploy.yml:206, docs/design/before-and-after.md); the only check that catches it is gated on code=='true', which a Markdown-only PR is not.
I checked the validate job's complete control flow and searched the scoped workflows for other invocations. The cost-table and before/after checks at deploy.yml:199-210 both require code == 'true', while the filter sets code=false when every changed path ends in .md. The always-running TestDocs and licensing steps do not invoke either generator. The supplied reproduction also exercises the precise Markdown-only case and demonstrates detectable drift being skipped.
ref 73b875458dcf2f9890b0838ab3e80b633d0f1251a90264d96ea51f5d5f519f60#R1
sbom.yml's `attach-to-release` job can never fire for a release cut by release.yml, because that release is created with GITHUB_TOKEN and GitHub does not start workflow runs from GITHUB_TOKEN-created events — so the SBOM is not attached to any release, contradicting this workflow's own header.
I checked both workflows for an independent release-event source or direct SBOM attachment. release.yml:97-134 creates the release through gh using github.token, while sbom.yml:40-54 attaches only during a separate release event. There is no workflow_run bridge, repository-dispatch, PAT, or attachment step in release.yml that would avoid GitHub's suppression of workflow runs triggered by GITHUB_TOKEN-generated events.
ref 73b875458dcf2f9890b0838ab3e80b633d0f1251a90264d96ea51f5d5f519f60#R2
release.yml passes `--latest` unconditionally and never `--prerelease`, so a release-candidate tag such as v1.0.0-rc.11 is published as a full release and displaces any stable release as `Latest` — the exact 'the Releases page advertises the wrong build' failure this workflow was written to prevent.
I inspected the complete publish command and repository tag history. release.yml:130-134 unconditionally supplies --latest and never supplies --prerelease, with no conditional classification of tags containing -rc. The repository contains v1.0.0-rc.1 through v1.0.0-rc.11, all cut after the release workflow was introduced. Nothing in the workflow prevents a successful RC publication from being classified as a normal latest release.
ref 73b875458dcf2f9890b0838ab3e80b633d0f1251a90264d96ea51f5d5f519f60#R3
In deploy.yml's self-hosted deploy job, `git checkout -- internal/ui/console.manifest.sig` is reached only on the success path under `set -euo pipefail`, so any failure in signing, signature verification, or either `go build` leaves the production clone dirty and every subsequent deploy fails at `git pull --ff-only` — the failure mode the line's own comment says it exists to prevent.
The cleanup defect is real, but the finding overstates its consequence: a dirty tracked console.manifest.sig does not make every later git pull --ff-only fail. Git accepts a fast-forward when incoming commits do not modify the dirty path. The script constructs that exact repository state, advances the remote on an unrelated file, and proves the fast-forward pull succeeds while the signature remains dirty. Also, a failure before sign-console-bundle.sh writes its atomic replacement need not dirty the file at all.
#!/bin/sh
set -eu
work=$(mktemp -d "${TMPDIR:-/tmp}/corral-r4.XXXXXX")
trap 'rm -rf "$work"' EXIT HUP INT TERM
git init --bare "$work/upstream.git" >/dev/null
git clone "$work/upstream.git" "$work/source" >/dev/null 2>&1
(
cd "$work/source"
git config user.name verifier
git config user.email verifier@example.invalid
mkdir -p internal/ui
printf '%s\n' original > internal/ui/console.manifest.sig
printf '%s\n' base > tracked.txt
git add internal/ui/console.manifest.sig tracked.txt
git commit -m base >/dev/null
git push origin HEAD >/dev/null 2>&1
)
git clone "$work/upstream.git" "$work/deploy" >/dev/null 2>&1
(
cd "$work/source"
printf '%s\n' upstream > unrelated.txt
git add unrelated.txt
git commit -m upstream >/dev/null
git push origin HEAD >/dev/null 2>&1
)
(
cd "$work/deploy"
printf '%s\n' dirty > internal/ui/console.manifest.sig
git pull --ff-only >/dev/null
test "$(cat internal/ui/console.manifest.sig)" = dirty
test "$(cat unrelated.txt)" = upstream
test -n "$(git status --short internal/ui/console.manifest.sig)"
)ref 73b875458dcf2f9890b0838ab3e80b633d0f1251a90264d96ea51f5d5f519f60#R4
deploy.yml's deploy job builds whatever `git pull --ff-only` produces in ~/corralai and never compares HEAD to `github.sha`, so a clone left on a branch other than main deploys code that is not the pushed commit and reports a green deploy; and because `mv -f corral.new corral` overwrites the running binary before the health probe, a failed /healthz leaves the service down with no rollback target.
I traced the entire deploy script. It enters an existing clone, runs an unqualified git pull --ff-only on whichever branch is checked out, and never compares HEAD, its branch, or the pulled commit with github.sha. It then stops the service and replaces both installed binaries with mv -f before starting and probing health. No saved binaries, rollback command, trap, or alternate service target exists.
ref 73b875458dcf2f9890b0838ab3e80b633d0f1251a90264d96ea51f5d5f519f60#R5
self-audit.yml's comment claims the audit runs 'the corral of the commit we CHECKED OUT', but on a pull_request event actions/checkout checks out the merge ref while `corral-version` is `head.sha` — the binary doing the auditing is built from a different tree than the one being audited.
I checked checkout and action installation semantics in the workflow. On pull_request, the unqualified actions/checkout step checks out GitHub's merge ref, but self-audit.yml:124 explicitly installs corral at pull_request.head.sha. The action audits GITHUB_WORKSPACE, so the installed head-revision binary audits the checked-out merge tree. The two revisions may coincide in content only when the synthetic merge adds no base-side differences; the workflow does not enforce that.
ref 73b875458dcf2f9890b0838ab3e80b633d0f1251a90264d96ea51f5d5f519f60#R6
self-audit.yml passes neither `attest` nor `ledger` to the action, so a self-audit budgeted at up to 340 minutes of paid model calls produces no signed statement, no attestation and no ledger entry — the action takes the `--no-ledger` branch and the run's only artifact is an ephemeral job summary.
I inspected all inputs passed at self-audit.yml:112-177 and followed their handling in action.yml. The call supplies neither attest nor ledger. Consequently ATTEST is not true, LEDGER_DIR is empty, the certify invocation receives --no-ledger, and the attestation and statement-upload steps remain disabled. The report is copied only into GITHUB_STEP_SUMMARY; no durable signed statement or ledger record is configured.
ref 73b875458dcf2f9890b0838ab3e80b633d0f1251a90264d96ea51f5d5f519f60#R7
cla.yml's allowlist entry `bot*` is turned into an unanchored regular expression by contributor-assistant (as the file's own comment states patterns containing `*` become regexes), which would exempt any contributor login merely containing that stem from signing the CLA.
I looked for a repository-side anchor, escaping rule, or validation test that narrows bot* to bot accounts and found none. cla.yml:33-41 expressly says entries containing * become regular expressions and supplies bot* without anchors. Under ordinary regular-expression semantics this is not a glob for names beginning with bot: t* is a repetition and the expression can match a substring. Confirming the dependency's precise implementation would strengthen the claim, but nothing in scope refutes the stated risk.
ref 73b875458dcf2f9890b0838ab3e80b633d0f1251a90264d96ea51f5d5f519f60#R8
release.yml triggers on any `v*` tag push with no dependency on the validate workflow's result, so a tag placed on a commit whose CI is red or never ran publishes a release and marks it latest.
I checked the complete trigger and job graph. release.yml responds directly to every v* tag push and contains no needs relationship, workflow_run trigger, commit-status query, branch-containment check, or validation of deploy.yml's required result. Its local signature and changelog checks are release-specific and do not establish that the tagged commit passed the repository's validation workflow.
ref 73b875458dcf2f9890b0838ab3e80b633d0f1251a90264d96ea51f5d5f519f60#R9
Recorded so that "found nothing here" can be told apart from "never looked here".
The workflows in this directory are unusually well-argued — most of the comments are post-mortems, and several of the traps a cold reviewer normally finds here (unpinned actions, `pull_request_target` with a checkout, a doc gate unreachable by doc changes, `tee` swallowing a gate's exit code) have already been found and closed, some with Go tests that read the YAML structurally. So the interesting failures are the ones the existing fixes did not generalise. Finding 1 is the one I would act on: deploy.yml carries a long, correct comment about the doc gates having been structurally unreachable by the one class of change they police — and then, forty lines further down, wires three GENERATED-Markdown drift checks (`gen-cost-table.sh --check`, `gen-before-after.py --check`) behind exactly the `if: steps.filter.outputs.code == 'true'` the comment above condemns. Their inputs are `.md` pages the header of each script says are 'never hand-edited'; a hand-edit of one is a Markdown-only PR; a Markdown-only PR is precisely the PR on which those checks do not run. The same shape, one door over. The script proves it end to end: the filter's own logic says `code=false`, and the skipped checker fails on a tampered page. Findings 2 and 3 are about the release path and I think both are live today. 2 says the `attach-to-release` job in sbom.yml is dead for every release this repo actually cuts, because `gh release create` runs under GITHUB_TOKEN and GITHUB_TOKEN-created events do not start workflow runs — sbom.yml's own header claims the opposite. 3 says every `v1.0.0-rc.N` tag has been published with `--latest` and without `--prerelease`, so the Releases page and `/releases/latest` have been serving a release candidate as the newest release — a workflow written to stop the Releases page from lying about what to install. Findings 4 and 5 are the self-hosted deploy job, which is the least defended thing here: it never checks that the commit it builds is the commit that was pushed, it leaves the production clone dirty on any failure between signing and the restore (poisoning every later deploy at `git pull --ff-only`, which is the failure its own comment names), and it destroys the running binary before the health check with nothing to roll back to. Finding 7 is a smaller thing but sits oddly against the project's stated position: corral's audit of corral is the one run that produces no receipt and no ledger entry.
R1, R2, R3, R5, R6, R7, R8, and R9 stand. R4 is refuted because the dirty signature file does not make every subsequent git pull --ff-only fail; Git permits a fast-forward pull when upstream changes do not overlap the dirty path. The underlying missing cleanup remains real, but its stated inevitable consequence is too broad.