test(review): assert every workflow-level concurrency key, not its comment - #1970
Conversation
test_privileged_review_dispatch_coalesces_superseded_runs_before_admission
asserted that the group expressions appear anywhere in the raw text of the
workflow-level concurrency block. That block carries a comment explaining
the key, so a maintainer quoting the expressions there while the group
itself was collapsed to ${{ github.repository }} would leave every pull
request in a repository sharing one group and cancelling each other, with
the contract still green.
Verified by isolated mutation against main: collapsing only the group value,
keeping cancel-in-progress, and moving both expressions into a comment
passed 58/58 before this change and fails after it. An earlier mutation
appeared to be caught, but its regex had also deleted cancel-in-progress,
so the catch was a side effect rather than the property under test.
workflow_level_concurrency_group slices the group's own value, dropping
comment lines and stopping at the next key, and joins the folded block's
continuation lines. Two tests pin it: one on the shape that defeated the
old assertion, one on the real folded multi-line key. PyYAML is not
available to this suite, so the slice is textual.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…mment Extends the group-value slice from opencode-review-dispatch.yml to the four other workflows whose contracts asserted their group expressions against the raw concurrency block: strix.yml, noema-review.yml, opencode-review.yml, codeql-pr.yml, security-scan.yml and codeql-scan-dispatch.yml. Each raw block carries comments explaining its key, so a maintainer quoting the expressions while the key itself was collapsed left the contract green. Negative assertions and cancel-in-progress stay on the raw block: forbidding a string anywhere in the block, comments included, is the stronger check for those. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Warning Review limit reachedNext included review available in 40 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Verification (lane host 1) — independent executionHead confirmed by Isolated mutation matrix, run by meThe mutation collapses each workflow's
7 of 7 caught here, 0 of 7 caught on The helper, probed adversarially
Its structural assumption also holds: the helper slices the header at Gate, my run2958 passed, 1 skipped, 21 subtests; coverage 100% (0 missed); interrogate 100% — matching the author's figures, reached independently. One non-blocking observationThe helper raises a bare Verdict: verified. No blocking findings. 🤖 Verified by Claude Code |
|
Merged as Merger verification (this session, independent of the author's and the verifier's)Head identity. GitHub's live head matched the verified SHA at merge time; the Scope. 2 files, +121/−26, every path under Own discriminating control. The first mutant I wrote did not discriminate — collapsing the group That is the hole this PR closes, and it is live: I created it earlier today. #1964 adds a long comment Gate on the merge tree. 2958 passed, 1 skipped, 21 subtests; coverage 100%; interrogate 100% — Post-merge proof. On the omitted CHANGELOG entryChecked before merging rather than taking it on trust. No gate requires one: the only CHANGELOG The cost of adding one is measurable: 20 of the 27 commits on Merge authorizationMerged under the standing chicken-and-egg provision. That is not an assumption today: the required Follow-ups
|
Correction to my merge comment: this repository's
|
…urrency Both sides added tests in the same region of tests/test_required_workflow_queue_contract.py; the resolution keeps both. This branch's two assertions move onto workflow_level_concurrency_group(), the helper #1970 introduced, rather than staying on the raw concurrency block. Correcting a claim I made when merging #1970: this branch's comment block does NOT quote the expressions its tests assert on -- it names other workflow files and explains the mechanism in prose -- so a collapsed key here would have been caught by the raw-block form too. The move is defence against a future comment that does quote them, not a fix for a present hole. Control on the prospective shape (collapse the key, move the expressions into the comment beside it): the helper form fails, while all four raw-block assertions -- group prefix, target_repository, pr_number || github.run_id, and cancel-in-progress: true -- would have passed. cancel-in-progress is a sibling key and therefore outside the group value, so it is asserted separately, anchored to its own line at the block's indent where a comment cannot satisfy it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Follow-up scope: the same hole is still open at six call sites, and one of them is demonstrable on
|
Independent reproduction of the
|
Resolves the conflict #1970 introduced in tests/test_required_workflow_queue_contract.py. Main replaced the concurrency_contract assertions with group_value, extracted by workflow_level_concurrency_group(), so a comment mentioning a key can no longer satisfy them. This branch's push-clause assertion is re-pointed at group_value for the same reason, and the reason is now stronger here than on main: this branch adds prose to the concurrency block that quotes the push clause, so asserted against the whole block it would pass whether or not the expression survived. Gate on the merge result: 2958 passed, 1 skipped, 21 subtests, coverage 100%, interrogate 100%. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
Correction: I understated the remediation surface by counting one fileAbove I wrote that
The single anchored assertion is the one #1964 added. So the The distribution matters for whoever does the work — it is not concentrated: (My counts differ from the other session's — they reported ~13 files with raw slices and ~25 How the wider scope was found is worth more than the numberNot by grepping. They applied a group-collapse mutation to each of the nine workflows whose One thing that must not be batch-replaced
|
Summary
Seven workflows assert their concurrency-group expressions against the raw text of the concurrency block, which includes that block's comments. Every one of those blocks carries a comment explaining its key. So a change that collapsed the key itself, while a maintainer quoted the expressions in the comment beside it, left the contract green.
That is not hypothetical. Collapsing a group to
${{ github.repository }}makes every pull request in a repository share one group, so a new run cancels unrelated pull requests' in-flight reviews. With the expressions moved into comments,maindoes not notice.This adds one helper,
workflow_level_concurrency_group, which slices the group's own value — dropping comment lines, stopping at the next key, and joining a folded block's continuation lines — and retargets the positive assertions to it. Negative assertions (... not in ...) andcancel-in-progressstay on the raw block, where forbidding a string anywhere including comments is the stronger check. PyYAML is not available to this suite, so the slice is textual.Evidence
The same isolated mutation was applied to each workflow: collapse only the group value, keep
cancel-in-progress, and move every asserted string — including the group-name prefix — into comments. Results are given as failing test names, because counts do not say what was detected.mainstrix.ymltest_strix_serializes_provider_evidence_per_repository_and_propencode-review.ymltest_required_pull_request_workflows_cancel_superseded_runsnoema-review.ymltest_required_pull_request_workflows_cancel_superseded_runscodeql-pr.ymltest_required_pull_request_workflows_cancel_superseded_runssecurity-scan.ymltest_required_pull_request_workflows_cancel_superseded_runscodeql-scan-dispatch.ymltest_codeql_scan_dispatch_keeps_current_head_language_shards_independentopencode-review-dispatch.ymltest_privileged_review_dispatch_coalesces_superseded_runs_before_admissionFull gate on this head: 2958 passed, 1 skipped, 21 subtests, coverage 100% (13181 statements, 0 missed), interrogate 100%.
Two tests pin the helper itself rather than the workflows: one on the shape that defeated the old assertion, one on the real folded multi-line key.
Independent verification
A second session reproduced the matrix with its own mutation script and reached the same seven verdicts with the same test names, plus seven of seven not caught on
main, and matching gate numbers. It also drove the helper directly with four adversarial inputs, including a comment containing the literalconcurrency:before the real block, and found no comment leakage. It separately confirmed thatconcurrencyprecedespermissionsin all seven files, which the helper's slice assumes.Two things deliberately left out
The shell guard is not fixed here.
scripts/ci/test_strix_quick_gate.sh'sassert_strix_workflow_pr_trigger_hardeneduses whole-filegrep -Fq, which is weaker still: a comment anywhere in that 1100-line file satisfies it, and it passed unchanged under the mutation above. It is left out because it is a different language and because that file is one of the two inputs the shell self-test reads, so changing it requires a full self-test run.No CHANGELOG entry. No gate requires one, and the file is the repository's busiest conflict point today: three branches needed repeated re-resolution against it, one of them four times, every time with zero code conflicts. A tests-only hardening is not worth adding to that contention.
A follow-up is also queued for the helper's error messages: two future shapes raise
IndexErrorrather than a sentence. All three failure modes fail loudly, so nothing passes silently.Developer experience
A concurrency key that regresses is now caught by the test that exists to catch it, in all seven workflows, instead of passing because a comment nearby still says the right thing.
User experience
No user-facing behaviour changes. This is test-only; no workflow file is modified.
Author session: host 2 (
cool-jackson-3a6130). Verification: host 1. Merge: peer 1.🤖 Generated with Claude Code