From 067b00e6c39c068251caf53b5fc1e55e836ea090 Mon Sep 17 00:00:00 2001 From: Ralf Anton Beier Date: Sat, 30 May 2026 06:44:10 +0200 Subject: [PATCH] ci(release-npm): preflight npm-auth check (loud-fail on bad/expired token) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The npm channel silently froze at 0.10.1 for ~6 releases because NPM_TOKEN expired, then was replaced with a classic *Publish* token that fails under the org's 2FA-on-publish with EOTP — and the only signal was a per-package `npm publish` E404/EOTP crash deep in the job. Add a `npm whoami` preflight right after setup-node in both publish jobs. A bad/expired/wrong-type token now fails immediately with a labeled ::error:: telling the maintainer exactly what to do (Automation or granular read-write token), instead of a cryptic per-platform publish failure. F2 loud-fail-over-silent-success ethos — the same principle rivet's own validators enforce. Refs: REQ-068 --- .github/workflows/release-npm.yml | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/.github/workflows/release-npm.yml b/.github/workflows/release-npm.yml index 060aecf5..259b981c 100644 --- a/.github/workflows/release-npm.yml +++ b/.github/workflows/release-npm.yml @@ -76,6 +76,23 @@ jobs: node-version: "20" registry-url: "https://registry.npmjs.org" + # Preflight: fail loud + early if NPM_TOKEN can't authenticate, instead + # of letting each per-package `npm publish` crash with a cryptic E404 + # (expired/no-access) or EOTP (a classic *Publish* token, which the + # org's 2FA-on-publish rejects in CI). npm publish needs a classic + # *Automation* token or a granular token with read-write on + # @pulseengine/*. This turns a silently-frozen npm channel (it sat at + # 0.10.1 for ~6 releases) into an immediate, labeled failure. + - name: Preflight — verify npm auth + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + if ! who=$(npm whoami 2>/dev/null); then + echo "::error title=npm auth failed::NPM_TOKEN is invalid, expired, or the wrong type. npm publish needs a classic *Automation* token (or a granular token with read-write on @pulseengine/*); a classic *Publish* token fails under 2FA with EOTP. Regenerate at npmjs.com -> Access Tokens and update the NPM_TOKEN secret." + exit 1 + fi + echo "npm auth OK as: $who" + - name: Resolve version id: version env: @@ -153,6 +170,23 @@ jobs: node-version: "20" registry-url: "https://registry.npmjs.org" + # Preflight: fail loud + early if NPM_TOKEN can't authenticate, instead + # of letting each per-package `npm publish` crash with a cryptic E404 + # (expired/no-access) or EOTP (a classic *Publish* token, which the + # org's 2FA-on-publish rejects in CI). npm publish needs a classic + # *Automation* token or a granular token with read-write on + # @pulseengine/*. This turns a silently-frozen npm channel (it sat at + # 0.10.1 for ~6 releases) into an immediate, labeled failure. + - name: Preflight — verify npm auth + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + if ! who=$(npm whoami 2>/dev/null); then + echo "::error title=npm auth failed::NPM_TOKEN is invalid, expired, or the wrong type. npm publish needs a classic *Automation* token (or a granular token with read-write on @pulseengine/*); a classic *Publish* token fails under 2FA with EOTP. Regenerate at npmjs.com -> Access Tokens and update the NPM_TOKEN secret." + exit 1 + fi + echo "npm auth OK as: $who" + - name: Resolve version id: version env: