Skip to content

fix(backupstrategy-controller): run backup clients on a package-owned image - #4756

Merged
Aleksei Sviridkin (lexfrei) merged 2 commits into
mainfrom
fix/backup-client-image
Oct 12, 2026
Merged

Aleksei Sviridkin (lexfrei) merged 2 commits into
mainfrom
fix/backup-client-image

Conversation

@androndo

@androndo Andrey Kolkov (androndo) commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

What this PR does

The Altinity (ClickHouse) and RabbitMQ backup strategy Pods ran platform-migrations: a 349 MB image carrying kubectl, helm, git, cozyhr and etcd-migrate, whose ENTRYPOINT is run-migrations.sh. Both pins were stamped from packages/core/platform/Makefile, so any migration change re-digested the backup clients too, and only the command: override kept the Pods from running platform migrations (#3420).

  • New packages/system/backupstrategy-controller/images/backup-http-client/: alpine:3.24 (digest-pinned, the same base the tree already uses) + curl + jq + ca-certificates, USER 65532:65532, no ENTRYPOINT. Everything is installed at build time, so the Pods still never run apk add and keep working air-gapped.
  • New image-backup-http-client target in the package's own Makefile, chained after image-redis-backup like the existing ones so only one yq -i writes values.yaml at a time. It stamps chBackupClientImage and rabbitmqBackupClientImage with the same ref.
  • Removed the cross-package stamps from packages/core/platform/Makefile, the WORKAROUND/TODO comments in the chart and the RabbitMQ example, and the stale "live violation" line in docs/agents/image-refs.md.
  • hack/image-pin-consistency.bats: dropped the platform-migrations-specific test, whose subject no longer exists. The general check (no repository pinned at more than one digest, computed from hack/promote-retag.sh --dry-run) still covers the two keys sharing one image.

Why one image for both strategies rather than ch-backup-client as the issue named it. The RabbitMQ strategy had the same reuse and the same cross-package stamp; leaving it would have kept the stamp alive. Its script needs curl --aws-sigv4 + ca-certificates, a subset of the ClickHouse one, so one image serves both. The two values keys stay separate so either strategy can move to its own image later.

Initial pin. The image does not exist in ghcr until CI builds it, so both keys are committed as backup-http-client:v1.6.0 without a digest, the same way redis-backup was introduced. PR CI rebuilds touched packages and overlays the fresh refs for e2e; release preparation's make image stamps tag+digest.

Image size: 6.9 MB vs 349 MB. Verified locally:

  • docker buildx build for linux/amd64,linux/arm64; in the image as uid 65532: curl 8.22 with --aws-sigv4, jq 1.8.2, date, seq, writes to /tmp (the RabbitMQ script's only write), TLS verification against the bundled CA store.
  • helm unittest (23/23), helm template renders both strategies with backup-http-client and no platform-migrations reference.
  • hack/cozytest.sh hack/image-pin-consistency.bats and hack/build-matrix_test.bats pass.

Not yet run end to end on a cluster; the e2e backup round-trips will exercise it.

Fixes #3420

Screenshots

N/A — no UI changes.

Downstream repositories

Walked the trigger map against the diff: it touches packages/system/backupstrategy-controller (new image, Makefile target, values comments/pins, template comments), packages/core/platform/Makefile (stamp removal only, no values.yaml key change), hack/image-pin-consistency.bats, docs/agents/image-refs.md and a comment in examples/backups/rabbitmq. No app package, schema, CRD, variant, asset, platform values key or hack/package.mk change. The website does not list first-party image repositories (searched for platform-migrations and redis-backup), so no mirror list needs the new one.

Release note

fix(backupstrategy-controller): the ClickHouse (Altinity) and RabbitMQ backup strategy Pods now run a dedicated `backup-http-client` image (alpine + curl + jq + ca-certificates, non-root, ~7 MB) instead of the 349 MB `platform-migrations` image. Air-gapped mirrors need the new `ghcr.io/cozystack/cozystack/backup-http-client` repository.

Summary by CodeRabbit

  • Improvements
    • Altinity and RabbitMQ backups now use a dedicated backup HTTP client image, configured separately from the platform migrations image.
    • The client image includes the tools required for backup operations and runs with a non-root identity.
    • Both backup configurations receive the same digest-pinned image reference when the image is built.

@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: cozystack/cozystack/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 1fc9dd1e-5d5d-4722-b069-e7de449b48af

📥 Commits

Reviewing files that changed from the base of the PR and between 8f6b7e8 and 770f515.


📒 Files selected for processing (2)
  • hack/image-pin-consistency.bats
  • packages/system/backupstrategy-controller/values.yaml

🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/system/backupstrategy-controller/values.yaml

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.



📝 Walkthrough

Walkthrough

The backup strategy controller now builds a dedicated backup HTTP client image and stamps its digest into both backup client image values. The platform Makefile no longer stamps those values. Related comments, image-pin tests, and documentation are updated.

Changes

Backup HTTP client image

Layer / File(s) Summary
Build and stamp the dedicated image
packages/system/backupstrategy-controller/values.yaml, packages/system/backupstrategy-controller/images/backup-http-client/Dockerfile, packages/system/backupstrategy-controller/Makefile, packages/system/backupstrategy-controller/templates/*, examples/backups/rabbitmq/03-rabbitmq-strategy.yaml
The controller package adds a dedicated image with curl, jq, and ca-certificates. Its Make target builds the image and stamps the digest into both backup client values. Related comments are updated; the example command remains unchanged.
Update image pin ownership
packages/core/platform/Makefile, hack/image-pin-consistency.bats, docs/agents/image-refs.md
The platform Makefile stops stamping the backup client values. Image-pin test guidance and image-reference documentation no longer identify the former migration-image pins as live violations. The test comparing three migration-image values is removed.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant Makefile as backupstrategy-controller Makefile
  participant Image as backup-http-client image
  participant Values as backupstrategy-controller values.yaml
  Makefile->>Image: Build image and read digest
  Makefile->>Values: Set both backup client image values
Loading

Merge Risk: ⚪ Minimal · up to 770f5

The image and build flow match both backup strategies. Supported release paths stamp the image before use, and no material merge-blocking risk remains.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 41969

The dedicated, non-root image reduces unnecessary tooling and migration coupling without changing backup credentials or workflow commands. However, the committed defaults lose their digest pins, making reproducible and trustworthy image selection depend on building and stamping values before deployment.

Retained concerns

  • Medium · security · inferred: Both credential-bearing backup clients change from digest-pinned images to a tag-only default. Unless deployment first uses the stamped values, executable identity depends on registry tag contents and node caches rather than the reviewed digest. The normal build restores pins, but the committed chart defaults and retained duplicate-pin check do not enforce that prerequisite.
Security review details

Security Blast Radius

  • inferred — The shared defaults can affect every Altinity or RabbitMQ strategy workload using them. Each client receives application API credentials; RabbitMQ also receives backup-storage credentials. Namespace-prefixed object keys describe normal addressing, not an IAM boundary. Maximum S3 exposure cannot be bounded without the effective credential policies.

Security Findings and Attack Paths

  • inferred — If unstamped defaults are deployed, an actor able to replace the referenced registry tag could substitute client executables and access injected credentials or authorized backup data. Registry-write authority is a prerequisite; no ordinary tenant exploit or actual substitution was established. Digest-pinned base references resisted this tag-substitution path.

Trust Boundaries and Controls

  • observed — Secret references and target construction are unchanged. The scripts retain authenticated in-cluster HTTP API access and RabbitMQ's S3 SigV4 requests, without disabling certificate verification for HTTPS. The PR changes executable supply and OS identity, not the declared credential or endpoint authority.

Resilience and Maintainability Implications

  • observed — Removing the migration-image dependency narrows backup runtime contents and eliminates cross-package pin updates. The remaining duplicate-pin check detects multiple collected digests per repository, but its digest-only collector skips these new tag-only defaults rather than proving their executable identity.

Pre-merge checks | Passed 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: replacing the shared image with a package-owned image for the backup strategy controller.
Linked Issues check Passed Issue #3420 requires a package-owned minimal image, build-time installation of curl, jq, and CA certificates, a package Makefile target that stamps the image value, and removal of the cross-packag…
Out of Scope Changes check Passed The reviewed changes support issue #3420. The RabbitMQ extension, shared image reference, related comments, and generalized pin-consistency test all address the same image reuse and stamping problem. …
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 3 files. (1 skipped: 1 …

✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR


🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added area/storage Issues or PRs related to storage (linstor, seaweedfs, bucket, velero, harbor) kind/bug Categorizes issue or PR as related to a bug size/L This PR changes 100-499 lines, ignoring generated files labels Oct 5, 2026
@androndo
Andrey Kolkov (androndo) marked this pull request as ready for review October 5, 2026 18:08
IvanHunters
IvanHunters previously approved these changes Oct 6, 2026

@IvanHunters IvanHunters left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

This swaps the ClickHouse/Altinity and RabbitMQ backup strategy Pods off the reused 349 MB platform-migrations image and onto a dedicated backup-http-client (alpine + curl + jq + ca-certificates, non-root 65532, ~7 MB) built by the package's own Makefile. It also removes the cross-package stamp in platform/Makefile that had left one key with no producer, frozen at v1.4.0-rc.2 (#3420). The design is clean: a single yq writes both keys to one digest, the target chains after image-redis-backup so the three yq -i writers never race under make -j, and both strategies render against the new ref with the command: override intact and no platform-migrations reference left in the rendered output.

Verified against a merge of current origin/main: helm unittest 23/23, image-pin-consistency and build-matrix bats green, both strategies render backup-http-client:v1.6.0 with zero platform-migrations refs, and the ClickHouse and RabbitMQ chainsaw suites each drive a real BackupJob and RestoreJob round-trip, so the new image is exercised in the E2E lane once the suite runs. A throwaway probe of the pinned alpine digest confirmed curl 8.22 with --aws-sigv4, jq 1.8.2, a writable /tmp, and pipefail under busybox ash, so the uid 65532 switch and the S3 transport both hold; the scripts write only to /tmp (RabbitMQ) or nothing (Altinity).

CI

The red Unit & controller tests on this head is not from this PR. Its three failures are internal/fluxcontract/snapshot_shape_test.go, the negated-assert audit flagging find's ! in select-e2e_test.bats:34, and the flux-install workflow contract. All three are main's own contracts broken by adjacent merges, already fixed on main by #4751 and three follow-up commits that landed after this branch's base. Merging current origin/main into this head makes all three pass (ran them locally: go test ok, both bats audits OK). A rebase clears the check. E2E (in-tree) was skipped only because it gates on that stale unit job.

Findings (all non-blocking, posted inline)

  • MINOR values.yaml:12: both keys committed as a bare tag that was never released and that make image will not reproduce; contradicts the invariant this PR edits in image-refs.md.
  • NIT values.yaml:41: comment reflow left one 135-column line in an otherwise ~84-column block.
  • NIT backup-http-client/Dockerfile:2: comment says both scripts parse JSON with jq, but the RabbitMQ script uses curl only.

Checked and correct

  • Bare-tag introduction is consistent with redis-backup and tolerated by the enumeration/promote suites (promote-rewrite-tags 17/0).
  • No orphaned platform-migrations consumer: platform/Makefile still stamps .migrations.image, the only remaining reference.
  • The dropped platform-migrations is pinned identically bats test loses no real coverage: exact tag-string equality is now guaranteed by one yq writing both keys, and the general duplicate-digest check still holds.
  • The previous image ran as root (no USER in platform-migrations), so the uid change is a hardening, not a regression; nothing in either script depends on root.

# release promotion (hack/image-pin-consistency.bats). They are separate keys
# so either strategy can move to its own image later.
# DO NOT hand-edit: `make image` stamps both.
chBackupClientImage: "ghcr.io/cozystack/cozystack/backup-http-client:v1.6.0"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MINOR] both keys committed as a bare tag that was never released and that make image will not reproduce

Both keys are committed as the bare tag backup-http-client:v1.6.0 with no digest. Unlike backupstrategy-controller:v1.6.0@sha256:... two lines up, this tag was never released (v1.6.0 predates the image) and make image in this tree stamps the dev version derived from git describe (v1.7.0-alpha.3-...), so the committed ref is unpullable as written. Release preparation and PR CI both stamp the real tag+digest before anything consumes the ref (overlay-main-images.sh classifies the *Image: keys as refs since #4257), and redis-backup:v1.6.0 was introduced the same way, so this is not a release or install defect. It does, though, contradict the invariant this same PR edits in docs/agents/image-refs.md ("A bare tag with no digest ... must not be committed"), and a dev applying the raw tree with helm template | kubectl apply (no build first) gets ImagePullBackOff on both the Altinity and RabbitMQ strategy Pods, where the previous platform-migrations pin resolved. Either note the "first commit of a new image" exception in that doc, or publish the image first and pin the digest.

# The Kafka metadata strategy carries no client image here: unlike the Altinity
# and RabbitMQ drivers (curl-only, so a shared platform-migrations image works),
# its driver runs the Kafka Admin-API CLI (kafka-topics / kafka-configs), which
# and RabbitMQ drivers, which need only curl and jq, its driver runs the Kafka Admin-API CLI (kafka-topics / kafka-configs), which

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[NIT] comment reflow left one 135-column line in an otherwise ~84-column block

The Kafka comment reflow left this line at 135 columns while the rest of the block wraps at ~84. Cosmetic, but it is the only line in the file that breaks the wrap.

@@ -0,0 +1,9 @@
# backup-http-client runs the Altinity (ClickHouse) and RabbitMQ strategy Pods:
# both scripts only drive an HTTP API and S3 with curl, parse JSON with jq, and

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[NIT] comment says both scripts parse JSON with jq, but the RabbitMQ script uses curl only

"both scripts ... parse JSON with jq" holds only for the Altinity script; the RabbitMQ script (templates/strategy-rabbitmq-default.yaml) uses curl only, with no jq call (5 jq invocations in the Altinity script, 0 in the RabbitMQ one). Harmless, since jq is installed regardless, but the comment overstates what the RabbitMQ Pod needs.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Andrey Kolkov (@androndo) NOT LGTM, but only because of the commit history. The image change itself is correct.

The second commit fixes comments that the first commit added: the Dockerfile header (only the Altinity script uses jq) and a rewrap in values.yaml. Its last paragraph walks through that diff, and with merge commits it lands in main as written. Please fold those two edits into d6b945a, so 8f6b7e8 keeps only the image-refs.md change and its first paragraph.

While there: the Kafka comment in values.yaml still says the Altinity and RabbitMQ drivers "need only curl and jq". The RabbitMQ script does not use jq, as the new Dockerfile header says.

What I checked on a trial merge with current main: helm unittest for the package, hack/image-pin-consistency.bats, hack/build-matrix_test.bats and hack/promote-rewrite-tags_test.bats pass. Both scripts already ran under busybox sh, and the date -u +FORMAT and seq calls work with busybox. The bare-tag keys are picked up by the *Image: branch in hack/overlay-main-images.sh.

The red E2E Tests is not caused by the code. clickhouse-2-backup-roundtrip failed on ImagePullBackOff: the e2e registry answers 403 Forbidden for the new backup-http-client repository. A new repository there is created private on first push, so a maintainer has to make it public before a rerun can pass. I still get the same 403 today with an anonymous pull token, while an existing repository in the same namespace accepts the same token.

… image

The Altinity and RabbitMQ strategy Pods ran platform-migrations, a 349 MB
image carrying kubectl, helm and etcd-migrate whose ENTRYPOINT is the
migration runner, and whose pins were stamped from packages/core/platform
so every migration change moved the backup clients too.

Build images/backup-http-client (alpine + curl + jq + ca-certificates,
non-root) from this package's Makefile and stamp both client keys from
it. The cross-package stamp in packages/core/platform/Makefile and the
platform-migrations-specific check in hack/image-pin-consistency.bats go
away; the general one-digest-per-repository check still covers the two
keys sharing one image.

Fixes #3420

Assisted-by: LLM
Signed-off-by: Andrey Kolkov <[email protected]>
docs/agents/image-refs.md forbade committing a bare tag without saying
how a new image's first pin can carry a digest it does not have yet.
Record the exception the backup client keys rely on: the bare tag is a
placeholder the producing `make image` replaces, and an unbuilt tree
pulls a tag that does not exist. Drop the securitygroup-controller
example, which is pinned by digest now.

Assisted-by: LLM
Signed-off-by: Andrey Kolkov <[email protected]>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Andrey Kolkov (@androndo) LGTM. The history and the Kafka comment are fixed. What still blocks E2E is on the maintainer side.

On a trial merge with current main (95c2d85), helm unittest for the package passes, and so do hack/image-pin-consistency.bats and hack/build-matrix_test.bats. Both keys are in packages/system/backupstrategy-controller/values.yaml, which the values.yaml glob in hack/lib/image-refs.sh covers.

The e2e registry still refuses an anonymous pull of backup-http-client. The anonymous token request is denied with "Anonymous users are only allowed read access on public repos", and the manifest fetch for this head's tag returns 403. redis-backup in the same namespace lists its tags with an anonymous token. A maintainer has to make the new repository public before the backup round-trip e2e can pass; nothing in the PR needs to change for that.

@lexfrei
Aleksei Sviridkin (lexfrei) merged commit 7c46fff into main Oct 12, 2026
21 checks passed
@lexfrei
Aleksei Sviridkin (lexfrei) deleted the fix/backup-client-image branch October 12, 2026 09:38
myasnikovdaniil added a commit that referenced this pull request Nov 9, 2026
## What this PR does

Backports become automatic. Fix merged to `main` with `fix` title, or
`security` for fix that comes through security advisory, reaches release
lines through batch that runs on Monday and Thursday, newest line first,
nobody requests, labels or opens backports by hand. Batch runs for two
newest lines with stable release (`released-lines` in policy block) and
every line branched after them that has no stable release yet: with 1.6
and 1.7 released, `release-1.8` created at `v1.8.0-rc.1` joins them, and
`v1.8.0` drops 1.6. Line counts as released once `vX.Y.Z` tag without
pre-release suffix exists on origin. Rules are in
`docs/release/backports.md`, `cmd/backport-batch` applies them,
`.github/workflows/backport-batch.yaml` runs it. Design is in
cozystack/community#114, merge shape of each original in
cozystack/community#119.

- `backport-batch run --line release-X.Y` takes PRs merged to `main`
since line branched (title and body read from merge commit) and skips
what rules exclude: other types and `deps`, breaking changes, platform
migrations, `targetVersion`, changed CRD documents, API changes that API
review gate calls sizeable (batch runs `internal/apigate` itself
whenever PR changes a file the gate parses:
`pkg/apiserver/apiserver.go`, an ApplicationDefinition, or YAML under
`packages/` or `internal/` naming `CustomResourceDefinition` or
`APIService`), and on older line what next newer line doesn't carry yet.
The rest goes onto `backport-batch/<line>-<date>` in merge order. PR
merged to `main` with merge commit goes as its own commits picked with
`cherry-pick -x --signoff`, so each keeps its author, message and
sign-offs and gets sign-off of whoever runs the batch (with `-m 1`
author was whoever merged on `main`), merges of `main` into PR branch
are left out, and merge commit joins them to the batch with original's
merge message and `Backported-from:` trailer. Squash-merged PR goes as
one pick. Conflict on any commit takes branch back to where it was
before that original, it's listed with the commit that failed, run goes
on. `--push` opens or updates draft PR, `--continue` carries on open
batch PR as fast-forward only, PR body it didn't write is never
rewritten. Same-day run over batch branch whose PR never got opened
refuses and names `run --line <line> --onto <head> --push`, which
continues it. Run or `--defer` that resets local batch branch over
commits only it has prints `git branch` command that restores them.
- `run --defer <N> --reason <why>` takes original out of open batch
(usually the one failing CI is pinned on). It rebuilds branch replaying
batch unit by unit without it, so merges and pushed conflict resolutions
keep their shape, and only this rebuild pushes with
`--force-with-lease`. Deferred original comes back in next batch.
- Line carries something only if its own history shows it: picks whose
`-x` line, the one git appends, names PR's merge commit or every commit
of its own, or pick that changes nothing. Picked commits keep their
messages and batch merge carries PR body, so text in them (`-x` lines,
`Backported-from:`, `Backport of #N`) counts only on commits from before
`batch-only` day in policy block, where it records old hand backports
and batches. Otherwise text in a merged fix could mark another fix as
already backported, and it would never reach the line. PR against line
never counts. Open batch PR counts only from this repo and from author
with write access or the batch's own bot (`BACKPORT_BATCH_BOT`, exact
login, `cozystack-ci[bot]` when unset, so maintainer's run by hand
continues scheduled batch instead of opening second one), and is read
the same way. Actions bot isn't trusted anymore, any workflow token
writes as it.
- Any failed GitHub API or git call stops the run with message naming
the call, no retries. Failed permission lookup used to count batch PR
out as look-alike, so `--continue` opened second batch PR and `notify`
posted second comment; now `run`, `check`, `verify` and `notify` exit 2
and write nothing.
- Policy applies fully from `release-1.7`. `release-1.6` takes only
fixes merged from 2026-10-26, older ones need `backport/include`. Start
days are in `backport-policy` block on the policy page, test keeps page
and code in sync.
- `backport-batch check --cut` replaces `backport-audit` as gate before
patch cut and before every rc after the first, it also fails while a fix
is only on open batch PR. Plain `check`, which scheduled run uses, lets
those through. `backport-batch fold` checks conflict resolution in the
same shape: merge on batch head whose second parent is straight line of
picks of PR's own commits in order, each with its `-x`, only PR's files
(one pick for squash). `backport-batch verify` holds every original on
batch to that shape, clean picks included, and `pr-labeler.yaml` runs it
on every push to batch PR: `pull_request_target` so it reaches
`release-*`, tool built from `main`, batch head fetched as data,
read-only token. Batch PR body says per original how many commits it
brought and which picks differ from their commits. `backport-batch
notify` reports batch that is still open from previous run and deferred
conflicts in one comment on batch PR, edited in place, with
`BACKPORT_ALERT_TEAM` mention.
- `hack/backport-batch-scheduled.sh` is what the workflow runs and
maintainer can run by hand (`--dry-run` changes nothing on GitHub): for
each line newest first `run --continue --push`, `check`, `notify`. It
pushes with `BACKPORT_BATCH_TOKEN` only and fails without it, never
`GITHUB_TOKEN`, because its pushes don't start CI. Workflow runs it as
cozystack-ci App: it mints token for this repo only with Contents and
Pull requests write, passes it as `BACKPORT_BATCH_TOKEN`, commits as
`cozystack-ci[bot]`, and sets `BACKPORT_BATCH_BOT` so the tool trusts
that bot's batch PR and comment. Job timeout is 30 minutes, under the
token's hour.
- App has no workflows permission, so workflow runs the script with
`--no-workflow-files`: original that changes `.github/workflows/` isn't
picked and waits on batch PR for maintainer, listed with its workflow
files in body and in notify comment. It's never a conflict. `check`
warns about it while it waits and `check --cut` fails on it. Maintainer
brings it over with own token by `run --continue --push` without the
flag, or takes it out with `--defer`.
- Deferred conflicts and failed batch CI wait for maintainer. `notify`
keeps one comment on batch PR listing stalled batch, conflicts and
workflow changes, mentioning `BACKPORT_ALERT_TEAM` (team or login) when
it's set. Failed batch CI isn't in the comment, it shows on batch PR
checks, and `check --cut` fails while batch is unmerged.
- Two steps that need judgement (resolve conflict, pin failed CI on
original and defer it) are written as runbooks in
`docs/release/backport-tasks/`: inputs, the only allowed output, check
it must pass before push, what never to do.
- `backport/include` and `backport/skip` let maintainer override rules
for single PR, they are new `backport/` category in `labels.yml`. Skip
wins over include, if open batch already picked it `--defer` takes it
out.
- Text written by other people (titles, release notes, reasons, file
names) goes to batch PR body only inside code spans or release-note
block, control, bidi and zero-width characters are dropped, file names
in deferred block included, git args go after `--end-of-options`, no
shell.
- Removed: `cmd/backport-audit`, `backport.yaml`, `kind/backport` and
`kind/backport-previous` labels with aliases and stale exemption,
trailer-check exemption for bot branches. `Commit trailers` job exempts
only `backport-batch/*` branches of this repo, changelog instructions
read originals from batch commits. Exemption lives in main's
`pre-commit.yml`, and batch PR runs its line's copy: `release-1.7` has
its own copy that exempts only old `backport-<pr>-to-<branch>` branches,
`release-1.6` has no such job. So on `release-1.7` picked commit with
bad trailer fails batch CI until line gets main's copy.
- `hack/close-manual-backport.sh` runs from `pr-labeler.yaml` on
`opened` and closes PR against `release-*` from outside contributor
(association contributor, first-time contributor or none, permission
read or none). Owners, members, collaborators, anyone with triage or
more and bots are left alone. When GitHub's answer on author's
permission can't be read, it closes nothing and fails the job naming the
failed read. Maintainer keeps release-only fix by reopening it.
Release-only PRs are occasional and opened by maintainers, for fix with
no counterpart on `main`, or one that on `main` came inside another PR
or was written for `main`; if its counterpart on `main` is a fix the
batch would take, the batch skips it once picking it changes nothing on
the line, otherwise maintainer labels it `backport/skip`.
- `docs/release.md` is split into pages under `docs/release/`, PR
template doesn't ask for `kind/backport` anymore. `security` type is
added to commit format in `docs/agents/contributing.md`, PR template,
Gemini review guide and labeler's list (labeler maps no `kind/*` to it,
`labels.yml` has no fitting one).
- `SECURITY.md`, `docs/security/incident-response.md` and
`GENERAL_TECHNICAL_REVIEW.md` now say two latest minor releases are
supported, same window the batch runs for, and link the backport policy
for which fixes go there.

Dry runs without push, on 2026-11-06, with `--no-workflow-files` as the
workflow runs it: `lines` gives `release-1.7` and `release-1.6`. On
`release-1.7` batch picks 12 fixes, defers 3 conflicts (#4756, #4867,
#5082), leaves #4888 and #4971 to a maintainer because they change
workflows, and skips 49. On `release-1.6` it picks #5088, defers 3
conflicts (#5071, #5086, #5087), leaves #5142 to a maintainer, and skips
590. `verify` passes both batches.

Setup after merge: no new secret. Batch runs as cozystack-ci App from
existing `COZYSTACK_CI_APP_ID` and `COZYSTACK_CI_PRIVATE_KEY`, job fails
when either is missing. App's installation already has Contents and Pull
requests write on all org repos, and no Workflows is needed: PRs that
change `.github/workflows/` wait for maintainer, who brings them over
with own token as "Changes to workflows" in `docs/release/backports.md`
says. Today that's #4888 and #4971 on `release-1.7` and #5142 on
`release-1.6`. Set `BACKPORT_ALERT_TEAM` to a team or a login (for
example `cozystack/maintainers`): unset, batch comment mentions nobody
and nobody is notified. Once this PR is merged, `Backport batch shape`
can be required check in the release lines ruleset (`release-*`
excluding `release-*.*.*`), with "Do not require status checks on
creation" on, because `cut-prerelease.yaml` creates `release-X.Y` by
push. `PR Auto-Label` with both new jobs runs on `pull_request_target`,
so it needs #5135 sorted before 2026-12-02. `kind/backport*` labels have
to be deleted by hand, label sync doesn't delete.

### Screenshots

Not a UI change.

### Downstream repositories

cozystack/community `contributors/README.md` lists commit types, so it
needs `security` too, it has no backport label text. Website has no
backport label instructions, and its links to `docs/release.md` carry no
anchor, the page stays as index. Trigger map lists commit convention
change for cozystack/ccp: this adds `security` type, but not message
format or trailer, and `package-bump` writes only `chore(...)` commits
and restates the trailer, so nothing changes there.

- [ ] No downstream repository is affected by this change
- [ ] [cozystack/website](https://github.com/cozystack/website) -
follow-up:
- [ ]
[cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack)
- follow-up:
- [ ]
[cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack)
- follow-up:
- [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up:
- [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up:
- [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) -
follow-up:
- [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) -
follow-up:
- [ ]
[cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server)
- follow-up:
- [ ]
[cozystack/external-apps-example](https://github.com/cozystack/external-apps-example)
- follow-up:
- [ ] [cozystack/examples](https://github.com/cozystack/examples) -
follow-up:
- [ ] [cozystack/community](https://github.com/cozystack/community) -
follow-up: add `security` to commit types in `contributors/README.md`

### Release note

```release-note
feat(release): backports are automatic. Fixes merged to main with fix or security title reach release lines through a batch built by cmd/backport-batch every Monday and Thursday, by the rules in docs/release/backports.md. The batch runs for the two newest lines with a stable release and for a line in its rc window: the release-X.Y branch the first rc creates joins at once, and its vX.Y.0 drops the oldest line. Features, chores, docs, dependency bumps, breaking changes, migrations, CRDs and API changes that the API review gate calls sizeable wait for the next minor. The policy applies fully from release-1.7, release-1.6 takes only fixes merged from 2026-10-26. Each original reaches the line as its own commits under a merge commit, keeping their authors and sign-offs. Maintainers override the rules for single PR with backport/include and backport/skip labels and take an original out of a batch with backport-batch run --defer. backport-batch check replaces backport-audit as the gate before a patch release and before a later rc. The label-driven backport workflow and kind/backport labels are removed. Backport PR opened by hand against a release branch by author with read access or less is closed automatically. The scheduled batch runs as the cozystack-ci App and needs no secret of its own; a fix that changes .github/workflows waits on the batch pull request for a maintainer, since the App may not push workflow changes. Release documentation now lives in one page per topic under docs/release/.
```
myasnikovdaniil added a commit that referenced this pull request Nov 10, 2026
… image (#4756)

## What this PR does

The Altinity (ClickHouse) and RabbitMQ backup strategy Pods ran
`platform-migrations`: a 349 MB image carrying `kubectl`, `helm`, `git`,
`cozyhr` and `etcd-migrate`, whose `ENTRYPOINT` is `run-migrations.sh`.
Both pins were stamped from `packages/core/platform/Makefile`, so any
migration change re-digested the backup clients too, and only the
`command:` override kept the Pods from running platform migrations
(#3420).

- New
`packages/system/backupstrategy-controller/images/backup-http-client/`:
`alpine:3.24` (digest-pinned, the same base the tree already uses) +
`curl` + `jq` + `ca-certificates`, `USER 65532:65532`, no `ENTRYPOINT`.
Everything is installed at build time, so the Pods still never run `apk
add` and keep working air-gapped.
- New `image-backup-http-client` target in the package's own `Makefile`,
chained after `image-redis-backup` like the existing ones so only one
`yq -i` writes `values.yaml` at a time. It stamps `chBackupClientImage`
and `rabbitmqBackupClientImage` with the same ref.
- Removed the cross-package stamps from
`packages/core/platform/Makefile`, the WORKAROUND/TODO comments in the
chart and the RabbitMQ example, and the stale "live violation" line in
`docs/agents/image-refs.md`.
- `hack/image-pin-consistency.bats`: dropped the
`platform-migrations`-specific test, whose subject no longer exists. The
general check (no repository pinned at more than one digest, computed
from `hack/promote-retag.sh --dry-run`) still covers the two keys
sharing one image.

**Why one image for both strategies rather than `ch-backup-client` as
the issue named it.** The RabbitMQ strategy had the same reuse and the
same cross-package stamp; leaving it would have kept the stamp alive.
Its script needs `curl --aws-sigv4` + `ca-certificates`, a subset of the
ClickHouse one, so one image serves both. The two values keys stay
separate so either strategy can move to its own image later.

**Initial pin.** The image does not exist in ghcr until CI builds it, so
both keys are committed as `backup-http-client:v1.6.0` without a digest,
the same way `redis-backup` was introduced. PR CI rebuilds touched
packages and overlays the fresh refs for e2e; release preparation's
`make image` stamps tag+digest.

Image size: 6.9 MB vs 349 MB. Verified locally:
- `docker buildx build` for `linux/amd64,linux/arm64`; in the image as
uid 65532: curl 8.22 with `--aws-sigv4`, jq 1.8.2, `date`, `seq`, writes
to `/tmp` (the RabbitMQ script's only write), TLS verification against
the bundled CA store.
- `helm unittest` (23/23), `helm template` renders both strategies with
`backup-http-client` and no `platform-migrations` reference.
- `hack/cozytest.sh hack/image-pin-consistency.bats` and
`hack/build-matrix_test.bats` pass.

Not yet run end to end on a cluster; the e2e backup round-trips will
exercise it.

Fixes #3420

### Screenshots

N/A — no UI changes.

### Downstream repositories

Walked the trigger map against the diff: it touches
`packages/system/backupstrategy-controller` (new image, Makefile target,
values comments/pins, template comments),
`packages/core/platform/Makefile` (stamp removal only, no `values.yaml`
key change), `hack/image-pin-consistency.bats`,
`docs/agents/image-refs.md` and a comment in
`examples/backups/rabbitmq`. No app package, schema, CRD, variant,
asset, platform values key or `hack/package.mk` change. The website does
not list first-party image repositories (searched for
`platform-migrations` and `redis-backup`), so no mirror list needs the
new one.

- [x] No downstream repository is affected by this change
- [ ] [cozystack/website](https://github.com/cozystack/website) -
follow-up:
- [ ]
[cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack)
- follow-up:
- [ ]
[cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack)
- follow-up:
- [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up:
- [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up:
- [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) -
follow-up:
- [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) -
follow-up:
- [ ]
[cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server)
- follow-up:
- [ ]
[cozystack/external-apps-example](https://github.com/cozystack/external-apps-example)
- follow-up:
- [ ] [cozystack/examples](https://github.com/cozystack/examples) -
follow-up:
- [ ] [cozystack/community](https://github.com/cozystack/community) -
follow-up:

### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same `type(scope):` prefix as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
fix(backupstrategy-controller): the ClickHouse (Altinity) and RabbitMQ backup strategy Pods now run a dedicated `backup-http-client` image (alpine + curl + jq + ca-certificates, non-root, ~7 MB) instead of the 349 MB `platform-migrations` image. Air-gapped mirrors need the new `ghcr.io/cozystack/cozystack/backup-http-client` repository.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Improvements**
* Altinity and RabbitMQ backups now use a dedicated backup HTTP client
image, configured separately from the platform migrations image.
* The client image includes the tools required for backup operations and
runs with a non-root identity.
* Both backup configurations receive the same digest-pinned image
reference when the image is built.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Backported-from: 7c46fff
myasnikovdaniil added a commit that referenced this pull request Nov 11, 2026
## What this PR does

Backports to `release-1.7` from `main`, picked by the rules of the
[backport
policy](https://github.com/cozystack/cozystack/blob/main/docs/release/backports.md)
in merge order. A merged pull request comes as its own commits, picked
with `git cherry-pick -x` so each keeps its author, message and
sign-offs, and a merge commit that carries the original's merge message
with a `Backported-from:` trailer naming it; a squash-merged one comes
as one pick. `backport-batch verify` checks that shape. A pick listed as
changed differs from the commit it came from; `git range-diff
<merge>^1..<merge>^2 <batch merge>^1..<batch merge>^2` shows how. A
conflict or a failing check here is a [backport
task](https://github.com/cozystack/cozystack/blob/main/docs/release/backport-tasks/README.md).

- [#4756](#4756)
`fix(backupstrategy-controller): run backup clients on a package-owned
image`, 2 commits, changed in the pick: `48d0cb2958a5`
- [#4867](#4867) `fix(e2e):
keep chainsaw asserts polling through transient API errors`, 1 commit
- [#4888](#4888) `fix(ci):
dispatch frozen-line builds with GITHUB_TOKEN`, 1 commit
- [#4985](#4985) `fix(etcd):
stop counting canceled watch streams as failed gRPC requests`, 1 commit
- [#5005](#5005)
`fix(tcp-balancer): cap HAProxy fds and threads by the pod's own
limits`, 1 commit
- [#4917](#4917)
`fix(kubernetes): run Proxmox CCM v0.16.1 and pin the Proxmox images by
digest`, 2 commits
- [#4974](#4974)
`fix(kubernetes-nodes): plan autoscaler capacity on the cores the VM
actually gets`, 1 commit
- [#4971](#4971) `fix(e2e):
keep the Proxmox tenant kubeconfig per run and remove it`, 2 commits
- [#4970](#4970) `fix(e2e):
read the KubernetesNodes pool release in the HelmRelease guard`, 3
commits
- [#4972](#4972) `fix(e2e):
validate the leak allowlist against every suite layout`, 3 commits
- [#5082](#5082)
`fix(marketplace): pin a tapped repository to a digest instead of a
mutable tag`, 15 commits, changed in the pick: `a31ae9090928`,
`b326e0badd62`, `a3d883b4bf5b`, `f8509450f7ca`
- [#4004](#4004)
`fix(dashboard): link a tenant row to its detail page`, 2 commits
- [#5212](#5212)
`fix(cilium): pass the CiliumNode list to jq on stdin in the IPAM hook`,
1 commit
- [#5213](#5213)
`fix(kubernetes): move the OIDC users out of the bootstrap Job's
script`, 1 commit
- [#5208](#5208)
`fix(clickhouse): restore the archive a Backup was taken as`, 3 commits
- [#5230](#5230)
`fix(backups): re-render the default backup objects when the S3 endpoint
changes`, 8 commits
- [#5133](#5133)
`fix(securitygroups): project a membership-only group to a policy Cilium
accepts`, 1 commit
- [#5091](#5091)
`fix(postgres): render the declared databases in a stable order`, 1
commit
- [#5123](#5123)
`fix(mariadb-operator): derive the cluster name from the platform
domain`, 2 commits
- [#5151](#5151) `fix(redis):
run one Sentinel when Redis runs a single pod`, 5 commits
- [#5124](#5124)
`fix(lineage, kubernetes): resolve CAPK node VMs to their cluster`, 2
commits
- [#5184](#5184) `fix(api):
read pool usage under the quota key the controller counts`, 1 commit
- [#5190](#5190)
`fix(platform): remove the dead registries value and patch-containerd
Secret`, 2 commits
- [#5211](#5211)
`fix(postgres): fail a backup job as soon as its cnpg Backup fails`, 1
commit
- [#5155](#5155)
`fix(postgres): refuse system databases and never drop them`, 1 commit
- [#5207](#5207)
`fix(mariadb): fail backup and restore jobs whose operator Job failed`,
5 commits
- [#5024](#5024)
`fix(kubernetes, monitoring): send tenant cluster metrics to the
tenant's vminsert`, 1 commit

### Maintainer overrides

- [#5083](#5083)
`fix(workloadmonitor): stop doubling the bucket- prefix in bucket
Workload names`: `backport/skip`, left out
- [#4973](#4973)
`fix(kubernetes-nodes): refuse a partial resources spec on every pool`:
`backport/skip`, left out
- [#5180](#5180) `fix(tests):
keep two unit tests green after the release image restamp`:
`backport/skip`, left out

### Skipped

- Rule 1, already on `release-1.7`: 19
- Rule 2, the title type is not `fix` or `security`, or the scope is
`deps`: 26
- Rule 3, a breaking change: 5
- Rule 4, touches platform migrations, `targetVersion` or a CRD, or
makes a sizeable API change: 2

<details><summary>Rule 1, already on `release-1.7`</summary>

- [#4815](#4815)
`fix(vm-disk): name the importer error in the disk's WorkloadsReady
message`, `its 2 commits picked, the last in 4323363`
- [#4293](#4293)
`fix(fluxcd): keep Helm uninstall working during flux-plunger recovery`,
`its 1 commit picked, the last in 0210407`
- [#4791](#4791)
`fix(kubernetes): keep NFS publish from hanging on a dead server`, `its
1 commit picked, the last in fa88bd1`
- [#4830](#4830)
`fix(multus): drop the CPU limit and make resources configurable`, `its
2 commits picked, the last in 363c842`
- [#4865](#4865) `fix(kafka):
pass the container limits to the Kafka JVMs`, `its 3 commits picked, the
last in fc38a54`
- [#4866](#4866)
`fix(linstor): mark volumes restored from a snapshot DRBD-initialized`,
`its 1 commit picked, the last in f9550b7`
- [#4819](#4819)
`fix(seaweedfs): build SeaweedFS in-tree with a bounded S3 read-ahead`,
`its 5 commits picked, the last in 7f4c346`
- [#3427](#3427)
`fix(backups): prepare standalone VMDisk restore targets and add VM
backup/restore e2e round-trips`, `its 3 commits picked, the last in
4ac0cd5`
- [#4889](#4889)
`fix(monitoring): send alerts to every Alertmanager replica`, `its 1
commit picked, the last in 5033d53`
- [#4929](#4929)
`fix(backups): gate every default Strategy CR on its CRD`, `its 2
commits picked, the last in dee1eef`
- [#4914](#4914)
`fix(fluxcd): close the flux-plunger review follow-ups for the hook,
drain and Warnings`, `its 7 commits picked, the last in a8e4916`
- [#4939](#4939)
`fix(cluster-api): resync capi-operator every minute`, `its 1 commit
picked, the last in cc8d6a4`
- [#5027](#5027) `fix(hack):
keep the backup stack in the vminstance selective install`, `its 1
commit picked, the last in 8ba8386`
- [#4955](#4955)
`fix(vm-disk): let CDI adopt the PVC a Velero restore recreates`, `its 2
commits picked, the last in 691d7bc`
- [#5071](#5071)
`fix(marketplace): do not install a connected repository's components on
connect`, `its 2 commits picked, the last in 25f8f11`
- [#5086](#5086)
`fix(tenant): stop the gateway release waiting on TenantGateway
listeners and certificates`, `its 1 commit picked, the last in
18b2249`
- [#5087](#5087)
`fix(controller): carry healthCheckExprs and waitStrategy to existing
releases`, `its 1 commit picked, the last in d2a452e`
- [#5088](#5088)
`fix(ingress-nginx): drop the admission-webhook policy a rebase brought
back`, `its 1 commit picked, the last in cf00b41`
- [#5142](#5142)
`fix(release): keep release bodies within GitHub's size limit`, `its 1
commit picked, the last in c740515`

</details>

<details><summary>Rule 2, the title type is not `fix` or `security`, or
the scope is `deps`</summary>

- [#4845](#4845)
`docs(governance): welcome new contributors and link LF sanctions
guidance`, `type docs`
- [#4881](#4881)
`feat(bucket): add a ui flag to skip the s3manager web UI`, `type feat`
- [#4899](#4899) `chore: link
the FOSSA license scan for CLOMonitor`, `type chore`
- [#4898](#4898)
`feat(backups): back up Valkey with the Redis strategy`, `type feat`
- [#4940](#4940)
`docs(release): add changelog for v1.6.5`, `type docs`
- [#4861](#4861)
`feat(release): sign the release assets and attach a source SBOM`, `type
feat`
- [#3780](#3780) `docs: move
the operator guides out of docs/ to where readers find them`, `type
docs`
- [#4936](#4936)
`docs(release): check changelog claims against the code`, `type docs`
- [#4959](#4959)
`docs(release): point changelog check B at the Talos installer profile`,
`type docs`
- [#3777](#3777)
`docs(agents): define where a new document belongs`, `type docs`
- [#5025](#5025)
`test(harbor): pin the resources of the nginx proxy and the portal`,
`type test`
- [#5039](#5039)
`feat(keycloak): load additional CA files from Secret or ConfigMap
keys`, `type feat`
- [#4860](#4860)
`feat(kubernetes-nodes): trust a factory CA in the Proxmox template
script`, `type feat`
- [#5090](#5090) `ci(e2e):
end the Proxmox lane's SSH key with a newline`, `type ci`
- [#4969](#4969)
`test(kubernetes): pin RetryOnFailure on the Proxmox csi release`, `type
test`
- [#5000](#5000)
`test(kubernetes): name the Proxmox fixture's node pool
<cluster>-<pool>`, `type test`
- [#5168](#5168)
`docs(agents): steer agents away from Helm lookup`, `type docs`
- [#4997](#4997)
`feat(release): attach an SBOM to every release image`, `type feat`
- [#3440](#3440)
`ci(api-review-gate): publish the gate as a commit status`, `type ci`
- [#5034](#5034) `docs: move
the repo-only guides onto the website`, `type docs`
- [#5215](#5215)
`feat(monitoring-agents): export PVC labels from kube-state-metrics`,
`type feat`
- [#5217](#5217)
`feat(monitoring-agents): keep application identity in container log
streams`, `type feat`
- [#5171](#5171) `feat(api):
expose HelmRelease failure state on Application status`, `type feat`
- [#5237](#5237)
`feat(operator): let the platform source trust a private registry CA`,
`type feat`
- [#5106](#5106)
`feat(release): make backports automatic with backport-batch`, `type
feat`
- [#4983](#4983) `feat(api):
add the reservation evaluator for tenant quotas`, `type feat`

</details>

<details><summary>Rule 3, a breaking change</summary>

- [#4790](#4790)
`fix(platform)!: refuse a networking variant change on a live cluster`,
`! in the title`
- [#4796](#4796)
`fix(vm-disk)!: refuse a golden-image clone CDI would leave unbound`, `!
in the title`
- [#5085](#5085)
`fix(kubernetes, opensearch, foundationdb)!: restrict managed
application images`, `! in the title`
- [#4818](#4818)
`fix(keycloak)!: make the KMS proxy keep its keys across restarts`, `!
in the title`
- [#5167](#5167)
`fix(monitoring-agents)!: isolate merged log payload under
log_processed`, `! in the title`

</details>

<details><summary>Rule 4, touches platform migrations, `targetVersion`
or a CRD, or makes a sizeable API change</summary>

- [#4941](#4941)
`fix(backups): keep the backupstrategy-controller Helm release under the
Secret size limit`, `a sizeable API change (breaking-change: [v1alpha1]
spec.spec.template: field "metadata" was removed, and 5 more), a CRD`
- [#5223](#5223)
`fix(backups): report sizeBytes for MariaDB and CNPG backup artifacts`,
`a CRD`

</details>

```backport-batch
{"line":"release-1.7","deferred":[]}
```

### Screenshots

See the original pull requests.

### Downstream repositories

- [ ] No downstream repository is affected by this change
- [ ] [cozystack/website](https://github.com/cozystack/website) -
follow-up:
- [ ]
[cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack)
- follow-up:
- [ ]
[cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack)
- follow-up:
- [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up:
- [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up:
- [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) -
follow-up:
- [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) -
follow-up:
- [ ]
[cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server)
- follow-up:
- [ ]
[cozystack/external-apps-example](https://github.com/cozystack/external-apps-example)
- follow-up:
- [ ] [cozystack/examples](https://github.com/cozystack/examples) -
follow-up:
- [ ] [cozystack/community](https://github.com/cozystack/community) -
follow-up:

### Release note

```release-note
fix(backupstrategy-controller): the ClickHouse (Altinity) and RabbitMQ backup strategy Pods now run a dedicated `backup-http-client` image (alpine + curl + jq + ca-certificates, non-root, ~7 MB) instead of the 349 MB `platform-migrations` image. Air-gapped mirrors need the new `ghcr.io/cozystack/cozystack/backup-http-client` repository.

fix(e2e): a chainsaw assert in the e2e suites keeps polling through a transient API error such as an etcd leader change, instead of failing the suite long before its timeout.

fix(ci): use GITHUB_TOKEN to start the initial packages build when freezing a release line

fix(etcd): the tenant etcd alert etcdHighNumberOfFailedGRPCRequests now counts only the gRPC codes that the etcd mixin and the platform copy of the alert count, so the Canceled watch streams of a Kubernetes API server that stops no longer fire it on every etcd member.

fix(tcp-balancer): HAProxy now takes its fd and thread caps from the replica's memory and CPU limits instead of the node, so a t1.nano balancer is no longer OOMKilled on nodes with many CPUs. maxconn follows the memory limit at about 16 connections per MiB, 2035 on t1.nano, and the pods roll once on upgrade.

fix(kubernetes): the Proxmox cloud-controller-manager now runs v0.16.1, and the Proxmox CCM and CSI driver images are pinned by digest. The v0.15.0 tag referenced before was re-pushed upstream to a build that panics on start, which left every new Proxmox worker with the uninitialized taint.

fix(marketplace): a tapped repository is pinned to a digest instead of following a mutable tag, so moving the tag upstream no longer changes what runs in the cluster; connect accepts oci://...@sha256:... and an optional keyless cosign verify policy (anchored to an exact identity and preserved across re-connects), and with verify flags the CLI verifies the signature and pins the verified digest at tap time.

fix(dashboard): tenant name in the tenant list links to its detail page now (where Delete is), and top level tenants get their Edit button back.

fix(cilium): the IPAM migration hook no longer fails with "Argument list too long" on clusters with more than a few nodes, which blocked the cilium upgrade and every package that depends on networking.

fix(kubernetes): the OIDC bootstrap Job no longer fails to start for a tenant cluster with about 240 or more oidc.users, the bindings now come from a ConfigMap the Job mounts.

fix(clickhouse): a RestoreJob now restores the archive its Backup was taken as, not the newest one. New Backups record the archive name, Backups taken before this release are restored best effort from the newest archive stamped no later than their takenAt, with a warning in the restore pod log. A ClickHouse BackupJob created again under a name whose Backup still exists now fails instead of reporting that Backup as its result.

fix(backups): the backup controller now re-renders the Velero BSL, the default backup strategies and the platform bucket's credentials Secret when their S3 endpoint is stale, so after the platform bucket's BucketAccess is re-granted for a new publishing.host, backups move to the new endpoint without forcing releases by hand.

fix(securitygroups): a SecurityGroup with attachments and no rules no longer leaves an invalid CiliumNetworkPolicy behind; its backing policy is now accepted by Cilium and still allows or denies nothing.

fix(postgres): the init script renders the declared databases in a stable order, so an upgrade that leaves the databases unchanged no longer rewrites the init-script Secret.

fix(mariadb-operator): the MariaDB operator now uses the platform's networking.clusterDomain instead of a hard-coded cozy.local, so replication and User/Database/Grant reconciliation work on clusters with a non-default cluster domain.

fix(redis): an instance with `replicas: 1` now runs one Sentinel instead of three, without a Sentinel PodDisruptionBudget; on upgrade, the PDB the operator created earlier is deleted. Instances with two replicas or more are unchanged.

fix(lineage, kubernetes): the virt-launcher pods of Kubernetes worker nodes are now resolved to their Kubernetes application and marked as managed by Cozystack, so a SecurityGroup attached to a Kubernetes cluster now applies to its worker nodes, not only to its control plane.

fix(api): tenant quota admission now counts the parent pool's usage of extended resources and hugepages, so a child tenant can no longer get a share the parent has already used. After upgrading, updates to existing tenants may be rejected if their quota for these resources exceeds the parent's remaining budget. This includes updates that leave the quota unchanged.

fix(postgres): a Postgres BackupJob now fails as soon as its CloudNativePG Backup fails, with the recorded error, instead of after 30 minutes, and a BackupJob waiting on a CloudNativePG Backup reports a WaitingForCNPGBackup condition with the Backup's phase.

fix(postgres): databases now refuses the PostgreSQL system databases postgres, template0 and template1, and the init job never runs DROP DATABASE on them. A system database a previous version took over is handed back to the superuser on the next upgrade (event trigger removed, ownership and public schema restored, its <db>_admin and <db>_readonly roles dropped). A release that declares one of them must remove the entry before upgrading.

fix(mariadb): a MariaDB BackupJob or RestoreJob whose operator Job failed now ends Failed instead of Succeeded, and a failed backup no longer creates a Ready Backup without an archive. Backups created by failed runs before this fix are not removed; restoring from one can fail or select another dump from the shared prefix.

fix(kubernetes, monitoring): the vmagent of tenant Kubernetes clusters now writes to the tenant's vminsert and labels series with the owning tenant instead of `cozy-monitoring`. Previously no tenant cluster metric reached the tenant's Monitoring.
```
myasnikovdaniil added a commit that referenced this pull request Nov 12, 2026
## What this PR does

Backports to `release-1.7` from `main`, picked by the rules of the
[backport
policy](https://github.com/cozystack/cozystack/blob/main/docs/release/backports.md)
in merge order. A merged pull request comes as its own commits, picked
with `git cherry-pick -x` so each keeps its author, message and
sign-offs, and a merge commit that carries the original's merge message
with a `Backported-from:` trailer naming it; a squash-merged one comes
as one pick. `backport-batch verify` checks that shape. A pick listed as
changed differs from the commit it came from; `git range-diff
<merge>^1..<merge>^2 <batch merge>^1..<batch merge>^2` shows how. A
conflict or a failing check here is a [backport
task](https://github.com/cozystack/cozystack/blob/main/docs/release/backport-tasks/README.md).

- [#5284](#5284)
`fix(seaweedfs): bump the COSI driver to v0.4.0 for the lost-grant fix`,
1 commit

### Maintainer overrides

- [#5083](#5083)
`fix(workloadmonitor): stop doubling the bucket- prefix in bucket
Workload names`: `backport/skip`, left out
- [#4973](#4973)
`fix(kubernetes-nodes): refuse a partial resources spec on every pool`:
`backport/skip`, left out
- [#5180](#5180) `fix(tests):
keep two unit tests green after the release image restamp`:
`backport/skip`, left out

### Skipped

- Rule 1, already on `release-1.7`: 46
- Rule 2, the title type is not `fix` or `security`, or the scope is
`deps`: 31
- Rule 3, a breaking change: 5
- Rule 4, touches platform migrations, `targetVersion` or a CRD, or
makes a sizeable API change: 2

<details><summary>Rule 1, already on `release-1.7`</summary>

- [#4815](#4815)
`fix(vm-disk): name the importer error in the disk's WorkloadsReady
message`, `its 2 commits picked, the last in 4323363`
- [#4756](#4756)
`fix(backupstrategy-controller): run backup clients on a package-owned
image`, `its 2 commits picked, the last in 4643366`
- [#4293](#4293)
`fix(fluxcd): keep Helm uninstall working during flux-plunger recovery`,
`its 1 commit picked, the last in 0210407`
- [#4791](#4791)
`fix(kubernetes): keep NFS publish from hanging on a dead server`, `its
1 commit picked, the last in fa88bd1`
- [#4830](#4830)
`fix(multus): drop the CPU limit and make resources configurable`, `its
2 commits picked, the last in 363c842`
- [#4865](#4865) `fix(kafka):
pass the container limits to the Kafka JVMs`, `its 3 commits picked, the
last in fc38a54`
- [#4866](#4866)
`fix(linstor): mark volumes restored from a snapshot DRBD-initialized`,
`its 1 commit picked, the last in f9550b7`
- [#4867](#4867) `fix(e2e):
keep chainsaw asserts polling through transient API errors`, `its 1
commit picked, the last in df75adc`
- [#4819](#4819)
`fix(seaweedfs): build SeaweedFS in-tree with a bounded S3 read-ahead`,
`its 5 commits picked, the last in 7f4c346`
- [#3427](#3427)
`fix(backups): prepare standalone VMDisk restore targets and add VM
backup/restore e2e round-trips`, `its 3 commits picked, the last in
4ac0cd5`
- [#4889](#4889)
`fix(monitoring): send alerts to every Alertmanager replica`, `its 1
commit picked, the last in 5033d53`
- [#4929](#4929)
`fix(backups): gate every default Strategy CR on its CRD`, `its 2
commits picked, the last in dee1eef`
- [#4914](#4914)
`fix(fluxcd): close the flux-plunger review follow-ups for the hook,
drain and Warnings`, `its 7 commits picked, the last in a8e4916`
- [#4888](#4888) `fix(ci):
dispatch frozen-line builds with GITHUB_TOKEN`, `its 1 commit picked,
the last in bf81e2d`
- [#4939](#4939)
`fix(cluster-api): resync capi-operator every minute`, `its 1 commit
picked, the last in cc8d6a4`
- [#5027](#5027) `fix(hack):
keep the backup stack in the vminstance selective install`, `its 1
commit picked, the last in 8ba8386`
- [#4955](#4955)
`fix(vm-disk): let CDI adopt the PVC a Velero restore recreates`, `its 2
commits picked, the last in 691d7bc`
- [#4985](#4985) `fix(etcd):
stop counting canceled watch streams as failed gRPC requests`, `its 1
commit picked, the last in 38e4089`
- [#5005](#5005)
`fix(tcp-balancer): cap HAProxy fds and threads by the pod's own
limits`, `its 1 commit picked, the last in 7a3d0b0`
- [#5071](#5071)
`fix(marketplace): do not install a connected repository's components on
connect`, `its 2 commits picked, the last in 25f8f11`
- [#5086](#5086)
`fix(tenant): stop the gateway release waiting on TenantGateway
listeners and certificates`, `its 1 commit picked, the last in
18b2249`
- [#5087](#5087)
`fix(controller): carry healthCheckExprs and waitStrategy to existing
releases`, `its 1 commit picked, the last in d2a452e`
- [#5088](#5088)
`fix(ingress-nginx): drop the admission-webhook policy a rebase brought
back`, `its 1 commit picked, the last in cf00b41`
- [#5142](#5142)
`fix(release): keep release bodies within GitHub's size limit`, `its 1
commit picked, the last in c740515`
- [#4917](#4917)
`fix(kubernetes): run Proxmox CCM v0.16.1 and pin the Proxmox images by
digest`, `its 2 commits picked, the last in 8ff6dca`
- [#4974](#4974)
`fix(kubernetes-nodes): plan autoscaler capacity on the cores the VM
actually gets`, `its 1 commit picked, the last in d68a163`
- [#4971](#4971) `fix(e2e):
keep the Proxmox tenant kubeconfig per run and remove it`, `its 2
commits picked, the last in 77227c5`
- [#4970](#4970) `fix(e2e):
read the KubernetesNodes pool release in the HelmRelease guard`, `its 3
commits picked, the last in 6b17a76`
- [#4972](#4972) `fix(e2e):
validate the leak allowlist against every suite layout`, `its 3 commits
picked, the last in 7ec550b`
- [#5082](#5082)
`fix(marketplace): pin a tapped repository to a digest instead of a
mutable tag`, `its 15 commits picked, the last in 9cff86f`
- [#4004](#4004)
`fix(dashboard): link a tenant row to its detail page`, `its 2 commits
picked, the last in bd5e0b5`
- [#5212](#5212)
`fix(cilium): pass the CiliumNode list to jq on stdin in the IPAM hook`,
`its 1 commit picked, the last in b28a2e2`
- [#5213](#5213)
`fix(kubernetes): move the OIDC users out of the bootstrap Job's
script`, `its 1 commit picked, the last in 02dd8e5`
- [#5208](#5208)
`fix(clickhouse): restore the archive a Backup was taken as`, `its 3
commits picked, the last in 9ded5c5`
- [#5230](#5230)
`fix(backups): re-render the default backup objects when the S3 endpoint
changes`, `its 8 commits picked, the last in 490eab5`
- [#5133](#5133)
`fix(securitygroups): project a membership-only group to a policy Cilium
accepts`, `its 1 commit picked, the last in b7c50a5`
- [#5091](#5091)
`fix(postgres): render the declared databases in a stable order`, `its 1
commit picked, the last in b658dff`
- [#5123](#5123)
`fix(mariadb-operator): derive the cluster name from the platform
domain`, `its 2 commits picked, the last in 17702dd`
- [#5151](#5151) `fix(redis):
run one Sentinel when Redis runs a single pod`, `its 5 commits picked,
the last in 5524a41`
- [#5124](#5124)
`fix(lineage, kubernetes): resolve CAPK node VMs to their cluster`, `its
2 commits picked, the last in c908560`
- [#5184](#5184) `fix(api):
read pool usage under the quota key the controller counts`, `its 1
commit picked, the last in 18c17af`
- [#5190](#5190)
`fix(platform): remove the dead registries value and patch-containerd
Secret`, `its 2 commits picked, the last in 617f889`
- [#5211](#5211)
`fix(postgres): fail a backup job as soon as its cnpg Backup fails`,
`its 1 commit picked, the last in 6645e21`
- [#5155](#5155)
`fix(postgres): refuse system databases and never drop them`, `its 1
commit picked, the last in 6f1bb80`
- [#5207](#5207)
`fix(mariadb): fail backup and restore jobs whose operator Job failed`,
`its 5 commits picked, the last in ef3de55`
- [#5024](#5024)
`fix(kubernetes, monitoring): send tenant cluster metrics to the
tenant's vminsert`, `its 1 commit picked, the last in 423a75b`

</details>

<details><summary>Rule 2, the title type is not `fix` or `security`, or
the scope is `deps`</summary>

- [#4845](#4845)
`docs(governance): welcome new contributors and link LF sanctions
guidance`, `type docs`
- [#4881](#4881)
`feat(bucket): add a ui flag to skip the s3manager web UI`, `type feat`
- [#4899](#4899) `chore: link
the FOSSA license scan for CLOMonitor`, `type chore`
- [#4898](#4898)
`feat(backups): back up Valkey with the Redis strategy`, `type feat`
- [#4940](#4940)
`docs(release): add changelog for v1.6.5`, `type docs`
- [#4861](#4861)
`feat(release): sign the release assets and attach a source SBOM`, `type
feat`
- [#3780](#3780) `docs: move
the operator guides out of docs/ to where readers find them`, `type
docs`
- [#4936](#4936)
`docs(release): check changelog claims against the code`, `type docs`
- [#4959](#4959)
`docs(release): point changelog check B at the Talos installer profile`,
`type docs`
- [#3777](#3777)
`docs(agents): define where a new document belongs`, `type docs`
- [#5025](#5025)
`test(harbor): pin the resources of the nginx proxy and the portal`,
`type test`
- [#5039](#5039)
`feat(keycloak): load additional CA files from Secret or ConfigMap
keys`, `type feat`
- [#4860](#4860)
`feat(kubernetes-nodes): trust a factory CA in the Proxmox template
script`, `type feat`
- [#5090](#5090) `ci(e2e):
end the Proxmox lane's SSH key with a newline`, `type ci`
- [#4969](#4969)
`test(kubernetes): pin RetryOnFailure on the Proxmox csi release`, `type
test`
- [#5000](#5000)
`test(kubernetes): name the Proxmox fixture's node pool
<cluster>-<pool>`, `type test`
- [#5168](#5168)
`docs(agents): steer agents away from Helm lookup`, `type docs`
- [#4997](#4997)
`feat(release): attach an SBOM to every release image`, `type feat`
- [#3440](#3440)
`ci(api-review-gate): publish the gate as a commit status`, `type ci`
- [#5034](#5034) `docs: move
the repo-only guides onto the website`, `type docs`
- [#5215](#5215)
`feat(monitoring-agents): export PVC labels from kube-state-metrics`,
`type feat`
- [#5217](#5217)
`feat(monitoring-agents): keep application identity in container log
streams`, `type feat`
- [#5171](#5171) `feat(api):
expose HelmRelease failure state on Application status`, `type feat`
- [#5237](#5237)
`feat(operator): let the platform source trust a private registry CA`,
`type feat`
- [#5106](#5106)
`feat(release): make backports automatic with backport-batch`, `type
feat`
- [#4983](#4983) `feat(api):
add the reservation evaluator for tenant quotas`, `type feat`
- [#5264](#5264)
`feat(release): keep a line's backport record and reports across batch
pull requests`, `type feat`
- [#5260](#5260) `ci(e2e):
skip final cleanup on disposable PR runners`, `type ci`
- [#5046](#5046)
`feat(backups): record the RDB snapshot location and size for Redis
backups`, `type feat`
- [#5214](#5214)
`feat(observability-proxy): serve tenant namespace logs through an
authorizing proxy`, `type feat`
- [#5282](#5282)
`test(release): isolate report deduplication from workflow attempts`,
`type test`

</details>

<details><summary>Rule 3, a breaking change</summary>

- [#4790](#4790)
`fix(platform)!: refuse a networking variant change on a live cluster`,
`! in the title`
- [#4796](#4796)
`fix(vm-disk)!: refuse a golden-image clone CDI would leave unbound`, `!
in the title`
- [#5085](#5085)
`fix(kubernetes, opensearch, foundationdb)!: restrict managed
application images`, `! in the title`
- [#4818](#4818)
`fix(keycloak)!: make the KMS proxy keep its keys across restarts`, `!
in the title`
- [#5167](#5167)
`fix(monitoring-agents)!: isolate merged log payload under
log_processed`, `! in the title`

</details>

<details><summary>Rule 4, touches platform migrations, `targetVersion`
or a CRD, or makes a sizeable API change</summary>

- [#4941](#4941)
`fix(backups): keep the backupstrategy-controller Helm release under the
Secret size limit`, `a sizeable API change (breaking-change: [v1alpha1]
spec.spec.template: field "metadata" was removed, and 5 more), a CRD`
- [#5223](#5223)
`fix(backups): report sizeBytes for MariaDB and CNPG backup artifacts`,
`a CRD`

</details>

```backport-batch
{"version":2,"line":"release-1.7","built":{"main":"76a34d3e53a14c39d8df63eec6271c2eaae5ffea","line":"3cd9d4c220b519972677c7ff756ae6c4db07ef4a","newer":"","policy":"76a34d3e53a14c39d8df63eec6271c2eaae5ffea","batch":"e27d6630a0008381f0bc105a87d117dfcc29680f","tool":"76a34d3e53a14c39d8df63eec6271c2eaae5ffea","run":"https://github.com/cozystack/cozystack/actions/runs/43209950053","at":"2026-11-12T11:33:16Z","options":{"noWorkflowFiles":true,"mode":"new"}},"report":"9ca0285a0bb30a09736f6a430878b3ce0d32a2811639861e80daa549f208d7b3","closing":null,"deferred":[],"dropped":[],"stale":[]}
```

```backport-batch-report
{"format":1,"id":"9ca0285a0bb30a09736f6a430878b3ce0d32a2811639861e80daa549f208d7b3","line":"release-1.7","built":{"main":"76a34d3e53a14c39d8df63eec6271c2eaae5ffea","line":"3cd9d4c220b519972677c7ff756ae6c4db07ef4a","newer":"","policy":"76a34d3e53a14c39d8df63eec6271c2eaae5ffea","batch":"e27d6630a0008381f0bc105a87d117dfcc29680f","tool":"76a34d3e53a14c39d8df63eec6271c2eaae5ffea","run":"https://github.com/cozystack/cozystack/actions/runs/43209950053","at":"2026-11-12T11:33:16Z","options":{"noWorkflowFiles":true,"mode":"new"}},"overrides":{"backport/include":[],"backport/skip":[4973,5083,5180]},"primary":{"picked":[5284],"missing":[],"deferred":[],"parked":[],"skipped":{"on-line":[3427,4004,4293,4756,4791,4815,4819,4830,4865,4866,4867,4888,4889,4914,4917,4929,4939,4955,4970,4971,4972,4974,4985,5005,5024,5027,5071,5082,5086,5087,5088,5091,5123,5124,5133,5142,5151,5155,5184,5190,5207,5208,5211,5212,5213,5230],"before-start":[],"type":[3440,3777,3780,4845,4860,4861,4881,4898,4899,4936,4940,4959,4969,4983,4997,5000,5025,5034,5039,5046,5090,5106,5168,5171,5214,5215,5217,5237,5260,5264,5282],"breaking":[4790,4796,4818,5085,5167],"touches":[4941,5223],"newer":[],"skip-label":[4973,5083,5180],"dropped":[]}},"overlays":{"dropped":[],"stale":[],"changed":[]},"diag":{},"other":[]}
```

### Screenshots

See the original pull requests.

### Downstream repositories

- [ ] No downstream repository is affected by this change
- [ ] [cozystack/website](https://github.com/cozystack/website) -
follow-up:
- [ ]
[cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack)
- follow-up:
- [ ]
[cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack)
- follow-up:
- [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up:
- [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up:
- [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) -
follow-up:
- [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) -
follow-up:
- [ ]
[cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server)
- follow-up:
- [ ]
[cozystack/external-apps-example](https://github.com/cozystack/external-apps-example)
- follow-up:
- [ ] [cozystack/examples](https://github.com/cozystack/examples) -
follow-up:
- [ ] [cozystack/community](https://github.com/cozystack/community) -
follow-up:

### Release note

```release-note
fix(seaweedfs): bucket users granted together could get S3 keys that never work (403 InvalidAccessKeyId). COSI driver is bumped to v0.4.0, which writes each grant to per-identity IAM file.
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/storage Issues or PRs related to storage (linstor, seaweedfs, bucket, velero, harbor) kind/bug Categorizes issue or PR as related to a bug size/L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[backupstrategy-controller] Replace platform-migrations with a dedicated ch-backup-client image

3 participants