Skip to content

Commit 1923cb2

Browse files
chore(release): swap SBOM tool to cdxgen — Corepack-proof (#69)
PR #68's `npm install --package-lock-only` SBOM fix did not survive contact with the runner. The v1.2.0 publish attempt at run 25407540759 hit the same "no evidence: no package lock file" error from @cyclonedx/cyclonedx-npm. Root cause: Corepack interception. When the workspace's `package.json#packageManager` is `pnpm@9.12.0`, Corepack (bundled with Node 20) intercepts direct `npm install` calls and either rejects them or rewrites them to pnpm — neither of which generates the `package-lock.json` that cyclonedx-npm requires as evidence. Fix: switch to `@cyclonedx/cdxgen@11`. cdxgen is the multi-package- manager CycloneDX generator and reads `pnpm-lock.yaml` natively from the workspace root. No transient lockfile round-trip; no Corepack interaction. Workflow change is local to the SBOM step: - Replace `npx @cyclonedx/cyclonedx-npm@2.1.0 ...` with `npx @cyclonedx/cdxgen@11 --type js --no-recurse --spec-version 1.5 ...` - Drop the `npm install --package-lock-only` and `rm package-lock.json` scaffolding (no longer needed). - `FETCH_LICENSE: "true"` env so the SBOM includes upstream license metadata where available. Updated `packages/k8s-baseline/tests/release-readiness.test.ts` invariant to assert `@cyclonedx/cdxgen` instead of `@cyclonedx/cyclonedx-npm`. After this PR merges: delete the failed v1.2.0 tag once more, retag at the new HEAD, push. git tag -d v1.2.0 git push origin --delete v1.2.0 git tag -a v1.2.0 -m "v1.2.0 — atomic four-package release: K8s security + Operations + pre-public-launch" git push origin v1.2.0 Verified locally: 487 tests pass; format/lint/license-boundary/pin-guard all clean. Signed-off-by: Sherif Mansour <13433538+kerberosmansour@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e536891 commit 1923cb2

2 files changed

Lines changed: 28 additions & 24 deletions

File tree

.github/workflows/release.yml

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -88,26 +88,31 @@ jobs:
8888
done
8989
ls -la .release-artifacts/
9090
91-
- name: Generate SBOMs (CycloneDX)
92-
# @cyclonedx/cyclonedx-npm requires npm-style evidence in each
93-
# package directory: a `package-lock.json`, an `npm-shrinkwrap.json`,
94-
# or a local `node_modules/`. Hulumi is a pnpm workspace — there is
95-
# no `package-lock.json` (deleted in runbook hulumi-pre-public-launch
96-
# M1) and pnpm hoists `node_modules/` to the workspace root rather
97-
# than per-package. We generate a transient `package-lock.json` per
98-
# package via `npm install --package-lock-only` (resolution only —
99-
# no install happens; `--ignore-scripts` blocks any postinstall
100-
# hooks), run the SBOM, then delete the transient lockfile so the
101-
# repo's pnpm-only invariant is preserved across the workflow run.
91+
- name: Generate SBOMs (CycloneDX, via cdxgen)
92+
# cdxgen is the multi-package-manager CycloneDX generator. It reads
93+
# `pnpm-lock.yaml` natively, so no transient `package-lock.json`
94+
# round-trip is needed. The previous fix (`npm install
95+
# --package-lock-only`) was intercepted by Corepack — when the
96+
# workspace's `package.json#packageManager` is `pnpm@9.12.0`,
97+
# Corepack rejects or rewrites direct npm calls, so the lockfile
98+
# never got created and `@cyclonedx/cyclonedx-npm` errored with
99+
# "No evidence: no package lock file nor `node_modules` dir".
100+
# Switching to cdxgen sidesteps the Corepack interaction
101+
# entirely.
102+
env:
103+
# cdxgen reads `pnpm-lock.yaml` from the workspace root and
104+
# the package.json from the per-package directory. Run from
105+
# the repo root so pnpm-lock.yaml is discoverable.
106+
FETCH_LICENSE: "true"
102107
run: |
103108
set -euo pipefail
104109
for pkg in baseline policies drift k8s-baseline; do
105-
(cd "packages/$pkg" && npm install --package-lock-only --ignore-scripts --silent)
106-
npx --yes @cyclonedx/cyclonedx-npm@2.1.0 \
107-
--output-format json \
108-
--output-file ".release-artifacts/sbom-${pkg}.cdx.json" \
110+
npx --yes @cyclonedx/cdxgen@11 \
111+
--type js \
112+
--no-recurse \
113+
--spec-version 1.5 \
114+
--output ".release-artifacts/sbom-${pkg}.cdx.json" \
109115
"packages/$pkg"
110-
rm -f "packages/$pkg/package-lock.json"
111116
done
112117
113118
- name: Attest provenance for tarballs

packages/k8s-baseline/tests/release-readiness.test.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,14 @@ describe("Feature: K8s package release readiness (Runbook M1)", () => {
5454

5555
it("release workflow generates a CycloneDX SBOM for k8s-baseline", () => {
5656
const yml = readRepoFile(".github/workflows/release.yml");
57-
// SBOM output filename per package (post-M5 release.yml writes
58-
// ".release-artifacts/sbom-${pkg}.cdx.json" inside a loop, so the
59-
// file path appears via the loop's variable expansion in the run
60-
// block; the literal `sbom-k8s-baseline.cdx.json` only appears if
61-
// the loop variable is statically referenced — which it isn't
62-
// post-pnpm-SBOM-fix. Instead, assert the loop iterates over the
63-
// four-package set + invokes cyclonedx-npm.
57+
// SBOM output filename per package: post-cdxgen-swap, release.yml
58+
// writes `.release-artifacts/sbom-${pkg}.cdx.json` inside a loop
59+
// that iterates the four-package set. cdxgen is the
60+
// multi-package-manager CycloneDX generator that reads
61+
// pnpm-lock.yaml natively (sidesteps the Corepack interception
62+
// that broke the previous @cyclonedx/cyclonedx-npm approach).
6463
expect(yml).toMatch(/for pkg in baseline policies drift k8s-baseline/);
65-
expect(yml).toMatch(/@cyclonedx\/cyclonedx-npm/);
64+
expect(yml).toMatch(/@cyclonedx\/cdxgen/);
6665
// The output-file template uses the loop variable.
6766
expect(yml).toMatch(/sbom-\$\{pkg\}\.cdx\.json/);
6867
});

0 commit comments

Comments
 (0)