fix(cnpg-barman): take the sidecar tag out of base64 and track it #536

Merged
k.renner merged 1 commits from fix-barman-sidecar-visible into master 2026-08-20 10:59:28 +00:00
Member

Fixes #535.

The problem

An image reference is not a secret. Encoding it as base64 data had two concrete costs:

  • no reviewer sees a version change in a diff
  • no $imagepolicy marker can attach to a base64 blob

Result: a two-minor version skew in the component that performs every base backup and WAL archive for seven Postgres clusters.

controller  plugin-barman-cloud:v0.14.0          <- auto-bumped by Flux
sidecar     plugin-barman-cloud-sidecar:v0.12.0  <- invisible, never moved

Not stale pods — ha-pg-1 was created hours ago during the recorder migration and still received v0.12.0.

Before:

data:
  SIDECAR_IMAGE: |
    Z2hjci5pby9jbG91ZG5hdGl2ZS1wZy9wbHVnaW4tYmFybWFuLWNsb3VkLXNpZGVjYXI6dj
    AuMTIuMA==

After:

stringData:
  SIDECAR_IMAGE: ghcr.io/cloudnative-pg/plugin-barman-cloud-sidecar:v0.14.0 # {"$imagepolicy": "flux-system:cnpg-barman-plugin-sidecar"}

Three changes

  1. stringData with the tag in plaintext + marker. The Secret kind is kept deliberately — the controller reads it via secretKeyRef, so a ConfigMap would need a matching edit and diverge further from upstream. stringData is accepted identically by the API server.
  2. ImageRepository + ImagePolicy for the sidecar, same filter and 0.x range as the controller, so the two cannot drift apart again. Only the controller was tracked before.
  3. Tag aligned to v0.14.0.

Verified before pinning

Pinning a non-existent tag would put all seven Postgres clusters into ImagePullBackOff, so I confirmed the image is pullable first:

$ kubectl run sidecar-tag-check --image=...sidecar:v0.14.0 --command -- true
error during container init: exec: "true": executable file not found in $PATH

The pull succeeded — that failure is the container command, not the image.

Also verified in the render that the Secret name is unchanged (it carries a kustomize hash suffix from upstream secretGenerator but is static here), so the deployment secretKeyRef stays valid — the name still appears twice, on the Secret and its reference.

Expected impact

Changing the sidecar tag changes every Postgres pod spec, so all seven CNPG clusters roll. CNPG handles it as a normal rolling restart.

I will confirm backups still work afterwards — 113 Backup CRs exist today, newest ~3h old and completed.

Note for future re-imports

Upstream ships this Secret as base64 data with no marker, so a wholesale re-import silently reintroduces the skew. The manifest now says so inline, next to the block.

Not fixed here

This does not fix #522 — the empty lastSuccessfulBackup is a plugin feature gap (v0.6.0 added only the failed status field), not version skew. Bumping the sidecar will not enable backup-age alerting.

🤖 Generated with Claude Code

