Summary
0ced540e ("chore: estate-wide security compliance", 2026-07-26) added actions: read to
governance-reusable.yml's own permissions: block. A called reusable workflow cannot
request more permissions than its caller grants — so every caller whose wrapper grants
only contents: read is now rejected before any job starts.
Symptom is startup_failure with zero jobs and no check run, which is materially harder
to diagnose than a normal red: there is nothing to click into, and gh pr checks does not
surface it.
hyperpolymath/standards' own main is currently red, so this is not confined to callers.
Evidence
The upstream change:
permissions:
+ actions: read
contents: read
A representative caller (hyperpolymath/gnpl/.github/workflows/governance.yml) before the fix:
permissions:
contents: read
jobs:
governance:
uses: hyperpolymath/standards/.github/workflows/governance-reusable.yml@main
Timeline in gnpl:
| When |
What |
| 2026-07-21 |
Governance success |
| 2026-07-26T13:53Z |
0ced540e lands upstream |
| 2026-07-27 |
next Governance run → startup_failure, 0 jobs |
.github/ was byte-identical to main across that window — the only variable is the
reusable.
Note the amplifier: callers pin this reusable at @main, not a SHA, so a permissions
change propagates to the whole estate the moment it merges, with no staged rollout.
Suggested fix (either)
- Preferred — don't require it at the caller. Move the
actions: read requirement to
the specific job inside the reusable that needs it (job-level permissions: are
allowed to be narrower and do not impose on callers), or drop it if the underlying step
can work without reading the Actions API.
- Otherwise — announce and sweep. If callers genuinely must grant it, the caller
wrappers need actions: read added across the estate in the same change, since the
reusable's requirement is not satisfiable retroactively.
Option 1 avoids a breaking interface change to a workflow that ~300 repos call.
Local status
gnpl is unblocked by mirroring the permission
(hyperpolymath/gnpl#7) — filing here because the same one-line break applies to every other
caller, and fixing it N times is the wrong shape.
Related from earlier passes: #516 (Hypatia ImageOS=ubuntu24), #520 (scorecard.yml
template vs the SARIF policy).
Summary
0ced540e("chore: estate-wide security compliance", 2026-07-26) addedactions: readtogovernance-reusable.yml's ownpermissions:block. A called reusable workflow cannotrequest more permissions than its caller grants — so every caller whose wrapper grants
only
contents: readis now rejected before any job starts.Symptom is
startup_failurewith zero jobs and no check run, which is materially harderto diagnose than a normal red: there is nothing to click into, and
gh pr checksdoes notsurface it.
hyperpolymath/standards' ownmainis currently red, so this is not confined to callers.Evidence
The upstream change:
permissions: + actions: read contents: readA representative caller (
hyperpolymath/gnpl/.github/workflows/governance.yml) before the fix:Timeline in
gnpl:0ced540elands upstream.github/was byte-identical tomainacross that window — the only variable is thereusable.
Note the amplifier: callers pin this reusable at
@main, not a SHA, so a permissionschange propagates to the whole estate the moment it merges, with no staged rollout.
Suggested fix (either)
actions: readrequirement tothe specific job inside the reusable that needs it (job-level
permissions:areallowed to be narrower and do not impose on callers), or drop it if the underlying step
can work without reading the Actions API.
wrappers need
actions: readadded across the estate in the same change, since thereusable's requirement is not satisfiable retroactively.
Option 1 avoids a breaking interface change to a workflow that ~300 repos call.
Local status
gnplis unblocked by mirroring the permission(hyperpolymath/gnpl#7) — filing here because the same one-line break applies to every other
caller, and fixing it N times is the wrong shape.
Related from earlier passes: #516 (Hypatia
ImageOS=ubuntu24), #520 (scorecard.ymltemplate vs the SARIF policy).