Skip to content

ci: publish through GitHub Actions trusted publishing - #1

Merged
julia-script merged 2 commits into
mainfrom
automate-trusted-publishing
Jul 26, 2026
Merged

ci: publish through GitHub Actions trusted publishing#1
julia-script merged 2 commits into
mainfrom
automate-trusted-publishing

Conversation

@julia-script

Copy link
Copy Markdown
Owner

Releases now happen by merging the Changesets version pull request. One workflow maintains that PR and publishes once no changesets remain; nothing else publishes.

What changed

  • release-pr.yml renamed to publish.yml and given the publish input plus id-token: write. The old manual-dispatch publish.yml is retired.
  • pnpm check and pnpm release:candidate now gate the release path, not just PRs.
  • Two guards against the Skipped OIDC fallback (see below).
  • Stale root RELEASING.md deleted; docs/RELEASING.md rewritten.

Why the filename is publish.yml

All four packages' npm trusted publishers already name publish.yml, and npm matches that against the OIDC token's job_workflow_ref claim. Renaming the file breaks releases silently, so the workflow header and the docs both say not to.

Why two guards

pnpm publish performs the npm OIDC exchange itself, but when it fails it only warns — Skipped OIDC — and publishes with whatever credential is reachable. A green run is therefore not evidence of a trusted release:

  • During publish: release:publish:ci wraps the publish, fails on the warning, and forwards stdout byte-for-byte (changesets/action parses it for published/publishedPackages).
  • After publish: verify-release-trust.mjs reads the registry packument and requires _npmUser.trustedPublisher + dist.attestations.provenance, one coordinated version, and no surviving workspace: ranges.

The verifier reads the packument directly rather than via npm view, which renders _npmUser as a display string and drops the nested trustedPublisher object.

Notes

  • No package source, public API, or consumer-visible behavior changes — hence no changeset.
  • Merging this does not release. The two pending changesets do, via the version PR.
  • 0.1.x carries no trust evidence, so the first automated release is a strict trust upgrade and cannot trip pnpm's install-side downgrade check.

Spec: openspec/changes/automate-trusted-publishing/

Releases now happen by merging the Changesets version pull request. One
workflow maintains that pull request and publishes once no changesets
remain; nothing else publishes.

Authentication uses a short-lived GitHub Actions OIDC credential. pnpm
performs the npm token exchange itself, and `changeset publish` resolves
the publishing tool from `packageManager`, so it is already on that path.
pnpm is also the only option that rewrites the `workspace:` ranges in
layout and three into registry-safe semver, so it stays the publish tool.

pnpm degrades a failed exchange to a `Skipped OIDC` warning and publishes
anyway, so a green run is not evidence of a trusted release. Two guards
cover that: a wrapper fails the release when the warning appears on the
publish output, and a post-publish check reads the registry packument and
requires trusted-publisher plus provenance evidence on every version. The
check reads the packument directly because `npm view` renders `_npmUser`
as a display string and drops the nested `trustedPublisher` object.

The workflow keeps the filename publish.yml because all four packages'
trusted publishers already name it, and npm matches that against the
token's job_workflow_ref claim. Renaming it now breaks releases silently,
so the file and the docs both say not to.

Also delete the stale root RELEASING.md, which still described the
pre-launch gates and the manual sequence that docs/RELEASING.md replaced.

No package source, public API, or consumer-visible behavior changes.
@cursor

cursor Bot commented Jul 26, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Group 1 confirmed against npm: all four packages already had a trusted
publisher naming publish.yml, which is why the workflow was renamed to
match rather than editing four npm forms. Group 4 rewritten — the OIDC
exchange cannot be rehearsed locally, since getIdToken() returns
undefined without GITHUB_ACTIONS, so the tasks now cover what can
actually be checked before the first publish.
@julia-script
julia-script merged commit 0e7b5a9 into main Jul 26, 2026
1 check 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