@@ -361,10 +361,34 @@ jobs:
361361 working-directory : packages/fula_client
362362 run : flutter pub publish --force
363363
364- # Publish to npm
364+ # Publish to npm via Trusted Publishing (OIDC, no long-lived token).
365+ #
366+ # Configured against npm's trusted-publisher entry on the
367+ # @functionland/fula-client package (npmjs.com → package settings →
368+ # Publishing → Trusted Publishers). The matching parameters are:
369+ # * Organization or username: functionland
370+ # * Repository: fula-api
371+ # * Workflow filename: flutter-release.yml
372+ # * Environment name: NPM_TOKEN (must equal `environment:` below)
373+ #
374+ # The `id-token: write` permission lets this job mint a GitHub-issued
375+ # OIDC token; npm validates it against the trusted-publisher rule and
376+ # issues a one-shot publish credential. There is no NPM_TOKEN secret
377+ # to rotate; the May 2026 "Mini Shai-Hulud" rotation that broke the
378+ # previous run cannot affect this path.
365379 publish-npm :
366380 needs : [build-wasm]
367381 runs-on : ubuntu-latest
382+ # MUST match the Environment name configured in the npm trusted-
383+ # publisher entry. The npm side stores it as a string compare; any
384+ # drift here re-introduces the 404-from-PUT we just fixed. Also
385+ # requires a GitHub Environment named `NPM_TOKEN` to exist under
386+ # repo Settings → Environments (create it without protection rules
387+ # — the OIDC binding is the security control).
388+ environment : NPM_TOKEN
389+ permissions :
390+ id-token : write # mint OIDC token for npm trusted publishing
391+ contents : read # default; explicit for clarity
368392 steps :
369393 - name : Download WASM package
370394 uses : actions/download-artifact@v4
@@ -375,20 +399,36 @@ jobs:
375399 - name : Setup Node.js
376400 uses : actions/setup-node@v4
377401 with :
378- node-version : ' 20'
402+ # Node 22 LTS ships npm 10.9+; OIDC trusted publishing
403+ # requires npm ≥ 11.5, so we explicitly install latest npm
404+ # below regardless of the Node version's bundled npm.
405+ node-version : ' 22'
379406 registry-url : ' https://registry.npmjs.org'
407+ always-auth : true
408+
409+ - name : Install latest npm (OIDC support — needs >= 11.5)
410+ run : npm install --global npm@latest
411+
412+ - name : Verify npm + OIDC readiness
413+ run : |
414+ echo "npm version: $(npm --version)"
415+ echo "node version: $(node --version)"
416+ # Trusted publishing needs npm ≥ 11.5. Fail fast if older.
417+ npm --version | awk -F. '$1*1000 + $2 < 11005 { exit 1 }'
380418
381419 - name : Verify package contents
382420 run : |
383421 echo "WASM package contents:"
384422 ls -la wasm-package/
385423 cat wasm-package/package.json
386424
387- - name : Publish to npm
425+ - name : Publish to npm (OIDC, no token)
388426 working-directory : wasm-package
389- run : npm publish --access public
390- env :
391- NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
427+ # npm publish detects OIDC automatically when the action env
428+ # exposes ACTIONS_ID_TOKEN_REQUEST_URL + ACTIONS_ID_TOKEN_REQUEST_TOKEN,
429+ # which the `id-token: write` permission above provides. No
430+ # NODE_AUTH_TOKEN env var, no secrets.NPM_TOKEN reference.
431+ run : npm publish --access public --provenance
392432
393433 # Upload artifacts to GitHub Release (created automatically from tag)
394434 upload-release-assets :
0 commit comments