Repository navigation
MILAB-7081: trusted publishing for node-matrix, node-matrix-pnpm, node-docker-simple-fast-pnpm, node-simple, java-gradle - #219
Conversation
npm no longer accepts 2FA-bypass tokens for direct publish. These workflows already publish from GitHub-hosted runners with id-token: write, so they need no split: - node-matrix-pnpm, node-docker-simple-fast-pnpm: pnpm -r publish via changesets/action is replaced by pack-unpublished + publish-tarballs in the same job. node-docker-simple-fast-pnpm keeps changesets/action for the version PR and publishes only when no changesets are pending. - node-matrix, node-simple, java-gradle (blocks/node/build-and-publish): new actions/node/prepare-trusted-publishing before `npm publish`: npm 11.5.1+ and, in public repositories, a package.json `repository` naming the repository (npm auto-enables provenance; the registry rejects it otherwise). The token stays as the fallback npm uses if OIDC fails. - npm-trust-setup.sh: npm prompts for 2FA only on a terminal; on EOTP the list call is re-run on /dev/tty so the browser approval appears.
| core.info('Private repository: npm adds no provenance, package.json left as is.'); | ||
| return; | ||
| } | ||
| const result = ensureRepository(pkgDir, root, sourceRepository); |
There was a problem hiding this comment.
GitHub Packages releases can fail
prepare applies npmjs repository checks to every public GitHub repository, including uploads to GitHub Packages—the default registry in all three callers. If a package's repository points to an upstream or separate repository, ensureRepository now stops the release even though npmjs provenance rules do not apply.
Resolve the package's target registry first and call ensureRepository only for npmjs uploads, as packWorkspace already does.
Prompt To Fix With AI
This is a comment left during a code review.
Path: actions/node/npm-split-publish/src/bin/prepare.ts
Line: 22
Comment:
**GitHub Packages releases can fail**
`prepare` applies npmjs repository checks to every public GitHub repository, including uploads to GitHub Packages—the default registry in all three callers. If a package's `repository` points to an upstream or separate repository, `ensureRepository` now stops the release even though npmjs provenance rules do not apply.
Resolve the package's target registry first and call `ensureRepository` only for npmjs uploads, as `packWorkspace` already does.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| if [ "${rc}" -ne 0 ] && grep -q 'EOTP' "${err}" && authenticate "${pkg}"; then | ||
| # Approved in the browser; the 2FA skip window covers the retry. | ||
| rc=0 | ||
| out="$(npm trust list "${pkg}" --json 2>"${err}")" || rc=$? |
There was a problem hiding this comment.
The new interactive approval and successful retry have no test coverage. The existing EOTP test expects failure, and the npm stub always fails for that package. The suite therefore cannot catch a broken approval-and-retry path.
Add a terminal-backed test or an injectable authentication helper covering EOTP, successful approval, and a successful JSON retry. Assert that approval output stays out of the captured JSON and that the batch continues.
Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/npm-trust-setup.sh
Line: 88-91
Comment:
**Approval retry lacks tests**
The new interactive approval and successful retry have no test coverage. The existing `EOTP` test expects failure, and the npm stub always fails for that package. The suite therefore cannot catch a broken approval-and-retry path.
Add a terminal-backed test or an injectable authentication helper covering `EOTP`, successful approval, and a successful JSON retry. Assert that approval output stays out of the captured JSON and that the batch continues.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
- pack refuses packages registry.npmjs.org does not have yet, before any script runs: without a token their first version needs a manual publish (npm only accepts a trusted publisher for an existing package). Avoids a partial release that keeps failing at upload. - prepare-trusted-publishing: switch to Node 24 when the job's Node is older than 22.14 (npm documents 22.14+ for trusted publishing); leave package.json alone for registries other than npmjs (publishConfig.registry wins), via a tested prepareRepository. - README: manifest.jsonl documented as a public contract (pframes-rs writes it); new-package rule.
Follow-up to #217: trusted publishing (OIDC) for the shared node workflows that #217 did not cover. npm no longer accepts our 2FA-bypass token for direct publish (
EOTPsince ~2026-10-16), so these callers currently cannot publish: runenv-r* (9 repos,node-matrix), runenv-python-3 and software-conda (node-matrix-pnpm), java-debug and makeblastdb (node-docker-simple-fast-pnpm), the MiXCR/MiTool/RepSeq.IO software packages (java-gradle), and the asset boilerplate (node-simple).All of these already publish from GitHub-hosted runners with
id-token: write, so no split job is needed.Changes
node-matrix-pnpm,node-docker-simple-fast-pnpm:changesets/action+pnpm -r publishis replaced byactions/node/pack-unpublished+actions/node/publish-tarballsin the same job (the path proven in MILAB-7081: npm trusted publishing (OIDC) for node-simple-pnpm #217).node-docker-simple-fast-pnpmkeepschangesets/actionfor the "chore: update versions" PR and packs/uploads only when itshasChangesetsoutput isfalse.node-matrix,node-simple,blocks/node/build-and-publish(used byjava-gradle): they keepnpm publish; a newactions/node/prepare-trusted-publishingstep runs before it:package.jsonrepositorynaming the repository and fails on one naming another: npm auto-enables provenance there and the registry rejects it (E422) otherwise, the same failure MILAB-7081: npm trusted publishing (OIDC) for node-simple-pnpm #217 reproduced and fixed for the split path. Other registries (GitHub Packages) are left alone;publishConfig.registrywins over the job'sregistry-url.The token stays configured; npm tries OIDC first and uses it only if the exchange fails.
npm-split-publish: third entrylib/prepare(src/bin/prepare.ts), public-repository detection moved tosrc/github.ts,prepareRepository/ensureRepositoryinsrc/repository.ts, tests intest/prepare.test.ts.pack-unpublished(all split-publish callers, incl. node-simple-pnpm): refuses a package registry.npmjs.org does not have yet, before any script runs. Without a token its first version needs a manual publish (npm accepts a trusted publisher only for an existing package); before, the upload failed midway and left a partial release.manifest.jsonldocumented as a public contract (pframes-rs writes it by hand).scripts/npm-trust-setup.sh: npm prompts for 2FA only when stdin and stdout are a terminal (npmlib/utils/auth.js), so the capturednpm trust list --jsonfailed withEOTPand the script stopped. OnEOTPthe call is now re-run on/dev/tty, which shows the browser approval; ticking "skip 2FA for 5 minutes" lets the rest of the batch through.Verified
lib/rebuilt from source.v4-beta).@v4-beta, so the first real run is a caller release after merge. Each package also needs its trusted publisher (repository +build.yaml, "npm publish" allowed) within 2 days of that release.Merge order
v4-beta, then promotev4-beta→v4(merge-beta.sh).prepare-trusted-publishing, which only exists after this PR), then promote github-ci-internal.pack-unpublished/publish-tarballs@v4, already onv4).Callers of these workflows can no longer publish with the token anyway, so after promotion each package needs its trusted publisher, added within 2 days before that repo's next release.
MILAB-7081