You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
tests/release/release-rehearsal.test.sh states the strongest supply-chain invariant in this repo: every uses: in every workflow pins a full 40-hex SHA. It reads those lines with a line-oriented grep:
The grep does not match - { uses:, so an action written that way is never handed to the SHA assertion.
#432 is open against this file and adds a floor: the extraction has to produce at least twenty lines or the run fails. That closes the case the extraction breaks wholesale. It does not close this one, because fifty-five real lines clear a floor of twenty however many flow-style entries sit beside them.
Measured
Against 31b9f2d6, which is #432's head with the floor in place. One flow-style, unpinned entry added to docs.yml next to the fifty-five ordinary ones:
The same mutation against main's copy of the test gives the same result, so this predates #432 and #432 neither creates it nor widens it.
Why it matters
Every other pin in this tree is checked. This one line is the difference between "every action is pinned, and a gate says so" and "every action a grep happened to notice is pinned". A workflow diff still gets a human read before it merges, which is the control that actually stands between a fork and the token, so this is a gate with a hole rather than a live hole. A gate with a hole is worth closing on its own terms: the whole reason it exists is so the human read is not the only thing.
The fix
Parse the YAML instead of grepping it. docs-and-hygiene already sets up Python 3.11 and #377 is landing a PyYAML-based workflow reader for a neighbouring check, so the dependency and the pattern are both about to exist here:
forjobindoc.get("jobs", {}).values():
forstepinjob.get("steps", []) or []:
if"uses"instep:
...
That reads block and flow mappings identically, because by the time PyYAML is done there is no difference between them. Keep #432's floor: a parser that returns an empty list for a file it could not read has the same failure mode the floor was written for.
Two things to hold on to while replacing the grep:
The ./... exemption. A reusable workflow in this repository is referenced by path and resolves at the caller's commit, so it cannot carry a SHA. The exemption must stay anchored to ./ so a third-party owner/repo/.github/workflows/x.yml@ref is still required to pin.
A negative fixture per spelling. test(release): fail if the action-pin check inspects nothing #432 added one for the flow mapping; the replacement should keep it and watch it turn green for the right reason, which means asserting the parser finds that uses: rather than asserting the run fails.
Blocked on #432 landing, so the floor and the fixture are in the file first.
tests/release/release-rehearsal.test.shstates the strongest supply-chain invariant in this repo: everyuses:in every workflow pins a full 40-hex SHA. It reads those lines with a line-oriented grep:That pattern reads
uses:at the start of a line, with an optional-in front. YAML also allows a flow mapping, and GitHub Actions accepts it:- { uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 }The grep does not match
- { uses:, so an action written that way is never handed to the SHA assertion.#432 is open against this file and adds a floor: the extraction has to produce at least twenty lines or the run fails. That closes the case the extraction breaks wholesale. It does not close this one, because fifty-five real lines clear a floor of twenty however many flow-style entries sit beside them.
Measured
Against
31b9f2d6, which is #432's head with the floor in place. One flow-style, unpinned entry added todocs.ymlnext to the fifty-five ordinary ones:The same mutation against
main's copy of the test gives the same result, so this predates #432 and #432 neither creates it nor widens it.Why it matters
Every other pin in this tree is checked. This one line is the difference between "every action is pinned, and a gate says so" and "every action a grep happened to notice is pinned". A workflow diff still gets a human read before it merges, which is the control that actually stands between a fork and the token, so this is a gate with a hole rather than a live hole. A gate with a hole is worth closing on its own terms: the whole reason it exists is so the human read is not the only thing.
The fix
Parse the YAML instead of grepping it.
docs-and-hygienealready sets up Python 3.11 and #377 is landing a PyYAML-based workflow reader for a neighbouring check, so the dependency and the pattern are both about to exist here:That reads block and flow mappings identically, because by the time PyYAML is done there is no difference between them. Keep #432's floor: a parser that returns an empty list for a file it could not read has the same failure mode the floor was written for.
Two things to hold on to while replacing the grep:
./...exemption. A reusable workflow in this repository is referenced by path and resolves at the caller's commit, so it cannot carry a SHA. The exemption must stay anchored to./so a third-partyowner/repo/.github/workflows/x.yml@refis still required to pin.uses:rather than asserting the run fails.Blocked on #432 landing, so the floor and the fixture are in the file first.
Found while reviewing #432.