Skip to content

Commit c447fe1

Browse files
ci: Harden CI workflows + add zizmor GH Actions linter (#13)
This commit hardens our Github Actions workflows, refactoring a `pull_request_target` workflow to use the lower permissions `pull_request` workflow type. Other improvements include not hanging on to Git auth tokens after checkout, and also pinning version SHAs for all outside actions. Signed-off-by: Philip Conrad <philip@chariot-chaser.net>
1 parent 575bbcd commit c447fe1

4 files changed

Lines changed: 59 additions & 72 deletions

File tree

.github/dependabot.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ updates:
88
groups:
99
dependencies:
1010
patterns:
11-
- "*"
11+
- "*"
12+
cooldown:
13+
default-days: 7

.github/workflows/post-tag.yaml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ jobs:
1313
release-build:
1414
name: Release Build (macos-latest)
1515
runs-on: macos-latest
16+
permissions:
17+
contents: read
1618
env:
1719
DEVELOPER_DIR: "/Applications/Xcode_26.0.app"
1820
SWIFT_VERSION: 6.2.3
@@ -23,11 +25,11 @@ jobs:
2325
xcodebuild -version
2426
- name: Show Swift version
2527
run: swift --version
26-
- name: Check out code
27-
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
28+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2829
with:
2930
fetch-depth: 0
3031
fetch-tags: true
32+
persist-credentials: false
3133
- name: Install jemalloc
3234
run: brew install jemalloc
3335
- name: Lint
@@ -41,16 +43,17 @@ jobs:
4143
name: Release Notes
4244
runs-on: ubuntu-24.04
4345
permissions:
44-
contents: write
46+
contents: write # Needed to create/update GH release.
4547
steps:
4648
- name: Set TAG_NAME in Environment
4749
# Subsequent jobs will be have the computed tag name
4850
run: echo "TAG_NAME=${GITHUB_REF##*/}" >> $GITHUB_ENV
4951
- name: Check out code
50-
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
52+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
5153
with:
5254
fetch-depth: 0
5355
fetch-tags: true
56+
persist-credentials: false
5457
- name: Create or Update Release
5558
env:
5659
# Required for the GitHub CLI
Lines changed: 36 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,75 @@
11
name: Release Check
22

3-
# This workflow is isolated into its own file, because it requires
4-
# elevated pull_request_target permissions. Any executable code
5-
# or scripts here should depend only on trusted code in main, and
6-
# not on anything from the PR.
73
on:
8-
workflow_dispatch: {}
9-
pull_request_target: {}
4+
workflow_dispatch:
5+
inputs:
6+
base_ref:
7+
description: 'Base branch to compare against (e.g. main)'
8+
required: true
9+
default: 'main'
10+
pull_request: {}
1011

1112
# When a new revision is pushed to a PR, cancel all in-progress CI runs for that
1213
# PR. See https://docs.github.com/en/actions/using-jobs/using-concurrency
1314
concurrency:
1415
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
1516
cancel-in-progress: true
1617

18+
permissions:
19+
contents: read
20+
1721
jobs:
1822
release-check:
1923
name: Release version check
2024
runs-on: ubuntu-latest
2125
permissions:
22-
pull-requests: write
26+
contents: read
2327
steps:
24-
- uses: actions/checkout@v6.0.1
28+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2529
with:
26-
ref: ${{ github.base_ref }} # Use scripts only from trusted base branch
2730
fetch-depth: 0 # Fetch full history to access all commits
28-
29-
- name: Fetch PR from fork
30-
run: |
31-
# Don't allow user to provide branch name. Bind to PR number ref explicitly.
32-
git fetch origin "pull/${{ github.event.pull_request.number }}/head:pr-head"
31+
persist-credentials: false
3332

3433
- name: Check for release commits
3534
id: check-release
3635
run: |
37-
RESULT=$(./tools/build/get-release-from-commits.sh "origin/${{ github.base_ref }}" "pr-head")
36+
RESULT=$(./tools/build/get-release-from-commits.sh "origin/${GITHUB_BASE_REF}" "HEAD")
3837
echo "Release commits detected: $RESULT"
3938
if [ -n "$RESULT" ]; then
4039
echo "result=true" >> $GITHUB_OUTPUT
40+
echo "commit_version=$RESULT" >> $GITHUB_OUTPUT
4141
else
4242
echo "result=false" >> $GITHUB_OUTPUT
4343
fi
44-
44+
4545
- name: Get CHANGELOG version from PR
4646
if: steps.check-release.outputs.result == 'true'
4747
id: changelog
4848
run: |
49-
# Checkout just the CHANGELOG from PR
50-
git show "pr-head:CHANGELOG.md" > /tmp/changelog-pr.md
51-
CHANGELOG_VERSION=$(grep -o -E '## [0-9.]+' /tmp/changelog-pr.md | head -n 1 | sed 's/## //' | grep -E '^[0-9.]+$' || echo "invalid")
49+
CHANGELOG_VERSION=$(grep -o -E '## [0-9.]+' CHANGELOG.md | head -n 1 | sed 's/## //' | grep -E '^[0-9.]+$' || echo "invalid")
5250
echo "version=$CHANGELOG_VERSION" >> "$GITHUB_OUTPUT"
5351
54-
- name: Post or update warning comment (release commit detected)
52+
- name: Verify release versions match
5553
if: steps.check-release.outputs.result == 'true'
5654
env:
57-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
58-
REPO: ${{ github.repository }}
59-
PR_NUMBER: ${{ github.event.pull_request.number }}
60-
MARKER: "<!-- release-commit-warning -->"
55+
COMMIT_VERSION: ${{ steps.check-release.outputs.commit_version }}
56+
CHANGELOG_VERSION: ${{ steps.changelog.outputs.version }}
6157
run: |
62-
COMMIT_VERSION=$(./tools/build/get-release-from-commits.sh "origin/${{ github.base_ref }}" "pr-head")
63-
CHANGELOG_VERSION="${{ steps.changelog.outputs.version }}"
64-
65-
COMMENT=$(mktemp)
66-
echo "ℹ️ **Release Commit Detected**" >> "$COMMENT"
67-
echo "" >> "$COMMENT"
68-
echo "This PR contains commit(s) that match the case-insensitive regex \`^Release .*\`" >> "$COMMENT"
69-
echo "" >> "$COMMENT"
70-
echo "Here are the latest versions reported from the places the release workflows will use:" >> "$COMMENT"
71-
echo "" >> "$COMMENT"
72-
echo "| Source | Version |" >> "$COMMENT"
73-
echo "| --- | --- |" >> "$COMMENT"
74-
echo "| Commit matching \`^Release .*\` | $COMMIT_VERSION |" >> "$COMMENT"
75-
echo "| \`CHANGELOG.md\` | $CHANGELOG_VERSION |" >> "$COMMENT"
76-
77-
echo "Posting or updating release warning comment."
78-
export COMMENT_BODY="$(cat "$COMMENT")"
79-
./tools/build/release-pr-comment.sh "$REPO" "$PR_NUMBER" "$MARKER"
58+
echo "ℹ️ Release Commit Detected"
59+
echo ""
60+
echo "This PR contains commit(s) that match the case-insensitive regex \`^Release .*\`"
61+
echo ""
62+
echo "Here are the latest versions reported from the places the release workflows will use:"
63+
echo ""
64+
echo "| Source | Version |"
65+
echo "| --- | --- |"
66+
echo "| Commit matching \`^Release .*\` | $COMMIT_VERSION |"
67+
echo "| \`CHANGELOG.md\` | $CHANGELOG_VERSION |"
68+
echo ""
8069
81-
- name: Update warning comment if present (no release commit)
82-
if: steps.check-release.outputs.result != 'true'
83-
env:
84-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
85-
REPO: ${{ github.repository }}
86-
PR_NUMBER: ${{ github.event.pull_request.number }}
87-
MARKER: "<!-- release-commit-warning -->"
88-
COMMENT_BODY: |
89-
ℹ️ A release commit was detected in earlier versions of this PR.
90-
91-
The current PR commits do not appear to be a release.
92-
run: |
93-
EXISTING_COMMENT=$(gh api repos/$REPO/issues/$PR_NUMBER/comments \
94-
--jq ".[] | select(.body | contains(\"$MARKER\")) | .id" | head -1) || {
95-
echo "Error: Failed to fetch existing comments" >&2
96-
exit 2
97-
}
70+
if [ "$COMMIT_VERSION" != "$CHANGELOG_VERSION" ]; then
71+
echo "❌ Version mismatch detected! All sources must agree before creating a release." >&2
72+
exit 1
73+
fi
9874
99-
if [ -n "$EXISTING_COMMENT" ]; then
100-
echo "Updating release warning comment."
101-
./tools/build/release-pr-comment.sh "$REPO" "$PR_NUMBER" "$MARKER"
102-
else
103-
echo "No release warning comment found."
104-
fi
75+
echo "✅ All version sources agree: $COMMIT_VERSION"

.github/workflows/pull-request.yaml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
DEVELOPER_DIR: "/Applications/Xcode_${{ matrix.xcode }}.app"
4242
SWIFT_VERSION: ${{ matrix.swift }}
4343
steps:
44-
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
44+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
4545
with:
4646
persist-credentials: false
4747
- name: Select Xcode version
@@ -75,4 +75,15 @@ jobs:
7575
- name: Test
7676
run: make test
7777
- name: Build
78-
run: make build
78+
run: make build
79+
80+
gh-actions-lint:
81+
name: Github Actions Lint
82+
runs-on: ubuntu-latest
83+
steps:
84+
- name: Checkout repository
85+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
86+
with:
87+
persist-credentials: false
88+
- name: Run zizmor
89+
uses: zizmorcore/zizmor-action@0dce2577a4760a2749d8cfb7a84b7d5585ebcb7d # v0.5.0

0 commit comments

Comments
 (0)