Repository navigation
ci: publish to npm with trusted publishing and automate the release - #931
Merged
Merged
Conversation
The release process documented in MAINTAINING.md stopped working when branch protection was added: `lerna version` commits to `main`, and `main` now requires a pull request and a review with admin enforcement on. Publishing was broken separately, because `yarn publish` prompts for a 2FA code and CI has no terminal, and because the npm token expired unnoticed after 90 days. Replace both halves. Versioning moves to release-please. It reads the conventional commits already enforced by commitlint and keeps a release pull request open with the version bump and changelog. That pull request is merged like any other, so branch protection is satisfied normally and nothing needs to bypass it. Publishing moves to npm trusted publishing. The runner mints a short-lived OIDC credential scoped to this workflow, so there is no npm token to store, rotate or leak, and no 2FA prompt to answer. npm records provenance automatically because the repository and the package are both public. `release-pr.yml` keeps publishing experimental versions from a labelled pull request, but on the same OIDC path, with `yarn publish` replaced by `npm publish` and the NPM_TOKEN reference removed. `googleapis/release-please-action` is pinned to a full commit SHA. Lerna stays for running workspace scripts. Its publish configuration is removed because it no longer publishes. This change is inert until the trusted publisher entries are configured on npmjs.com, and the NPM_TOKEN secret should only be deleted once a release has succeeded on the new path.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
2 Skipped Deployments
|
Review found that the release job could not have opened its pull request. This repository does not allow GitHub Actions to create pull requests, so the default GITHUB_TOKEN that release-please falls back to is refused and no release pull request would ever appear. The repository setting that would allow it is a single switch covering both creating and approving pull requests. Turning it on would let any workflow approve, which would weaken the review requirement on `main`, so this mints an app installation token scoped to this repository instead. It also means CI runs on the release pull request without someone first releasing the held runs a GITHUB_TOKEN-authored pull request produces. Two smaller fixes from the same review: Drop `npm install -g npm@latest` from both publish jobs. It fetched an unpinned executable into a job holding `id-token: write`, next to an action pinned to a full SHA for that exact reason. Every current Node 24 release ships npm 11.19.0, past the 11.5.1 trusted publishing needs, so the requirement is now asserted and fails the job loudly if a future runner image regresses. Document how to cut a prerelease. Removing the Lerna steps took away the only documented way to produce one, while later sections still branch on prereleases and a `canary` branch. Requires two new repository secrets, RELEASE_APP_ID and RELEASE_APP_PRIVATE_KEY, before the release workflow can run.
The comment said a GITHUB_TOKEN-authored pull request would not trigger CI at all. It does trigger it, but the runs are held in an approval-required state until someone releases them. The reason for the app token is unchanged; only the description of the side benefit was overstated.
…on the app Review raised that everything needed to stand this up lived only in a pull request body, which is how the previous process went stale without anyone noticing. Add a "First-time setup" section covering the two npm trusted publisher entries, the app and its permissions, and the two repository secrets. That section also corrects a real gap: the app needs Issues read and write, not just Contents and Pull requests. release-please applies its `autorelease` labels through the issues API, so without it a release tags and then fails partway. Two smaller fixes from the same review. The "Publishing credentials" section described the npm account settings as a statement of current fact rather than as setup, so a maintainer could read it and skip configuring them. And the Drupal module section still told the reader packages are released with Lerna, which the section below it contradicts. Drop the permissions block from the release-please job. Both of its steps authenticate with the app token, so the block only widened a GITHUB_TOKEN that is never used, in a job whose purpose is to avoid widening anything.
robdecker
force-pushed
the
chore/oidc-release-automation
branch
from
September 22, 2026 19:09
be30eaa to
925d312
Compare
thejimbirch
approved these changes
Sep 22, 2026
This branch was successfully deployed
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request is for: (mark with an "x")
examples/*modules/nextpackages/next-drupalstarters/basic-starterstarters/graphql-starterstarters/pages-starterGitHub Issue: n/a
Describe your changes
Automates releases and moves publishing off a stored npm token.
Why
The release process in MAINTAINING.md no longer works. Three things broke, and because nothing had been released in a while, none of them surfaced until someone tried:
lerna versioncommits straight tomain, which now requires a pull request and a review, so the documentedgit pushis rejected.yarn publishprompts for a two-factor code when the account has 2FA enabled. CI has no terminal, so it fails withCan't answer a question unless a user TTY.This is also the direction npm is moving. Per GitHub's npm supply chain roadmap: classic tokens are being deprecated, granular tokens with publish rights are being cut to a 7-day lifetime, and the option to bypass 2FA for local publishing is being removed. Both halves of the old process are going away, so this is not worth fixing in place.
Versioning: release-please
release-please reads the conventional commits already enforced by commitlint and keeps a release pull request open with the version bump and changelog. Merging it tags the release and triggers publishing.
The point is that the release commit arrives as a normal pull request, so branch protection is satisfied the ordinary way. Nothing needs to bypass or relax a protection rule.
Tag format is configured to keep continuity with the existing Lerna tags (
next-drupal@2.1.0, notnext-drupal-v2.1.0), and the manifest starts at the currently published 2.0.1. Prereleases, which the removed Lerna steps used to handle, are now documented via aRelease-As:footer.Lerna stays for running workspace scripts. Only its publish configuration is removed, since it no longer publishes.
Publishing: npm trusted publishing
release.ymlpublishes with an OIDC credential minted per workflow run and scoped to this repository and workflow filename. Nothing is stored, and it cannot be replayed elsewhere. Provenance attestations are generated automatically because the repository and package are both public.release-pr.ymlkeeps publishing experimental versions from a labelled pull request, on the same OIDC path:yarn publishreplaced withnpm publish, the token reference removed, Node moved to 24. Its same-repo guard is unchanged, so forks still cannot publish.Both publish jobs assert npm is at least 11.5.1 rather than installing a newer npm, so nothing unpinned is fetched into a job holding
id-token: write. Every current Node 24 release already ships npm 11.19.0.The one credential this adds, and why
This does not leave the repository credential-free. It trades a long-lived npm token for a long-lived GitHub App private key, stored as
RELEASE_APP_PRIVATE_KEY. That is worth reviewing rather than glossing over.release-please cannot open its pull request with the default
GITHUB_TOKEN, because this repository does not allow GitHub Actions to create pull requests. There are two ways to fix that:main.This takes the second, on the grounds that a review requirement which automation can satisfy is not much of a requirement. The App private key is the one long-lived secret in the release path, it can be rotated without a publishing outage, and it is owned by the organization rather than an individual.
Note that release-please's own README recommends a personal access token here, not an App token. A PAT would work, but it belongs to a person and carries broader scope. GitHub's own Triggering a workflow docs name both an App installation token and a PAT as the options, so this is a deliberate choice between two supported paths rather than a workaround.
The App is created under the
chapter-threeorganization rather than a personal account, so it does not depend on one person's account remaining active.Both third-party actions are pinned to full commit SHAs.
This change is inert until it is configured
Merging this enables nothing by itself. Three things must exist first, and they are deliberately not in the diff:
chapter-threeorg, installed on this repository, with its ID and private key set as repository secrets.release.ymlwith no environment.release-pr.ymlwith environmentPreview.All of it is written up under "First-time setup" in MAINTAINING.md rather than left in this description, so it survives the merge.
One detail there is easy to get wrong and worth calling out: the App needs Issues read and write as well as Contents and Pull requests. release-please applies its
autoreleaselabels through the issues API, so without it a release tags and then fails partway.Not verified by CI
The publish path cannot be exercised before merge, because OIDC only works once npm trusts a workflow on the default branch. First real proof will be the 2.1.0 release. Specifically unverified: whether npm accepts an OIDC credential from a
pull_requestevent when the job declaresenvironment: Preview, and whether release-please picks upe56c636as the 2.1.0 trigger.The workflows parse, permissions are scoped per job, both action SHAs match the tags named beside them, and the npm version comparison was checked against both a passing and a failing version. That is the limit of what has been checked here.
References
Publishing:
Why the App token is needed:
GITHUB_TOKENevents generally do not start new workflow runs, and a pull request it authors produces runs held in an approval-required state; names App installation tokens and PATs as the alternativesTooling:
release-please and its action
Lerna: OIDC trusted publishing — background on why Lerna 8 could not do this
Was AI used in this pull request?