diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a682669..81d328d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -20,16 +20,21 @@ # Renaming this file silently breaks publishing — npm will refuse the exchange # because the run no longer matches what was configured. # -# What that looks like when it goes wrong, since the error names neither OIDC -# nor trusted publishing: +# When it goes wrong the error names neither OIDC nor trusted publishing: # # npm error code E404 # npm error 404 Not Found - PUT https://registry.npmjs.org/moshcode # npm error 404 ... could not be found or you do not have permission # -# There is no credential at all in that case, and npm reports it as if the -# package did not exist. If you see it, the publisher is not registered, or is -# registered against a different workflow filename. +# That is an unauthenticated PUT, reported as though the package did not exist. +# It has two quite different causes, and it took v0.24.3 to tell them apart: +# +# 1. anything that leaves an empty auth token in an .npmrc, which stops npm +# attempting the exchange at all — see the setup-node note below; or +# 2. no trusted publisher registered for this package, or one registered +# against a different workflow filename. +# +# Check 1 first. It is in this file, and it is the one that looks like 2. name: publish on: @@ -56,16 +61,27 @@ jobs: # with ERR_PNPM_BAD_PM_VERSION. - uses: pnpm/action-setup@v4 + # Deliberately no `registry-url`. With it, setup-node always writes + # + # //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN} + # + # into an .npmrc — correct for token auth, and quietly fatal here. Under + # trusted publishing there is no NODE_AUTH_TOKEN, so that line resolves to + # an empty token, and npm stops before ever attempting the OIDC exchange: + # it believes it already has credentials. The registry then answers the + # unauthenticated PUT with E404, which names nothing to do with OIDC and + # is what sent us looking at the npmjs.com config instead of at this file. + # + # actions/setup-node#1551. Without registry-url no .npmrc is written and + # npm defaults to registry.npmjs.org anyway, which is where we publish. - uses: actions/setup-node@v4 with: - node-version: 22 + node-version: 24 cache: pnpm - registry-url: https://registry.npmjs.org - # Node 22 bundles npm 10, which predates trusted publishing and would fall - # back to looking for a token that no longer exists — an auth failure that - # reads as a credential problem rather than a version one. 11.5.1 is the - # floor; the check below says so plainly if that ever regresses. + # Node 24 bundles npm 11, but pin the floor anyway rather than depend on + # what a runner image happens to ship: below 11.5.1 there is no trusted + # publishing, and the failure would again look like a credential problem. - name: Install an npm that understands trusted publishing run: | npm install -g npm@latest @@ -122,11 +138,13 @@ jobs: echo "already=false" >> "$GITHUB_OUTPUT" fi - # No token, and no `--provenance` either: publishing through trusted - # publishing generates and attaches the attestation on its own. + # No token. `--provenance` is passed even though npm documents it as + # automatic under trusted publishing: reports differ on whether it really + # is, and asking for it explicitly costs nothing and cannot produce a + # weaker result. v0.24.2 published with an attestation using this flag. - name: Publish if: steps.published.outputs.already == 'false' - run: npm publish --access public + run: npm publish --access public --provenance - name: Confirm the registry has it if: steps.published.outputs.already == 'false'