Skip to content

Commit 8a70712

Browse files
committed
ci: secure workflows with zizmor
Signed-off-by: Eli <88557639+lishaduck@users.noreply.github.com> Co-authored-by: Eli <elisha.dukes@gmail.com> Amp-Thread-ID: https://ampcode.com/threads/T-019fbb44-bcba-718f-849a-12815326f2e6
1 parent c100fe1 commit 8a70712

13 files changed

Lines changed: 255 additions & 156 deletions

File tree

.github/actions/spelling/expect.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ apidojo
88
apostrophecms
99
apps
1010
arobase
11+
artipacked
1112
asi
1213
audioscrobbler
1314
Autoloaded
@@ -27,6 +28,7 @@ codelines
2728
codeql
2829
colorsets
2930
Consolas
31+
cooldown
3032
datapoints
3133
dded
3234
Dexcom
@@ -291,3 +293,4 @@ ytmusic
291293
Zabcdefghijklmnopqrstuvwxyz
292294
zenhei
293295
zenorocha
296+
zizmor

.github/dependabot.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ updates:
1414
- dependency-name: vue-prism-component
1515
versions:
1616
- 2.0.0
17+
cooldown:
18+
default-days: 7
1719
- package-ecosystem: github-actions
1820
labels:
1921
- 📦 dependencies
@@ -24,3 +26,5 @@ updates:
2426
- lishaduck
2527
commit-message:
2628
prefix: "ci(deps)"
29+
cooldown:
30+
default-days: 7

.github/scripts/build.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ function testcase(name, env, args) {
176176

177177
if (env === "prod") {
178178
result.if = "${{ success() || failure() }}"
179-
result.uses = "gh-metrics/metrics@master"
179+
result.uses = "$/"
180180
Object.assign(result.with, {output_action: "none", delay: 120})
181181

182182
for (const {property, value} of [{property: "user", value: "gh-metrics"}, {property: "plugins_errors_fatal", value: "yes"}]) {

.github/scripts/files/examples.yml

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ on:
3232
required: true
3333
WAKATIME_TOKEN:
3434
required: true
35+
36+
permissions: {}
37+
3538
jobs:
3639
# ======================================================================================
3740
# Examples renders
@@ -44,12 +47,15 @@ jobs:
4447
if: ${{ github.repository == 'gh-metrics/metrics' && false }}
4548

4649
permissions:
47-
contents: write
50+
contents: write # Push generated examples to the examples branch.
51+
packages: read # Pull the private/package-backed metrics action if required.
4852

4953
steps:
54+
# zizmor: ignore[artipacked] Credentials are required to publish generated examples.
5055
- name: Checkout repository
51-
uses: actions/checkout@v4
56+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0
5257
with:
58+
persist-credentials: true
5359
fetch-depth: 0
5460
ref: examples
5561

@@ -81,18 +87,24 @@ jobs:
8187
runs-on: ubuntu-latest
8288
needs: [examples]
8389

90+
permissions:
91+
contents: write # Push repository assets to the examples branch.
92+
packages: read # Pull the private/package-backed metrics action if required.
93+
8494
# Skip until I secure the workflows enough to feel comfortable minting tokens.
8595
if: ${{ github.repository == 'gh-metrics/metrics' && false }}
8696
steps:
97+
# zizmor: ignore[artipacked] Credentials are required to publish generated examples.
8798
- name: Checkout repository
88-
uses: actions/checkout@v4
99+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0
89100
with:
101+
persist-credentials: true
90102
fetch-depth: 0
91103
ref: examples
92104

93105
- name: Contributors
94106
if: ${{ success() || failure() }}
95-
uses: gh-metrics/metrics@master
107+
uses: $/
96108
with:
97109
filename: metrics.contributors.svg
98110
token: ${{ secrets.METRICS_TOKEN }}
@@ -108,7 +120,7 @@ jobs:
108120
delay: 120
109121
- name: Sponsors
110122
if: ${{ success() || failure() }}
111-
uses: gh-metrics/metrics@master
123+
uses: $/
112124
with:
113125
filename: metrics.sponsors.svg
114126
token: ${{ secrets.METRICS_TOKEN_PERSONAL }}
@@ -124,7 +136,7 @@ jobs:
124136
delay: 120
125137
- name: Licenses
126138
if: ${{ success() || failure() }}
127-
uses: gh-metrics/metrics@master
139+
uses: $/
128140
with:
129141
filename: metrics.licenses.svg
130142
token: ${{ secrets.METRICS_TOKEN }}

.github/workflows/branches.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
name: Check automated branches
22

33
on:
4+
# zizmor: ignore[dangerous-triggers] This workflow only comments through a pinned action and never executes PR code.
45
pull_request_target:
56
branches:
67
- main
78
- latest
89
- examples
910

11+
permissions: {}
12+
1013
jobs:
1114
notice:
1215
name: Notice for automated branches
1316
runs-on: ubuntu-latest
17+
18+
permissions:
19+
pull-requests: write # Explain why automated branches reject the pull request.
20+
1421
steps:
1522
- name: Comment on pull request
16-
uses: actions/github-script@v9
23+
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9.0.0
1724
with:
1825
script: |
1926
const {issue:{number:issue_number}, repo:{owner, repo}} = context
@@ -28,5 +35,5 @@ jobs:
2835
"",
2936
"Thanks for your cooperation 🦾!"
3037
].join("\n")})
31-
- name: Change base branch
38+
- name: Fail workflow
3239
run: exit 1

.github/workflows/ci.yml

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,42 @@ on:
55
branches: [ master ]
66
workflow_dispatch:
77

8+
permissions: {}
9+
810
jobs:
911

1012
# Build, test and analyze
1113
build-test-analyze:
1214
name: Build, test and analyze
1315
if: ${{ !contains(github.event.head_commit.message, '[skip test]') }}
14-
uses: gh-metrics/metrics/.github/workflows/test.yml@master
16+
uses: $/.github/workflows/test.yml
17+
permissions:
18+
contents: read # Check out and test the repository.
1519

1620
# Update plugins and template indexes, along with README.md
1721
update-indexes:
1822
name: Publish rebuilt metrics indexes
1923
runs-on: ubuntu-latest
2024
needs: [build-test-analyze]
2125
permissions:
22-
contents: write
26+
contents: write # Commit and push regenerated indexes.
2327
steps:
28+
# zizmor: ignore[artipacked] Credentials are required to publish regenerated files.
2429
- name: Checkout repository
25-
uses: actions/checkout@v6
30+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0
2631
with:
32+
persist-credentials: true
2733
fetch-depth: 0
2834
ref: master
2935
- name: Setup NodeJS
30-
uses: actions/setup-node@v6
36+
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0
3137
with:
3238
node-version: 20
3339
cache: "npm"
3440
- name: Setup metrics
3541
run: npm ci --ignore-scripts --no-audit --no-fund
3642
- name: Publish rebuild metrics indexes
43+
# zizmor: ignore[use-trusted-publishing] This publishes generated files to Git, not an npm package.
3744
run: npm run build -- publish
3845

