Skip to content

Commit b88b22f

Browse files
dmartinochoaclaude
andauthored
ci: add SBOM, signed provenance, and publish-side npm audit (#27)
Resolves the 7 open code-scanning findings (GHA-006, GHA-007, GHA-020, GHA-024) on ci.yml and publish.yml: - publish.yml: gate on `npm audit --omit=dev --audit-level=high` before packaging so a vuln landing between CI and tag-push still trips the publish. - both workflows: produce a CycloneDX SBOM via anchore/sbom-action. Publish attaches it to the GitHub release; CI uploads it as the `sbom` artifact. - both workflows: emit a signed SLSA build provenance attestation for the .vsix via actions/attest-build-provenance (OIDC + Sigstore keyless). Covers both signing and provenance in one step. CI's attest step is gated on `push` events — fork-PR runs get read-only tokens and can't mint OIDC tokens or write attestations. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c2211dc commit b88b22f

2 files changed

Lines changed: 66 additions & 2 deletions

File tree

.github/workflows/ci.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ permissions:
1919
# gracefully without this (GitHub strips write tokens for forks), so
2020
# the gap only surfaced on the first push: main run.
2121
security-events: write
22+
# attest-build-provenance needs an OIDC token (id-token) and write
23+
# access to the repo's attestations store. Same fork caveat as
24+
# security-events — declared here for push:main runs, gated by
25+
# `if:` on the attest step so fork-PR runs don't fail trying to use
26+
# them.
27+
id-token: write
28+
attestations: write
2229

2330
jobs:
2431
check:
@@ -115,6 +122,29 @@ jobs:
115122
# bumps it via the npm config. `npm ci` has already installed it.
116123
run: npx vsce package --out pipeline-check.vsix
117124

125+
- name: Generate SBOM (CycloneDX)
126+
# Linux-only — one SBOM per run is enough; the matrix legs
127+
# would produce identical content from the same lockfile.
128+
# Mirrors the publish workflow's SBOM step so a release SBOM
129+
# can be diffed against a CI SBOM if the trees diverge.
130+
if: matrix.os == 'ubuntu-latest'
131+
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
132+
with:
133+
format: cyclonedx-json
134+
output-file: pipeline-check-sbom.cdx.json
135+
artifact-name: sbom
136+
137+
- name: Attest build provenance
138+
# Produces a signed SLSA build provenance attestation for the
139+
# CI .vsix via OIDC + Sigstore keyless signing. Gated on
140+
# `push` because fork-PR runs get read-only tokens that
141+
# cannot mint OIDC tokens or write attestations. Linux-only
142+
# — same one-per-run rationale as the SBOM step.
143+
if: github.event_name == 'push' && matrix.os == 'ubuntu-latest'
144+
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
145+
with:
146+
subject-path: pipeline-check.vsix
147+
118148
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
119149
# Single artefact upload from the Linux job; identical-name
120150
# uploads from the matrix would collide.

.github/workflows/publish.yml

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ jobs:
5050
# publish steps will block on the environment gate.
5151
environment: production
5252
permissions:
53-
contents: write # needed by the "Create GitHub release" step
53+
contents: write # needed by the "Create GitHub release" step
54+
id-token: write # OIDC for sigstore signing via attest-build-provenance
55+
attestations: write # store the SLSA provenance attestation on the repo
5456
steps:
5557
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
5658
with:
@@ -121,6 +123,13 @@ jobs:
121123
- name: Bundle smoke
122124
run: npm run smoke
123125

126+
- name: npm audit (prod deps, high+)
127+
# Block the publish if a HIGH/CRITICAL advisory affects a
128+
# runtime dependency. Dev-only deps are out of scope — they
129+
# don't ship in the .vsix. Mirrors the CI gate so a vuln that
130+
# lands between CI and tag-push still trips here.
131+
run: npm audit --omit=dev --audit-level=high
132+
124133
- name: Detect pre-release tag
125134
# A tag like `v0.2.0-rc.1` (anything with a `-` after the
126135
# semver core) ships to the marketplace's pre-release channel
@@ -151,6 +160,31 @@ jobs:
151160
npx vsce package $PRERELEASE_FLAG --out "pipeline-check-${version}.vsix"
152161
ls -lh "pipeline-check-${version}.vsix"
153162
echo "VSIX_PATH=pipeline-check-${version}.vsix" >> $GITHUB_ENV
163+
echo "SBOM_PATH=pipeline-check-${version}-sbom.cdx.json" >> $GITHUB_ENV
164+
165+
- name: Generate SBOM (CycloneDX)
166+
# Scans package-lock.json so the SBOM captures the full
167+
# production + transitive dep set, not just the tree-shaken
168+
# bundle inside the .vsix. Output is attached to the GitHub
169+
# release below so marketplace consumers can ingest it into
170+
# their vuln-management pipeline.
171+
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
172+
with:
173+
format: cyclonedx-json
174+
output-file: ${{ env.SBOM_PATH }}
175+
# Suppress the action's own artifact upload — we ship the
176+
# SBOM via `gh release create` below instead.
177+
upload-artifact: false
178+
179+
- name: Attest build provenance
180+
# Produces a signed SLSA build provenance attestation for the
181+
# .vsix using GitHub's OIDC token and Sigstore's keyless
182+
# signing flow. Satisfies both signing (cosign/sigstore) and
183+
# SLSA provenance — consumers can verify with
184+
# `gh attestation verify <vsix> --owner greylag-ci`.
185+
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
186+
with:
187+
subject-path: ${{ env.VSIX_PATH }}
154188

155189
- name: Publish to VS Code Marketplace
156190
env:
@@ -175,6 +209,6 @@ jobs:
175209
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
176210
run: |
177211
version=$(node -p "require('./package.json').version")
178-
gh release create "v${version}" "$VSIX_PATH" $GH_PRERELEASE \
212+
gh release create "v${version}" "$VSIX_PATH" "$SBOM_PATH" $GH_PRERELEASE \
179213
--title "v${version}" \
180214
--notes-file <(awk '/^## \[/{n++} n==2{exit} n==1{print}' CHANGELOG.md)

0 commit comments

Comments
 (0)