Repository navigation
Conversation
|
@thomasbeaudry this has a few impacts to existing deployments
|
thomasbeaudry
left a comment
There was a problem hiding this comment.
Found two release-channel rollback cases that should be fixed before merging. Reviewed the merge result; lint passes and the github project passes all 10 tests with 100% coverage. Full workspace coverage/e2e and real publishing were not run; local Node was 24.22.0.
If delegated to Claude Code, Fable 5 is the skill-recommended size for changes spanning release planning and publishing.
Reviewed at commit 8e83c56.
| echo "Publishing ${name}@${version}" | ||
| pnpm --filter "${name}" publish --no-git-checks | ||
| echo "Publishing ${name}@${version} under ${NPM_TAG}" | ||
| pnpm --filter "${name}" publish --no-git-checks --tag "${NPM_TAG}" |
There was a problem hiding this comment.
[P2] Reconcile the selected dist-tag for already-published npm versions
The new npmTag can change between whole-run retries, but --tag is only applied after the existing-version check has continued past published packages. For example, 2.5.3 can publish its packages under latest and then fail before creating v2.5.3. If 2.6.0 succeeds before the whole 2.5.3 run is retried, the retry correctly plans npmTag=release-2.5; however, every already-published 2.5.3 package is skipped, so release-2.5 is never created or advanced for those packages. The workflow can finish green while installs using that maintenance channel fail or get an older version. I reproduced this with the current planRelease and the exact Publish Packages shell block: exit 0, only npm view invoked, no channel update. Please reconcile or verify the planned dist-tag even when the tarball exists, or fail explicitly and require a fresh patch, and cover this retry scenario. See npm dist-tag documentation for the distinction between publishing and tagging an existing version.
Reviewed at commit a9a35d7.
There was a problem hiding this comment.
Fixed in 68aa1e3, with the explicit failure. A reconcile with npm dist-tag add would need the opt-in "Allow npm dist-tag" setting on all six trusted publishers, because OIDC trusted publishing cannot move a dist-tag otherwise.
The shell loop is now .github/scripts/publish-npm.cjs, run through actions/github-script. It skips a published version only while the planned npmTag points at it. Otherwise it throws:
@odc/a@2.5.3 is already published, but its release-2.5 dist-tag is on '2.5.2'; trusted publishing cannot move a dist-tag, so cut a fresh patch
Your scenario (2.5.3 published under latest, then 2.6.0 releases, then a whole-run retry of 2.5.3 that plans release-2.5) is the test should fail a re-run whose planned dist-tag is elsewhere, so the channel is never left behind silently in .github/scripts/__tests__/publish-npm.test.ts. The normal re-run, where the tag still points at the version, is covered by should skip a published version whose planned dist-tag already points at it. 15 tests in the github project, and both scripts have 100% coverage. The docs (release-channels.md, cut-a-release.md, the odc-release skill) state the rule and the recovery.
|
I think we should do some kind of hybrid between the current and proposed approaches We need to define a specific policy for what constitutes a breaking change Which can be more conservative than what I have been doing (basically, "will it work if you pull the latest version with existing data") Then, only support major versions (say, releases within N years) Or, some kind of LTS release system Only major security issues or bugs (needs to be clearly defined) will be fixed |
The release decision moves into a tested planRelease function in .github/scripts/release.cjs. A run releases only when v<version> is not a git tag yet. latest (GHCR, npm, GitHub) moves only with a release whose version is higher than every tag. Every push to main builds edge and sha-<short>. A release/<major>.<minor> branch releases on dispatch, publishes <version> and <major>.<minor>, and uses the release-<major>.<minor> npm dist-tag when it is not the newest line. The GitHub tag now goes on the built commit. CI also runs on pull requests to release branches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G73CpTPk1EjKYeBAKPacit
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
…d branches A release branch cut from a commit before release-branch support has the old configure and ci.yaml, so the cut-a-release playbook now takes them from main in the branch's first commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G73CpTPk1EjKYeBAKPacit
planRelease decides from a tag snapshot, so overlapping runs on two refs could both plan latest, and the one that finished last owned it, or they could release one version from two commits. The concurrency group now spans every ref and never cancels a running release. planRelease also refuses an untagged version lower than a tag on its own line, so a late retry cannot move the line tag back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G73CpTPk1EjKYeBAKPacit
A re-run planned after a newer release can carry another npmTag than the run that published. The publish loop skipped every published version, so the release-<major>.<minor> channel stayed on an older version while the run finished green. Trusted publishing cannot move a dist-tag, so the new tested .github/scripts/publish-npm.cjs skips a published version only while npmTag points at it, and otherwise fails with a request for a fresh patch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G73CpTPk1EjKYeBAKPacit
Co-Authored-By: GLM 5.3 Flash
68aa1e3 to
0f5a6de
Compare
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
Why
The October 2026 Node.js security releases fix four High CVEs in Node 24 (TLS hostname checks, the Brotli decoder,
dns), and the api and gateway images run Node. The publishedlatestand2.5.2images were built on 2026-10-07 from432dec8with Node 24.21.0, so they are vulnerable.Those images are also not the code at the
v2.5.2tag (3c3f081): every push tomainre-pushed2.5.2andlatest. This PR changes that, so that we can shipv2.5.3from arelease/2.5branch built from the code that deployments run now.What changed
ci:release branches, andlatestonly on tagged releases.github/scripts/release.cjsnow exports a pureplanRelease({ ref, tags, version }). A run is a release only whenv<version>is not a git tag. It reads git tags only, never GHCR or npm.mainpushesedgeandsha-<7>. A release pushes<version>and<major>.<minor>, and alsolatest(GHCR, npm dist-tag, GitHub "latest release") only when its version is higher than every tag.release/<major>.<minor>branches release onworkflow_dispatchonly. On a branch that is not the newest line, npm publishes under dist-tagrelease-<major>.<minor>.configurefails on another ref, on a version that is already tagged, or on a version that is not on the branch's line.target_commitish: ${{ github.sha }}. Before this change, a new tag was created on the default branch.ci.yamlalso runs on PRs torelease/**..agents/docs/architecture/release-channels.md.cut-a-release.mdgets a "From a release branch" section. Theodc-releaseandodc-testingskills,testing-strategy.md,.env.templateand the playground deployment doc are updated.fix:Node 24.22.1engines.nodeis^24.22.1 || >=26.12.1. This is stricter than a new minimum: it also refuses the vulnerable 26.x before 26.12.1. pnpm only warns, becauseengine-strictis off.mainkeepsFROM node:lts-krypton, which already resolves to 24.22.1, so the next build is patched. A release branch pinsFROM node:<exact>(documented in the playbook and inrelease-channels.md).After merge
The merge run pushes
edgeonly, becausev2.5.2exists, solatestdoes not change. Next: addrelease/*to thereleaseenvironment's deployment-branch policy, cutrelease/2.5, pin Node, bump to 2.5.3, and dispatch. That dispatch is the first run ofpublish-npm --tag,make_latestandtarget_commitish.Verification
Run locally on Node 24.22.1:
pnpm lint: passes.pnpm test:coverage: passes at 100%. New vitest projectgithubwith.github/scripts/__tests__/release.test.ts(10 tests;release.cjshas 100% statement and branch coverage).pnpm test:e2e: 276 of 278 pass. The two failures are not related to this change:record-file-deletion.spec.tsgets a 503 because the local.envhasSTORAGE_ENABLED=false, andsubject-detail.spec.tstimed out on a detached element, then passed 9 of 9 on a second run../scripts/increment-version.ts --bump patch --yesdry run: the 2.5.3 changelog section generates from all 321 commits sincev2.5.2(I undid the dry run).Exceptions:
release/2.5dispatch.excludeentry'**/scripts/**'is narrowed to'{apps,packages,runtime}/*/scripts/**', because it also matched.github/scripts/. No file in the earlier coverage scope is under ascripts/directory.workspace-map.mdgets no row for thegithubproject, because.githubis not a workspace.Rebase note (2026-11-04)
Rebased onto
d6eeabcaa.main'svitest.config.tsrestructure (namedbaseConfigexport) iskept; the
.githubcoverage include, scripts exclude narrowing and project entry now live in itsmergeConfigblock, and.github/vitest.config.tsimportsbaseConfigby name like the otherproject configs. Carries
test(web): match walkthrough button label casingfor the same reason as#1855:
5fa1391a2renamed the walkthrough button and broke the unit suite onmain.Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com