Skip to content

Commit b3bbf59

Browse files
Copilotjkowalleck
andauthored
chore: add zizmor GitHub Actions security workflow (#518)
### Description Adds `.github/workflows/zizmor.yml` to continuously audit all workflows in `.github/workflows/**` for security issues using [`zizmor`](https://docs.zizmor.sh). **Workflow behaviour** - **`pull_request`** (path-filtered to `.github/workflows/**`): runs on every PR touching workflow files; job fails on any findings, blocking merge - **`push`** (path-filtered to `.github/workflows/**`): runs on every push touching workflow files - **`schedule`**: weekly full scan every Saturday 00:00 UTC regardless of changes **Implementation details** - `advanced-security: false` — emits findings as workflow-command annotations (`::error file=…`) rather than uploading a SARIF report to GitHub's Security tab; produces a non-zero exit on findings (blocking). Uploading SARIF would require `security-events: write` and GitHub Advanced Security (GHAS), both of which are unnecessary here and would violate the least-privilege policy. The two modes are mutually exclusive: `advanced-security` must be `false` for `annotations` to take effect. - `annotations: true` — surfaces findings as GitHub PR annotations (up to 10 rendered inline; remainder in job log) - `persist-credentials: false` on checkout - Least-privilege: `permissions: {}` at workflow level, `contents: read` at job level only - `timeout-minutes: 10` - All action refs pinned to full commit SHAs with version comments, matching repo conventions Also fixes all zizmor findings in the existing `nodejs.yml` and `release.yml` workflows: - Added `persist-credentials: false` to all checkout steps - Updated `actions/setup-node` SHA to current v6 tag (`48b55a011bda`) - Fixed `DerLev/eslint-annotations` impostor SHA → correct v2 SHA (`a79ea65c1b45`) - Replaced `softprops/action-gh-release` with `gh release` CLI commands Resolves or fixes issue: none ### AI Tool Disclosure - [ ] My contribution does not include any AI-generated content - [x] My contribution includes AI-generated content, as disclosed below: - AI Tools: `GitHub Copilot` - LLMs and versions: `Claude Sonnet 4.5` - Prompts: `Create a zizmor GitHub Actions security workflow per the issue spec` ### Affirmation - [x] My code follows the [CONTRIBUTING.md](https://github.com/CycloneDX/cyclonedx-node-yarn/blob/main/CONTRIBUTING.md) guidelines --------- Signed-off-by: Jan Kowalleck <[email protected]> Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: jkowalleck <[email protected]> Co-authored-by: Jan Kowalleck <[email protected]>
1 parent 1391795 commit b3bbf59

3 files changed

Lines changed: 93 additions & 20 deletions

File tree

.github/workflows/nodejs.yml

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ jobs:
3535
- name: Checkout
3636
# see https://github.com/actions/checkout
3737
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
38+
with:
39+
persist-credentials: false
3840
- name: Setup Node.js ${{ env.NODE_ACTIVE_LTS }}
3941
# see https://github.com/actions/setup-node
40-
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
42+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
4143
with:
4244
node-version: ${{ env.NODE_ACTIVE_LTS }}
4345
package-manager-cache: false
@@ -81,10 +83,12 @@ jobs:
8183
- name: Checkout
8284
# see https://github.com/actions/checkout
8385
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
86+
with:
87+
persist-credentials: false
8488
- run: mkdir -p ${{ env.REPORTS_DIR }}
8589
- name: Setup Node.js ${{ matrix.node-version }}
8690
# see https://github.com/actions/setup-node
87-
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
91+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
8892
with:
8993
node-version: ${{ env.NODE_ACTIVE_LTS }}
9094
package-manager-cache: false
@@ -107,7 +111,7 @@ jobs:
107111
- name: Annotate Code
108112
if: ${{ failure() || success() }}
109113
# see https://github.com/DerLev/eslint-annotations
110-
uses: DerLev/eslint-annotations@e75c54a2984700c03d60c5252c9c6a203bf013f5 # v2
114+
uses: DerLev/eslint-annotations@a79ea65c1b45a649c48bcc6efc0103b6fd2e4c5f # v2
111115
with:
112116
eslint-report: ${{ env.REPORTS_DIR }}/eslint.json
113117
- name: artifact eslint result
@@ -127,10 +131,12 @@ jobs:
127131
- name: Checkout
128132
# see https://github.com/actions/checkout
129133
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
134+
with:
135+
persist-credentials: false
130136
- run: mkdir -p ${{ env.REPORTS_DIR }}
131137
- name: Setup Node.js ${{ matrix.node-version }}
132138
# see https://github.com/actions/setup-node
133-
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
139+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
134140
with:
135141
node-version: ${{ env.NODE_ACTIVE_LTS }}
136142
package-manager-cache: false
@@ -156,10 +162,12 @@ jobs:
156162
- name: Checkout
157163
# see https://github.com/actions/checkout
158164
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
165+
with:
166+
persist-credentials: false
159167
- run: mkdir -p ${{ env.REPORTS_DIR }}
160168
- name: Setup Node.js ${{ matrix.node-version }}
161169
# see https://github.com/actions/setup-node
162-
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
170+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
163171
with:
164172
node-version: ${{ env.NODE_ACTIVE_LTS }}
165173
package-manager-cache: false
@@ -186,6 +194,8 @@ jobs:
186194
- name: Checkout
187195
# see https://github.com/actions/checkout
188196
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
197+
with:
198+
persist-credentials: false
189199
- name: fetch build artifact
190200
# see https://github.com/actions/download-artifact
191201
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
@@ -229,9 +239,11 @@ jobs:
229239
- name: Checkout
230240
# see https://github.com/actions/checkout
231241
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
242+
with:
243+
persist-credentials: false
232244
- name: Setup Node.js ${{ matrix.node-version }}
233245
# see https://github.com/actions/setup-node
234-
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
246+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
235247
with:
236248
node-version: ${{ matrix.node-version }}
237249
package-manager-cache: false
@@ -299,9 +311,11 @@ jobs:
299311
- name: Checkout
300312
# see https://github.com/actions/checkout
301313
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
314+
with:
315+
persist-credentials: false
302316
- name: Setup Node.js ${{ matrix.node-version }}
303317
# see https://github.com/actions/setup-node
304-
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
318+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
305319
with:
306320
node-version: ${{ matrix.node-version }}
307321
package-manager-cache: false

.github/workflows/release.yml

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ jobs:
4848
ref: ${{ needs.bump.outputs.version }}
4949
fetch-depth: 0
5050
fetch-tags: true
51+
persist-credentials: false
5152
- name: Configure Git
5253
# needed for push back of changes
5354
run: |
@@ -56,7 +57,7 @@ jobs:
5657
git config --local user.name "${GITHUB_ACTOR}"
5758
- name: Setup Node.js ${{ env.NODE_ACTIVE_LTS }}
5859
# see https://github.com/actions/setup-node
59-
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
60+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
6061
with:
6162
node-version: ${{ env.NODE_ACTIVE_LTS }}
6263
package-manager-cache: false
@@ -88,11 +89,13 @@ jobs:
8889
git add package.json yarn.lock
8990
git commit -s -m "$GCOMMIT_MESSAGE"
9091
git tag -a -m "$GCOMMIT_MESSAGE" "$GTAG_NAME"
92+
git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
9193
git push --follow-tags
9294
env:
9395
COMMIT_MESSAGE: ${{ github.event.inputs.commitMessage }}
9496
GTAG_NAME: ${{ steps.bump.outputs.version }}
9597
VERSION_PLAIN: ${{ steps.bump.outputs.version_plain }}
98+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
9699

97100
build:
98101
needs: [ "bump" ]
@@ -105,9 +108,10 @@ jobs:
105108
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
106109
with:
107110
ref: ${{ needs.bump.outputs.version }}
111+
persist-credentials: false
108112
- name: Setup Node.js ${{ env.NODE_ACTIVE_LTS }}
109113
# see https://github.com/actions/setup-node
110-
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
114+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
111115
with:
112116
node-version: ${{ env.NODE_ACTIVE_LTS }}
113117
package-manager-cache: false
@@ -152,6 +156,7 @@ jobs:
152156
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
153157
with:
154158
ref: ${{ needs.bump.outputs.version }}
159+
persist-credentials: false
155160
- name: fetch build artifact
156161
# see https://github.com/actions/download-artifact
157162
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
@@ -176,9 +181,10 @@ jobs:
176181
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
177182
with:
178183
ref: ${{ needs.bump.outputs.version }}
184+
persist-credentials: false
179185
- name: Setup Node.js ${{ env.NODE_ACTIVE_LTS }}
180186
# see https://github.com/actions/setup-node
181-
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
187+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
182188
with:
183189
node-version: ${{ env.NODE_ACTIVE_LTS }}
184190
package-manager-cache: false
@@ -222,7 +228,7 @@ jobs:
222228
path: .
223229
- name: Setup Node.js ${{ env.NODE_ACTIVE_LTS }}
224230
# see https://github.com/actions/setup-node
225-
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
231+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
226232
with:
227233
node-version: ${{ env.NODE_ACTIVE_LTS }}
228234
package-manager-cache: false
@@ -288,14 +294,20 @@ jobs:
288294
"$DIST_DIR/NOTICE" \
289295
"$DIST_DIR/bom.json"
290296
- name: Create Release
291-
id: release
292-
# see https://github.com/softprops/action-gh-release
293-
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
294297
env:
295298
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
296-
with:
297-
tag_name: ${{ needs.bump.outputs.version }}
298-
name: ${{ needs.bump.outputs.version_plain }}
299-
prerelease: ${{ github.event.inputs.prerelease }}
300-
files: '${{ env.ASSETS_DIR }}/*'
301-
# If a tag already has a GitHub release, the existing release will be updated with the release assets.
299+
R_PRERELEASE: ${{ github.event.inputs.prerelease }}
300+
R_TITLE: ${{ needs.bump.outputs.version_plain }}
301+
R_VERSION: ${{ needs.bump.outputs.version }}
302+
run: |
303+
set -exu
304+
prerelease_flag=""
305+
if [ "$R_PRERELEASE" = "true" ]; then
306+
prerelease_flag="--prerelease"
307+
fi
308+
gh release create \
309+
"$R_VERSION" \
310+
$prerelease_flag \
311+
--title "$R_TITLE" \
312+
--notes "" \
313+
"$ASSETS_DIR"/*

.github/workflows/zizmor.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# For details of what checks are run for PRs please refer below
2+
# docs: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
3+
4+
name: GitHub Actions Security with zizmor
5+
6+
on:
7+
pull_request:
8+
paths:
9+
- '.github/workflows/**'
10+
push:
11+
paths:
12+
- ".github/workflows/**"
13+
schedule:
14+
# Every Saturday 00:00 UTC
15+
- cron: '0 0 * * 6'
16+
17+
concurrency:
18+
group: '${{ github.workflow }}-${{ github.ref }}'
19+
cancel-in-progress: true
20+
21+
permissions: {}
22+
23+
jobs:
24+
zizmor:
25+
name: zizmor
26+
runs-on: ubuntu-latest
27+
timeout-minutes: 10
28+
permissions:
29+
contents: read
30+
steps:
31+
- name: Checkout
32+
# see https://github.com/actions/checkout
33+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
34+
with:
35+
persist-credentials: false
36+
- name: Run zizmor
37+
# see https://github.com/zizmorcore/zizmor-action
38+
uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3
39+
with:
40+
# advanced-security: false => emit findings as workflow-command annotations (::error file=…) rather than
41+
# uploading a SARIF report to GitHub's Security tab.
42+
# Uploading SARIF requires `security-events: write` and GitHub Advanced Security (GHAS),
43+
# both of which are unnecessary here and would violate the least-privilege policy.
44+
# The two modes are mutually exclusive: advanced-security must be false for
45+
# annotations to take effect.
46+
advanced-security: false
47+
annotations: true

0 commit comments

Comments
 (0)