Back openDesk Edu for a sovereign, open-source education — every vote counts.
Vote nowSave products you love by clicking the heart icon.
Traditional CI/CD pipelines are evolving into AI/CD systems where agentic workflows handle testing, deployment, rollback, and optimization autonomously. This article explores the architecture, benefits, and implementation patterns for bringing intelligence to your delivery pipelines.
Every now and then a CI check you barely think about tells you something
true by failing in a surprising way. Our image-tag validator — the script
that guards every image reference in our compose files against typos and
disappeared tags — started failing on one tool and would not stop. The tool
was MinIO. The validator insisted its latest tag did not exist. MinIO is a
top-tier, heavily used object store; of course the tag exists.
The validator was wrong, and it was wrong for an interesting reason: it was asking the wrong registry.
Most software you docker pull comes from Docker Hub, so a naive validator
only ever talks to one endpoint. It fetches the tag list from Docker Hub and
calls it a day. That assumption silently broke for MinIO because MinIO's
image has a quirk: its RELEASE / latest-style tags are only published on
quay.io, not on Docker Hub.
The result is a deceptively specific failure:
$ curl -s "https://hub.docker.com/v2/repositories/minio/minio/tags/latest" | jq .name
null
Docker Hub returns a null / not-found even for a tag that obviously exists.
To docker pull minio/minio:latest it works fine (the daemon resolves the
right backend). But a tag-list HTTP request against Docker Hub for that tag
404s. Your validator reads "tag missing" and flags a perfectly good image —
which, if it's a hard gate, now blocks every pipeline that references it.
The fix is to stop assuming the registry and detect where a tag actually lives. The general pattern that works across Docker Hub and quay.io:
Resolve which registry to ask. For images you control the pinning
for, you already know. For third-party images, keep a small mapping that
routes known projects to their correct registry — generally this means
routing minio/minio and minio/mc to quay.io.
Request the manifest, not the tag list. Doing a HEAD against the
manifest URL is the most robust existence check, because it survives
registries whose tag-list APIs differ.
Authenticate anonymously where required. quay.io expects a Bearer
token. The flow is: probe for a challenge, exchange credentials (here:
anonymous) for a token, then HEAD the manifest with Authorization: Bearer <token>.
# quay.io anonymous bearer-token flow
token=$(curl -s "https://quay.io/v2/auth?service=quay.io&scope=repository:minio/minio:pull" \
| jq -r .token)
curl -sI -H "Authorization: Bearer $token" \
"https://quay.io/v2/minio/minio/manifests/latest"
A 200 on the HEAD means the tag exists. Combined with the small routing
table (minio/* → quay.io), the validator now trusts real facts instead of
a single registry's assumptions.
latest specially. latest is a moving tag; pin immutable
digests for production and let the validator check what you actually
run.The satisfying part was the scope of the fix: a rough guess ("MinIO is missing!") turned out to be a missing feature ("we never asked the right registry"). We shipped the routing table and the manifest check, and the same validator went from failing on every MinIO-referencing pipeline to silently guarding 26 image defaults. The tags were real all along — we had just been asking the wrong question.