From f917c80c9ec742e539ca406f5c36fb7c3410644e Mon Sep 17 00:00:00 2001 From: Roger Chappel Date: Wed, 2 Sep 2026 19:09:26 +1000 Subject: [PATCH 1/3] test: require trusted publishing npm preparation --- scripts/check-release-workflows.mjs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/scripts/check-release-workflows.mjs b/scripts/check-release-workflows.mjs index 85c709f..e535ef2 100644 --- a/scripts/check-release-workflows.mjs +++ b/scripts/check-release-workflows.mjs @@ -3,6 +3,28 @@ import { readFile } from "node:fs/promises"; const release = await readFile(".github/workflows/release.yml", "utf8"); const dryRun = await readFile(".github/workflows/release-dry-run.yml", "utf8"); +const trustedPublishingNpmVersion = "11.5.1"; + +function assertTrustedPublishingNpm(workflow, name) { + const prepareIndex = workflow.indexOf("- name: Prepare trusted publishing npm"); + const installIndex = workflow.indexOf("- name: Install dependencies"); + + assert.notEqual(prepareIndex, -1, `${name} must prepare npm for trusted publishing`); + assert.ok( + prepareIndex < installIndex, + `${name} must prepare trusted publishing npm before dependency installation`, + ); + assert.match( + workflow, + new RegExp(`npm install --global npm@${trustedPublishingNpmVersion.replaceAll(".", "\\.")}`), + `${name} must pin npm ${trustedPublishingNpmVersion}`, + ); + assert.match( + workflow.slice(prepareIndex, installIndex), + /npm --version/, + `${name} must print the effective npm version`, + ); +} function assertSinglePack(workflow, name) { assert.equal( @@ -17,6 +39,8 @@ function assertSinglePack(workflow, name) { assertSinglePack(release, "release workflow"); assertSinglePack(dryRun, "release dry-run workflow"); +assertTrustedPublishingNpm(release, "release workflow"); +assertTrustedPublishingNpm(dryRun, "release dry-run workflow"); assert.match( release, @@ -34,4 +58,6 @@ assert.match( "dry run must publish the packed artifact without repacking", ); -console.log("release workflows pack once and reuse the package artifact"); +console.log( + `release workflows prepare npm ${trustedPublishingNpmVersion}, pack once, and reuse the package artifact`, +); From c1af95ce57f06be65489b77b920e880060063271 Mon Sep 17 00:00:00 2001 From: Roger Chappel Date: Wed, 2 Sep 2026 19:09:49 +1000 Subject: [PATCH 2/3] ci: pin npm for trusted publishing --- .github/workflows/release-dry-run.yml | 4 ++++ .github/workflows/release.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/release-dry-run.yml b/.github/workflows/release-dry-run.yml index a4f364f..5c92cb9 100644 --- a/.github/workflows/release-dry-run.yml +++ b/.github/workflows/release-dry-run.yml @@ -28,6 +28,10 @@ jobs: node-version: 22 cache: npm registry-url: https://registry.npmjs.org + - name: Prepare trusted publishing npm + run: | + npm install --global npm@11.5.1 + npm --version - name: Install dependencies run: npm ci - name: Install ReleaseBox diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 43e8fa2..0b8c318 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,6 +25,10 @@ jobs: node-version: 22 cache: npm registry-url: https://registry.npmjs.org + - name: Prepare trusted publishing npm + run: | + npm install --global npm@11.5.1 + npm --version - name: Install dependencies run: npm ci - name: Install ReleaseBox From 01dd22f196ee5052741d16727e360d988455e264 Mon Sep 17 00:00:00 2001 From: Roger Chappel Date: Wed, 2 Sep 2026 19:10:12 +1000 Subject: [PATCH 3/3] docs: record trusted publishing npm requirement --- CHANGELOG.md | 2 ++ docs/release-readiness.md | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60764fa..f7ce193 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ format and uses semantic versioning when versioned releases are published. ## [Unreleased] +- Pinned npm 11.5.1 preparation in release and dry-run workflows, with regression checks and release-readiness guidance for trusted publishing. + ### Fixed - Join shell continuations and recognize leading environment assignments when diff --git a/docs/release-readiness.md b/docs/release-readiness.md index b47cbba..a05d0d9 100644 --- a/docs/release-readiness.md +++ b/docs/release-readiness.md @@ -19,9 +19,9 @@ Run `npm run package:smoke` when available and review the dry-run file list for ## Automated publication -The release workflow uses npm trusted publishing (GitHub Actions OIDC) and requires the npm package to trust this repository's `release.yml` workflow. A version tag packs the package once, publishes that exact tarball to npm with public access and provenance, and attaches the same file to the GitHub release. +The release workflow uses npm trusted publishing (GitHub Actions OIDC) and requires the npm package to trust this repository's `release.yml` workflow. Both release workflows install and print npm `11.5.1` before installing dependencies; trusted publishing requires npm `11.5.1` or later. A version tag packs the package once, publishes that exact tarball to npm with public access and provenance, and attaches the same file to the GitHub release. -The release dry-run workflow exercises the same artifact handoff on relevant pull requests: it packs once and runs `npm publish --dry-run --access public`. `npm run release:workflow-check` guards both workflows against repacking or failing to reuse the artifact. +The release dry-run workflow exercises the same npm preparation and artifact handoff on relevant pull requests: it packs once and runs `npm publish --dry-run --access public`. `npm run release:workflow-check` guards both workflows against omitting or downgrading the pinned trusted-publishing npm version, repacking, or failing to reuse the artifact. ## Notes