Summary
gh actions-lock v0.1.6 does not appear to consider job-level reusable-workflow uses:
refs (jobs.<id>.uses:) when reconciling workflows against actions.lock. GitHub's own
startup validation does enforce them, so the tool disagrees with the platform in both
directions:
- a missed desync that caused a real startup failure and was reported by nothing, and
- a false
stale on a ref that is present in the workflow.
Consequently fix mode would prune a lockfile entry that is actually required, reintroducing
the startup failure.
Environment
gh actions-lock v0.1.6 (gh extension install github/gh-actions-lock --pin v0.1.6)
- lockfile
version: 'v0.0.2', 30–31 workflows
- public repository, Linux runner and local Linux both reproduce
1. Missed desync (false negative) — caused a startup failure
A workflow whose only uses: is job-level:
# .github/workflows/mirror.yml
jobs:
mirror:
uses: hyperpolymath/standards/.github/workflows/mirror-reusable.yml@4d104d325b96c348d685956c6678139640c15c4b
actions.lock recorded the previous commit under that path:
workflows:
'.github/workflows/mirror.yml':
- 'hyperpolymath/standards@d135b05b...'
Observed:
- GitHub refused to start the run — zero jobs created, no log, only
"This run likely failed because of a workflow file issue."
gh actions-lock --no-fix → not reported
gh actions-lock --verify-local → not reported; output was
"All 30 workflows have complete lockfile coverage"
- fix mode → did not repair the entry
So a desync that GitHub treats as fatal is invisible to all three modes.
2. False stale (false positive)
A different workflow with a job-level ref on line 144:
# .github/workflows/release.yml:144
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@f7dd8c54c2067bafc12ca7a55595d5ee9b75204a # v2.1.0
This ref was absent from the lock entirely and was not reported as missing. After adding
the required entry by hand, --verify-local reports:
{
"workflow": ".github/workflows/release.yml",
"category": "stale",
"severity": "warning",
"confidence": "high",
"dependency": "slsa-framework/slsa-github-generator@f7dd8c54c2067bafc12ca7a55595d5ee9b75204a",
"detail": "lockfile pins slsa-framework/slsa-github-generator@f7dd8c54c2067bafc12ca7a55595d5ee9b75204a but no uses: in this workflow references it",
"remediation": "remove the entry or re-run `gh actions-lock`"
}
The claim "no uses: in this workflow references it" is false; the ref is on line 144.
Following the remediation — removing the entry — reintroduces the startup failure from §1.
Why the two cases differ
mirror.yml parses 0 step-level refs, so the stale check appears to be skipped for it.
release.yml parses 9 step-level refs, so the unmatched job-level entry looks orphaned. That
also means fix mode would prune the correct slsa entry as stale, which is the most
damaging consequence: running the tool on a correct lockfile makes it incorrect.
Suggested fix
Treat jobs.<id>.uses: as a dependency reference, normalising
owner/repo/.github/workflows/<file>@<ref> to owner/repo@<ref> the same way action subpaths
are normalised today, for coverage, staleness and fix mode alike.
Related
severity is warning for both stale and sha-as-ref, so downstream tooling cannot use
severity to distinguish an advisory finding from a blocking one. That may be worth separating.
Reported separately: the management banner is not idempotent and fix mode de-pins bare SHAs (#130).
🤖 Generated with Claude Code
https://claude.ai/code/session_01X3hgXxWm6umMgZkjYyHnnm
Summary
gh actions-lockv0.1.6 does not appear to consider job-level reusable-workflowuses:refs (
jobs.<id>.uses:) when reconciling workflows againstactions.lock. GitHub's ownstartup validation does enforce them, so the tool disagrees with the platform in both
directions:
staleon a ref that is present in the workflow.Consequently fix mode would prune a lockfile entry that is actually required, reintroducing
the startup failure.
Environment
gh actions-lockv0.1.6 (gh extension install github/gh-actions-lock --pin v0.1.6)version: 'v0.0.2', 30–31 workflows1. Missed desync (false negative) — caused a startup failure
A workflow whose only
uses:is job-level:actions.lockrecorded the previous commit under that path:Observed:
"This run likely failed because of a workflow file issue."
gh actions-lock --no-fix→ not reportedgh actions-lock --verify-local→ not reported; output was"All 30 workflows have complete lockfile coverage"
So a desync that GitHub treats as fatal is invisible to all three modes.
2. False
stale(false positive)A different workflow with a job-level ref on line 144:
This ref was absent from the lock entirely and was not reported as missing. After adding
the required entry by hand,
--verify-localreports:{ "workflow": ".github/workflows/release.yml", "category": "stale", "severity": "warning", "confidence": "high", "dependency": "slsa-framework/slsa-github-generator@f7dd8c54c2067bafc12ca7a55595d5ee9b75204a", "detail": "lockfile pins slsa-framework/slsa-github-generator@f7dd8c54c2067bafc12ca7a55595d5ee9b75204a but no uses: in this workflow references it", "remediation": "remove the entry or re-run `gh actions-lock`" }The claim "no uses: in this workflow references it" is false; the ref is on line 144.
Following the remediation — removing the entry — reintroduces the startup failure from §1.
Why the two cases differ
mirror.ymlparses 0 step-level refs, so the stale check appears to be skipped for it.release.ymlparses 9 step-level refs, so the unmatched job-level entry looks orphaned. Thatalso means fix mode would prune the correct
slsaentry as stale, which is the mostdamaging consequence: running the tool on a correct lockfile makes it incorrect.
Suggested fix
Treat
jobs.<id>.uses:as a dependency reference, normalisingowner/repo/.github/workflows/<file>@<ref>toowner/repo@<ref>the same way action subpathsare normalised today, for coverage, staleness and fix mode alike.
Related
severityiswarningfor bothstaleandsha-as-ref, so downstream tooling cannot useseverity to distinguish an advisory finding from a blocking one. That may be worth separating.
Reported separately: the management banner is not idempotent and fix mode de-pins bare SHAs (#130).
🤖 Generated with Claude Code
https://claude.ai/code/session_01X3hgXxWm6umMgZkjYyHnnm