ci: OIDC cannot do the first publish — keep a token for it (#6) #1
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 }} |