Skip to content

fix(ci): pin the Hypatia scanner to a commit instead of cloning its moving tip - #747

Merged
hyperpolymath merged 11 commits into
mainfrom
fix/pin-hypatia-scanner-in-governance-reusable
Sep 8, 2026
Merged

hyperpolymath merged 11 commits into
mainfrom
fix/pin-hypatia-scanner-in-governance-reusable

Conversation

@hyperpolymath

@hyperpolymath hyperpolymath commented Sep 7, 2026 •

Copy link
Copy Markdown
Owner

Why

validate-hypatia-baseline is a required status check on roughly 120 consumer repositories, and 342 of the 349 callers pin this reusable to a full SHA. Inside the job that pin protected nothing: the resolve step ran git ls-remote … HEAD and the clone step ran git clone --depth 1, so every run scanned with whatever hyperpolymath/hypatia main held at that moment. A consumer could go red with no change on its own side.

What

  • "Resolve pinned Hypatia commit" now emits a fixed HYPATIA_PIN (hypatia main tip 0e913426e20282accb49d2fa5d14d5bedbc5a6c2, 2026-09-06) with the bump procedure recorded beside it.
  • "Clone Hypatia at the pinned commit" does git fetch --depth 1 origin <sha> + checkout FETCH_HEAD on a cache miss.
  • Cache key unchanged; it already embeds the resolved SHA, so a future bump rebuilds by construction.
  • Workflow-level permissions: is now the empty map {} and every job declares its own least-privilege block (workflow-staleness and validate-hypatia-baseline gain contents: read). Three gates disagree on how permissions must be spelled on this file — SonarCloud S8264, the workflow linter's grep, and Hypatia's missing_permissions rule — and the empty workflow-level map with per-job grants is the one shape all three accept; verified on this PR's own CI.
  • Never the v1.0.0 tag: it is not an ancestor of main and is over 1,000 commits behind.

No uses: reference changes, so actions.lock is untouched.

Propagation

SHA-pinned callers run the reusable as it was at their pinned SHA, so this reaches them only when re-pinned. The 41 open chore/bump-governance-pin-to-standards-main PRs will be re-pointed at the merge SHA of this PR.

🤖 Generated with Claude Code

hyperpolymath and others added 3 commits September 7, 2026 09:45
…oving tip

`validate-hypatia-baseline` is a REQUIRED status check on roughly 120
consumer repositories, and 342 of the 349 callers pin this reusable to
a 40-character SHA. That care was defeated inside the job: the
"Resolve Hypatia HEAD commit" step ran `git ls-remote ... HEAD` and the
clone step ran `git clone --depth 1`, so every run scanned with
whatever hyperpolymath/hypatia's default branch held at that moment. A
consumer could turn red with no change on its own side, and the SHA in
the caller's `uses:` protected nothing about what actually executed.

