Skip to content

Resolve the latest release image to a published version - #7786

Open
CharlieTLe wants to merge 3 commits into
cortexproject:masterfrom
CharlieTLe:release-1.22-pr-a-fix-latest-release-image
Open

Resolve the latest release image to a published version#7786
CharlieTLe wants to merge 3 commits into
cortexproject:masterfrom
CharlieTLe:release-1.22-pr-a-fix-latest-release-image

Conversation

@CharlieTLe

@CharlieTLe CharlieTLe commented Aug 20, 2026

Copy link
Copy Markdown
Member

What this fixes

getLatestReleaseImage() in integration/util.go derives the "latest release" image
straight from the VERSION file, and .github/workflows/test-build-deploy.yml mirrors it
as docker pull quay.io/cortexproject/cortex:v$(cat testdata/VERSION).

That holds on master, where VERSION is the last GA and its image exists. It does not
hold on a release branch: VERSION is bumped to the version being prepared (e.g.
1.22.0-rc.0) long before anything publishes that tag, and the deploy job that would
publish it has needs: [build, test, lint, integration]. So the integration_query_fuzz
leg would try to pull an image that does not exist yet, and release-1.22 would be red
from the moment VERSION gains its -rc.0 suffix.

The same applies on the GA tag push, where VERSION is 1.22.0 with no suffix: the
v1.22.0 image is only pushed by deploy, which again runs after integration.

This mechanism landed in #7737 (2026-07-30), after v1.21.1, so it has never been through
a release.

The fix

VERSION names the version being prepared, so it cannot answer "what is published".
The registry can, so ask it — thanks @SungJin1212 for the suggestion.

A new Resolve Latest Release Image step lists the GA tags (^v\d+\.\d+\.\d+$) published
to quay.io, takes the highest one that does not exceed VERSION, and exports it as
CORTEX_LATEST_RELEASE_IMAGE for the preload and test steps. It runs only on the
integration_query_fuzz matrix leg, which is the only caller of getLatestReleaseImage().

Against a registry whose newest GA is v1.21.1:

VERSION resolves to
1.21.1 v1.21.1 master's steady state
1.22.0-rc.0 v1.21.1 release branch preparing a minor
1.22.0 v1.21.1 the GA tag build
1.21.2-rc.0 v1.21.1 release branch preparing a patch
2.0.0-rc.0 v1.21.1 a major pre-release
1.19.0 v1.19.0 an older branch — note it does not jump forward
1.19.5-rc.0 v1.19.1 the newest published patch, not a guessed 1.19.4

The <= bound (rather than simply "the newest published GA tag") only changes the result
when a newer release already exists on quay than the branch being tested, e.g. preparing
1.21.2 on release-1.21 after v1.22.0 has shipped.

Setting the CORTEX_LATEST_RELEASE_IMAGE repository variable bypasses the lookup
entirely.

The bash mirror of the Go derivation is gone. latestReleaseVersion() stays in
integration/util.go as the offline fallback for local runs, where nothing sets the env
var and a network call is unwelcome; CI always resolves against the registry.

Verification

  • The workflow step was extracted from the YAML and run under bash -e (what Actions
    actually uses — no pipefail, no nounset) against the live registry, producing every
    row in the table above, plus errors for a VERSION below everything published and for a
    malformed VERSION. The repository-variable override was exercised too.
  • shellcheck is clean on the step. actionlint reports the same 13 pre-existing SC2086
    findings as master and no new ones.
  • latestReleaseVersion() keeps its table test; getLatestReleaseImage() is tested end to
    end against a scratch checkout and for the env override.
  • go vet passes with every integration build tag set.

@dosubot dosubot Bot added ci/cd go Pull requests that update Go code labels Aug 20, 2026
@CharlieTLe
CharlieTLe requested review from a team and danielblando and removed request for a team August 20, 2026 19:09
@SungJin1212

SungJin1212 commented Sep 7, 2026

Copy link
Copy Markdown
Member

Thanks for catching this.

I think the issue with this PR is:
When we push the v1.22.0 tag, VERSION is 1.22.0, and this resolves to quay.io/cortexproject/cortex:v1.22.0. That image is published by deploy, and deploy needs integration to pass.

Can we ask the registry what is actually published? The registry is the only source of truth for "published".

  1. Pick the highest published GA tag (^v\d+\.\d+\.\d+$) that is <= the base of VERSION
    ㄴ The <= bound only changes the result when a newer release already exists on quay than the branch being tested (e.g. preparing 1.21.2 on release-1.21 after v1.22.0 shipped).
  2. Export it as CORTEX_LATEST_RELEASE_IMAGE

