Skip to content

ci: OIDC cannot do the first publish — keep a token for it (#6) #1

ci: OIDC cannot do the first publish — keep a token for it (#6)

ci: OIDC cannot do the first publish — keep a token for it (#6) #1

Workflow file for this run

name: Publish
# Publishing is driven by a version tag, so the released artifact is always
# traceable to a commit. `npm version` creates the tag; pushing it ships.
on:
push:
tags: ['v*']
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
# Required for npm provenance — proves on the registry that this tarball
# was built by this workflow from this commit.
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
# npm >= 11.5.1 is required for trusted publishing (OIDC); Node 24 ships it.
node-version: '24'
registry-url: 'https://registry.npmjs.org'
- run: npm ci --ignore-scripts
# Never publish something that would not have passed CI.
- run: npm run verify
# Refuse to publish a tag whose version does not match package.json,
# rather than silently shipping the wrong number.
- name: Check tag matches package version
run: |
tag="${GITHUB_REF_NAME#v}"
pkg=$(node -p "require('./package.json').version")
if [ "$tag" != "$pkg" ]; then
echo "Tag v$tag does not match package.json version $pkg" >&2
exit 1
fi
# OIDC (id-token above) is the preferred credential and needs no secret.
# But trusted publishing is configured per package on npmjs.com, and a
# package that has never been published cannot have it configured — so
# OIDC alone cannot do the FIRST publish. Confirmed on ai-forms: the
# provenance statement was signed and logged to sigstore, then the PUT
# returned E404 "could not be found or you do not have permission",
# which reads like a missing package rather than a missing credential.
#
# NPM_TOKEN covers only that first publish. Once this package exists and
# a trusted publisher is configured, npm prefers OIDC and the secret can
# be deleted.
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}