Summary
aicr validate fails with ErrImagePull / ImagePullBackOff when run from any tagged-release binary because the validator catalog rewrites validator image tags to :sha-<commit> of the binary's own build, but the release workflow publishes those validator images tagged with the git tag (e.g. :v0.13.0-rc3), not :sha-<commit>. The two naming schemes never meet, so every release install of aicr hits a 404 on the first validate against a cluster.
This is structurally the same gap that AICR_VALIDATOR_IMAGE_TAG was added for (per pkg/validator/catalog/catalog.go:197-202, intended for feature-branch dev builds where no :sha-<commit> image exists). It turns out tagged-release builds are in the same bucket — but those are the binaries end users actually install.
Repro
-
Install a released aicr binary (e.g. 0.13.0-rc3; homebrew tap, gh release download, or build from the v0.13.0-rc3 git tag).
-
Run any aicr validate that schedules a job in-cluster:
aicr validate --config aicr-config.yaml --phase conformance --output report.json
-
The job's pod stalls in ImagePullBackOff:
Failed to pull image \"ghcr.io/nvidia/aicr-validators/conformance:sha-481507af51a9cc4a9b9501f35d680734bfb5a925\":
ghcr.io/nvidia/aicr-validators/conformance:sha-481507af51a9cc4a9b9501f35d680734bfb5a925: not found
-
GHCR confirms the per-SHA image was never pushed for that commit, but the release workflow did push v0.13.0-rc3:
gh api 'orgs/NVIDIA/packages/container/aicr-validators%2Fconformance/versions?per_page=100' \
--jq '[.[] | .metadata.container.tags[]] | unique | map(select(test(\"^v[0-9]\")))'
# → [\"v0.13.0-rc1\",\"v0.13.0-rc2\",\"v0.13.0-rc3\", ...]
Root cause
The validator catalog (pkg/validator/catalog/catalog.go) has one tag-rewrite path: when the binary's version string carries a non-empty commit, rewrite :latest to :sha-<commit> (see replaceLatestWithSHA, comment at catalog.go:52 and catalog.go:85-88). That rule was written against the on-push.yaml publishing scheme, which tags by commit SHA on every main push. The release workflow (goreleaser / release-tag CI) doesn't push sha-<commit> aliases — it tags validators with the same v<version> string goreleaser stamps into the binary. So:
| Build path |
What CI publishes |
What binary asks for |
Works? |
main push (on-push.yaml) |
sha-<commit>, edge |
sha-<commit> |
✅ |
Tagged release (v0.13.0-rc3) |
v0.13.0-rc3 |
sha-<commit> |
❌ |
Local make build |
nothing |
sha-<commit> |
❌ |
| Feature branch / fork |
nothing |
sha-<commit> |
❌ |
AICR_VALIDATOR_IMAGE_TAG (per catalog.go:197-209 / replaceTag) is the existing escape hatch for the last two rows. The second row — every shipping release install — should not need an escape hatch.
Severity
User-visible: validate is unusable from the install path most users follow (tagged release). The error surfaces as a 5-minute ImagePullBackOff loop with no actionable hint in aicr output, so time-to-debug is high. No data loss path.
Proposed fix (binary side, preferred)
Teach the catalog to detect a release-style version string and prefer :<version> over :sha-<commit>. Sketch in pkg/validator/catalog/catalog.go:
// resolveDefaultTag picks the right tag for the bundled-in default validator
// images. Precedence (highest to lowest):
// 1. AICR_VALIDATOR_IMAGE_TAG env var (explicit override; existing).
// 2. Release-style version (matches /^v\d+\.\d+\.\d+([.-].+)?$/) — use :<version>.
// This is what goreleaser stamps into the binary AND what the release
// workflow publishes the validator image as. The two move in lockstep.
// 3. Non-empty hex commit SHA — use :sha-<commit> (matches on-push.yaml).
// 4. Fall back to :latest (dev builds; user can override with the env var).
The detection only needs version.Version() (already plumbed through to the catalog) plus a regexp; goreleaser emits exactly the same string into the binary version metadata and into the image tag, so the alignment is structural.
Optional follow-on: when the resolved tag is unreachable (image pull would 404), fall back to :edge and log a single slog.Warn — but this needs a registry probe which is a separable concern and arguably out of scope.
Test plan
- Unit: table-driven tests in
pkg/validator/catalog/catalog_test.go exercising (a) v0.13.0-rc3 → :v0.13.0-rc3, (b) ca62d0c4e97f... (40-char hex) → :sha-ca62d0c4..., (c) (devel) → :latest, (d) env-var override beats all of the above.
- Integration: run the existing
aicr validate --no-cluster chainsaw tests under a version.Version() = v0.13.0-rc3 fixture and assert the rendered job manifests reference :v0.13.0-rc3.
- Manual: install
v0.13.0-rc3 binary on a fresh cluster, run aicr validate --config aicr-config.yaml --phase conformance — should pull ghcr.io/nvidia/aicr-validators/conformance:v0.13.0-rc3 and succeed without AICR_VALIDATOR_IMAGE_TAG.
Alternatives considered
- CI side: release workflow also pushes
sha-<commit> aliases. Cheap, doesn't require a binary change, but duplicates tags on every release and doesn't help local make build or feature-branch builds (those rows still need the env var). Doesn't fix the broken default for the install path most users take.
- Document
AICR_VALIDATOR_IMAGE_TAG=v<version> in the install path. Pushes Kubernetes-image-tag trivia onto users for a problem the binary already knows the answer to (its own version is right there).
Affected paths
pkg/validator/catalog/catalog.go — tag resolution (replaceLatestWithSHA, replaceTag, surrounding wiring).
pkg/validator/job/deployer.go:248 — comment already nods at this exact failure mode ("override or it will resolve to the same unpublished :sha-"); the fix removes the need for the override on releases.
internal/version/ (or wherever version.Version() is sourced) — no change, but its current shape determines the regexp.
Workaround until fixed
AICR_VALIDATOR_IMAGE_TAG=v0.13.0-rc3 aicr validate --config aicr-config.yaml \
--phase conformance \
--output report.json
Or use the floating edge tag (current main HEAD) if the user is comfortable running validator images ahead of the binary's release version:
AICR_VALIDATOR_IMAGE_TAG=edge aicr validate ...
Related
Are you willing to contribute?
Maybe, with guidance — happy to PR the binary-side fix once a maintainer signs off on the version-string regexp shape (and whether to deal with the + build-metadata suffix goreleaser sometimes appends).
Summary
aicr validatefails withErrImagePull/ImagePullBackOffwhen run from any tagged-release binary because the validator catalog rewrites validator image tags to:sha-<commit>of the binary's own build, but the release workflow publishes those validator images tagged with the git tag (e.g.:v0.13.0-rc3), not:sha-<commit>. The two naming schemes never meet, so every release install ofaicrhits a 404 on the firstvalidateagainst a cluster.This is structurally the same gap that
AICR_VALIDATOR_IMAGE_TAGwas added for (perpkg/validator/catalog/catalog.go:197-202, intended for feature-branch dev builds where no:sha-<commit>image exists). It turns out tagged-release builds are in the same bucket — but those are the binaries end users actually install.Repro
Install a released
aicrbinary (e.g.0.13.0-rc3; homebrew tap,gh release download, or build from thev0.13.0-rc3git tag).Run any
aicr validatethat schedules a job in-cluster:The job's pod stalls in
ImagePullBackOff:GHCR confirms the per-SHA image was never pushed for that commit, but the release workflow did push
v0.13.0-rc3:Root cause
The validator catalog (
pkg/validator/catalog/catalog.go) has one tag-rewrite path: when the binary's version string carries a non-empty commit, rewrite:latestto:sha-<commit>(seereplaceLatestWithSHA, comment atcatalog.go:52andcatalog.go:85-88). That rule was written against theon-push.yamlpublishing scheme, which tags by commit SHA on everymainpush. The release workflow (goreleaser/ release-tag CI) doesn't pushsha-<commit>aliases — it tags validators with the samev<version>stringgoreleaserstamps into the binary. So:mainpush (on-push.yaml)sha-<commit>,edgesha-<commit>v0.13.0-rc3)v0.13.0-rc3sha-<commit>make buildsha-<commit>sha-<commit>AICR_VALIDATOR_IMAGE_TAG(percatalog.go:197-209/replaceTag) is the existing escape hatch for the last two rows. The second row — every shipping release install — should not need an escape hatch.Severity
User-visible:
validateis unusable from the install path most users follow (tagged release). The error surfaces as a 5-minuteImagePullBackOffloop with no actionable hint inaicroutput, so time-to-debug is high. No data loss path.Proposed fix (binary side, preferred)
Teach the catalog to detect a release-style version string and prefer
:<version>over:sha-<commit>. Sketch inpkg/validator/catalog/catalog.go:The detection only needs
version.Version()(already plumbed through to the catalog) plus a regexp; goreleaser emits exactly the same string into the binary version metadata and into the image tag, so the alignment is structural.Optional follow-on: when the resolved tag is unreachable (image pull would 404), fall back to
:edgeand log a singleslog.Warn— but this needs a registry probe which is a separable concern and arguably out of scope.Test plan
pkg/validator/catalog/catalog_test.goexercising (a)v0.13.0-rc3→:v0.13.0-rc3, (b)ca62d0c4e97f...(40-char hex) →:sha-ca62d0c4..., (c)(devel)→:latest, (d) env-var override beats all of the above.aicr validate --no-clusterchainsaw tests under aversion.Version() = v0.13.0-rc3fixture and assert the rendered job manifests reference:v0.13.0-rc3.v0.13.0-rc3binary on a fresh cluster, runaicr validate --config aicr-config.yaml --phase conformance— should pullghcr.io/nvidia/aicr-validators/conformance:v0.13.0-rc3and succeed withoutAICR_VALIDATOR_IMAGE_TAG.Alternatives considered
sha-<commit>aliases. Cheap, doesn't require a binary change, but duplicates tags on every release and doesn't help localmake buildor feature-branch builds (those rows still need the env var). Doesn't fix the broken default for the install path most users take.AICR_VALIDATOR_IMAGE_TAG=v<version>in the install path. Pushes Kubernetes-image-tag trivia onto users for a problem the binary already knows the answer to (its own version is right there).Affected paths
pkg/validator/catalog/catalog.go— tag resolution (replaceLatestWithSHA,replaceTag, surrounding wiring).pkg/validator/job/deployer.go:248— comment already nods at this exact failure mode ("override or it will resolve to the same unpublished :sha-"); the fix removes the need for the override on releases.internal/version/(or whereverversion.Version()is sourced) — no change, but its current shape determines the regexp.Workaround until fixed
AICR_VALIDATOR_IMAGE_TAG=v0.13.0-rc3 aicr validate --config aicr-config.yaml \ --phase conformance \ --output report.jsonOr use the floating
edgetag (currentmainHEAD) if the user is comfortable running validator images ahead of the binary's release version:Related
demos/cuj1-gke-config.mdruns cleanly end-to-end with no manual steps on a tagged-release binary.Are you willing to contribute?
Maybe, with guidance — happy to PR the binary-side fix once a maintainer signs off on the version-string regexp shape (and whether to deal with the
+build-metadata suffix goreleaser sometimes appends).