Skip to content

Commit ac95fbe

Browse files
flavorjonesclaude
andauthored
ci: harden GitHub Actions workflows (#44)
* Add lint-actions CI job for GitHub Actions auditing Adds actionlint and zizmor checks to the CI workflow, placed alongside the existing lint job. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Configure dependabot with batching and cooldown Groups all GitHub Actions updates into a single PR and adds cooldown periods to both gomod and github-actions ecosystems. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Pin all GitHub Actions to SHA hashes with pinact Ensures exact version comments match pinned SHAs across all workflow files. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix high-severity zizmor findings - Suppress dangerous-triggers on ai-labeler and sensitive-change-gate (both only call reusable workflows, no PR code checked out) - Fix bot-conditions in dependabot-auto-merge with dual actor check - Move release.yml permissions to job-level (excessive-permissions) - Suppress cache-poisoning on setup-go in release (branch-isolated) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix medium-severity zizmor findings - Fix ref-version-mismatch: update create-github-app-token comment from v2 to v3.0.0 to match pinned SHA - Move security.yml permissions to job-level (excessive-permissions) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix low-severity zizmor findings: add persist-credentials: false Add persist-credentials: false to all checkout steps to prevent credential leakage through artifacts (artipacked). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Move all permissions to job-level across all workflows Set permissions: {} at workflow level and declare per-job permissions for ci.yml, test.yml, ai-labeler.yml, dependabot-auto-merge.yml, direct-push-alert.yml, sensitive-change-gate.yml, and scorecard.yml. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix actionlint shellcheck finding in release workflow Use ./*.test glob pattern to avoid filenames with dashes being interpreted as options (SC2035). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Harden gitleaks install with SHA256 checksum and pin govulncheck version Address Copilot review feedback: - Verify gitleaks tarball with SHA256 checksum before extracting - Pin govulncheck to v1.1.4 instead of @latest for reproducibility Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 3f62c1f commit ac95fbe

10 files changed

Lines changed: 171 additions & 81 deletions

.github/dependabot.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,20 @@ updates:
55
schedule:
66
interval: weekly
77
open-pull-requests-limit: 10
8+
cooldown:
9+
semver-major-days: 7
10+
semver-minor-days: 3
11+
semver-patch-days: 2
12+
default-days: 7
813

914
- package-ecosystem: github-actions
10-
directory: /
15+
directory: "/"
16+
groups:
17+
github-actions:
18+
patterns:
19+
- "*"
1120
schedule:
1221
interval: weekly
1322
open-pull-requests-limit: 10
23+
cooldown:
24+
default-days: 7

.github/workflows/ai-labeler.yml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
name: Classify PR
22

33
on:
4-
pull_request_target:
4+
pull_request_target: # zizmor: ignore[dangerous-triggers] -- required for write access to PRs from forks; workflow only calls reusable workflows, no PR code is checked out or executed
55
types: [opened, synchronize, reopened]
66

77
concurrency:
88
group: classify-pr-${{ github.event.pull_request.number }}
99
cancel-in-progress: true
1010

11-
permissions:
12-
contents: read
13-
issues: write
14-
models: read
15-
pull-requests: write
11+
permissions: {}
1612

1713
jobs:
1814
classify:

.github/workflows/ci.yml

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,71 +5,114 @@ on:
55
branches: [main, master]
66
pull_request:
77

8-
permissions:
9-
contents: read
8+
permissions: {}
109

1110
jobs:
1211
test:
1312
runs-on: ubuntu-latest
13+
permissions:
14+
contents: read
1415
steps:
15-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
16-
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
16+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
17+
with:
18+
persist-credentials: false
19+
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
1720
with:
1821
go-version-file: go.mod
1922
- run: make test
2023

2124
vet:
2225
runs-on: ubuntu-latest
26+
permissions:
27+
contents: read
2328
steps:
24-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
25-
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
29+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
30+
with:
31+
persist-credentials: false
32+
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
2633
with:
2734
go-version-file: go.mod
2835
- run: make vet
2936

3037
fmt-check:
3138
runs-on: ubuntu-latest
39+
permissions:
40+
contents: read
3241
steps:
33-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
34-
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
42+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
43+
with:
44+
persist-credentials: false
45+
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
3546
with:
3647
go-version-file: go.mod
3748
- run: make fmt-check
3849

3950
build:
4051
runs-on: ubuntu-latest
52+
permissions:
53+
contents: read
4154
steps:
42-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
43-
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
55+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
56+
with:
57+
persist-credentials: false
58+
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
4459
with:
4560
go-version-file: go.mod
4661
- run: make build
4762

4863
surface-compat:
4964
runs-on: ubuntu-latest
65+
permissions:
66+
contents: read
5067
steps:
51-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
52-
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
68+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
69+
with:
70+
persist-credentials: false
71+
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
5372
with:
5473
go-version-file: go.mod
5574
- run: go test ./internal/cmd/ -run TestSurface -v
5675

5776
lint:
5877
runs-on: ubuntu-latest
78+
permissions:
79+
contents: read
5980
steps:
60-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
61-
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
81+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
82+
with:
83+
persist-credentials: false
84+
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
6285
with:
6386
go-version-file: go.mod
64-
- uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9
87+
- uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
6588
with:
6689
version: v2.10.1
6790

91+
lint-actions:
92+
name: GitHub Actions audit
93+
runs-on: ubuntu-latest
94+
permissions:
95+
contents: read
96+
steps:
97+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
98+
with:
99+
persist-credentials: false
100+
- name: Run actionlint
101+
uses: rhysd/actionlint@393031adb9afb225ee52ae2ccd7a5af5525e03e8 # v1.7.11
102+
- name: Run zizmor
103+
uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2
104+
with:
105+
advanced-security: false
106+
68107
test-race:
69108
runs-on: ubuntu-latest
109+
permissions:
110+
contents: read
70111
steps:
71-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
72-
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
112+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
113+
with:
114+
persist-credentials: false
115+
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
73116
with:
74117
go-version-file: go.mod
75118
- run: go test -race ./...

.github/workflows/dependabot-auto-merge.yml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,19 @@ name: Dependabot Auto-Merge
22

33
on: pull_request
44

5-
permissions:
6-
contents: write
7-
pull-requests: write
5+
permissions: {}
86

97
jobs:
108
auto-merge:
119
runs-on: ubuntu-latest
12-
if: github.actor == 'dependabot[bot]'
10+
permissions:
11+
contents: write
12+
pull-requests: write
13+
if: github.actor == 'dependabot[bot]' && github.event.pull_request.user.login == 'dependabot[bot]' # zizmor: ignore[bot-conditions] -- dual check: actor validates current trigger, user.login validates PR origin
1314
steps:
1415
- name: Fetch Dependabot metadata
1516
id: metadata
16-
uses: dependabot/fetch-metadata@21025c705c08248db411dc16f3619e6b5f9ea21a # v2
17+
uses: dependabot/fetch-metadata@21025c705c08248db411dc16f3619e6b5f9ea21a # v2.5.0
1718
with:
1819
github-token: ${{ secrets.GITHUB_TOKEN }}
1920

.github/workflows/direct-push-alert.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ on:
44
push:
55
branches: [main]
66

7-
permissions:
8-
contents: read
9-
issues: write
7+
permissions: {}
108

119
jobs:
1210
alert:

.github/workflows/release.yml

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ concurrency:
99
group: release-${{ github.ref }}
1010
cancel-in-progress: false
1111

12-
permissions:
13-
contents: write
14-
attestations: write
15-
security-events: write
16-
pull-requests: read
17-
models: read
12+
permissions: {}
1813

1914
jobs:
2015
test:
2116
uses: ./.github/workflows/test.yml
17+
permissions:
18+
contents: read
2219

2320
security:
2421
uses: ./.github/workflows/security.yml
22+
permissions:
23+
contents: read
24+
security-events: write
2525

2626
release:
2727
name: Release
@@ -35,12 +35,13 @@ jobs:
3535
attestations: write
3636
models: read
3737
steps:
38-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
38+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
3939
with:
4040
fetch-depth: 0
41+
persist-credentials: false
4142

4243
- name: Set up Go
43-
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
44+
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 # zizmor: ignore[cache-poisoning] -- cache is branch-isolated; fork PRs cannot write to this cache
4445
with:
4546
go-version-file: go.mod
4647

@@ -62,7 +63,7 @@ jobs:
6263
failed=$((failed + 1))
6364
fi
6465
done
65-
rm -f *.test
66+
rm -f ./*.test
6667
if [ "$failed" -gt 0 ]; then
6768
echo "WARNING: $failed package(s) failed benchmarking — PGO profile may be incomplete"
6869
fi
@@ -77,7 +78,7 @@ jobs:
7778
uses: sigstore/cosign-installer@ba7bc0a3fef59531c69a25acd34668d6d3fe6f22 # v4.1.0
7879

7980
- name: Install Syft
80-
uses: anchore/sbom-action/download-syft@57aae528053a48a3f6235f2d9461b05fbcb7366d # v0
81+
uses: anchore/sbom-action/download-syft@57aae528053a48a3f6235f2d9461b05fbcb7366d # v0.23.1
8182

8283
- name: Generate shell completions
8384
run: |
@@ -171,15 +172,15 @@ jobs:
171172

172173
- name: Generate GitHub App token
173174
id: app-token
174-
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3
175+
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
175176
with:
176177
app-id: ${{ vars.RELEASE_APP_ID }}
177178
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
178179
repositories: homebrew-tap
179180
permission-contents: write
180181

181182
- name: Install GoReleaser
182-
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7
183+
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0
183184
with:
184185
version: 'v2.14.1'
185186
install-only: true
@@ -242,7 +243,9 @@ jobs:
242243
contents: read
243244
if: startsWith(github.ref, 'refs/tags/v')
244245
steps:
245-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
246+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
247+
with:
248+
persist-credentials: false
246249

247250
- name: Check AUR secret
248251
id: check
@@ -274,11 +277,13 @@ jobs:
274277
permissions:
275278
contents: read
276279
steps:
277-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
280+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
281+
with:
282+
persist-credentials: false
278283

279284
- name: Generate token for skills repo
280285
id: skills-token
281-
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v2
286+
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
282287
with:
283288
app-id: ${{ vars.RELEASE_APP_ID }}
284289
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}

.github/workflows/scorecard.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
- cron: '30 1 * * 6'
88
workflow_dispatch:
99

10-
permissions: read-all
10+
permissions: {}
1111

1212
jobs:
1313
analysis:
@@ -17,7 +17,7 @@ jobs:
1717
id-token: write
1818
contents: read
1919
steps:
20-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
20+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2121
with:
2222
persist-credentials: false
2323

@@ -33,7 +33,7 @@ jobs:
3333
path: results.sarif
3434
retention-days: 5
3535

36-
- uses: github/codeql-action/upload-sarif@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4
36+
- uses: github/codeql-action/upload-sarif@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0
3737
continue-on-error: true
3838
with:
3939
sarif_file: results.sarif

0 commit comments

Comments
 (0)