Fix tag-based manifest pulls 404ing while digest-based pulls succeed - #2438
Fix tag-based manifest pulls 404ing while digest-based pulls succeed#2438wussh wants to merge 2 commits into
Conversation
|
Verified this fix end-to-end against the live cluster that originally hit #2417 (Domains + on-demand + follow-latest distribution, S3 storage, pulpcore 3.113.0 / pulp_container 2.28.0):
|
319a366 to
75a7a9f
Compare
- error_code: use the CON00XX naming convention (CON0001) jobselko and gerrod3 agreed on, instead of PLP_CONTAINER_BUILD_0001. - CHANGES fragment: use single backticks, since they render as markdown. - cdomain_factory: adopt gerrod3's version of the namespace cleanup from pulp#2424 (suppress errors per-namespace/guard instead of letting one failure abort the rest, and wait on the delete task via monitor_task). - Drop the ruff<0.16 pin: no longer needed after rebasing on main, where the 0.16 lint findings were already fixed elsewhere.
806b30a to
5fae027
Compare
|
Addressed the mechanical review feedback:
Still not addressed: your point about the accept-header check itself (removing it from |
|
Squash the commits please |
b3003c1 to
6ac19e0
Compare
6ac19e0 to
c60a884
Compare
gerrod3
left a comment
There was a problem hiding this comment.
Looking pretty good. Few changes and we should be good to merge.
| @@ -0,0 +1 @@ | |||
| Fixed tag-based manifest pulls returning 404 when the client's ``Accept`` header did not list the tagged manifest's media type, while the identical digest-based pull succeeded. | |||
There was a problem hiding this comment.
Fixed — single backticks now, both here and in the docstring.
| """ | ||
| Return whether a manifest media type satisfies an Accept header. | ||
|
|
||
| Supports exact media type matches and the ``*/*`` wildcard used by some clients. |
| for accepted in accepted_media_types: | ||
| if accepted in ("*/*", media_type): | ||
| return True | ||
| return False |
There was a problem hiding this comment.
Looking at this I think we can do this:
| for accepted in accepted_media_types: | |
| if accepted in ("*/*", media_type): | |
| return True | |
| return False | |
| return accepted in ("*/*", *accepted_media_types) |
There was a problem hiding this comment.
Applied, with one tweak: your literal snippet references accepted outside the loop it was defined in, and checking media_type against a tuple of ("*/*", *accepted_media_types) doesn't actually catch the wildcard case (it only matches if media_type itself equals "*/*", which it never does). Collapsed the loop into return any(accepted in ("*/*", media_type) for accepted in accepted_media_types) instead — same semantics as before, just a one-liner. Pushed in 01f7832.
|
@gerrod3 addressed all three review comments in 01f7832 — single backticks in the changelog and docstring, and Also confirming the earlier |
|
@wussh Can you squash and repush? Hopefully github actions are working again, then I can approve and merge. |
The Accept-header comparison in from_tag() did not strip parameters (e.g. q-values) from each entry and had no support for the */* wildcard, so a client sending a qualified Accept header for the correct media type was incorrectly rejected with a 404. Fixed the parsing in get_accepted_media_types() and added is_media_type_accepted() to perform the comparison correctly, restoring the negotiation check gerrod3 flagged as silently dropped. Also raises a proper PulpException subclass (ContainerBuildError) instead of a bare Exception when building or pushing an OCI image fails, so the error isn't sanitized away by pulpcore in a future release.
5320f75 to
ab61e13
Compare
|
Squashed into a single commit and repushed — ab61e13. Also dropped some stray |
113a13e to
ab61e13
Compare
Summary
ManifestResponse.from_tagrejected requests based on the clientAcceptheader, raisingManifestNotFoundwhen the tag's manifest media type wasn't explicitly listed.from_manifest(the digest lookup path) never had this check, so the identical content served200by digest and404by tag — most visible for manifest-list/OCI-index tags whose media type clients often omit fromAccept.8479d527), which moved manifest serving from a content-app redirect (that ignoredAccept) into the registry API view.from_tagnow mirrorsfrom_manifest: it always serves the tagged manifest, only rewriting schema v1 to the signed content type.Fixes #2417
Test plan
test_pull_content.py::test_api_performes_schema_conversion(previously asserted a 4xx with the comment "I don't understand what this is testing") intotest_api_serves_tag_regardless_of_accept_header, which pulls the same manifest by tag and by digest with a narrowAcceptheader and asserts identical200responses.registry_api.pyout of the runningpulp-apipod, applied only thefrom_tagdiff from this PR on top of it (no unrelated version drift), wrote it back into the running container, and reloaded gunicorn workers (no pod restart). Results:404, digest pull200(matches the issue exactly).200, digest pull200,tags/list200, and the tag/digest response bodies are byte-identical.404baseline — no lasting changes were left on the cluster.