ci: add OSV-Scanner, CycloneDX SBOM, and build attestations#1529
ci: add OSV-Scanner, CycloneDX SBOM, and build attestations#1529
Conversation
- Add OSV-Scanner workflow (push/PR/weekly) with results in the Security tab for broader advisory coverage than `npm audit`. - Generate a CycloneDX 1.6 SBOM (production deps only) during the release workflow and attach it to the GitHub Release. - Produce GitHub build-provenance and SBOM attestations for the published dist bundles via actions/attest-build-provenance and actions/attest-sbom, complementing npm's --provenance.
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
There was a problem hiding this comment.
Pull request overview
This PR enhances the project’s release and CI security posture by adding automated vulnerability scanning, generating a release SBOM, and producing GitHub-native supply chain attestations to complement npm provenance.
Changes:
- Add an OSV-Scanner workflow that runs on pushes, PRs, and a weekly schedule and uploads results to the GitHub Security tab.
- Generate a CycloneDX 1.6 SBOM during the release workflow and upload it as a GitHub Release asset.
- Add build provenance and SBOM attestations for release artifacts via GitHub’s
actions/attest-*actions.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| .github/workflows/release.yml | Adds SBOM generation, artifact attestations, and uploads SBOM to the GitHub Release. |
| .github/workflows/osv-scanner.yml | Introduces OSV scanning on push/PR/schedule with SARIF upload permissions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Pin @cyclonedx/cyclonedx-npm to 4.2.1 so release SBOMs are reproducible; previously @latest could shift contents on each run. - Expand attest-build-provenance and attest-sbom subject-path to cover every file pattern shipped by the npm package (dist/**/*.js, dist/**/*.js.map, dist/**/*.d.ts, index.d.ts), preventing partial attestations over .js bundles only.
Move @cyclonedx/cyclonedx-npm from a workflow-pinned npx invocation to a real devDependency at 4.2.1 so Dependabot's npm ecosystem proposes upgrades automatically. The release workflow now resolves the binary from the project install instead of fetching @latest.
Coverage Report
File CoverageNo changed files found. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 4 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
@cyclonedx/cyclonedx-npm declares libxmljs2 (a node-gyp-built native XML module) as an optionalDependency for XML-output validation. We only emit JSON, so it is unused at runtime, but it still bloats CI installs and risks node-gyp/prebuild failures on Node 25 runners. Add a top-level npm override mapping libxmljs2 to the published no-op stub noop2@2.0.0. This eliminates the native compile, removes ~100 transitive deps from the install, and leaves JSON SBOM generation working unchanged (verified locally with the real project tree).
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 4 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Three review fixes: 1. Invoke cyclonedx-npm via ./node_modules/.bin/cyclonedx-npm instead of `npx @cyclonedx/cyclonedx-npm`. `npx --no` still contacts the registry when a package is missing, so the previous form could silently bypass the lockfile pin if the devDep ever went missing. The direct binary path fails fast with no network call and only ever runs the version installed by `npm install`. 2. Reorder the publish job so `npm publish` is the final irreversible step. Previously SBOM generation, attestations, and the GitHub-Release SBOM upload all ran *after* publish, meaning any failure there would leave the package published but the release in a partial state. New order: SBOM -> npm pack -> attest provenance -> attest SBOM -> upload SBOM to release -> npm publish. 3. Pack the npm tarball with `npm pack` and use that single tarball as the subject for both attestations, then publish that exact tarball. The previous subject-path glob covered only dist/** and index.d.ts even though the published package also includes package.json, README, and LICENSE. Attesting the tarball guarantees the attestation covers exactly what npm ships.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Bump engines.node from >=20.0.0 to >=20.18.0. The previous floor was already understated: 90 transitive devDeps (ESLint, csstools, cyclonedx, etc.) declare a >=20.18 or >=20.19 minimum, so installs on Node 20.0-20.17 would emit EBADENGINE warnings (or fail under engine-strict). 20.18 is the precise floor cyclonedx-npm needs. - Move the libxmljs2 -> noop2 stub from a top-level override to two parent-scoped entries under @cyclonedx/cyclonedx-npm and @cyclonedx/cyclonedx-library. This shrinks the override's blast radius so any future dep that legitimately depends on libxmljs2 will receive the real package rather than the stub. Both scopes are required because both packages declare libxmljs2 directly, and a single-parent scope leaves the other consumer's copy un-overridden after dedupe. Verified the resolved tree contains exactly one libxmljs2 entry pointing at noop2@2.0.0 with no native build artifacts.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 4 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- engines.node: >=20.18.0 -> >=20.19.0. Verified with semver against every engine range in the lockfile: the strictest effective lower bound is 20.19.0, driven by csstools/* (>=20.19.0), ESLint v10 family, jsdom, asamuzakjp css packages, rolldown bindings, and undici. Anything lower would still surface EBADENGINE warnings on transitive devDeps. - Pin both OSV-Scanner reusable workflow refs from @v2.2.4 to the immutable commit SHA (9bb69575e74019c2ad085a1860787043adf47ccb, with `# v2.2.4` trailer for legibility). Tags can be retargeted upstream; a SHA guarantees the workflow code that was reviewed is what runs in CI. Dependabot's github-actions ecosystem understands SHA pins and will open update PRs when new versions ship.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Jonathan Putney <42720634+jcputney@users.noreply.github.com>
Security tab for broader advisory coverage than
npm audit.release workflow and attach it to the GitHub Release.
published dist bundles via actions/attest-build-provenance and
actions/attest-sbom, complementing npm's --provenance.