feat(release): adopt npm OIDC trusted publishing with provenance#1011
feat(release): adopt npm OIDC trusted publishing with provenance#1011kylemcd wants to merge 1 commit into
Conversation
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
03a5f27 to
f635535
Compare
f635535 to
5ac4ce1
Compare
5ac4ce1 to
d118806
Compare
cd9ae1f to
6a2f4c2
Compare
6a2f4c2 to
5ad53bd
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 5ad53bd. Configure here.
5ad53bd to
a36cbd3
Compare
Replace the long-lived NPM_TOKEN with short-lived OIDC trusted publishing and provenance. Split release.yml into version/build/publish/release jobs so id-token: write is isolated to a publish job that runs nothing but `yarn npm publish` (no install, no build, no dependency scripts) — the post-TanStack architecture. - Bump Yarn 4.9.1 -> 4.16.0 for scoped-package OIDC; keep main's enableScripts:false hardening, pin the publish registry to npm - Publish via Yarn native OIDC; provenance attestations on every package - Registry-diff publish gate + fail-loud pre-flight for unenrolled packages - Preserve git tags + GitHub Releases via changesets/action (release job) - Add repository metadata to all packages (required for provenance) - Add trusted-publisher enrollment script; document OIDC publishing and the new-package bootstrap in RELEASES.md KNO-13137
a36cbd3 to
f547f23
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1011 +/- ##
=======================================
Coverage 64.71% 64.71%
=======================================
Files 212 212
Lines 10275 10275
Branches 1406 1406
=======================================
Hits 6649 6649
Misses 3601 3601
Partials 25 25 |


Description
Replaces the long-lived
NPM_TOKENinrelease.ymlwith npm OIDC trusted publishing + provenance, and restructures the release pipeline so the short-lived OIDC token is isolated to a job that runs nothing butyarn npm publish. Implements KNO-13137.Why. Today one static
NPM_TOKENcan publish every@knocklabspackage from anywhere if it leaks. OIDC swaps it for a token minted per run that expires in minutes and only works from this repo'srelease.yml, and provenance cryptographically links each published tarball to the exact commit + workflow run. The job split is the post-TanStack architecture: that compromise worked because the release job held publish power while also runningyarn install/build, so malicious dependency code read the token from runner memory. Here, install/build run in a job with no publish power, and theid-tokenjob runs no untrusted code.Why now. The July 9 stable release (run) failed publishing
@knocklabs/eslint-config@0.0.6— npm rejected theNPM_TOKENPUT with a 404 (a masked permission rejection; the package exists) — and the topological publish aborted, stranding 6 packages (client@0.21.14,react@0.11.23, …) versioned onmainbut absent from npm. OIDC replaces the token whose per-package grants are failing, and the registry-diff gate below picks up the stranded versions automatically on the first post-merge release.How —
release.ymlis now four jobs:id-tokenversionbuildyarn build:packages, uploadsdist(runs dependency scripts)publishyarn npm publish→ OIDC + provenancereleasechangesets/actionAlso in this PR:
npmMinimalAgeGate: 0pinned in.yarnrc.ymlto preserve pre-bump behavior (install-script hardening already landed onmainin chore: harden Yarn install scripts in the JS SDK #1019);npmPublishRegistryset toregistry.npmjs.org.version/publishcommand argument parsing..github/scripts/list-unpublished-packages.mjs) sobuild/publish/releaseonly run when there are new versions, plus a fail-loud pre-flight that points a new (unenrolled) package at the bootstrap runbook instead of a cryptic npm auth error.repositorymetadata (incl.directory) added/fixed on all 9 packages — required for provenance.prepublishOnlyremoved from@knocklabs/client— Yarn Berry only runsprepack/postpack/prepublish, so it never executed under our publish flow; removing it keeps the install-lesspublishjob honest.scripts/configure-trusted-publishers.mjs(yarn release:configure-trust) to enroll trusted publishers, and the OIDC publishing + new-package bootstrap runbook folded intoRELEASES.md.TODO(changesets-action-v2)note inrelease.yml: changesets/action v2 + Changesets v3 (both prerelease) decompose into sub-actions that would replace the custom gate/artifact/tag glue here once stable — blocked today on v2/v3 stabilizing and Changesets publishing yarn repos through npm (which can't rewriteworkspace:ranges).Preserved (no functional regression): npm dist-tags (
latest/canary/rc),workspace:→ version substitution,--tolerate-republish, prerelease/canary→main promotion logic, git tags (incl. private example apps), and GitHub Releases with changelog notes.Validated locally:
build,type:check,lint,format:check, and the full test suite (940 tests) pass on Yarn 4.17.1;yarn --immutablepasses with the committed lockfile;yarn npm publishsubstitutesworkspace:ranges and engages--provenancewith no install. The OIDC handshake itself is exercised on the first real release (going direct tomain, no canary pre-flight).Todos
Out-of-repo rollout (npm org admin / GitHub settings), not code changes:
npm login→yarn release:configure-trustproduction-releaseenvironment in GitHub settingsproduction-release(deployment branch policy formain/canary/rc; optionally required reviewers) — it currently has none, so it only scopes the OIDC claimNPM_TOKENsecret (kept until then as a one-revert rollback)