Fixes #535. ## The problem An image reference is not a secret. Encoding it as base64 `data` had two concrete costs: - **no reviewer sees a version change in a diff** - **no `$imagepolicy` marker can attach to a base64 blob** Result: a two-minor version skew in the component that performs every base backup and WAL archive for seven Postgres clusters. ``` controller plugin-barman-cloud:v0.14.0 <- auto-bumped by Flux sidecar plugin-barman-cloud-sidecar:v0.12.0 <- invisible, never moved ``` Not stale pods — `ha-pg-1` was created hours ago during the recorder migration and still received v0.12.0. Before: ```yaml data: SIDECAR_IMAGE: | Z2hjci5pby9jbG91ZG5hdGl2ZS1wZy9wbHVnaW4tYmFybWFuLWNsb3VkLXNpZGVjYXI6dj AuMTIuMA== ``` After: ```yaml stringData: SIDECAR_IMAGE: ghcr.io/cloudnative-pg/plugin-barman-cloud-sidecar:v0.14.0 # {"$imagepolicy": "flux-system:cnpg-barman-plugin-sidecar"} ``` ## Three changes 1. **`stringData` with the tag in plaintext + marker.** The Secret *kind* is kept deliberately — the controller reads it via `secretKeyRef`, so a ConfigMap would need a matching edit and diverge further from upstream. `stringData` is accepted identically by the API server. 2. **ImageRepository + ImagePolicy for the sidecar**, same filter and `0.x` range as the controller, so the two cannot drift apart again. Only the controller was tracked before. 3. **Tag aligned to v0.14.0.** ## Verified before pinning Pinning a non-existent tag would put **all seven Postgres clusters into ImagePullBackOff**, so I confirmed the image is pullable first: ``` $ kubectl run sidecar-tag-check --image=...sidecar:v0.14.0 --command -- true error during container init: exec: "true": executable file not found in $PATH ``` The pull succeeded — that failure is the container *command*, not the image. Also verified in the render that the Secret name is unchanged (it carries a kustomize hash suffix from upstream `secretGenerator` but is static here), so the deployment `secretKeyRef` stays valid — the name still appears twice, on the Secret and its reference. ## Expected impact Changing the sidecar tag changes every Postgres pod spec, so **all seven CNPG clusters roll**. CNPG handles it as a normal rolling restart. I will confirm backups still work afterwards — 113 Backup CRs exist today, newest ~3h old and `completed`. ## Note for future re-imports Upstream ships this Secret as base64 `data` with no marker, so a wholesale re-import silently reintroduces the skew. The manifest now says so inline, next to the block. ## Not fixed here This does **not** fix #522 — the empty `lastSuccessfulBackup` is a plugin feature gap (v0.6.0 added only the *failed* status field), not version skew. Bumping the sidecar will not enable backup-age alerting. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
claude-bot added 1 commit 2026-08-20 10:50:54 +00:00
fix(cnpg-barman): take the sidecar tag out of base64 and track it
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
ci/woodpecker/pr/pr-review Pipeline was successful
154c933177
An image reference is not a secret. Encoding it as base64 `data` had two real
costs: no reviewer sees a version change in a diff, and no $imagepolicy marker
can attach to a base64 blob.

