Skip to content

test(ci): pin required status contexts to the jobs that report them - #1923

Open
seonghobae wants to merge 6 commits into
mainfrom
ci/pin-required-status-contexts
Open

test(ci): pin required status contexts to the jobs that report them#1923
seonghobae wants to merge 6 commits into
mainfrom
ci/pin-required-status-contexts

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

.github is excluded from the organization required-workflow ruleset (repository_name.exclude lists it), so its default branch is guarded by classic branch protection with twelve named required status contexts. GitHub matches a context on the check-run name — a job's name: when it has one, and the job id otherwise.

That makes renaming such a job a repository-wide outage rather than a local edit. Branch protection keeps waiting for a context nothing will ever report, so every pull request stays blocked with no failing check to point at. Nothing in this suite pinned these names.

Why now

.github/workflows/ is under active consolidation — 21 consolidation/coalescing commits between 2026-09-01 and 2026-09-05 (#1826 OSV/Scorecard, Gitleaks, Noema/OpenCode/Strix bootups, SBOM attestation, empty-PR cleanup, head coalescing folded into the scheduler). Folding jobs together is precisely the edit that renames or removes them.

The drift this guards against is not hypothetical — it already exists: job id opencode-review-target reports the context opencode-review. Renaming only the name: breaks protection while the job id still looks correct.

What it checks

Each of the twelve live contexts is pinned to the workflow whose job reports it, accepting either spelling GitHub accepts:

context reported via
opencode-review, coverage-evidence, required-workflow-bootstrap, noema-review, Detect CodeQL languages explicit name:
trivy-fs, scorecard, dependency-review, scan-pr-queue, osv-scan job id (no name: declared)
CodeQL compatibility analysis (actions|python) matrix template (${{ matrix.language }})

That split is worth noting: four of these jobs declare no name: at all, so their context is the YAML key. A guard that only looked for name: would pass while leaving them unprotected.

Verification

The test failed on unmodified main on the first attempt — my initial mapping assumed every context came from a name: line, and the four id-derived ones exposed that. Fixed, then verified in both directions:

  • green on unmodified main
  • fails when a job with an explicit name: is renamed (opencode-reviewopencode-review-consolidated)
  • fails when a job identified only by its id is renamed (trivy-fstrivy-filesystem)

Both negative cases matter, because a guard that passes today but wouldn't catch the rename it exists to catch is worse than none. Full suite: 2886 passed, 1 skipped, 21 subtests. interrogate: 100%.

If a context is ever deliberately retired, update branch protection first, then this test — changing the test alone re-arms the outage. The docstring says so.

🤖 Generated with Claude Code

.github is excluded from the organization required-workflow ruleset, so its
default branch runs classic branch protection with twelve named required status
contexts. GitHub matches those on the check-run name, which comes from a job's
name: when it has one and from the job id otherwise.

Renaming or folding away such a job is therefore a repository-wide outage rather
than a local edit: protection keeps waiting for a context nothing will report, so
every pull request stays blocked with no failing check to point at. Nothing in the
suite pinned these names, and the two identifiers can drift apart -- they already
have, since job id opencode-review-target reports the context opencode-review.

The hazard is live because .github/workflows/ is under active consolidation (21
consolidation/coalescing commits between 2026-09-01 and 2026-09-05), and folding
jobs together is exactly the edit that renames them.

Verified the guard fails for both spellings: renaming an explicit name: and
renaming a job id each trip it, and it is green on unmodified main.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 4 minutes.

Check out review usage here.

View limit details

Limit 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.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 0b034494-ac82-42c8-a48b-763571a8be4d

📥 Commits

Reviewing files that changed from the base of the PR and between efb8926 and 386db98.

📒 Files selected for processing (2)
  • CHANGELOG.md
  • tests/test_branch_protection_required_context_jobs.py

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…names

A sweep of branch protection across all 76 organization repositories found 13
using classic protection, several of which pin the job names these central
workflows declare: opencode-review and coverage-evidence are each required by 7
repositories, strix by 5, scan-pr-queue by 4, required-workflow-bootstrap by 3,
and coverage-source-tree by 2. strix and coverage-source-tree are required by
siblings but not by .github, so pinning only this repository's own contexts left
them unguarded -- renaming either blocks every pull request in those repositories.
admit-current-head is required by none, so it stays out.

The check also had a false negative. It accepted either a `name:` match or a job
id match, so renaming a job's `name:` passed whenever the id still matched, even
though GitHub names the check run after `name:` when one is present. It now
resolves each job's effective check-run name instead. Verified by mutation:
renaming a job id, and renaming a `name:` on a job that also has an id, are both
caught -- the latter was not caught before this change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@seonghobae

Copy link
Copy Markdown
Contributor Author

Live proof, found the same day this PR was opened. Sweeping branch protection across all 76 organization repositories turned up two that already hit exactly this failure, both from consolidation commits merged on 2026-09-04:

repo commit what happened result
contextual-orchestrator f16bd35 (#1054) renamed 4 jobs (Hypothesis property tests -> Property and coverage-guided fuzzing, ...) protection still requires the old names; every post-#1054 PR blocked -- ContextualWisdomLab/contextual-orchestrator#1079
bandscope 314ddea (#1165) removed codeql.yml protection still requires Analyze (python) / Analyze (javascript-typescript); default setup not-configured -- ContextualWisdomLab/bandscope#1170

Neither repository has a failing check to point at. Both look like queue congestion from the outside. This is the failure this test exists to make loud.

The sweep also drove the two additions in the second commit here: strix (required by 5 sibling repositories) and coverage-source-tree (by 2) are not in .github's own protection, so pinning only this repository's contexts would have left them unguarded.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Merged origin/main into this branch at 56c04764 to clear the dirty state. Sole conflict was CHANGELOG.md -- #1937, #1926 and #1922 all prepended entries after this branch did; resolved keep-both (their three sections, this PR's section on top), zero markers left. Diff against main is unchanged: the guard test plus its CHANGELOG section, nothing else.

Gates on the merged head: 2896 passed, 1 skipped, 21 subtests; interrogate 100%. The two positive controls (renaming a name:, renaming a job id) were re-verified before the earlier push and the merge touched neither the test nor any workflow file.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Merged origin/main at f2f91b806 (#1939, round-robin catalog fill) into this branch → head 0eb9144b. Two reasons, both from the post-#1939 recovery note: the required strix/noema runs bind workflow_sha at creation, so a re-run of a failed job would execute the pre-#1939 sidecar — only a new event binds the current one; and this branch had gone dirty against that same commit. Sole conflict was CHANGELOG.md again (#1939 prepended a section); resolved keep-both, this PR's section on top, zero markers. Diff against main is unchanged: the guard test plus its CHANGELOG section.

Gates on 0eb9144b: guard 3 passed; 2899 passed, 1 skipped, 21 subtests; interrogate 100%.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Merged origin/main at fe827e13 (#1943, #1944, #1945) into this branch → head bbb49edc. Third CHANGELOG-only conflict on this PR in ~24h — each round is other PRs prepending entries at the same anchor. Resolved keep-both again (their sections, this PR's on top), --diff-filter=U confirmed CHANGELOG was the sole conflicted file, zero markers. Diff against main is unchanged: the guard test plus its CHANGELOG section.

Gates on bbb49edc: guard 3 passed; 2907 passed, 1 skipped, 21 subtests; interrogate 100%.

One note for anyone reading the PR state: GitHub reported mergeable_state=unknown for over 30 minutes before this — it was masking dirty. A fresh GET pair settled it, and a local git merge-tree --write-tree origin/main <head> confirmed the conflict independently of GitHub's lazy compute.

Copy link
Copy Markdown
Contributor Author

BandScope now provides a live consumer-repository instance of the same required-context drift class, but across the organization required-workflow boundary rather than inside .github itself.

Fresh 2026-09-06 evidence: protected ContextualWisdomLab/bandscope@develop is still 314ddeae7b775a4957594b599358c8255617eb2e and requires 14 contexts, including retired Analyze (javascript-typescript) and Analyze (python). #1165 removed the repository codeql.yml. The current central required CodeQL PR source instead emits CodeQL compatibility analysis (${{ matrix.language }}); BandScope #866 run 34001982927 is currently injected from that required workflow and begins with Detect CodeQL languages.

I updated BandScope #1172 with the exact repair contract: preserve CodeQL coverage, migrate the two stale required contexts to CodeQL compatibility analysis (javascript-typescript) / (python), do not restore a duplicate repository scanner or manufacture a pass-through success, and verify both names on an unchanged exact PR head before closure.

For this guard lane, please treat required-workflow producer names plus consumer branch/ruleset required-context names as one rollout invariant. A central workflow can remain perfectly self-consistent while consumer repositories are permanently blocked on retired contexts.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Merged origin/main at efb89269 (sidecar pin bump) into this branch → head 386db983. Fourth CHANGELOG-only conflict on this PR; same cause (a prepended entry at the shared anchor), same keep-both resolution, --diff-filter=U confirmed CHANGELOG was the sole conflicted file, zero markers. Diff against main is unchanged: the guard test plus its CHANGELOG section.

Gates on 386db983: guard 3 passed; 2907 passed, 1 skipped, 21 subtests; interrogate 100%.

GitHub reported mergeable_state=unknown for this round too (third time it has masked dirty here); a local git merge-tree --write-tree origin/main <head> showed the conflict at once.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant