-
Notifications
You must be signed in to change notification settings - Fork 0
test(ci): pin required status contexts to the jobs that report them #1923
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
seonghobae
wants to merge
13
commits into
main
Choose a base branch
from
ci/pin-required-status-contexts
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+175
−0
Open
Changes from 8 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
f3d0c3b
test(ci): pin required status contexts to the jobs that report them
seonghobae 5eab19a
test(ci): pin cross-repo required contexts and resolve effective job …
seonghobae 56c0476
Merge remote-tracking branch 'origin/main' into ci/pin-required-statu…
seonghobae 0eb9144
Merge remote-tracking branch 'origin/main' into ci/pin-required-statu…
seonghobae bbb49ed
Merge remote-tracking branch 'origin/main' into ci/pin-required-statu…
seonghobae 386db98
Merge remote-tracking branch 'origin/main' into ci/pin-required-statu…
seonghobae 5c9920a
Merge remote-tracking branch 'origin/main' into ci/pin-required-statu…
seonghobae dc146b4
Merge remote-tracking branch 'origin/main' into ci/pin-required-statu…
seonghobae f1513cf
Merge origin/main into ci/pin-required-status-contexts
seonghobae 9671802
Merge origin/main into ci/pin-required-status-contexts
seonghobae 8717757
Merge origin/main into ci/pin-required-status-contexts
seonghobae 3b9baaf
Merge origin/main into ci/pin-required-status-contexts
seonghobae 0f6a398
fix(test): require the matrix template for matrix-named required cont…
seonghobae File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| """Pin every classic-branch-protection required context to the job that produces it. | ||
|
|
||
| This repository is excluded from the organization required-workflow ruleset | ||
| (``repository_name.exclude`` lists ``.github``), so its default branch is guarded by | ||
| *classic* branch protection with a fixed list of named required status contexts. A | ||
| context is matched by the **check-run name**, which GitHub takes from a job's ``name:`` | ||
| when present and from the job id otherwise. | ||
|
|
||
| That makes a job rename a repository-wide outage, not a local edit: branch protection | ||
| keeps waiting for a context that nothing will ever report, so every pull request stays | ||
| blocked with no failing check to point at. Nothing else in this suite catches it -- | ||
| these names are not pinned anywhere, and the two identifiers can drift apart. They | ||
| already have: the job id ``opencode-review-target`` reports the context | ||
| ``opencode-review``, so renaming only the ``name:`` breaks protection while the job id | ||
| still looks correct. | ||
|
|
||
| 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 or removes them. | ||
|
|
||
| The blast radius is not limited to this repository. A sweep of all 76 organization | ||
| repositories on 2026-09-05 found 13 with classic protection, and several 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. Renaming one | ||
| job here blocks every pull request in all of them at once, and those repositories | ||
| cannot see the change coming. ``admit-current-head`` is required by none, which is why | ||
| it is absent below. | ||
|
|
||
| If a context here is deliberately retired, update branch protection **first** -- in | ||
| every repository that requires it, not just this one -- then this test. Changing this | ||
| test alone re-arms the outage. | ||
| """ | ||
|
|
||
| from pathlib import Path | ||
|
|
||
| import yaml | ||
|
|
||
| WORKFLOW_DIR = Path(".github/workflows") | ||
|
|
||
| # Live `required_status_checks.contexts` on this repository's default branch, | ||
| # read from the branch-protection API on 2026-09-05, paired with the workflow | ||
| # file whose job definition reports each one. | ||
| REQUIRED_CONTEXT_SOURCES = { | ||
| "CodeQL compatibility analysis": "codeql-pr.yml", | ||
| "Detect CodeQL languages": "codeql-pr.yml", | ||
| "coverage-evidence": "opencode-review.yml", | ||
| "dependency-review": "security-scan.yml", | ||
| "noema-review": "noema-review.yml", | ||
| "opencode-review": "opencode-review.yml", | ||
| "osv-scan": "security-scan.yml", | ||
| "required-workflow-bootstrap": "opencode-review.yml", | ||
| "scan-pr-queue": "pr-review-merge-scheduler.yml", | ||
| "scorecard": "security-scan.yml", | ||
| "trivy-fs": "security-scan.yml", | ||
| # Required by sibling repositories but NOT by `.github` itself, so a sweep of | ||
| # this repository's own protection would miss them. Measured 2026-09-05 across | ||
| # all 76 organization repositories: `strix` is required by pg-erd-cloud, | ||
| # bandscope, naruon, linux-cluster-ops and contextual-orchestrator; | ||
| # `coverage-source-tree` by naruon and linux-cluster-ops. Renaming either job | ||
| # in the central workflow blocks every pull request in those repositories. | ||
| "strix": "strix.yml", | ||
| "coverage-source-tree": "opencode-review.yml", | ||
| } | ||
|
|
||
| # `CodeQL compatibility analysis` is reported once per matrix language, so branch | ||
| # protection names the expanded contexts (`... (actions)`, `... (python)`) while the | ||
| # workflow declares the template. | ||
| MATRIX_NAME_TEMPLATES = { | ||
| "CodeQL compatibility analysis": ( | ||
| "CodeQL compatibility analysis (${{ matrix.language }})" | ||
| ), | ||
| } | ||
|
|
||
|
|
||
| def _effective_check_names(workflow_name: str) -> set[str]: | ||
| """Return the check-run names one workflow can report. | ||
|
|
||
| GitHub names a check run after the job's ``name:`` when it has one and after the | ||
| job id **only when it does not**. Accepting either spelling unconditionally would | ||
| pass a job whose id still matches while its ``name:`` was renamed away -- which is | ||
| precisely the break this test exists to catch, since the renamed name is what | ||
| branch protection would then wait for. | ||
| """ | ||
| document = yaml.safe_load((WORKFLOW_DIR / workflow_name).read_text(encoding="utf-8")) | ||
| names = set() | ||
| for job_id, job in (document.get("jobs") or {}).items(): | ||
| declared = job.get("name") if isinstance(job, dict) else None | ||
| names.add(str(declared) if declared else str(job_id)) | ||
| return names | ||
|
|
||
|
|
||
| def _declares_context(workflow_name: str, context: str) -> bool: | ||
| """Report whether one workflow can report `context` as a check-run name.""" | ||
| names = _effective_check_names(workflow_name) | ||
| if context in names: | ||
| return True | ||
| template = MATRIX_NAME_TEMPLATES.get(context) | ||
| return template is not None and template in names | ||
|
|
||
|
|
||
| def test_every_required_context_is_declared_by_a_job() -> None: | ||
| """Each required status context is still declared as a job name or job id.""" | ||
| missing = [] | ||
| for context, workflow_name in sorted(REQUIRED_CONTEXT_SOURCES.items()): | ||
| if not _declares_context(workflow_name, context): | ||
| missing.append(f"{context!r} not declared by any job in {workflow_name}") | ||
| assert not missing, ( | ||
| "Required status contexts lost their producing job. Branch protection will " | ||
| "wait forever for these and every pull request will stay blocked:\n " | ||
| + "\n ".join(missing) | ||
| ) | ||
|
|
||
|
|
||
| def test_required_context_workflow_files_exist() -> None: | ||
| """Every workflow named as a context source is present.""" | ||
| absent = sorted( | ||
| { | ||
| workflow_name | ||
| for workflow_name in REQUIRED_CONTEXT_SOURCES.values() | ||
| if not (WORKFLOW_DIR / workflow_name).is_file() | ||
| } | ||
| ) | ||
| assert not absent, f"Required-context workflow files are missing: {absent}" | ||
|
|
||
|
|
||
| def test_matrix_templates_reference_only_known_contexts() -> None: | ||
| """The matrix-template override table cannot name an unlisted context.""" | ||
| unknown = sorted(set(MATRIX_NAME_TEMPLATES) - set(REQUIRED_CONTEXT_SOURCES)) | ||
| assert not unknown, f"Matrix templates name unlisted contexts: {unknown}" | ||
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.