CharlieTLe added a commit to CharlieTLe/cortex that referenced this pull request Sep 8, 2026
Deriving the previous release from VERSION alone left one case broken, as
SungJin1212 pointed out on cortexproject#7786: on the GA tag push VERSION is 1.22.0 with no
pre-release suffix, so it resolves to v1.22.0 — an image that only `deploy`
publishes, and `deploy` needs `integration` to pass first.

Ask quay.io what actually exists instead. The registry is the only source of
truth for "published", so list the GA tags (^v\d+\.\d+\.\d+$) and take the
highest one that does not exceed VERSION, then export it as
CORTEX_LATEST_RELEASE_IMAGE for the preload and test steps.

The <= bound only changes the result when a newer release already exists on
quay than the branch being tested, e.g. preparing 1.21.2 on release-1.21 after
v1.22.0 has shipped.

This also drops the bash mirror of the Go derivation, and stops guessing at the
previous minor's .0: with the registry answering, 1.19.5-rc.0 resolves to the
v1.19.1 that exists rather than a v1.19.4 that never shipped, and a major
pre-release such as 2.0.0-rc.0 no longer needs a manual override.

The derivation stays in integration/util.go as the offline fallback for local
runs, where no env var is set and no network call is wanted.

Signed-off-by: Charlie Le <charlie_le@apple.com>
@CharlieTLe
CharlieTLe requested a review from a team as a code owner September 8, 2026 18:06
Comment thread integration/util_test.go Outdated
@@ -0,0 +1,94 @@
//go:build integration

@SungJin1212 SungJin1212 Sep 8, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The discover-tags job excludes integration so util.test cannot be tested. We need to use something like an integration_query_fuzz.

