What happens
.github/workflows/release.yml:44 uses a third-party action pinned to a moving branch:
uses: StephaneBour/actions-calver@master
.github/workflows/test.yml:156 does the same with jlumbroso/free-disk-space@main.
zizmor would flag both, but unpinned-uses is disabled in zizmor.yml:
rules:
unpinned-uses:
disable: true
Why it matters
The two cases are not equivalent.
actions-calver runs in the release workflow. That job has write permissions, it commits back to the repository through stefanzweifel/git-auto-commit-action, it tags, and the release chain it starts ends at pypa/gh-action-pypi-publish with id-token: write and at docker/login-action pushing to GHCR. A change to master in that repository — whether malicious or simply a bad release — executes inside that chain with no review and no way to tell after the fact which revision ran.
free-disk-space@main is in the test workflow, which has permissions: {} at the top level, so the exposure is much smaller.
The rest of the workflows use tags such as actions/checkout@v7 and astral-sh/setup-uv@v9.0.0. Tags are also mutable, but they are at least a version the maintainer chose, which @master is not.
Suggested resolution
Pin the actions in release.yml to full commit SHAs, with a comment giving the version, which is the usual form:
uses: StephaneBour/actions-calver@<sha> # v1.x.x
Dependabot's github_actions ecosystem updates SHA pins and keeps the version comment in sync, and it is already configured for this repository, so this does not create ongoing manual work.
Whether to pin the non-release workflows too is a separate judgement. If they are pinned, unpinned-uses can be re-enabled in zizmor.yml and the property is then enforced rather than remembered. If not, it is worth recording in zizmor.yml why the rule is off, since the current disable: true gives no reason and the release workflow is a case the rule would have caught.
What happens
.github/workflows/release.yml:44uses a third-party action pinned to a moving branch:.github/workflows/test.yml:156does the same withjlumbroso/free-disk-space@main.zizmorwould flag both, butunpinned-usesis disabled inzizmor.yml:Why it matters
The two cases are not equivalent.
actions-calverruns in the release workflow. That job has write permissions, it commits back to the repository throughstefanzweifel/git-auto-commit-action, it tags, and the release chain it starts ends atpypa/gh-action-pypi-publishwithid-token: writeand atdocker/login-actionpushing to GHCR. A change tomasterin that repository — whether malicious or simply a bad release — executes inside that chain with no review and no way to tell after the fact which revision ran.free-disk-space@mainis in the test workflow, which haspermissions: {}at the top level, so the exposure is much smaller.The rest of the workflows use tags such as
actions/checkout@v7andastral-sh/setup-uv@v9.0.0. Tags are also mutable, but they are at least a version the maintainer chose, which@masteris not.Suggested resolution
Pin the actions in
release.ymlto full commit SHAs, with a comment giving the version, which is the usual form:Dependabot's
github_actionsecosystem updates SHA pins and keeps the version comment in sync, and it is already configured for this repository, so this does not create ongoing manual work.Whether to pin the non-release workflows too is a separate judgement. If they are pinned,
unpinned-usescan be re-enabled inzizmor.ymland the property is then enforced rather than remembered. If not, it is worth recording inzizmor.ymlwhy the rule is off, since the currentdisable: truegives no reason and the release workflow is a case the rule would have caught.