feat: resolve a declared registry, then fall back to Docker Hub - #42
Merged
CptSchnitz merged 3 commits intoSep 22, 2026
Merged
Conversation
A values file usually splits the registry off from the repository:
`repository: my-service` under a `global.imageRegistry` names
`myreg.example.com/my-service`, and reading the repository alone gets the
image wrong. Every reference now carries the registry its document declared,
so the registry package has something to resolve a bare name against.
A sibling `registry` key wins, then a document-level one found through a
precedence-ordered table of key paths: `global.imageRegistry`,
`global.registry`, `imageRegistry`, `registry`. A table rather than a chain
of conditionals, because that list is the whole rule — the next convention
somebody's charts follow is a new row, not a new branch.
The declared string is emitted as written, from raw source text with a real
range, exactly as `repository` and `tag` are. Deciding what a host means,
and whether the string even is one, is OCI naming semantics and belongs in
the registry package.
"Templated, non-scalar, or empty counts as absent" was already spelled out
twice and would have been four sites once registry joined, so it folds into
one `readUsableScalar` that every field reads through. A templated sibling
registry therefore falls through to the document-level one instead of
shadowing it, which is what a chart writing
`registry: "{{ .Values.global.registry }}"` means by it.
The extension's test fixtures gain the new field. Nothing in the extension
reads it yet; that arrives with the resolution chain.
Refs #23
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A reference that is not fully qualified now gets checked instead of refused. Resolution runs in three steps: a host the repository names itself, then the registry the document declared, then Docker Hub. So `repository: my-service` under a `global.imageRegistry` is checked where the chart says it lives, and `nginx` verifies against Hub with no setup at all — with Docker's own `library/` normalization applied, since the distribution API knows only `library/nginx` and answers the short form with a 404 that reads exactly like a missing image. The third step is a guess, and a guess is not allowed to accuse. A not-found from the Hub fallback is downgraded to unverifiable, because a bare internal service name is the ordinary reference in this organisation's charts and Hub has never heard of any of them, so reporting that as a missing image would be the false negative this whole feature exists to avoid. A positive answer from the guess still stands, so public images keep their checkmark. The downgrade sits on the single verdict the entry point returns rather than on each 404 branch, so no later edit to those branches can make "we guessed the registry" and "we are confident the image is missing" hold at once. `no-registry` is gone: every repository resolves to some registry now, so nothing reaches it. What replaces it is two reasons rather than one, because the old one conflated them. `guessed-registry` is the downgrade above. `malformed-reference` widens from the tag to the whole reference — a repository name outside the OCI grammar, or a declared registry that is not a host, is rejected before a request is built. A declared registry that is not a host is a malformed document, not an invitation to guess Hub instead: falling through would answer a question about a registry nobody asked about. `resolve-explicit-host.ts` becomes `resolve-reference.ts`, one module owning OCI naming. `resolveExplicitHost` keeps its behaviour and its export, because the extension asks it a different question — what host the file itself spells out — to decide whether a checkmark should name the registry that answered. That path is reachable for the first time here, so a bare `nginx` verified on Hub now says `docker.io` on the line rather than claiming a registry the file never mentioned. Closes #23 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`registrySuffixOf` names the answering registry only when it differs from
the one the file names, and it was still asking only what the repository
string spells out — a question this branch had just made the wrong one. A
values file declaring `global.imageRegistry: ghcr.io` got ` ✓ ghcr.io`
appended to every bare repository under it, which is the wallpaper that rule
exists to prevent. The comparison now runs against the registry the file
names by either route. A file naming none still gets Docker Hub spelled out,
because "we guessed" and "you wrote it" are different things and the mark is
where that difference shows.
The rest is review fallout from the same pass.
`documentRegistry` becomes `declaredRegistry`, and its `RegistrySource` arm
`'document'` becomes `'declared'`. ADR 0001 says the registry package knows
nothing about Helm, YAML, or editors, and a document is the caller's idea,
not this package's. No dependency crossed that line, only vocabulary, which
is how it gets crossed for real later.
`ImageReference.registry` narrows from a `RawScalar` to a plain string. Only
its text was ever read, and its range was a hazard rather than a spare
feature: a document-level declaration sits on a line that has nothing to do
with the reference, so the first consumer to underline it would have
underlined `global:` for a diagnostic about an image forty lines down.
`ResolvedReference` extends `RepositoryLocation` instead of respelling its
two fields. The empty-string branch in `selectRegistry` keeps its fallback
and gains the test and the comment it was missing: an empty declared
registry is a caller reading a half-typed file saying "nothing declared",
not a registry named badly, so it falls back rather than failing. A
`{@link UnverifiableReason}` in `check-image-existence.ts` pointed at a
symbol that file does not import, so it resolved to nothing.
Both new assertions were mutation-checked against the code they cover.
Refs #23
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CptSchnitz
deleted the
ticket-23/document-registry-and-docker-hub-fallback
branch
September 22, 2026 08:25
This was referenced Sep 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
References that are not fully qualified start working.
repository: my-serviceunder aglobal.imageRegistryis checked against the registry the chart declares, and a barenginxverifies against Docker Hub with no setup at all. Before this, both came back unverifiable with a shrug.Resolution runs in three steps: a host the repository names itself, else the registry declared elsewhere in the document, else Docker Hub. The third step is a guess, and a guess is not allowed to accuse — a not-found from the Hub fallback is downgraded to unverifiable, because a bare internal service name is the ordinary reference in this organisation's charts and Hub has never heard of any of them. A positive answer from the guess still stands, so public images keep their checkmark. The downgrade sits on the single verdict the entry point returns rather than on each 404 branch, so no later edit to those branches can make "we guessed the registry" and "we are confident the image is missing" hold at once.
The Helm package emits the declared registry as a raw string and interprets nothing; the registry package decides what a host means, per the ticket. Which keys count as a declaration is a precedence-ordered table —
global.imageRegistry,global.registry,imageRegistry,registry, with a siblingregistrykey beating all of them — so the next convention somebody's charts follow is a new row rather than a new branch.no-registryis gone, since every repository now resolves to something. It is replaced by two reasons, because it conflated them:guessed-registryis the downgrade above, andmalformed-referencewidens from the tag to the whole reference.Reviewer notes
library/normalization applies wherever the host is Hub, not only on the fallback.docker.io/nginxneeds it too: the distribution API serves only the long form and answersnginxwith a 404 that reads exactly like a missing image.malformed-referencerather than falling through to Hub. Falling through would answer a question about a registry nobody asked about. An empty declared registry is different — it is a caller reading a half-typed file saying "nothing declared" — and falls back.Known gap
A Harbor-style
registry: myreg.example.com/projectfails the host grammar and comes backmalformed-reference, so those references go unverified rather than wrong. Filed as #41.Closes #23