Skip to content

chore(cd): publish through the npm CLI so provenance works - #535

Merged
ShaneK merged 1 commit into
mainfrom
fix/cd-provenance-release-main
Aug 19, 2026
Merged

chore(cd): publish through the npm CLI so provenance works#535
ShaneK merged 1 commit into
mainfrom
fix/cd-provenance-release-main

Conversation

@ShaneK

@ShaneK ShaneK commented Aug 19, 2026

Copy link
Copy Markdown
Member

Fixes the release pipeline so it can publish 13.0.0. Landing on main first; stable needs the same change before CD can run, tracked in #534.

What is the current behavior?

Currently the release workflow cannot publish. Run 32296237958 failed on the Ensure Latest npm step, and there are three more failures queued up behind it. None of this had run before, because #526 moved the workflow off tokens after the last release, so 12.3.0 was published by the older token-based workflow.

  1. npm install -g npm@latest resolves to npm 12.0.2, which requires node ^22.22.2 || ^24.15.0 || >=26.0.0. The workflow pins Node 20, so the install fails with EBADENGINE.
  2. lerna publish --provenance cannot work. Lerna 4's CLI is yargs .strict() and publish does not declare a provenance option, so it exits with Unknown argument: provenance.
  3. Lerna 4 uploads through libnpmpublish@4.0.2, which has no provenance support and no OIDC support. Since it never shells out to npm publish, upgrading the global npm does nothing for the upload, and trusted publishing is unreachable from lerna publish at this version.
  4. permissions: contents: read cannot push the release commit or tags, or create the GitHub release. Before chore(npm): Update release npm action to stop using tokens #526 there was no permissions block, so the default write access applied.

What is the new behavior?

The release is split in two. Versioning stays with lerna, so bumps, changelogs, tags, and the GitHub release all work exactly as before. The upload moves to the npm CLI, which is what actually supports provenance and OIDC trusted publishing.

  • version:ci runs lerna version, keeping the lerna.json config (allowBranch, conventionalCommits, createRelease, the [skip ci] message, tagVersionPrefix).
  • publish:ci runs scripts/publish-packages.sh, which publishes each package with npm publish --provenance.
  • npm is pinned to npm@11, the newest line that runs on Node 20 and still supports provenance and OIDC. This keeps CD on the same Node version as CI.
  • contents is now write.

The publish script skips any package whose version is already on the registry, because these version independently and a release may bump only one of them.

Does this introduce a breaking change?

  • Yes
  • No

No package code changes. This commit touches only .github/workflows/cd.yml, the root package.json, and a new script, so lerna attributes it to neither package and it does not affect the computed versions.

Other information

I verified locally that both packages still compute a major from the v9 squash on stable (0883d9b), which carries the BREAKING CHANGE: footer:

packages/schematics            commits=1  => MAJOR (12.3.0 -> 13.0.0)
packages/cordova-builders      commits=1  => MAJOR (12.3.0 -> 13.0.0)

lerna changed lists both packages, and npm run version:ci parses its flags and loads the lerna.json config cleanly, failing only on the missing GH_TOKEN that CI supplies. The publish script's skip logic was tested against both the already-published case and a simulated 13.0.0.

Note: I could not verify the OIDC handshake itself without running a real publish, so that part is unproven. It also depends on trusted publishing being configured on npmjs.com for both @ionic/angular-toolkit and @ionic/cordova-builders. If either is missing, the publish step will fail on auth, and the fix is to add the trusted publisher for that package rather than to change the workflow again.

This does not trigger CD, which only runs on stable.

The release workflow has never completed a publish since #526 moved it off tokens.
Four separate problems, none of which had run yet:

- `npm install -g npm@latest` now resolves to npm 12, which requires Node >=22.22.2
  while the workflow pins Node 20. Pinned to npm 11, the newest line that runs on
  Node 20 and still supports provenance and OIDC.
- `lerna publish --provenance` fails outright. Lerna 4's CLI is yargs `.strict()` and
  does not declare that option, so it exits with "Unknown argument: provenance".
- Lerna 4 uploads through `libnpmpublish@4`, which supports neither provenance nor
  OIDC trusted publishing, so no npm CLI upgrade can make `lerna publish` work. The
  release is now split: `lerna version` still handles bumps, changelogs, tags and the
  GitHub release, and `scripts/publish-packages.sh` does the upload with `npm publish
  --provenance`.
- `permissions: contents: read` cannot push the release commit or tags, or create the
  GitHub release. Before #526 there was no permissions block, so the default write
  access applied.

The publish script skips any package whose version is already on the registry, since
lerna versions these independently and a release may bump only one of them.
@ShaneK
ShaneK merged commit 7519cbc into main Aug 19, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant