Publish on a v* tag alone, and stop the changelog drifting from the version - #147
Conversation
Every release was blocked by a gate nobody configured. The publish job declared `environment: npm-publish`, and since 3.3.3 the ungated `validate` job refused to release unless that environment carried a required reviewer. It never got one, so `v3.4.4` was tagged on 2026-09-04 and the run failed ten seconds in. npm has been on 2.0.0 while main sat at 3.4.4. Drop the gate rather than configure it, matching how e-stack publishes: a `v*` tag whose commit is reachable from main runs start to finish with nothing to approve. What authorizes a release is who can create the tag. The hardening that was not in the way stays: no write access, SHA-pinned actions, split ungated validate job, `cancel-in-progress: false`, test suite and `npm pack --dry-run` before publish. `environment: npm-publish` stays on the job because npm's trusted publisher names that environment and the OIDC claim has to match it; the workflow comment and RELEASING.md both now say that is all it does. Add scripts/check-release.mjs and `npm run release:check`. CONTRIBUTING.md and CHANGELOG.md both say the tag, package.json, and the newest changelog entry are the same number, and nothing enforced it. The workflow compared the tag against package.json only, so a PR that bumped the version but skipped its changelog entry shipped green. The script also catches an entry copied from the one below it and never renumbered, an out-of-order entry, and a duplicated version. It has no dependencies, so validate rejects a bad tag before `npm ci` costs anything. Closes #50. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6ba0b9b453
ℹ️ 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".
| # This is NOT an approval gate and is not relied on as one. It is here | ||
| # because npm's trusted publisher for this package names `npm-publish` as its | ||
| # environment, so the OIDC identity this job presents has to carry that claim | ||
| # or the publish is rejected. The environment has no protection rules; what |
There was a problem hiding this comment.
Upgrade npm before unblocking trusted publishing
On the first v* tag now allowed past validate, the publish job will still fail authentication: the current Node 24 distribution resolves to Node 24.15.0 with npm 11.4.2, while npm's Trusted Publishers requirements specify “npm CLI version 11.5.1 or later” (npm documentation). actions/setup-node does not upgrade the bundled npm, and this workflow proceeds directly through npm ci to npm publish, so the CLI cannot perform the OIDC exchange and the release remains blocked; install or pin a supported npm version in the publish job.
Useful? React with 👍 / 👎.
Closes #50.
Why
mainhas been at 3.4.4 since 2026-09-03. npm has been on 2.0.0 since July. The release path has been broken the whole time, and it was broken on purpose by a guard I added.Since 3.3.3 the ungated
validatejob refused to release unless thenpm-publishGitHub environment had a required reviewer configured. That was written as a fail-closed check so a missing approval gate could not silently publish. The environment never got a reviewer, so the check did exactly its job:v3.4.4was tagged on 2026-09-04 and the run failed ten seconds in.#50 asked @karthikcsq to tick the required-reviewer box. He'd rather not have the gate at all, which is a fair call, so this PR takes the other branch: drop the approval step and make a
v*tag onmainsufficient on its own.What a release looks like now
Same shape as e-stack, where a tag push is the whole release:
npm run release:check # tag, package.json, and CHANGELOG must agree git tag vX.Y.Z git push origin vX.Y.ZCI takes it from there. Nothing to approve, no environment to configure, no npm token anywhere.
What still stands between a tag and npm
Dropping the approval does not drop the hardening. Everything below is unchanged:
contents: readand no write access; it cannot push anything back.id-token: writeis scoped to thepublishjob alone, so the ungatedvalidatejob cannot mint the OIDC token npm accepts.persist-credentials: false.main. Av*tag pushed from a local or unmerged branch fails validation. A release can only contain code that already went through review.cancel-in-progress: false, so a second tag queues behind a running publish instead of cancelling it mid-npm publish.npm pack --dry-runrun before publishing.What authorizes a release is now who can create a
v*tag.RELEASING.mdpoints at the tag ruleset that makes that a real restriction if you want it; the workflow does not depend on it existing.About
environment: npm-publishIt stays on the
publishjob. Not as a gate: npm's trusted publisher for this package namesnpm-publishas its environment, so the OIDC claim the job presents has to carry it or the publish is rejected. Removing the line would mean editing the npm side too. Both the workflow comment andRELEASING.mdnow say plainly that it is doing nothing but satisfying that claim. Adding a required reviewer to the environment later turns a real approval step back on with no code change.New:
scripts/check-release.mjsCONTRIBUTING.mdandCHANGELOG.mdboth state the same rule — the version at the top of the changelog, the version inpackage.json, and the tag are always the same number. Nothing enforced it. The workflow compared the tag againstpackage.jsononly, so a PR that bumped the version but forgot its changelog entry produced a green release with a changelog that never mentioned what shipped.The script checks all three, plus three failure modes that are invisible once a release is out:
Dependency-free on purpose, so
validateruns it beforenpm cicosts anything, andnpm run release:checkworks locally without a network round trip.Docs
RELEASING.mdnow leads with the three commands a release takes, drops the required-reviewer setup step, states the security argument that actually applies, records why the gate was removed rather than configured, and documents re-running a release whose tag already exists (delete and re-push the tag — a secondgit pushof an existing tag does not re-trigger anything).docs/architecture.mdno longer describes publishing as gated on an environment.Verification
tests/releaseConsistency.test.jsadds 10 cases overcheck-release.mjs, including one that asserts this branch's ownpackage.jsonandCHANGELOG.mdagree.tests/fixtures/mcp-migration-inventory.jsonis regenerated for the new test file (3 lines).After merging
v3.4.4already exists remotely and points at a commit that predates this fix, so it will not retrigger. Tagv3.4.5on the merge commit and 3.4.5 ships — the first release since 2.0.0.🤖 Generated with Claude Code