Skip to content

Feat/fix actions policy - #458

Open
hyperpolymath wants to merge 3 commits into
mainfrom
feat/fix-actions-policy
Open

Feat/fix actions policy#458
hyperpolymath wants to merge 3 commits into
mainfrom
feat/fix-actions-policy

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Summary

Closes #

Type of change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (would change existing behaviour)
  • 🕳️ Soundness fix (fixes a checker/proof false-negative)
  • 📖 Documentation
  • 🧹 Refactor / tech debt (behaviour-preserving)
  • ⚡ Performance
  • 🔧 Build / CI / tooling

How has this been verified?

Checklist

  • My commits are signed (git commit -S).
  • I ran the project's own checks/tests locally and they pass.
  • New files carry the correct SPDX-License-Identifier (code/config MPL-2.0,
    prose CC-BY-SA-4.0); I did not relicense existing files.
  • Docs are updated, and no public claim now overstates what the code does.
  • I have not introduced a soundness hole (or I have flagged where I might have).

Notes for reviewers

hyperpolymath and others added 3 commits July 21, 2026 06:44
…cy outage

Implements the "fastest shippable" item of gitbot-fleet#362.

## The fault

An onboarding stamp set `allowed_actions=selected` + `sha_pinning_required=true`
but never populated `patterns_allowed`, leaving it `[]`. An empty selected-list
rejects every non-github-owned `uses:` at workflow-parse time, so runs die as
`startup_failure` with ZERO jobs — looks like "CI is broken", is actually a
settings fault, and no amount of workflow editing fixes it.

MEASURED 2026-07-21: 80 of 306 scanned hyperpolymath repos are in this state.

## Why this fixer is shaped unlike the others

Every other fix-*.sh takes a REPO_PATH and edits files, so its blast radius is
a reviewable diff. This one writes repository *settings* via the API: no diff,
no branch, no PR. Per #362 that demands gating, so:

  * default mode is --list (READ ONLY; never writes)
  * --apply is required to write
  * HYPATIA_AUTOMATION={off,disabled,0} halts writes (exit 4)
  * the estate exclusion registry is consulted FAIL-CLOSED before any write
    (unreadable registry => refuse to write, exit 5)
  * every PUT is GET-verified and the sweep ABORTS (exit 3) if sha_pinning was
    silently reset — never trade pinning away for permissiveness

## Dual invocation contract

dispatch-runner.sh calls fixers as `<script> <repo_path> <finding.json>`, but a
standalone sweep is `<script> <owner> --apply`. The script detects a directory
in $1 and derives owner/repo from the git origin, so one tool serves both paths
instead of silently misreading a filesystem path as an owner. In the dispatcher
path it stays report-only unless FIX_ACTIONS_POLICY_APPLY=1 — a credentialed
diff-less write must not auto-fire just because a finding routed to it.

Registered under by_category ActionsPolicyTooRestrictive and by_recipe
recipe-actions-allow-all so dispatch-runner auto-routes hypatia findings.

## Verification

shellcheck clean; bash -n clean; registry re-parsed with jq.

Guard rails, exit codes measured directly (not through a masking pipeline):
  no owner / bad --mode / unknown flag -> 2
  HYPATIA_AUTOMATION=off with --apply  -> 4
  HYPATIA_AUTOMATION=off with --list   -> 0   (read-only unaffected)

Classification, against an independently-collected 306-repo ground truth:
  typefix-zero, stateful-artefacts, trope-checker -> BROKEN-M1  (correct)
  svalinn, thejeffparadox                         -> ok         (correct)
  5/5 agreement.

Dispatcher path exercised exactly as dispatch-runner invokes it:
  fix-actions-policy.sh <path-to-trope-checker> <finding.json>
  -> "dispatcher mode — hyperpolymath/trope-checker (action=list)"
  -> BROKEN-M1, exit 0.

NOT run with --apply anywhere: widening allowed_actions is a security-posture
change across ~80 repos and needs the owner's explicit sign-off first.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… allowlist)

Converges this fixer with a parallel remediation effort
(llm-coding-configs/claude-code/notification-storm-remediation/FINDINGS.md)
rather than letting two incompatible fixes race on the same 98 repos.

#362's decision of record was `allowed_actions=all`. That works, but it is a
security-posture change: it removes the owner allowlist and leaves mandatory
SHA-pinning as the only control. The parallel effort established a strictly
safer route reaching the same outcome:

  keep allowed_actions=selected, keep sha_pinning_required=true,
  and simply POPULATE the empty patterns_allowed.

Its natural experiment over 426 repos:
  allowed_actions=all                    286 repos -> wrappers run
  selected + `hyperpolymath/*` present    42 repos -> wrappers run
  selected + patterns_allowed=[]          98 repos -> ALL startup_failure

So the breakage is the list being EMPTY, not the list existing. Populating it
restores CI *and* keeps the allowlist as a real control. `--mode all` remains
available as an explicit fallback; it is no longer the default.

Changes:
  * MODE now defaults to `selected` (was `all`)
  * new `--allowlist FILE` to supply a curated patterns_allowed document
  * refuse an allowlist whose patterns_allowed is EMPTY — that is precisely
    the fault being repaired, and applying it would be a silent no-op
  * `[ x = y ] && rm` replaced with a total `if` — under `set -e` the bare
    `&&` form returns 1 when the test is false and would abort the sweep

Verified: shellcheck clean; bash -n clean; empty-allowlist guard exercised;
`--list` still classifies correctly (trope-checker, now populated with 87
patterns, reports `selected true 87 ok` — it was `selected true 0 BROKEN-M1`).

Target lists reconcile exactly: this tool's 95 (--source, non-archived) is a
subset of the parallel effort's 98; the 3 extra are forks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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