fix(release): pin AuthBridge injection images + guard against :latest (#508) - #512
Conversation
The operator chart pinned the cortex-built AuthBridge injection images (authbridge, -envoy, -lite, proxy-init) at :latest — non-reproducible, and release.yml only pins the controller-manager image, so every release shipped :latest (#508). Pin them to cortex v0.7.0-alpha.3, and add a release.yml guard that fails the release if any injected image is a floating tag so it can't regress silently. Closes #508 Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: cwiklik <cwiklikj@gmail.com>
huang195
left a comment
There was a problem hiding this comment.
Dobra robota — the pin is correct and verified: v0.7.0-alpha.3 is cortex's current release (published 14 min before this PR) and cortex's Build-Publish matrix tags all four images with github.ref_name on tag push, run green. Guard logic is sound (CHARTS_PATH resolves, grep under if is errexit-safe).
Three non-blocking notes: the guard fires after the operator images are already pushed, it's a 3-tag deny-list rather than a positive pin assertion, and the compiled Go defaults in defaults.go still carry :latest where the grep can't reach them.
One question: the guard happily passes a prerelease tag, so operator v0.7.0 GA would ship cortex alpha images. Intended, or does the GA cut need a re-pin once cortex has a v0.7.0?
Areas reviewed: CI/GitHub Actions, Helm values · Agent/IDE config (.claude/.vscode): none · Commits: 1, all signed-off: yes · CI: 16 pass, E2E pending
Assisted-By: Claude Code
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Guard — injected AuthBridge images must be version-pinned (no floating tags) |
There was a problem hiding this comment.
Guard sits in the release job, which is needs: build-and-push + if: ref_type == 'tag'. By the time it fails, kagenti-operator and agentcard-signer are already built and pushed to ghcr with the release tag — half-published release (images out, chart not), manual cleanup.
Two cheaper spots: a pre-flight job that build-and-push depends on, or the Helm Chart Lint job in security-scans.yaml which runs on every PR — then a :latest regression is caught at review time, not mid-release.
| # Fail the release if any is a floating tag so it can never regress silently. | ||
| run: | | ||
| cd ${{ env.CHARTS_PATH }}/operator | ||
| if grep -nE 'ghcr\.io/rossoctl/cortex/[a-z-]+:(latest|main|master)([^0-9a-zA-Z.-]|$)' values.yaml; then |
There was a problem hiding this comment.
Deny-list of 3 tag names + hardcoded registry path. These all pass the guard:
- no tag at all (
.../authbridge-envoy→ implicit:latest) :dev/:edge/:nightly- any move off
ghcr.io/kagenti/kagenti-extensions/
Positive assertion is strictly tighter, and yq is already installed in this job:
for k in envoyProxy authbridge authbridgeLite proxyInit; do
img=$(yq ".defaults.images.$k" values.yaml)
[[ "$img" =~ :v[0-9]+\.[0-9]+\.[0-9]+ ]] || { echo "::error::defaults.images.$k not version-pinned: $img"; exit 1; }
doneKeys the check on the 4 values that matter instead of on the registry string.
| authbridge: ghcr.io/rossoctl/cortex/authbridge:latest | ||
| authbridgeLite: ghcr.io/rossoctl/cortex/authbridge-lite:latest | ||
| proxyInit: ghcr.io/rossoctl/cortex/proxy-init:latest | ||
| envoyProxy: ghcr.io/rossoctl/cortex/authbridge-envoy:v0.7.0-alpha.3 |
There was a problem hiding this comment.
Chart layer pinned, compiled fallback not: operator/internal/webhook/config/defaults.go:34-45 still has all four at :latest, and loader.go:45 overlays the ConfigMap on top of CompiledDefaults() (fields absent from the file keep the compiled value). So any deploy without kagenti-platform-config — kustomize make deploy, or webhook.enable=false where the ConfigMap isn't rendered — still injects :latest. The new grep only reads values.yaml, so it will never catch it.
defaults.go already carries a Keep in sync with charts/operator/values.yaml comment for the spiffe-helper config; same treatment fits here.
Related: operator/test/e2e/e2e_suite_test.go:66-69 still pulls :latest (and is missing authbridge-lite), so e2e never exercises the images the chart actually ships.
The chart-layer pin (values.yaml) didn't cover the compiled fallbacks in config/defaults.go, which loader.go overlays the platform-config ConfigMap on top of. Any deploy without that ConfigMap (kustomize make deploy, or webhook.enable=false) therefore still injected :latest — the exact paths the values.yaml grep guard can't see. Pin all four compiled defaults to v0.7.0-alpha.3 to match the chart, with a keep-in-sync note. Also pin the e2e sidecar images (they still pulled :latest, so e2e never exercised the shipped tags) and add the missing authbridge-lite image. Addresses review feedback on #512. Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: cwiklik <cwiklikj@gmail.com>
….go (#508) Addresses review feedback on #512 (findings #1 and #2): - #1 (guard runs too late): the release.yml guard only fired after build-and-push had already pushed the operator images, risking a half-published release. Add the same check to the Helm Chart Lint job in security-scans.yaml, which runs on every PR, so a :latest regression is caught at review time. - #2 (deny-list too loose): replace the 3-tag deny-list with a positive :vX.Y.Z assertion over the four defaults.images.* keys (via yq), which also rejects untagged/:dev/:edge and registry moves. - Both checks now also cover operator/internal/webhook/config/defaults.go (loader.go overlays the ConfigMap on top of these compiled fallbacks), so a regression in the Go defaults is caught too — not just values.yaml. Verified locally: guard passes on the pinned state and errors on :latest and untagged images; both workflow files parse. Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: cwiklik <cwiklikj@gmail.com>
Summary
The operator chart pinned the cortex-built AuthBridge injection images (
authbridge,authbridge-envoy,authbridge-lite,proxy-init) at:latestincharts/operator/values.yaml.release.ymlonly pins the controller-manager image, so every published operator-chart shipped:latestfor the injected images — non-reproducible (surfaced during the v0.7.0 GA cut).Changes
:latest→v0.7.0-alpha.3(current cortex release; all 4 images published).release.yml: fail the release if any injected image is a floating tag (:latest/:main/:master) — so it can't regress silently.Closes #508
Assisted-By: Claude Code