MapColonies / MapColonies/infra-tools
oci-registry: a non-JSON 404 body silently degrades a real repository-not-found to unverifiable
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 0
- Forks
- 0
- Avg merge
- 22h 52m
- Merged PRs (30d)
- 13
Description
Parent
#17
What's wrong
checkImageExistence's readErrorCode (packages/oci-registry/src/check-image-existence.ts) assumes every 404 is the OCI distribution spec's JSON error envelope — {"errors":[{"code": "NAME_UNKNOWN" | "MANIFEST_UNKNOWN"}]}. Some registries don't return that shape for a missing repository. registry.k8s.io is a live example: it answers a missing-repository request with a plain-text body, not JSON.
$ curl -sI https://registry.k8s.io/v2/paus/manifests/3.8
HTTP/2 404
content-type: text/plain; charset=utf-8
$ curl -s https://registry.k8s.io/v2/paus/manifests/3.8
repository does not exist
response.json() throws on that body, readErrorCode catches it and returns undefined, and checkImageExistence falls through to { kind: 'unverifiable', reason: 'unexpected-response' }. Per the invariant #19 established — an unverifiable verdict never produces a diagnostic — a genuinely missing repository under this registry is silently swallowed instead of flagged as repository-not-found. Discovered while manually verifying #20 against a real values.yaml pointing at a typo'd registry.k8s.io repository: no diagnostic ever appeared, with no way to tell "no problem" from "couldn't tell."
Note this is specific to the repository-level 404: a bad tag against an existing repository on the same registry works correctly today, because registry.k8s.io 307-redirects tag lookups to a GCP Artifact Registry backend that does return the standard JSON envelope.
$ curl -sL https://registry.k8s.io/v2/pause/manifests/99.99.99
{"errors":[{"code":"MANIFEST_UNKNOWN","message":"Failed to fetch \"99.99.99\""}]}
Why this needs a design call, not just a patch
The tempting fix — pattern-match the plain-text body for phrases like "does not exist" — is fragile per-registry and risks the opposite failure: a WAF page, a maintenance page, or a rate-limit page could use similar wording and get misread as a confirmed miss. Given the invariant this package is built around (unverifiable must never look like a missing image, but the reverse matters too — a confident wrong "not found" is exactly the kind of false signal the design has otherwise gone out of its way to avoid), the right fix probably isn't "trust the prose" and needs a decision on scope: known non-conforming registries handled by name, a more conservative structural signal, or accepting this as a documented gap for non-conforming registries.
Acceptance criteria
- A decision recorded on how far this package goes to recognize a non-JSON-bodied repository-not-found, and why
- Whatever is implemented does not weaken the existing invariant: an outcome this package cannot confidently interpret still resolves to
unverifiable - The existing
repository-not-found/tag-not-founddistinction for spec-conformant (JSON-bodied) registries is unaffected - Covered by a test asserting the verdict for the chosen non-JSON 404 shape(s), with the fetch implementation injected per the package's existing testing seam
Evidence
registry.k8s.io/v2/paus/manifests/3.8→404,content-type: text/plain, bodyrepository does not existregistry.k8s.io/v2/pause/manifests/99.99.99→307→europe-west8-docker.pkg.dev→ JSON body withMANIFEST_UNKNOWN
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in packages/oci-registry/src/check-image-existence.ts, focusing on checkImageExistence and readErrorCode, then review the existing repository-not-found/tag-not-found handling and injected fetch testing seam. Reproduce the registry.k8s.io non-JSON 404 shape and compare it with the spec-conformant JSON cases. Done means a recorded decision, a focused test for the chosen shape, and unchanged unverifiable behavior for responses that cannot be interpreted confidently.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100