feat(rules): ShaBumpPropagation — detection for estate reusable SHA bumps (#418)#419
Merged
Merged
Conversation
…SHA bumps (#418) Detection-half of the three-system propagation architecture: hypatia (this commit) -> gitbot-fleet -> .git-private-farm Pure-data rule consuming a PR-merge event, returning a finding per matched estate reusable workflow / composite action. Strategy `:review` (flag-only); title-keyword exclusion stays in actuation per feedback_pr_sweep_title_keyword_exclusion. - lib/rules/sha_bump_propagation.ex — module + known_reusables registry (10 standards reusables + a2ml-validate-action composite). Accepts both atom- and binary-keyed event maps (webhook-friendly). - test/rules/sha_bump_propagation_test.exs — sensitivity + specificity oracle suite; pr_title carried verbatim; malformed-event safety. Local mix can't run tests (elixir 1.14 vs phoenix 1.15+); a standalone runner exercised every assertion before commit. CI will run the ExUnit module via the project's normal pipeline. Origin trace: .git-private-farm#66 (propagation primitive) + standards#341 + neurophone#107 (both closed redundant). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 146 issues detected
View findings[
{
"reason": "Action urin 21 JRE\n uses: actions/setup-java@be666c2fcd27 needs attention",
"type": "unpinned_action",
"file": "verify-proofs.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in clusterfuzzlite.yml",
"type": "missing_timeout_minutes",
"file": "clusterfuzzlite.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
Owner
Author
|
Status check (2026-06-02): PR has 10 failing checks across governance, AsciiDoc build, dogfooding, and CodeQL. Failing categories:
Not blocking on you — these look like persistent estate-wide gates the broader sweep is working through. Flagging for visibility; not merging via admin-merge while real (non-skipped) checks are red. |
This was referenced Jun 2, 2026
🔍 Hypatia Security ScanFindings: 146 issues detected
View findings[
{
"reason": "Action urin 21 JRE\n uses: actions/setup-java@be666c2fcd27 needs attention",
"type": "unpinned_action",
"file": "verify-proofs.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in clusterfuzzlite.yml",
"type": "missing_timeout_minutes",
"file": "clusterfuzzlite.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
2 tasks
hyperpolymath
added a commit
to hyperpolymath/standards
that referenced
this pull request
Jun 2, 2026
… SARIF + gitleaks unblock) (#352) ## Summary Two reusable workflows consume third-party actions that need GitHub-API permissions the reusables didn't grant. Reusable workflow permission blocks OVERRIDE the caller's, so adding perms at every consumer wrapper is a no-op — **the fix must live here at source**. This unblocks SARIF upload + gitleaks PR scan across **every estate consumer** of these reusables. ## Reproducing failures (before this PR) From `.git-private-farm#69` runs (verified Jun 02 18:34 UTC): ### hypatia SARIF upload ``` hypatia.sarif written: 48 result(s). Run github/codeql-action/upload-sarif@... sarif_file: hypatia.sarif Validating hypatia.sarif Adding fingerprints to SARIF file. ##[error]Resource not accessible by integration - GET /actions/runs/... ``` The scan + SARIF generation **succeed**. The upload-sarif step then calls `GET /repos/{owner}/{repo}/actions/runs/{run_id}` to attach the blob and fails because `actions: read` is not granted. ### gitleaks ScanPullRequest ``` [hyperpolymath] is an individual user. No license key is required. gitleaks version: 8.24.3 Gitleaks restored from cache RequestError [HttpError]: Resource not accessible by integration at ... ScanPullRequest ... ``` The gitleaks binary scan **succeeds**. The post-scan `ScanPullRequest` step calls additional API endpoints (PR-files, workflow-run metadata, PR comment post) and fails because `pull-requests: write` + `actions: read` are not granted. ## Changes ### `hypatia-scan-reusable.yml` — workflow-level ```yaml permissions: contents: read security-events: write pull-requests: write + actions: read # NEW — for upload-sarif's GET /actions/runs/{id} ``` Single-job workflow, so workflow-level is the right scope. ### `secret-scanner-reusable.yml` — gitleaks job-level only The other jobs (`trufflehog`, `rust-secrets`, `shell-secrets`) only need `contents: read`. Adding wider perms at workflow level would over-grant. Gitleaks gets a job-level block instead: ```yaml gitleaks: + permissions: + contents: read + pull-requests: write # NEW — for PR comment post + actions: read # NEW — for PR-files / workflow-run API calls steps: ... ``` ## Why this is safe Both new grants are **read-only** (`actions: read`) or **scoped to PRs only** (`pull-requests: write`). They match GitHub's documented permission requirements for these specific third-party actions: - `codeql-action/upload-sarif` docs explicitly require `actions: read` when calling from a wrapper. - `gitleaks-action` v2 docs require `pull-requests: write` for PR commenting + `actions: read` for the new PR-files API. No new write capability beyond PR-comment posting, which already had to be granted somewhere (incorrectly assumed it'd inherit from the caller). ## Blast radius - `hypatia-scan-reusable.yml`: ~estate-wide consumer of Hypatia security scan. - `secret-scanner-reusable.yml`: 281 estate deployments per the reusable's own header comment. All consumers will see the fix on their next run via SHA-bump propagation (which is exactly the cascade the 3-system propagation track was designed for — `.git-private-farm#66` + `gitbot-fleet#249` + `hypatia#419`). ## Test plan - [ ] After merge: rerun `.git-private-farm#69` checks; both SARIF + gitleaks transition to GREEN. - [ ] Propagation cascade fires (or manual SHA bump if propagation not yet live), and other estate consumers green up too. ## Related - hyperpolymath/.git-private-farm#69 — local fixes that hit this upstream wall - hyperpolymath/.git-private-farm#66, #68 — 3-system propagation cascade (this PR's merge SHA will be the first real propagation candidate) - hyperpolymath/hypatia#419 — detection rule - hyperpolymath/gitbot-fleet#249 — actuation script 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath
added a commit
to hyperpolymath/gitbot-fleet
that referenced
this pull request
Jun 2, 2026
… (#249) ## Summary Actuation-half of the three-system propagation architecture (#248): ``` hypatia (detection) → gitbot-fleet (THIS) → .git-private-farm (propagation) ``` - \`scripts/propagate-sha-bump.sh\` consumes a hypatia finding with rule \`reusable_workflow_sha_bump_needs_propagation\`, pre-filters the upstream PR title (HARD), enumerates consumers via \`gh search code\`, drops forks, and fires a \`propagate-sha-bump\` \`repository_dispatch\` event into \`.git-private-farm\`. - \`scripts/fix-script-registry.json\` wires the recipe → script; \`dispatch-runner.sh\` routes via the existing \`by_recipe\` map. - \`tests/propagate-sha-bump-smoke.sh\` exercises the refusal + DRY_RUN paths (10/10 passing locally). ## Safety properties Canonical title-keyword gate lives HERE (per \`feedback_pr_sweep_title_keyword_exclusion\` + \`feedback_no_automated_licence_edits\`). The receiver workflow re-checks belt-and-braces. - \`pr_title\` matching \`license|SPDX|PMPL|MPL|AGPL|GPL|Apache|copyright|attribution|relicens|secret|vulnerab|CVE-\` → exit 0 (REFUSED, routed to manual review — not an error path). - \`title_suffix\` synthesised from **safe** metadata (workflow slug + short SHA), NOT from \`pr_title\`. So even if a forbidden keyword somehow slipped past the pre-filter, the dispatched PR title would not carry it. - \`old_sha == new_sha\` rejected. - \`source_repo\` constrained to \`hyperpolymath/*\`. - \`source_workflow\` constrained to \`.github/workflows/*.{yml,yaml}\` or \`action.{yml,yaml}\`. - Forks dropped via \`gh repo view --json isFork\`. - \`DRY_RUN=true\` prints the payload instead of dispatching. ## Coupling with the other two PRs - **Depends on**: hyperpolymath/hypatia#419 — the finding shape this script consumes. - **Triggers**: hyperpolymath/.git-private-farm#68 — the receiver workflow + scripts (#66). Each can land independently; once all three land, the chain end-to-ends. ## Test plan - [x] Wrong rule name → exit 1 - [x] Malformed SHA → exit 1 - [x] \`old_sha == new_sha\` → exit 1 - [x] Non-estate \`source_repo\` → exit 1 - [x] License keyword in \`pr_title\` → exit 0 (REFUSED message printed) - [x] DRY_RUN with valid finding → exit 0, payload composed - [x] \`branch_name\` slug correct (\`ci/bump-<workflow-slug>-<short-sha>\`) - [x] \`title_suffix\` synthesised from safe metadata only - [ ] End-to-end (post-merge): hypatia emits → dispatch-runner picks up → this script dispatches → farm receiver runs → consumer PRs land - [ ] Smoke test as a CI job (follow-up — leaving as local script for first landing) ## Related - #248 — this PR closes - hyperpolymath/hypatia#419 — detection rule (PR open) - hyperpolymath/.git-private-farm#66 — propagation scripts (PR open) - hyperpolymath/.git-private-farm#68 — receiver workflow (PR open) Closes #248 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: hyperpolymath <hyperpolymath@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
Detection-half of the three-system propagation architecture filed in #418:
lib/rules/sha_bump_propagation.ex— pure-data ruleHypatia.Rules.ShaBumpPropagation.check/1consuming a PR-merge event, returning one finding per matched estate reusable workflow / composite action. Strategy is:review(flag-only — actuation pre-filters by title keyword, hypatia never does).governance-reusable.yml,rust-ci-reusable.yml, etc.) +a2ml-validate-action. Easy to extend.test/rules/sha_bump_propagation_test.exs— sensitivity + specificity oracle suite (pr_titlecarried verbatim, malformed-event safety, multi-workflow PR fans out).Why this shape
feedback_pr_sweep_title_keyword_exclusion+feedback_no_automated_licence_edits, hypatia emits + the actuator rejects. Thepr_titlefield is carried verbatim to the actuator so it has the full string to test.cicd_rules.ex. That file is already 1506 LoC and event-driven detection is a different shape from path/content scanning. Separate module keeps the contract clean.estimated_consumersis a hint field set by the caller — actuation (gitbot-fleet#248) owns the enumeration, since it's the one fanning out.Verification
Local mix can't run tests in this checkout (elixir 1.14 vs phoenix 1.15+ ABI break). A standalone runner exercised all 27 assertions before commit:
CI runs the ExUnit module via the project's normal pipeline; expect the same outcome.
Test plan
action.ymlpr_titlecarried verbatim (so actuator can keyword-filter)[][]Related
Closes #418
🤖 Generated with Claude Code