feat: enhance manifest retrieval error handling - #60
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adjusts manifest retrieval to return distribution.ErrManifestUnknownRevision (mapped to HTTP 404 MANIFEST_UNKNOWN) when stored blob content is readable but not a valid/recognized manifest, and fixes a panic in the schemaVersion=2 empty-mediaType branch when index unmarshalling fails.
Changes:
- Convert non-manifest content cases (invalid JSON, unrecognized schemaVersion, unrecognized schemaVersion=2 mediaType) from generic/untyped errors to
ErrManifestUnknownRevisionwith warning logs. - Prevent a panic by checking the OCI index unmarshal error before type-asserting the returned manifest.
- Add targeted unit tests to ensure these failure modes return
ErrManifestUnknownRevisionand that malformed index content does not panic.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
registry/storage/manifeststore.go |
Normalizes “not a manifest” retrieval failures to ErrManifestUnknownRevision and hardens empty-mediaType index detection to avoid panics. |
registry/storage/manifeststore_test.go |
Adds regression tests covering non-manifest content and the previously reachable panic path. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Nice catch on the panic — type-asserting the index result before checking the error was a genuine crash, and the guard is right. One thing I'd like fixed before this lands, in the empty- So the panic is gone, but it's replaced by a silent wrong answer: the client is handed a manifest that describes nothing, with no error and nothing in the logs to explain it. That's harder to debug than either the crash or a clean 404. Could we return the same Related: |
Added handling for cases where content lacks a media type or config descriptor during manifest retrieval. This ensures that malformed content is correctly identified and reported as an unknown revision, preventing potential panics and improving overall stability.
|
LGTM. The config-descriptor check is the right servability test, and the malformed-index test actually asserts something now. This closes the reported DOCR-2302 case — an image config blob reads as Two non-blocking follow-ups:
|
Agreed on the explicit media-type branches — confirmed both deserializers validate only the media type, so One thing I'd adjust in the framing: it isn't only reachable through corruption. Because On the test run — you were right that nothing had exercised these assertions, and it turned out to be worse than that. I've included a one-line fix for that here, printing the error type with 40 pass, 4 fail. All four fail identically on a clean Note that Everything else under that tree passes. A test file that no longer compiles is probably the strongest argument for adding a Go build and test job alongside the semgrep scan — happy to open that separately if you think it's worth doing. |
|
Fair correction on the reachability — you're right, a pushed blob reaches it the same way as the case fixed here. One thing for the follow-up ticket: the statter resolves across the whole bucket, not just the repository, but in DOCR each registry gets its own Spaces bucket resolved per-request from the auth subject, so it doesn't cross tenants. Worth writing down so it isn't re-triaged later as a cross-tenant leak. Good catch on the panic. The Yes please on the Go build and test job. We can keep that separate. LGTM. |
fix: return 404 instead of 500 for unrecognized manifest content
Addresses: https://do-internal.atlassian.net/browse/DOCR-2302
manifestStore.Getreturned untyped errors when blob content was readable but was not a recognizable manifest. The GET/HEAD handler only convertsdistribution.ErrManifestUnknownRevisioninto404 MANIFEST_UNKNOWN, so every other error fell through toerrcode.ErrorCodeUnknownand returned HTTP 500. Clients that pass an image config digest to the manifests endpoint hitunrecognized manifest schema version 0and burned the availability SLO on what is a client-side request error.Return
ErrManifestUnknownRevision, with a warning log, from the threeGetpaths that mean "this content is not a manifest":json.Unmarshalfailure on the blob contentmediaTypeunderschemaVersion2, previouslyErrManifestVerification, which only the PUT path inspectsschemaVersionfallthrough, which returned a barefmt.Errorfand logged nothingThe
blobStore.Geterror path is unchanged, so genuine Spaces and storage failures still return 500.Also fixes a reachable panic in the empty-
mediaTypebranch. The image index result was type-asserted before its error was checked, andocischemaIndexHandler.Unmarshalreturns a nil manifest when unmarshalling fails, so malformed content panicked the request.Behaviour is unchanged for valid manifests. This only changes which error is returned on an already-failing path, so there is no change to what is read from storage and no perf impact.
Testing: added
TestManifestGetNonManifestContentcovering an image config blob, an unregistered media type, and non-JSON content, each assertingErrManifestUnknownRevision. AddedTestManifestGetMalformedIndexWithoutMediaType, which panics against the pre-fix code.Note for reviewers:
TestManifestStoragealready fails onmasterat the post-deleteGetassertion, unrelated to this change.linkedBlobStore.Statuses the global statter, so a deleted repo link does not hide a blob that still exists globally.