The result was a two-minor version skew in the component that performs every
base backup and WAL archive for seven Postgres clusters (#535):

  controller  plugin-barman-cloud:v0.14.0          <- auto-bumped by Flux
  sidecar     plugin-barman-cloud-sidecar:v0.12.0  <- invisible, never moved

Not stale pods: ha-pg-1 was created hours ago during the recorder migration and
still received v0.12.0.

Three changes:

  1. The Secret now uses stringData with the tag in plaintext, carrying an
     $imagepolicy marker. The Secret KIND is kept because the controller reads it
     via secretKeyRef; switching to a ConfigMap would need a matching edit to that
     reference and diverge further from upstream. stringData is accepted
     identically by the API server.

  2. ImageRepository + ImagePolicy added for the sidecar image, with the same
     filter and 0.x range as the controller, so the two cannot drift apart again.
     Only the controller was tracked before.

  3. Tag aligned to v0.14.0 to match the controller.

The Secret name carries a kustomize hash suffix from upstream's secretGenerator
but is static here, so editing the value does not change the name and the
deployment's secretKeyRef stays valid — verified in the render, which still shows
the name twice (Secret + reference).

Verified the tag EXISTS before pinning it: pulling
plugin-barman-cloud-sidecar:v0.14.0 succeeds (the pod fails later on a missing
`true` binary in that minimal image, which is the container command, not the
pull). Pinning a non-existent tag would have put all seven Postgres clusters into
ImagePullBackOff.

EXPECTED IMPACT: bumping the sidecar changes every Postgres pod spec, so all
seven CNPG clusters roll. CNPG handles this as a normal rolling restart. Backups
should be confirmed working afterwards — 113 Backup CRs exist today, newest ~3h
old and completed.

Note for future re-imports: upstream ships this Secret as base64 `data` with no
marker, so a wholesale re-import silently reintroduces the skew. The manifest now
says so inline.

Refs #535

Co-Authored-By: Claude Bot <noreply@anthropic.com>
review-bot left a comment
Member

🤖 Automated review — model CLI default (complexity: complex), commit 154c933177234d59b58ed9b01cef125469545812.

Advisory review by the review-bot pipeline. It never approves; a human merges. Push new commits to get a fresh review.


Summary

This PR fixes a real, previously-invisible version-skew bug: the CNPG Barman
plugin sidecar image tag was base64-encoded inside a Secret's data, so Flux's
image-automation could never find it, and it silently trailed the controller by
two minor versions. The fix (a) switches the Secret to stringData with a
plaintext tag and $imagepolicy marker, (b) adds a matching ImageRepository

  • ImagePolicy pair to track the sidecar going forward, and (c) bumps the tag
    to v0.14.0. I independently verified the mechanics below and found no
    correctness or security issues — only a documentation gap.

🟡 Suggestions

  • kubernetes/infrastructure/image-automation/README.md — the "Re-import
    hazard: cnpg-barman-plugin" section (lines 122–130) and the "Currently
    enrolled" table row (line 56) still describe only the controller's marker
    (plugin-barman-cloud on the image line) being at risk from a wholesale
    upstream re-import. This PR adds a second marker in the same
    upstream-imported file (the Secret's stringData.SIDECAR_IMAGE), which is
    exactly as vulnerable to being clobbered by a re-import and isn't mentioned
    there — even though the in-manifest comment added by this PR
    (manifest.yaml:936-937) does call it out locally. A future maintainer who
    goes to the README section specifically written for this hazard (rather than
    reading the manifest's inline comments first) would only restore one of the
    two markers. Worth a one-line addition to that section and the table.

Tests

No unit tests apply to this kind of change; the repo's relevant gate is the
kustomize-build step in .woodpecker/ci-manifests-test.yml, which runs
kubectl kustomize over every kustomization directory including both edited
ones (kubernetes/infrastructure/cnpg-barman-plugin and
kubernetes/infrastructure/image-automation), catching YAML/wiring breakage.
I manually reviewed both files for structural correctness (see below) since I
could not execute kubectl/kustomize in this environment.

Verification performed against the checkout:

  • Decoded the removed base64 blob — it is exactly
    ghcr.io/cloudnative-pg/plugin-barman-cloud-sidecar:v0.12.0, confirming the
    PR's stated before-state.
  • Confirmed the Secret name plugin-barman-cloud-kg5c2795f7
    (manifest.yaml:943) is unchanged and is referenced via
    secretKeyRef.name/key: SIDECAR_IMAGE at manifest.yaml:996-1000, so the
    Deployment's env var still resolves correctly under stringData.
  • Confirmed kubernetes/infrastructure/cnpg-barman-plugin/kustomization.yaml
    has no secretGenerator/name-hash transformer, so the "name is static, not
    regenerated" claim in the new comment holds.
  • Confirmed the controller image is already pinned to v0.14.0
    (manifest.yaml:1001), so the sidecar bump to the same version does align
    the two components as intended, and both now sit inside the shared 0.x
    policy range.
  • Confirmed the new ImagePolicy name (cnpg-barman-plugin-sidecar in
    flux-system) matches the marker
    {"$imagepolicy": "flux-system:cnpg-barman-plugin-sidecar"}, and the filter
    regex ^v(?P<ver>\d+\.\d+\.\d+)$ matches v0.14.0.
  • Confirmed cnpg-barman-plugin.yaml is already listed in
    image-automation/kustomization.yaml, so the two new resources (added as
    extra YAML docs in an existing file) need no kustomization edit.

Recommendation

Looks reasonable — no blocking issues; the documentation-gap comment above is optional.

🤖 **Automated review** — model `CLI default` (complexity: complex), commit `154c933177234d59b58ed9b01cef125469545812`. > Advisory review by the `review-bot` pipeline. It never approves; a human merges. Push new commits to get a fresh review. --- ## Summary This PR fixes a real, previously-invisible version-skew bug: the CNPG Barman plugin sidecar image tag was base64-encoded inside a Secret's `data`, so Flux's image-automation could never find it, and it silently trailed the controller by two minor versions. The fix (a) switches the Secret to `stringData` with a plaintext tag and `$imagepolicy` marker, (b) adds a matching `ImageRepository` + `ImagePolicy` pair to track the sidecar going forward, and (c) bumps the tag to v0.14.0. I independently verified the mechanics below and found no correctness or security issues — only a documentation gap. ## 🟡 Suggestions - **`kubernetes/infrastructure/image-automation/README.md`** — the "Re-import hazard: cnpg-barman-plugin" section (lines 122–130) and the "Currently enrolled" table row (line 56) still describe only the *controller's* marker (`plugin-barman-cloud` on the image line) being at risk from a wholesale upstream re-import. This PR adds a second marker in the same upstream-imported file (the Secret's `stringData.SIDECAR_IMAGE`), which is exactly as vulnerable to being clobbered by a re-import and isn't mentioned there — even though the in-manifest comment added by this PR (`manifest.yaml:936-937`) does call it out locally. A future maintainer who goes to the README section specifically written for this hazard (rather than reading the manifest's inline comments first) would only restore one of the two markers. Worth a one-line addition to that section and the table. ## Tests No unit tests apply to this kind of change; the repo's relevant gate is the `kustomize-build` step in `.woodpecker/ci-manifests-test.yml`, which runs `kubectl kustomize` over every kustomization directory including both edited ones (`kubernetes/infrastructure/cnpg-barman-plugin` and `kubernetes/infrastructure/image-automation`), catching YAML/wiring breakage. I manually reviewed both files for structural correctness (see below) since I could not execute `kubectl`/`kustomize` in this environment. Verification performed against the checkout: - Decoded the removed base64 blob — it is exactly `ghcr.io/cloudnative-pg/plugin-barman-cloud-sidecar:v0.12.0`, confirming the PR's stated before-state. - Confirmed the Secret name `plugin-barman-cloud-kg5c2795f7` (`manifest.yaml:943`) is unchanged and is referenced via `secretKeyRef.name`/`key: SIDECAR_IMAGE` at `manifest.yaml:996-1000`, so the Deployment's env var still resolves correctly under `stringData`. - Confirmed `kubernetes/infrastructure/cnpg-barman-plugin/kustomization.yaml` has no `secretGenerator`/name-hash transformer, so the "name is static, not regenerated" claim in the new comment holds. - Confirmed the controller image is already pinned to `v0.14.0` (`manifest.yaml:1001`), so the sidecar bump to the same version does align the two components as intended, and both now sit inside the shared `0.x` policy range. - Confirmed the new `ImagePolicy` name (`cnpg-barman-plugin-sidecar` in `flux-system`) matches the marker `{"$imagepolicy": "flux-system:cnpg-barman-plugin-sidecar"}`, and the filter regex `^v(?P<ver>\d+\.\d+\.\d+)$` matches `v0.14.0`. - Confirmed `cnpg-barman-plugin.yaml` is already listed in `image-automation/kustomization.yaml`, so the two new resources (added as extra YAML docs in an existing file) need no kustomization edit. ## Recommendation Looks reasonable — no blocking issues; the documentation-gap comment above is optional. <!-- pr-review:sha=154c933177234d59b58ed9b01cef125469545812 -->
k.renner merged commit e8ad1f704e into master 2026-08-20 10:59:28 +00:00
Sign in to join this conversation.