Skip to content

Commit e3c413f

Browse files
committed
security: add zizmor check for unpinned GitHub Actions
1 parent 1779b75 commit e3c413f

1 file changed

Lines changed: 61 additions & 0 deletions

File tree

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
name: "Check pinned GitHub Actions"
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- ".github/workflows/**"
7+
- ".github/actions/**"
8+
push:
9+
branches:
10+
- main
11+
paths:
12+
- ".github/workflows/**"
13+
- ".github/actions/**"
14+
15+
permissions: {}
16+
17+
jobs:
18+
check-pinned-actions:
19+
name: "Scan for unpinned actions"
20+
runs-on: ubuntu-latest
21+
permissions:
22+
contents: read
23+
steps:
24+
- name: "Checkout code"
25+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
26+
with:
27+
persist-credentials: false
28+
29+
- name: "Install uv"
30+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
31+
32+
# Only fails on unpinned-uses: zizmor's other audits are out of scope for this check.
33+
- name: "Scan for unpinned actions"
34+
env:
35+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36+
run: |
37+
TARGETS=".github/workflows"
38+
[ -d ".github/actions" ] && TARGETS="$TARGETS .github/actions"
39+
40+
uvx "zizmor@1.29.0" --format=json-v1 --no-exit-codes $TARGETS > zizmor-results.json
41+
42+
UNPINNED=$(jq '[.[] | select(.ident == "unpinned-uses")]' zizmor-results.json)
43+
COUNT=$(echo "$UNPINNED" | jq 'length')
44+
45+
if [ "$COUNT" -gt 0 ]; then
46+
echo "::error::Found $COUNT unpinned GitHub Action reference(s). All actions must be pinned to a full 40-character commit SHA."
47+
echo "$UNPINNED" | jq -r '
48+
.[] as $finding |
49+
(($finding.locations[] | select(.symbolic.kind == "Primary")) // $finding.locations[0]) as $loc |
50+
" - \($loc.symbolic.key.Local.verbatim_path // $loc.concrete.feature // "unknown location"):\(($loc.concrete.location.start_point.row // 0) + 1): \($finding.desc)"
51+
'
52+
echo ""
53+
echo "To fix: replace the tag/branch with the action's full commit SHA and add a '# vX.Y.Z' comment, e.g."
54+
echo " uses: owner/repo@<40-char-sha> # v1.2.3"
55+
echo ""
56+
echo "If a version genuinely cannot be pinned to a SHA, add an inline exception with justification:"
57+
echo " uses: owner/repo@ref # zizmor: ignore[unpinned-uses] <reason>"
58+
exit 1
59+
fi
60+
61+
echo "No unpinned GitHub Actions found."

0 commit comments

Comments
 (0)