fix(ci): overlay images from the PR base branch, and publish per-line artifacts - #3471
Conversation
The PR finalize job pulls cozystack-packages:main and repoints every package the PR did not rebuild at current-main images. On a main-based PR that is the whole point: it stops e2e from testing last-release images for everything outside the build matrix. On a release-line PR it is wrong — the committed refs there are not stale, they are that line`s released digests, and the charts are written against exactly those. So a release-line PR was installing main`s binaries onto its own charts, and the mismatch grows with every commit main gains. #3437 is the demonstration: a one-line change on release-1.6 that deactivates an app failed install deterministically, twice, with SchemaError(...core/v1alpha1.Option.spec): unknown model in reference: "...core~1v1alpha1.OptionSpec" from main`s cozystack-controller serving an aggregated OpenAPI that branch`s charts cannot validate against. Nothing in the PR was broken; the lane was. Left alone this makes every 1.6 backport look red, which is when release-branch PRs are busiest. Both overlay steps are now gated on `github.base_ref == main`, so a release-line PR keeps its committed digests — the behaviour that predates the overlay. Retargeting the overlay at a per-line artifact would be better but is not possible today: build-main.yaml publishes only cozystack-packages:main, and the registry carries no release-* equivalent (verified against the packages repo`s tag list: `main` plus per-PR tags, nothing else). hack/overlay-main-images_test.bats pins the wiring per step, so adding a third overlay step without the guard fails the suite. Mutation-checked by removing one guard. 12/12 green; actionlint clean. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
📝 WalkthroughWalkthroughRelease-line builds now publish branch-tagged package artifacts with cache writes disabled. Pull-request finalization retrieves the artifact for the pull request’s base branch, falls back to committed refs on failure, and overlays base-branch refs for unbuilt packages. Bats tests validate the workflow wiring. ChangesRelease-aware package artifacts
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@hack/overlay-main-images_test.bats`:
- Around line 157-177: Harden the wiring test around the overlay step loop so it
validates a standalone YAML if: key rather than any matching text in the step
block. Add a mutation check for each step that removes its base-branch guard and
asserts the test fails, ensuring the guard is structurally required and cannot
be satisfied by run content or comments.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 246369e4-4f9a-44d1-9b4a-d734a1e33c85
📒 Files selected for processing (2)
.github/workflows/pull-requests.yamlhack/overlay-main-images_test.bats
IvanHunters
left a comment
There was a problem hiding this comment.
LGTM. The if: github.base_ref == 'main' guard targets the root cause, not a symptom: the current-main overlay's premise (committed refs are stale, repoint them at main digests) only holds for main-based PRs. On release-line PRs it was deploying main binaries onto release charts — the failure mode #3437 hit.
Verified: pull_request trigger always populates base_ref; release branches use the release-* naming so == 'main' is an exact discriminator; _out/mainpkgs is consumed only by these two steps, so release-line PRs skip both cleanly with no dangling refs. bats 12/12 green incl. the new guard test (mutation-checked). No regressions — main-based behaviour is byte-identical.
… artifacts Supersedes the interim guard in this branch`s first commit, which skipped the overlay entirely for release-line PRs. Skipping fixed the wrong images but left those PRs testing their line`s last release: for any package the PR did not rebuild, the committed ref is the released digest, so a component changed by an earlier backport was exercised as its pre-backport binary until the next rc. The overlay now reads `cozystack-packages:<base branch>` instead of always `:main`, and build-release.yaml publishes that artifact for every maintained `release-<major>.<minor>` branch the way build-main.yaml does for main: images tagged with the branch, and the whole packages tree pushed with each reference digest-pinned to what the run just built. Each base branch therefore has its own generation to overlay from, which is what the original bug was really about — #3437 failed install because main`s cozystack-controller served an aggregated OpenAPI release-1.6`s charts could not validate against. Three deliberate choices: * The trigger matches line branches only (`release-[0-9]+.[0-9]+`). The per-release and rc staging branches promote-rc.yaml and tags.yaml create (release-1.6.1, release-1.6.0-rc.4) must not trigger a full rebuild — their images come from the tag build, and rebuilding them would be waste. * WRITE_CACHE stays 0. CACHE_REGISTRY/<img>:buildcache is a single ref per image and build-main.yaml is deliberately its only, serialized writer so concurrent builds cannot race on the cache manifest (the 409 class #2711 fixed for image tags). A line build can overlap a main build, so writing here would reintroduce that race. Line builds read the cache. * A missing artifact still degrades to committed refs, but on a release line it now emits a ::warning:: naming the branch. Silent degradation is indistinguishable from a working overlay, which is how a mis-specified branch filter would hide for a whole release cycle. Cost: one `make build` per push to a maintained line, i.e. per merged backport. hack/overlay-main-images_test.bats pins the artifact tag to the base branch, rejects a hardcoded :main in either overlay step, and pins build-release.yaml`s branch filter, image tag and WRITE_CACHE=0. Mutation-checked: restoring :main, setting WRITE_CACHE=1, and broadening the filter to release-* each fail a test. 13/13 green; actionlint and zizmor clean. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/build-release.yaml:
- Around line 69-72: Update the “Set up build toolchain” step to stop piping the
mutable fluxcd.io installer directly into sudo bash; download a version- or
commit-pinned Flux installation asset, verify its SHA-256 checksum against a
pinned expected value, and only then execute it, preserving the existing
command-availability check.
In @.github/workflows/pull-requests.yaml:
- Around line 405-409: Update the BASE_REF == "main" branch in the
missing-artifact handling to emit the same GitHub Actions ::warning annotation
as the release-line branch, while retaining the existing context that committed
refs are being kept. Ensure missing artifacts on main trigger a workflow warning
rather than stdout-only logging.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: eff05ab2-66be-4c0c-ae84-47400ae21b9a
📒 Files selected for processing (3)
.github/workflows/build-release.yaml.github/workflows/pull-requests.yamlhack/overlay-main-images_test.bats
| - name: Set up build toolchain | ||
| run: | | ||
| command -v flux >/dev/null \ | ||
| || curl -fsSL https://fluxcd.io/install.sh | sudo bash |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '--- workflow context ---\n'
sed -n '1,140p' .github/workflows/build-release.yaml 2>/dev/null || true
printf '\n--- matching workflow references ---\n'
rg -n "curl .*install\.sh|fluxcd|OCIR|registry|docker|podman|cosign|cosign|ghcr|docker login|registry-oci|ocir|token|password|secrets" .github/workflows/build-release.yaml .github/workflows 2>/dev/null || trueRepository: cozystack/cozystack
Length of output: 248
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- workflow context ---'
sed -n '1,140p' .github/workflows/build-release.yaml 2>/dev/null || true
echo
echo '--- matching workflow references ---'
rg -n "url .*install\.sh|fluxcd|OCIR|registry|docker|podman|cosign|ghcr|docker login|registry-oci|ocir|token|password|secrets" .github/workflows/build-release.yaml .github/workflows 2>/dev/null || trueRepository: cozystack/cozystack
Length of output: 38144
Pin and verify the Flux installer.
.github/workflows/build-release.yaml:72 pipes a mutable https://fluxcd.io/install.sh script directly into sudo bash before logging into OCIR. Use a version/pinned-build asset plus SHA-256 verification, or a commit-pinned trusted action, so a compromised installer cannot persist on the runner and compromise later registry-authenticated build/push steps.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/build-release.yaml around lines 69 - 72, Update the “Set
up build toolchain” step to stop piping the mutable fluxcd.io installer directly
into sudo bash; download a version- or commit-pinned Flux installation asset,
verify its SHA-256 checksum against a pinned expected value, and only then
execute it, preserving the existing command-availability check.
| if [ "${BASE_REF}" = "main" ]; then | ||
| echo "cozystack-packages:${BASE_REF} pull failed — keeping committed refs" | ||
| else | ||
| echo "::warning title=No packages artifact for ${BASE_REF}::Keeping committed refs, so unbuilt packages use this line's last release rather than its tip. Check that build-release.yaml has run for ${BASE_REF}." | ||
| fi |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Emit a workflow warning for a missing main artifact too.
The main fallback only logs stdout on Line 406, unlike the release-line path’s ::warning annotation. This misses the stated missing-artifact warning contract and makes a degraded main PR easier to overlook.
Proposed fix
if [ "${BASE_REF}" = "main" ]; then
- echo "cozystack-packages:${BASE_REF} pull failed — keeping committed refs"
+ echo "::warning title=No packages artifact for ${BASE_REF}::Keeping committed refs; unbuilt packages may use the last released images."📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if [ "${BASE_REF}" = "main" ]; then | |
| echo "cozystack-packages:${BASE_REF} pull failed — keeping committed refs" | |
| else | |
| echo "::warning title=No packages artifact for ${BASE_REF}::Keeping committed refs, so unbuilt packages use this line's last release rather than its tip. Check that build-release.yaml has run for ${BASE_REF}." | |
| fi | |
| if [ "${BASE_REF}" = "main" ]; then | |
| echo "::warning title=No packages artifact for ${BASE_REF}::Keeping committed refs; unbuilt packages may use the last released images." | |
| else | |
| echo "::warning title=No packages artifact for ${BASE_REF}::Keeping committed refs, so unbuilt packages use this line's last release rather than its tip. Check that build-release.yaml has run for ${BASE_REF}." | |
| fi |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/pull-requests.yaml around lines 405 - 409, Update the
BASE_REF == "main" branch in the missing-artifact handling to emit the same
GitHub Actions ::warning annotation as the release-line branch, while retaining
the existing context that committed refs are being kept. Ensure missing
artifacts on main trigger a workflow warning rather than stdout-only logging.
|
Pushed a second commit that changes the approach — worth re-reading rather than diffing, since the mechanism is now different. Title and description updated to match; Before ( Now ( Three decisions to check, all load-bearing:
The branch-filter pattern is the one claim no local test can settle, since only GitHub evaluates it. If it does not match, Verification: Cost, stated plainly: one |
Aleksei Sviridkin (lexfrei)
left a comment
There was a problem hiding this comment.
LGTM — the base-branch resolution is real code and not a behaviour pinned only by tests, the two new wiring tests actually go red when the thing they protect is removed, and nothing here changes what gets published to the release registry.
Business context: the PR-finalize overlay could only ever read the main packages artifact, so a PR based on a release line was handed main's binaries to run against that line's charts; this makes the overlay read the PR's own base branch and adds the workflow that publishes the per-line artifact it needs.
What I checked
The problem reproduces from source on main, not just from the description. The pull_request trigger carries no branch filter, and the finalize step pulls cozystack-packages:main unconditionally before overlaying it onto every package the PR did not rebuild. So a release-line PR gets the cross-generation mix — and the quieter half of that is that a green e2e on such a PR proves nothing about the line it targets.
The base-branch resolution is implemented, not merely asserted. pull-requests.yaml pulls cozystack-packages:${BASE_REF} with BASE_REF: ${{ github.base_ref }} wired into that step's env. hack/overlay-main-images.sh is untouched and does not need to change: it consumes an extracted directory and never resolves a branch itself. The producer side closes the loop — build-release.yaml sets IMAGE_TAG: ${{ github.ref_name }}, the root build target ends in make -C packages/core/installer image, and that Makefile's image-packages pushes oci://$(REGISTRY)/cozystack-packages:$(IMAGE_TAG).
The changed step did execute on this head: the finalize job logged pulling artifact from …/cozystack-packages:main followed by overlaid=4 same=127 skipped=40 drift=0 failed=0, so the main path is proven by a real run and not only by a YAML assertion. Neither the release-line path nor build-release.yaml is exercised by any PR run — the latter is push-triggered on a line branch, so it cannot run until it is on one. That is worth stating plainly since the description already acknowledges the branch filter as locally unprovable.
I mutation-checked the two new tests rather than trusting the green. Reverting the tag to :main, dropping BASE_REF from that step's env, renaming the step, broadening the trigger to release-*, flipping WRITE_CACHE to '1', pointing IMAGE_TAG away from github.ref_name, and deleting build-release.yaml each turn the file red with a TAP not ok and 12 of the declared 13 ok lines — under plain bats and under hack/cozytest.sh, which is what make unit-tests runs. These are not assert-the-guard-exists tests.
The branch filter is the same glob shape GitHub documents for a version pattern: the character class matches one digit, + repeats it, . is literal, and the match is anchored to the whole ref. It selects release-1.6 and rejects release-1.6.1 and release-1.6.0-rc.4, all three of which exist on the remote right now.
The backport label is applicable as written: the squashed diff applies cleanly against the current release-1.6 tree, and that branch's build-main.yaml, hack/common-envs.mk and installer Makefile are identical in every part this depends on, including the runner label and the artifact push. The first merge into the line bootstraps the line's own artifact, so there is no chicken-and-egg step to perform by hand.
Merging this to main alone fixes nothing — a push workflow runs the copy present on the pushed branch, and a pull_request run uses the base branch's copy — so the backport is the delivery, not a follow-up. I do not treat that as a blocker: it is stated in the description, the label that automates it is already on the PR, and the new annotation is what surfaces the gap if the rollout stalls.
Blast radius on release engineering is nil. Everything here pushes to the CI registry; stable publishing runs against the public registry from the release finalize path, which this does not touch.
Non-blocking follow-ups
-
The naming this change invalidates deserves a sweep.
hack/overlay-main-images.shstill names themainartifact as its source of truth in both the header and the usage block, still printsOverlay current-main images:and-> current-mainper file, anddocs/agents/image-refs.mdstill describes the tool as overlaying "current-main references". This PR's own finalize log showsoverlay: packages/system/seaweedfs/values.yaml -> current-main; on a release-line PR that same line will say "current-main" while overlaying that line's refs. I am not blocking on descriptive text and the corrective paragraph is right there in the workflow — but the incident being fixed here was itself a misdiagnosis, so a log line that lies about which generation was applied is the wrong thing to leave behind. -
The comment this diff added on the overlay step says the script handles "the empty directory the step above leaves when a line has no artifact yet". The step does
rm -rf _out/mainpkgson failure, so it leaves no directory at all, and the script's guard is the missing-directory branch. Behaviour is right, the comment is not, and it is a comment this diff wrote. Related: the paragraph directly above the changed step still asserts:mainas the source and is contradicted by the new paragraph under it. -
Trigger breadth against cost.
paths-ignore: ['docs/**']means any non-docs push to a maintained line fires the full build — a workflow edit, a test-only change, a merged promote PR. Onmainthat breadth pays for itself because the run warms the shared cache; hereWRITE_CACHEis'0', so a run that produces no new image is pure cost on a large runner. Narrowing to the paths that can actually change an image would remove most of it without weakening the guarantee. -
On a fork PR the registry login step is skipped, so
flux pullfails for want of credentials. Againstmainthat is the quiet echo, but against a release line it now emits "Check that build-release.yaml has run for …", which points at the wrong cause. Distinguishing "no credentials" from "no artifact" costs one condition. -
build-release.yamlis close to a copy ofbuild-main.yamland nothing pins the two in sync, so a future fix to the toolchain or buildx setup in one silently misses the other. Same for the missing repository guard: a fork that syncs a release line triggers a large, long job that dies at login with empty secrets. Both files share that gap, so this mirrors the house pattern rather than introducing one. -
The
::warningon a missing artifact is presented as a deliberate design choice, but nothing pins it — a later edit can drop it silently, which is the same class of gap the rest of this change closes. -
The two open review-bot comments still stand. On pinning the flux installer in particular: this job holds registry push credentials and the artifact it produces becomes the image source for every PR on that line, so an unpinned installer piped into
sudo bashmatters more here than its age inbuild-main.yamlsuggests. If it gets fixed, fixing both files in one pass is the cheaper move.
The latest run on this head came from a `labeled` event carrying a label other than full-e2e. pull-requests.yaml discards those by design — `plan` skips, and checks, build, build-talos, finalize and e2e all skip behind it — so the run reported nothing. Two side effects made that worse than a wasted run: the required "E2E Tests" context was left SKIPPED, which branch protection counts as satisfied, and cancel-in-progress killed the in-flight api-review-gate run that was carrying the real signal. Empty commit to get a genuine run against this head. No content change. Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
|
Backport failed for Please cherry-pick the changes locally and resolve any conflicts. git fetch origin release-1.6
git worktree add -d .worktree/backport-3471-to-release-1.6 origin/release-1.6
cd .worktree/backport-3471-to-release-1.6
git switch --create backport-3471-to-release-1.6
git cherry-pick -x fea40d6314424a4105d31c7ee77f818062f5bc1a 2330d6f3ca42306da92190b5e9dddf0bc1054fcd 007d0b1a22ec1aadca95960645d8232a5b202fcb |
…h, and publish per-line artifacts (#3514) ## What this PR does Hand backport of #3471 to `release-1.6`. Two clean cherry-picks, each carrying its `-x` reference; the resulting tree is byte-identical to #3471's merged state for all three files. The overlay must be fixed **on this branch** to have any effect here. For `pull_request` events GitHub builds the workflow from the merge ref, and for `push` events it reads the workflow from the pushed ref — so neither half of #3471 reaches this line while it lives only on `main`. Concretely, `build-release.yaml` on `main` never fires for a push to `release-1.6`, and a `release-1.6` PR keeps using this branch's copy of `pull-requests.yaml`. ## Why the bot could not do this The automatic backport reported success on every job and opened nothing (run 30817682877). It is not a conflict — #3471 carries an empty commit, `007d0b1a` (`chore(ci): re-trigger CI after a label event produced a no-op run`, zero files). `korthout/backport-action` cherry-picks commit-by-commit without `--allow-empty`, so that commit fails with `The previous cherry-pick is now empty`; the `draft_commit_conflicts` fallback then runs `git commit --all -m BACKPORT-CONFLICT`, which also has nothing to commit, and the action aborts: ``` git cherry-pick -x 007d0b1 The previous cherry-pick is now empty, possibly due to conflict resolution. git commit --all -m BACKPORT-CONFLICT The previous cherry-pick is now empty, possibly due to conflict resolution. git cherry-pick --abort Backport failed for `release-1.6`, because it was unable to cherry-pick the commit(s). ``` This is a general gap, not specific to this PR: any labelled PR containing an empty commit backports to nothing, and the failure surfaces as three green jobs. Worth a follow-up on the workflow — skipping empty commits, or having the action's failure fail the job — but that is out of scope here. ## What this unblocks #3437 fails install deterministically on this line today, because the unguarded overlay hands it main's `cozystack-controller` to run against `release-1.6`'s charts. The binary indexes `internal.cozystack.io/v1alpha1 TenantProjection` at startup, this branch ships no such CRD, so it fatals and every release that depends on it stalls. With this merged, the overlay reads `cozystack-packages:release-1.6` instead. That works even before the first `build-release.yaml` run publishes the artifact: a missing artifact degrades to the committed refs, which on this branch are the v1.6.0 digests its charts are written against. The degraded path is also no longer silent — it emits a warning naming the branch. #3437 will need a new head commit rather than a re-run, since the finalize job is reused on re-run and its existing `pr.patch` already has main's refs baked in. ## Note on cost Merging this is itself a push to `release-1.6`, so `build-release.yaml` fires on it and runs a full `make build` (up to 2h on a 24-cpu runner) to publish the line's images and `cozystack-packages:release-1.6`. That recurs per push to this line; `concurrency` with `cancel-in-progress` collapses bursts, and `paths-ignore` only exempts `docs/**`. ## Verification `hack/overlay-main-images_test.bats` 13/13 green on this branch, including the two wiring tests the backport brings (`the overlay reads the artifact for the PR's own base branch`, `every maintained release line publishes its own packages artifact`). `actionlint` clean on both workflows, and both parse as YAML. `hack/common-envs.mk` is byte-identical between `main` and `release-1.6`, so `IMAGE_TAG`, `WRITE_CACHE`, `PUBLISH_VERSIONED` and `PUBLISH_FLOATING` behave here exactly as they do on main. ### Release note ```release-note NONE ```
build-release.yaml publishes `cozystack-packages:<line>` on push to a release line, and pull-requests.yaml's overlay reads it so a release-line PR tests its own line's binaries instead of main's (#3471, #3437). It cannot fire for the push that creates the line. The freeze points release-X.Y at a commit that is already on main, so the push carries no new commits, and GitHub does not run a workflow whose paths/paths-ignore filter finds no changed files ("If there are no files changed, the workflow will not run"). The line would therefore have no artifact until its first cherry-pick merged, and in that window the overlay finds nothing to pull and leaves every package on its committed ref — at freeze time the previous release's, which is exactly the cross-generation mix #3437 fixed. The old flow had no such window: it branched at the promote merge commit, which carried real commits and its own release's refs. Add workflow_dispatch to build-release.yaml and have the freeze step dispatch it for the branch it just created, so the artifact exists from the moment the line does. The dispatch is non-fatal: without it the overlay no-ops and early cherry-pick PRs test their committed refs, which is where they were before #3471. The tag is pushed and the line is frozen by that point, so failing there would misreport both. The trigger also gives a line build a re-run button, which previously needed an empty commit pushed to the line. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
What this PR does
The PR finalize job overlays image refs for every package a PR did not rebuild, so e2e and the installer do not test last-release images for everything outside the PR's build matrix. It could only ever read
cozystack-packages:main, which meant a release-line PR was handed main's binaries to run against its own line's charts.#3437 is the demonstration: a one-line change on
release-1.6deactivating an app failed install deterministically, twice, withmain's
cozystack-controllerserved an aggregated OpenAPI thatrelease-1.6's charts could not validate against. Nothing in that PR was broken; the lane was. Both branches carryoption_types.goand keyOptionSpecidentically in the committed generated OpenAPI, so this is a generation mismatch at runtime, not a codegen drift.This PR fixes it by giving every base branch its own artifact to overlay from, rather than by turning the overlay off.
The change
pull-requests.yamlreadscozystack-packages:${BASE_REF}(github.base_ref) instead of a hardcoded:main.build-release.yaml(new) publishes that artifact for maintainedrelease-<major>.<minor>branches exactly asbuild-main.yamldoes for main: every image tagged with the branch, and the whole packages tree pushed with each reference digest-pinned to what the run just built.An earlier revision of this branch simply skipped the overlay for non-main bases. That fixed the wrong-images problem but left release-line PRs testing their line's last release: for any package the PR did not rebuild, the committed ref is the released digest, so a component changed by an earlier backport was still exercised as its pre-backport binary until the next rc. Per-line artifacts remove that gap too, which is why the guard was replaced rather than kept.
Three deliberate choices
The trigger matches line branches only (
release-[0-9]+.[0-9]+). The per-release and rc staging branchespromote-rc.yamlandtags.yamlcreate —release-1.6.1,release-1.6.0-rc.4— must not trigger a full rebuild; their images come from the tag build and rebuilding them is waste.WRITE_CACHEstays0.CACHE_REGISTRY/<img>:buildcacheis a single ref per image andbuild-main.yamlis deliberately its only, serialized writer so concurrent builds cannot race on the cache manifest — the 409 class #2711 fixed for image tags. A line build can overlap a main build, so writing here would reintroduce that race. Line builds read the cache.A missing artifact still degrades to committed refs, but says so. On a release line it emits a
::warning::naming the branch. Silent degradation is indistinguishable from a working overlay, which is how a mis-specified branch filter could hide for a whole release cycle.Cost
One
make buildper push to a maintained line — in practice per merged backport. That is the price of release-line PRs testing their line's tip instead of its last release.Verification
hack/overlay-main-images_test.batspins the artifact tag to the base branch, rejects a hardcoded:mainin either overlay step, and pinsbuild-release.yaml's branch filter, image tag andWRITE_CACHE: '0'. Mutation-checked: restoring:main, settingWRITE_CACHE: '1', and broadening the filter torelease-*each fail a test. 13/13 green;actionlintandzizmorclean.Worth an explicit ack in review: the branch-filter pattern is the one thing no local test can prove, since only GitHub evaluates it. If it does not match,
build-releasenever runs and the new::warning::is what surfaces it on the next release-line PR.Backport
release-1.6needs this too — forpull_requestevents GitHub builds the workflow from the merge ref, so a release-line PR only stops receiving main's images once the change is on its base branch. #3472 carried the interim guard and is closed in favour of backporting this instead.Release note
Summary by CodeRabbit
New Features
release-<major>.<minor>branches.Bug Fixes
Tests