Now the step emits a fixed HYPATIA_PIN (hypatia main tip
0e913426e20282accb49d2fa5d14d5bedbc5a6c2, "fix(security): validate
actions lock integrity (#741)", 2026-09-06) and the clone fetches
exactly that commit with `git fetch --depth 1 origin <sha>` followed
by `checkout FETCH_HEAD`. The cache key already embedded the resolved
SHA, so it keeps working unchanged: a future bump misses the cache and
rebuilds the escript by construction. The bump procedure is recorded
in-file next to the pin, and a comment records why the v1.0.0 tag must
never be used (not an ancestor of main, over 1,000 commits behind).

No `uses:` reference changes, so `actions.lock` is untouched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 7, 2026 •

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: cd2a7a20-c691-42f3-a4dd-2d2b13a02fe9

📥 Commits

Reviewing files that changed from the base of the PR and between 60a64bb and 8365077.

📒 Files selected for processing (1)
  • .github/workflows/governance-reusable.yml

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.

📜 Recent review details
🔇 Additional comments (5)
.github/workflows/governance-reusable.yml (5)

24-25: LGTM!


176-177: LGTM!


200-200: LGTM!

Also applies to: 218-220


239-240: LGTM!


19-19: 🩺 Stability & Availability

No change required for workflow permissions.

Every job in .github/workflows/governance-reusable.yml declares contents: read, which covers its checkout and github.token usage. permissions: {} does not break these jobs.


📝 Summary

Summary by CodeRabbit

  • Chores
    • Validation now uses a fixed Hypatia baseline rather than the latest development version.
    • The baseline is retrieved using a shallow checkout of the specified revision, providing more consistent validation results.
    • Workflow permissions are now restricted by default, with read-only access granted only where required.

Walkthrough

The governance workflow now restricts permissions and uses a fixed Hypatia commit for cache keys and checkouts. Cache misses fetch only the pinned commit instead of the repository’s moving default branch.

Changes

Governance workflow hardening

Layer / File(s) Summary
Restrict workflow permissions
.github/workflows/governance-reusable.yml
The workflow clears global permissions and grants contents: read only to the workflow-staleness and Hypatia baseline jobs.
Resolve and fetch the pinned commit
.github/workflows/governance-reusable.yml
The workflow emits the pinned Hypatia SHA, uses it in the cache key, and fetches only that commit on cache misses.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 83650

The governance workflow now validates with a deterministic Hypatia revision and narrower permissions, reducing moving-branch and privilege exposure without an evidenced current-head merge blocker.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The description clearly explains the Hypatia pinning change, the workflow permission changes, and the propagation impact. It is directly related to the changeset.
Title check ✅ Passed The title clearly and concisely identifies the main change: pinning the Hypatia scanner to a commit instead of cloning the moving tip.

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

A rabbit guards the workflow gate
Read-only paths now set the state
One Hypatia commit stays in view
The cache fetches only what is due
Stable checks hop through the gate

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

coderabbitai[bot]
coderabbitai Bot previously approved these changes Sep 7, 2026
hyperpolymath and others added 6 commits September 7, 2026 20:52
…e ruleset

The "Shared scanner content safety" ruleset requires a Scorecard code-scanning
analysis on the PR's head or merge commit. actions/checkout on a pull_request
event checks out refs/pull/N/merge, which GitHub regenerates whenever main
moves, so the analysis binds to a merge commit that stops matching before the
PR can merge. Checking out github.event.pull_request.head.sha instead binds the
upload to the head commit, which is stable for the life of the push.

codeql-action's getRef() rewrites refs/pull/N/merge to refs/pull/N/head when
HEAD differs from GITHUB_SHA, so the upload lands on the head SHA without any
further change.
The "Shared scanner content safety" ruleset evaluates code scanning per
(tool, category). scorecard-action forces Local mode on pull_request
events, so a PR upload carries only supply-chain/local while the
scheduled main run carries branch-protection and online-scm as well.
Every PR therefore fails with "expecting 2 results from Scorecard".

Local proof with the v5.5.0 CLI: a repo-mode scan at the PR head SHA
skips the repo-state checks (2 categories, no branch-protection); only
a HEAD scan yields all 3. So the PR job now installs the pinned
scorecard CLI (release tarball, sha256-verified), runs exactly the
seven repo-level checks at repository HEAD with the policy file taken
from scorecard-action's pinned SHA, and appends those two runs to the
scorecard-action SARIF before the existing upload. The local category
remains the scorecard-action measurement of the checked-out PR tree.
The step fails unless exactly three categories result.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
SonarCloud (githubactions:S6506) flags curl -L without a protocol
restriction: a redirect could in principle land on plain HTTP. Both
downloads are checksum-verified afterwards, so a downgrade could not
smuggle content in, but there is no reason to permit one at all.
Restrict the initial request and any redirect to HTTPS.

Verified locally with curl 8.14: both URLs still fetch and both
sha256 checks still pass under the restricted protocol set.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tia-scanner-in-governance-reusable

Bring the Scorecard head-sha fix (#745) into this branch so the required
'scorecard / Run Scorecard PR' context can be produced on this PR's head.
…to job level

SonarCloud githubactions:S8264 on this PR flags the workflow-level
`permissions:` block ("Move this read permission from workflow level to
job level"). Thirteen of the fifteen jobs already declare their own
block, which overrides the workflow-level one entirely; only
workflow-staleness and validate-hypatia-baseline inherited it.

Give those two jobs an explicit `contents: read` and delete the
workflow-level block. Neither job needs `actions: read`: the staleness
script only calls the public compare endpoint, and the Hypatia job only
checks out, caches and runs the scanner. With every job now explicit,
removing the workflow-level default cannot widen any job's token.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
hyperpolymath and others added 2 commits September 7, 2026 22:06
… map

The S8264 cure (b5c729b) removed the workflow-level `permissions:` block
because Sonar githubactions:S8264 flags read grants declared at workflow
level. That turned two estate gates red on the same file:

- the workflow-security self-lint step greps for `^permissions:` and
  reported "missing top-level 'permissions:' declaration"
- Hypatia workflow_audit `missing_permissions` (~r/^permissions:/m)
  raised one new medium finding, failing Validate Hypatia Baseline

`permissions: {}` satisfies both regex gates (a declaration exists) while
granting nothing at workflow level, so every grant stays at job level as
S8264 requires. All 15 jobs keep their job-level permissions blocks.

Whether Sonar tolerates an empty map is verified live on this push; if it
does not, the three gates are genuinely contradictory and that is reported,
not papered over.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Sep 8, 2026

Copy link
Copy Markdown

@hyperpolymath
hyperpolymath merged commit 9e9513b into main Sep 8, 2026
49 checks passed
@hyperpolymath
hyperpolymath deleted the fix/pin-hypatia-scanner-in-governance-reusable branch September 8, 2026 06:45
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