feat(ci): gate on required status contexts nothing can publish - #869
Merged
Merged
Conversation
GitHub matches a required status check by string equality against the name it publishes for that run, and never checks that the name is producible. A rule requiring a name no publisher can supply is unsatisfiable: every pull request stays BLOCKED while the CI board shows green, and nothing on the CI side names the cause. That is the general form of hyperpolymath/tropical-types#17 (the bare `Hypatia Neurosymbolic Analysis` required while the wrapper published `scan / Hypatia Neurosymbolic Analysis`) and of the wrapper-prefix mismatch recorded in docs/audits/audit-hypatia-pin-orphan-2026-05-27.adoc. Adds, all read-only and dependency-free (bash + awk + jq + gh + curl): * scripts/check-required-contexts.sh — derives the names a repository's workflows can publish (job display names, `<job id> (*)` matrix forms, and `<caller> / <inner job>` for reusable-wrapper callers), reads the required contexts from every enabled branch ruleset (and legacy branch protection when the credential can read it), and reports any required context that neither a workflow nor a bound app integration can satisfy. App-bound contexts are skipped by design: CodeRabbit, SonarCloud and the code-scanning app own their names. Advisory by default (REQUIRED_CONTEXTS_STRICT=1 to gate), and an API failure is reported as "not inspected" rather than "nothing is required" — a gate that fails open on the failure of the call it depends on is worse than no gate. * scripts/tests/check-required-contexts-test.sh — drives the built-in hermetic fixture: a synthetic repository, a stubbed reusable in a cache directory, and JSON required-context sets. No network, no token, no API. Five branches, including a regression case for exact-versus-prefix matching. * docs/audits/audit-ci-context-producibility-2026-09-20.adoc — the audit that produced the gate. Census of all 365 non-archived public repositories: 337 required contexts, of which 168 are app-owned, 156 producible, 4 app-named and 5 unsatisfiable across 4 repositories (awesome-gleam, casket-ssg, coord-tui, vext — every one a retired CodeQL-era job name). Records the tropical-types case study, the two honest remediations for a bare-name requirement (with the defiant inline-implementation precedent), the caller-id drift across the estate (200 `scan` versus 8 `hypatia`), the caveats (legacy branch protection needs Administration: read; matrix forms are matched as a family), and the adjacent RE001-versus-allowlist inconsistency (step-security/harden-runner is not in the allowed-actions list the same estate enforces). Deliberately not wired into governance-reusable.yml: that changes the check surface of every repository pinned to it, and the audit records the shape and the advisory-first rationale instead.
Contributor
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (3)
✨ Finishing Touches📝 Generate docstrings
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 |
|
hyperpolymath
added a commit
that referenced
this pull request
Sep 20, 2026
…in the gate header (#871) ## What Two self-inflicted defects in the artefacts that merged as #869, both caught by re-reading them against the census data they quote. **1. The audit miscounted its own census.** It said *337 required contexts across 179 repositories*; the verdicts it prints alongside (app-owned 168 + producible 156 + app-named 4 + unsatisfiable 5) total **333**. Corrected, plus the fact that all 333 were ruleset-sourced, so no repository in the census still enforced required status checks through legacy branch protection. **2. The gate's header described `hyperpolymath/tropical-types#17` in the present tense** ("the wrapper publishes `scan / Hypatia Neurosymbolic Analysis`"). That repository publishes the bare name from an inline job and the prefixed name from its wrapper caller now — the sentence was stale on merge. Also records why the five unsatisfiable contexts matter rather than being app-configuration work: every one binds `integration_id: 15368` (GitHub Actions), so they are repository-owned workflow job names. No external publisher could ever satisfy them, and the fix is a rename or a re-armed rule, not a settings tweak. ## Why it is worth a PR rather than a quiet push The whole point of this audit is that unverified claims about CI state are how a required context becomes unsatisfiable without anyone noticing. A census document that miscounts its own census, and a header that describes a fixed condition as live, are the same failure at one remove. ## Verification * `bash scripts/tests/check-required-contexts-test.sh` — 5/5 pass (unchanged by the edit; run to confirm nothing else moved). * `bash -n scripts/check-required-contexts.sh` — parses. * Counts cross-checked against the census records: 333 contexts over 179 repositories, 5 unsatisfiable in 4 repositories (`awesome-gleam` ×2, `casket-ssg`, `coord-tui`, `vext`), all `integration_id: 15368`.
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.




What
Adds a gate for a class of rule that is invisible from the CI side: a required status context that nothing can publish.
GitHub matches a required status check by string equality against the name it publishes for that check run, and never checks that the name is producible. A rule requiring a name no publisher can supply is unsatisfiable — every pull request stays
BLOCKED, the board shows green, and no CI output names the cause.This is the general form of
hyperpolymath/tropical-types#17(bareHypatia Neurosymbolic Analysisrequired while the wrapper publishedscan / Hypatia Neurosymbolic Analysis) and of the wrapper-prefix mismatch this estate already documented indocs/audits/audit-hypatia-pin-orphan-2026-05-27.adoc.Contents
scripts/check-required-contexts.shscripts/tests/check-required-contexts-test.shdocs/audits/audit-ci-context-producibility-2026-09-20.adocRead-only;
bash+awk+jq+gh+curl, no new dependency.Rules it encodes
name:— or<job id> (<matrix values>)when it has a matrix and noname:— or the job id alone;<caller display name or job id> / <inner job display name or job id>, so a wrapper can never publish the reusable's bare inner name;Behaviour
REQUIRED_CONTEXTS_STRICT=1to gate) — a check that reds nobody yet is a warning, not a red;--print-commandsemits the remediation,--json FILEemits a machine-readable report,--no-network/REUSABLE_CACHE_DIRmake it hermetic.Census (2026-09-20, all 365 non-archived public repositories)
337 required contexts: 168 app-owned, 156 producible, 4 app-named, 5 unsatisfiable across 4 repositories —
awesome-gleamAdjust Configuration,Analyze (actions)casket-ssgAnalyze Code (actions)coord-tuiCodeQL Analysis (actions, none)vextCodeQL Analysis (actions, none)Every one is a retired CodeQL-era job name. The same audit records the correct way to satisfy a bare-name requirement (the
defiantinline-implementation precedent), the caller-id drift across 208 wrappers (200scanvs 8hypatia) against the canonical string already documented, and the caveat that legacy branch protection needsAdministration: readto inspect.Deliberately not included
Wiring this into
governance-reusable.yml. That changes the check surface of every repository pinned to it; the audit records the shape and the advisory-first rationale for the owner to arm when ready.Adjacent finding
Hypatia's
research_extensions: RE001asks jobs that reference the secrets context to installstep-security/harden-runner— which is not inrhodium-standard-repositories/actions-allowlist/allowed-actions.json(89 patterns, nostep-security/*). A repository under the allowlist cannot satisfy RE001 by the route the rule suggests. Either the rule or the allowlist should move; meanwhile the workable answer isgithub.token(as tropical-types now does) or routing the credentialed work through a reusable withsecrets: inherit.Verification
bash scripts/tests/check-required-contexts-test.sh— 5/5 branches pass.bash scripts/check-canonical-names.sh origin/main— clean.