3946
# Rebase main branch on master
@@ -42,11 +49,12 @@ jobs:
4249
runs-on: ubuntu-latest
4350
needs: [update-indexes]
4451
permissions:
45-
contents: write
52+
contents: write # Merge master into and push the main branch.
4653
steps:
4754
- name: Checkout repository
48-
uses: actions/checkout@v6
55+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0
4956
with:
57+
persist-credentials: true
5058
fetch-depth: 0
5159
ref: main
5260
- name: Configure Git Identity
@@ -64,12 +72,18 @@ jobs:
6472
runs-on: ubuntu-latest
6573
needs: [update-indexes]
6674
permissions:
67-
packages: write
75+
contents: read # Build the image from repository contents.
76+
packages: write # Publish master and beta container images.
6877
steps:
6978
- name: Checkout repository
70-
uses: actions/checkout@v6
79+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0
80+
with:
81+
persist-credentials: false
7182
- name: Login to GitHub registry
72-
run: echo ${{ github.token }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
83+
env:
84+
GITHUB_ACTOR: ${{ github.actor }}
85+
GITHUB_TOKEN: ${{ github.token }}
86+
run: echo "$GITHUB_TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin
7387
- name: Build docker image
7488
run: docker build -t ghcr.io/gh-metrics/metrics:master .
7589
- name: Publish to GitHub registry
@@ -98,7 +112,9 @@ jobs:
98112
if: github.repository_owner == 'lowlighter'
99113
steps:
100114
- name: Deploy web instance
101-
run: "curl -X POST -H 'Authorization: ${{ secrets.WEB_DEPLOY_BETA_TOKEN }}' https://beta-metrics.lecoq.io/.control/stop"
115+
env:
116+
WEB_DEPLOY_TOKEN: ${{ secrets.WEB_DEPLOY_BETA_TOKEN }}
117+
run: "curl -X POST -H 'Authorization: $WEB_DEPLOY_TOKEN' https://beta-metrics.lecoq.io/.control/stop"
102118
- name: Wait for redeploy
103119
run: sleep 120
104120
- name: Check deployment status
@@ -111,7 +127,7 @@ jobs:
111127
needs: [docker-master]
112128
steps:
113129
- name: Run tests
114-
uses: gh-metrics/metrics@master
130+
uses: $/
115131
with:
116132
token: MOCKED_TOKEN
117133
plugins_errors_fatal: yes
@@ -123,10 +139,10 @@ jobs:
123139
publish-examples:
124140
name: Publish examples
125141
needs: [action-master-test]
126-
uses: gh-metrics/metrics/.github/workflows/examples.yml@master
142+
uses: $/.github/workflows/examples.yml
127143
permissions:
128-
contents: write
129-
packages: read
144+
contents: write # Publish generated examples.
145+
packages: read # Pull the metrics action image.
130146
secrets:
131147
METRICS_TOKEN: ${{ secrets.METRICS_TOKEN }}
132148
METRICS_TOKEN_WITH_SCOPES: ${{ secrets.METRICS_TOKEN_WITH_SCOPES }}
@@ -146,21 +162,29 @@ jobs:
146162
publish-examples-presets:
147163
name: Publish examples (presets)
148164
needs: [action-master-test]
149-
uses: gh-metrics/metrics/.github/workflows/examples.presets.yml@master
165+
uses: $/.github/workflows/examples.presets.yml
150166
permissions:
151-
contents: write
167+
contents: write # Publish generated preset examples.
152168

153169
# Build docker image from master and publish it to GitHub registry with release tag
154170
docker-release:
155171
name: Publish release to GitHub registry
156172
runs-on: ubuntu-latest
157173
needs: [publish-examples]
158174
if: contains(github.event.head_commit.message, '[release]')
175+
permissions:
176+
contents: read # Read release metadata from the repository.
177+
packages: write # Publish release and latest container images.
159178
steps:
160179
- name: Checkout repository
161-
uses: actions/checkout@v6
180+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0
181+
with:
182+
persist-credentials: false
162183
- name: Login to GitHub registry
163-
run: echo ${{ github.token }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
184+
env:
185+
GITHUB_ACTOR: ${{ github.actor }}
186+
GITHUB_TOKEN: ${{ github.token }}
187+
run: echo "$GITHUB_TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin
164188
- name: Pull docker image (master)
165189
run: docker pull ghcr.io/gh-metrics/metrics:master
166190
- name: Tag docker image (release)
@@ -181,10 +205,13 @@ jobs:
181205
name: Rebase latest on master
182206
runs-on: ubuntu-latest
183207
needs: [docker-release]
208+
permissions:
209+
contents: write # Merge master into and push the latest branch.
184210
steps:
185211
- name: Checkout repository
186-
uses: actions/checkout@v6
212+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0
187213
with:
214+
persist-credentials: true
188215
fetch-depth: 0
189216
ref: latest
190217
- name: Configure Git Identity
@@ -201,9 +228,11 @@ jobs:
201228
name: Test gh-metrics/metrics@latest
202229
runs-on: ubuntu-latest
203230
needs: [update-latest]
231+
permissions:
232+
packages: read # Pull the metrics action image.
204233
steps:
205234
- name: Run tests
206-
uses: gh-metrics/metrics@latest
235+
uses: gh-metrics/metrics@latest # zizmor: ignore[unpinned-uses] First-party action must test latest.
207236
with:
208237
token: MOCKED_TOKEN
209238
plugins_errors_fatal: yes
@@ -219,7 +248,9 @@ jobs:
219248
if: github.repository_owner == 'lowlighter'
220249
steps:
221250
- name: Deploy web instance
222-
run: "curl -X POST -H 'Authorization: ${{ secrets.WEB_DEPLOY_TOKEN }}' https://metrics.lecoq.io/.control/stop"
251+
env:
252+
WEB_DEPLOY_TOKEN: ${{ secrets.WEB_DEPLOY_TOKEN }}
253+
run: "curl -X POST -H 'Authorization: $WEB_DEPLOY_TOKEN' https://metrics.lecoq.io/.control/stop"
223254
- name: Wait for redeploy
224255
run: sleep 120
225256
- name: Check deployment status
@@ -230,11 +261,16 @@ jobs:
230261
name: Publish release
231262
runs-on: ubuntu-latest
232263
needs: [action-latest-test, deploy-latest]
264+
permissions:
265+
contents: write # Create the GitHub release.
233266
steps:
267+
# zizmor: ignore[artipacked] Credentials are required to replace an existing release tag.
234268
- name: Checkout repository
235-
uses: actions/checkout@v6
269+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0
270+
with:
271+
persist-credentials: true
236272
- name: Setup NodeJS
237-
uses: actions/setup-node@v6
273+
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0
238274
with:
239275
node-version: 20
240276
cache: "npm"

.github/workflows/clean.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,23 @@ on:
66
- published
77
workflow_dispatch:
88

9+
permissions: {}
10+
911
jobs:
1012
clean:
1113
name: Clean untagged docker images
1214
runs-on: ubuntu-latest
1315
continue-on-error: true
16+
17+
permissions:
18+
contents: read # Check out the cleanup script.
19+
packages: write # Delete untagged container images.
20+
1421
steps:
1522
- name: Checkout repository
16-
uses: actions/checkout@v6
23+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0
24+
with:
25+
persist-credentials: false
1726
- name: Run script
1827
run: ./delete_ghcr_dangling_images.sh gh-metrics metrics
1928
working-directory: .github/actions/ghcr-clean

0 commit comments

Comments
 (0)