Repository navigation
ci: publish releases from GitHub Actions via npm trusted publishing - #13
Conversation
Releases needed an interactive 2FA OTP at the keyboard, so publishing could not be automated. npm's trusted publishing (OIDC) removes both the OTP and any stored NPM_TOKEN: the workflow exchanges a short-lived GitHub OIDC token for publish rights, and provenance is attested automatically. Pushing a `v*` tag cut from main now runs `.github/workflows/release.yml`, which re-runs the CI gates (publishing can't be undone, so it doesn't trust that the tag points at a green commit) and then publishes both packages in the required order, with three small scripts: - check-release-versions.mjs — tag == package versions, core and wrapper in lockstep, and the wrapper's caret range actually covers the core version being published (a stale ^0.3.0 would strand `npm create opencanva@latest` on the old core). - publish-if-needed.mjs — skips a version already on the registry, so a run that failed halfway can be re-run via workflow_dispatch. - wait-for-registry.mjs — gates the wrapper publish on core being resolvable, or `npm create opencanva@latest` fails with ETARGET in that window. One-time setup outside this repo: npmjs.com needs a Trusted Publisher on BOTH @opencanva/core and create-opencanva, pointing at this repository and the workflow filename release.yml. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
npm documents provenance as automatic under trusted publishing, but it is reported often enough as not applied that stating it beats discovering the gap in a failed release. Both packages' `repository` fields already point at this repo, which is what provenance verifies against. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e4f7ce9cfc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| run: npm run check:sync | ||
|
|
||
| - name: Check the tag matches the package versions | ||
| run: node scripts/check-release-versions.mjs "${{ github.ref_type == 'tag' && github.ref_name || '' }}" |
There was a problem hiding this comment.
Require manual releases to target a version tag
When workflow_dispatch is launched with a branch selected, github.ref_type is not tag, so this expression passes an empty string and check-release-versions.mjs deliberately skips tag validation; checkout and both publish steps then operate on that branch's HEAD. The suggested half-finished-release path can therefore publish an untagged version—or the next version after main has advanced—instead of resuming the intended release. Require a tag ref or explicit version-tag input and validate it before publishing.
Useful? React with 👍 / 👎.
| - name: Check committed skills/template/lockfile are in sync | ||
| run: npm run check:sync |
There was a problem hiding this comment.
Run the template release gates before publishing
When a tag points at a commit whose init template is invalid, this sequence proceeds from the demo typecheck directly to check:sync and publishing, even though .github/workflows/ci.yml also runs the template TypeScript check and scripts/check-template-scaffold.mjs isolation check. Those checks catch template dependency and packed-scaffold failures that the core/demo checks cannot, so the workflow's stated defense against releasing an unverified tag still permits publishing a broken opencanva init; include both existing CI steps before the publish steps.
Useful? React with 👍 / 👎.
Why
Releasing required an interactive npm 2FA OTP, so publishing could not be automated. npm trusted publishing (OIDC, GA since July 2025) removes both the OTP and any stored
NPM_TOKEN— the workflow exchanges a short-lived GitHub OIDC token for publish rights, and provenance is attested automatically.What
Pushing a
v*tag cut frommainruns.github/workflows/release.yml, which:check:sync) — a publish can't be undone, so it doesn't assume the tag points at a green commit;create-opencanva's caret range covers the core version being published;@opencanva/core, waits for it to resolve on the registry, then publishescreate-opencanva.Three helper scripts, each covering a failure this repo has actually hit or is exposed to:
check-release-versions.mjs^0.3.0wrapper dep strandingnpm create opencanva@lateston the old corepublish-if-needed.mjsworkflow_dispatchcan re-run itwait-for-registry.mjsETARGETfor anyone scaffolding in that windowRequired one-time setup (outside this repo)
npmjs.com needs a Trusted Publisher on both packages —
@opencanva/coreandcreate-opencanva— each with: organization/userdaniellee-ux, repositoryopen-canva, workflow filenamerelease.yml, environment blank. All fields are case-sensitive and must match exactly.Requirements met by the workflow:
id-token: writepermission, Node 22, npm upgraded tolatest(trusted publishing needs npm ≥ 11.5.1; Node 22 ships npm 10.x).Verification
check-release-versions.mjsandwait-for-registry.mjswere run locally: the version guard passes onv0.4.0, fails with a clear message on a mismatched tag, and the registry wait correctly reports@opencanva/core@0.4.0as not yet published. The publish step itself is exercised by the first real tag.🤖 Generated with Claude Code