Repository navigation
ci: release from release/<major> branches and stop re-pushing release tags - #1901
Merged
joshunrau merged 6 commits intoNov 10, 2026
Merged
Conversation
Node v24.22.1 fixes CVE-2026-105482, CVE-2026-105483, CVE-2026-106069 and CVE-2026-111497 (High) and four Medium and Low CVEs: TLS hostname checks, the Brotli decoder, dns names and keep-alive sockets. engines.node now accepts only the patched 24 and 26 lines. The images build from the floating node:lts-krypton tag, which already resolves to 24.22.1. https://nodejs.org/en/blog/vulnerability/october-2026-security-releases Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G73CpTPk1EjKYeBAKPacit
…e tags Every push to main re-pushed latest and the current version tag, so both pointed at whatever main was. The release decision is now a tested planRelease in .github/scripts/release.cjs, which reads the root version and the git tags and nothing else. A run releases only when v<version> is not a tag yet. Every push to main pushes edge and sha-<7>; a release pushes <version> and <major>, and a release from main also moves latest on GHCR and GitHub and publishes npm. A release/<major> branch releases on dispatch, only once a higher major is tagged, so it can never plan latest, and it skips npm: the npm trusted publisher and the release environment stay on main. One Release runs at a time across every ref, an untagged version older than a tag on its line is refused, and the GitHub tag goes on the commit the run built. CI also runs on pull requests to release branches. Refs DouglasNeuroInformatics#1870. Supersedes DouglasNeuroInformatics#1822, whose planRelease and tests this adapts. Co-Authored-By: Gabriel A. Devenyi <gdevenyi@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A new reference page says what a version promises, which versions receive which fixes for how long, which image tag to run, and how to install from and upgrade between release tags. It carries the end-of-support table that increment-version.ts keeps current. SECURITY.md links to it instead of promising fixes to the most recent version only, and points reporters at private vulnerability reporting. The deployment guide clones a release tag rather than main. Refs DouglasNeuroInformatics#1870. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RELEASE_CHANNEL defaults to 2 instead of latest, so a new deployment receives every release of its major, fixes included, and never crosses to a new major on its own. increment-version.ts rewrites it on a major bump. Refs DouglasNeuroInformatics#1870. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
increment-version.ts now takes the bump from a set the policy allows. Once a breaking commit is in range it offers and accepts major only. On a superseded major, one with a higher major tagged, it offers and accepts patch only, refuses a breaking or feat commit in range outright, and names the release/<major> branch as the base of the PR. It reads both version parsing and that superseded check from .github/scripts/release.cjs, which makes the same decision for the release workflow. A major bump also rewrites RELEASE_CHANNEL in .env.template and adds the new major to the support table, marking the previous one superseded with its end of support. Both edits are computed before any file is written, so a missing line or row fails the run with the tree untouched. Refs DouglasNeuroInformatics#1870. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A new architecture doc, release-channels.md, holds the model: the outputs of planRelease, what each run publishes, release/<major> branches, the bump rules and what a major bump rewrites. cut-a-release.md follows the new jobs and adds the steps for a release branch, and testing-strategy.md lists the github vitest project and the new CI and Release triggers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Implements the release and support policy decided in #1870 and supersedes #1822. A merge to
mainstops overwriting the publishedlatestand2.5.2images, deployers get a published policy saying which versions receive which fixes, and a superseded major can ship fixes from arelease/<major>branch.Changes
mainpublishes onlyedgeandsha-<7>images.<version>,<major>andlatestmove only when the root version has nov*tag yet, which means after a version bump.latestand2.5.2stop trackingmain.<version>and<major>(for example2), and a release frommainalso moveslatestand publishes npm.<major>.<minor>is never published.release/<major>on dispatch, and only once a higher major is tagged. That run publishes images and a GitHub release not marked latest, and skips npm with a notice. CI now runs on pull requests torelease/**.main, the next push releases the version anyway..env.templatedefaultsRELEASE_CHANNELto2instead oflatest. A.envgenerated from now on tracks the current major.engines.nodeis^24.22.1 || >=26.12.1, Gabriel's October 2026 Node security fix from ci: release from release branches and keep latest on tagged releases #1822, unchanged.scripts/increment-version.tsenforces the policy:featcommit.RELEASE_CHANNELand the end-of-support table.docs/en/5-reference/5.10-versioning.md), covering:git checkout.SECURITY.mdlinks to it and points reporters at private vulnerability reporting. The deployment guide clones a release tag instead ofmain.Decisions
latestand npm move only with a release frommain. A branch release cannot move them, becauseplanReleaserefuses arelease/<major>dispatch until a higher major is tagged. With that guarantee, ci: release from release branches and keep latest on tagged releases #1822's dist-tag reconciliation (publish-npm.cjs) is no longer needed.featcommit in range fails the bump instead of producing a new minor on the branch.Risks
2image tag exists until the first release after this merges. Until then, a.envgenerated frommainpoints at a tag GHCR does not have. Existing deployments keepRELEASE_CHANNEL=latest, which now moves only on a release. The fix is to release 2.6.0 soon after merging.make_latestandtarget_commitish.release/<major>dispatch will first run after 3.0.0 ships.planRelease's unit tests are the only check of that path.Filed: #1896, #1900
Notes
I ran
scripts/increment-version.tsby hand on throwaway state and reverted every run:RELEASE_CHANNEL=3and the table: it added3 | 2026-11and marked 2 superseded in 2026-11, supported until 2028-05.v3.0.0tag,--bump minorand afeatcommit were both refused.--bump minorafter afeat!commit was refused.The docs site builds with the new page at
/en/docs/reference/versioning/.Adversarial review
Reviewed at commit f67a438. pnpm check: green.
Findings
.env.templateand the support table only after every version file and both changelogs, so a missingRELEASE_CHANNELline or table row leaves the tree half-bumped and a rerun bumps from the wrong version — compute and check both edits before the first write.featcommit in range as the breaking case is refused..github/scripts/release.cjs, two artifacts that must agree — export them fromrelease.cjsand import them.rule ?? 'it is not allowed here'can never run — make every restricted case carry its rule and drop the fallback.{apps,packages,runtime}/*/scripts/**matches no file the coverage include admits — delete it.readFileSyncandgetExecOutputwithout checking their arguments, so reading the wrong file or listing the wrong tags would still pass — assert both calls.ReleasePlantypedef says what each field is in doc comments — drop them and letrelease-channels.md's output table be the one explanation.Fixed
patch; afeator breaking commit in range fails the run.release.cjsexportsparseVersionandisSupersededMajor,planReleaseuses the latter, andincrement-version.tsimports both.allowBumpstakes the requested bump and throws with the rule of the branch that restricted it; the fallback is gone.readFileSync('package.json', 'utf-8')andgetExecOutput('git', ['tag', '--list', 'v*']).release-channels.md.Attestation
I, Claude Opus 5.5, attest that the review block above reports the adversarial review as it ran on the commit named, with every finding it returned.
🤖 Generated with Claude Code