done < <(grep -hE "^//go:build " integration/*.go \
         | sed -E 's|^//go:build ||' \
         | sort -u | grep -v '^integration$')

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch, and it was worse than dead weight — thank you.

You're right that nothing ran. The binary did compile them, since the compile step sets ALL_TAGS="slicelabels,integration,${tags_csv}", but Generate Run-Pattern Manifest iterates tags_csv alone, so no -test.run regex ever named them. I reproduced the pattern generation across all 12 matrix tags and every one selected zero of the three functions.

Moved to integration_query_fuzz in 58b5278, since that's the only leg calling getLatestReleaseImage().

Retagging then exposed a second bug that your comment saved me from shipping: that leg is exactly where the new resolve step exports CORTEX_LATEST_RELEASE_IMAGE, which short-circuits getLatestReleaseImage(). So the moment the test started running, it asserted against the override instead of the derivation it exists to cover:

--- FAIL: TestGetLatestReleaseImage
    expected: "quay.io/cortexproject/cortex:v1.21.0"
    actual  : "quay.io/cortexproject/cortex:v1.21.1"

Same commit clears the variable for that test. I verified by reverting the guard that the failure is real, then re-ran the way CI does — compiled with the full ALL_TAGS, regenerated the run-pattern (all three now selected), and ran the binary with CORTEX_LATEST_RELEASE_IMAGE and CORTEX_CHECKOUT_DIR set as the query_fuzz leg sets them. All three pass.

I should be straight about one thing: I'd said earlier this was verified, but that run used -tags integration — the one tag CI never sets. It proved nothing about CI, which is exactly the gap you found.

The registry lookup you suggested is in f4182fd; the PR description has the resolution table.

integration/util.go derived the "latest release" image straight from the VERSION
file. That holds on master, where VERSION is the last GA, but not on a release
branch: VERSION is bumped to the version being prepared (e.g. 1.22.0-rc.0) long
before the deploy job publishes that tag, and the integration job is a dependency
of deploy. So the query fuzz leg would pull an image that does not exist yet.

Resolve a pre-release version to the release preceding it instead, and add
CORTEX_LATEST_RELEASE_IMAGE as an escape hatch for the cases the version math
cannot cover (a major pre-release). The preload step in test-build-deploy.yml
mirrors the same rule.

Signed-off-by: Charlie Le <charlie_le@apple.com>
Deriving the previous release from VERSION alone left one case broken, as
SungJin1212 pointed out on cortexproject#7786: on the GA tag push VERSION is 1.22.0 with no
pre-release suffix, so it resolves to v1.22.0 — an image that only `deploy`
publishes, and `deploy` needs `integration` to pass first.

Ask quay.io what actually exists instead. The registry is the only source of
truth for "published", so list the GA tags (^v\d+\.\d+\.\d+$) and take the
highest one that does not exceed VERSION, then export it as
CORTEX_LATEST_RELEASE_IMAGE for the preload and test steps.

The <= bound only changes the result when a newer release already exists on
quay than the branch being tested, e.g. preparing 1.21.2 on release-1.21 after
v1.22.0 has shipped.

This also drops the bash mirror of the Go derivation, and stops guessing at the
previous minor's .0: with the registry answering, 1.19.5-rc.0 resolves to the
v1.19.1 that exists rather than a v1.19.4 that never shipped, and a major
pre-release such as 2.0.0-rc.0 no longer needs a manual override.

The derivation stays in integration/util.go as the offline fallback for local
runs, where no env var is set and no network call is wanted.

Signed-off-by: Charlie Le <charlie_le@apple.com>
util_test.go was tagged `integration`, which discover-tags filters out of the
matrix (`grep -v '^integration$'`). The binary still compiled the tests, since
the compile step sets ALL_TAGS="slicelabels,integration,${tags_csv}", but the
run-pattern manifest is built from tags_csv alone, so no -test.run regex ever
named them and they never executed.

Move them to `integration_query_fuzz`, the only leg that calls
getLatestReleaseImage().

Running them then exposed a second problem: that leg now exports
CORTEX_LATEST_RELEASE_IMAGE, which short-circuits getLatestReleaseImage() and
made TestGetLatestReleaseImage assert against the override instead of the
derivation it is meant to cover. Clear the variable for that test.

Signed-off-by: Charlie Le <charlie_le@apple.com>
@CharlieTLe
CharlieTLe force-pushed the release-1.22-pr-a-fix-latest-release-image branch from 58b5278 to f9f15ee Compare September 12, 2026 18:58
CharlieTLe added a commit that referenced this pull request Sep 12, 2026
* Pull minio from quay.io instead of Docker Hub

Every integration leg is failing at Preload Images:

  Error response from daemon: pull access denied for minio/minio,
  repository does not exist or may require 'docker login':
  denied: requested access to the resource is denied

minio/minio is the first Docker Hub pull in the step, so no leg gets past
it and all 24 fail in about 30 seconds. A CHANGELOG-only pull request
reproduces it, so this is not specific to any change under test. master
was last green at 4061a3d.

This is not a rate limit: the same pull fails right after a successful
'docker login' with the repository credentials. The docker.io/minio/minio
repository is simply no longer accessible.

MinIO still publishes the identical image to quay.io. quay.io/minio/minio
:RELEASE.2024-05-28T17-19-04Z is public and is a manifest list with 8
children, so it covers both the amd64 and arm64 runners.

Point the integration tests, the CI preload list, and the three
development docker-compose stacks at quay.io. The tag is unchanged, so no
behaviour changes.

Signed-off-by: Charlie Le <charlie_le@apple.com>

* Authenticate the integration job's remaining Docker Hub pulls

Preload Images still pulls consul, memcached, redis and postgres from
Docker Hub. #7464 removed the Install Docker Client step from this job,
and that script is where 'docker login' runs, so those pulls have been
anonymous since and are subject to the anonymous rate limit.

Log in explicitly, matching what the build job does. Pull requests from
forks have no secrets, so skip the login there and leave those pulls
anonymous instead of failing the step.

This is hardening, not the fix for the current breakage: minio failed
even when authenticated.

Signed-off-by: Charlie Le <charlie_le@apple.com>

* Resolve the latest release image to a published version

Backport of #7786 onto release-1.22.

integration/util.go derived the query fuzz comparison image straight from
VERSION. The moment VERSION becomes 1.22.0-rc.0 on this branch,
integration_query_fuzz tries to pull
quay.io/cortexproject/cortex:v1.22.0-rc.0, which does not exist: that
image is pushed by the tag build's deploy job, and deploy is gated on
integration passing first.

Ask quay.io which GA tags are actually published instead, and take the
highest one at or below VERSION. The CI step mirrors the same resolution
and exports CORTEX_LATEST_RELEASE_IMAGE for the preload step.

Set the CORTEX_LATEST_RELEASE_IMAGE repository variable to bypass the
lookup.

Signed-off-by: Charlie Le <charlie_le@apple.com>

* Mark release 1.22.0 in progress

Add a '## 1.22.0 in progress' section below an empty
'## master / unreleased', move the existing unreleased entries into it,
and order them [CHANGE] -> [FEATURE] -> [ENHANCEMENT] -> [BUGFIX] per
RELEASE.md.

Also fill the gaps reported by
./tools/release/check-changelog.sh v1.21.1...master:

- new entries for #7513, #7514 and #7559
- fold #7323, #7434, #7458, #7463, #7487, #7505, #7687, #7691, #7716,
  #7726, #7775 and #7807 into the entries they belong to

Signed-off-by: Charlie Le <charlie_le@apple.com>

* Update version to 1.22.0-rc.0

Signed-off-by: Charlie Le <charlie_le@apple.com>

---------

Signed-off-by: Charlie Le <charlie_le@apple.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd go Pull requests that update Go code size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants