Relay cache-miss blob Range requests to the upstream when
proxy.rangepassthrough is enabled, without populating the blob cache.
Preserve upstream 200, 206 and 416 responses while keeping ordinary GET
cache fills and cache-hit handling unchanged.
Reuse the authenticated client, abort interrupted streams, and exclude
416 responses from blob transfer metrics and pull notifications.
Document the option and cover the HTTP and cache behavior in tests.
Signed-off-by: jeongho-kim <jeongho.kim@toss.im>
registry/client (*blobs).Get fetched a blob by digest but returned the
bytes with no digest verification, so a malicious or compromised registry
(or a MITM) could substitute arbitrary content for a digest-pinned blob
(image config, layer) and any library consumer that trusted the returned
bytes received the substituted content. This is the same integrity gap
addressed for manifests in GHSA-685w-q87j-wqw3, one layer down.
Get now buffers and verifies the whole blob against the requested digest,
and rejects a digest whose algorithm is unsupported (fail closed) rather
than allowing dgst.Verifier() to panic.
Open is left as an unverified streaming reader, now documented as such: a
content digest can only be checked after the entire blob has been read,
but Open yields bytes as they stream and callers may read partially or
seek, so single-pass verification cannot be guaranteed. Callers that rely
on the digest for integrity must use Get. The pull-through proxy's local
cache is protected independently by the storage blob writer's commit-time
digest validation.
Related to GHSA-685w-q87j-wqw3.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
registry/client (*manifests).Get fetched a manifest by digest but never
hashed the returned body and compared it against the requested digest.
A malicious or compromised registry, or a MITM on the registry
connection, could serve arbitrary manifest bytes for a digest-pinned
request and the client returned the substituted content transparently.
The server-supplied Docker-Content-Digest header was trusted verbatim.
When the manifest is requested by digest (no tag option), verify that
the returned content hashes to the requested digest, using digest.Verifier
over the exact received bytes. A digest whose algorithm is unsupported is
rejected (fail closed) rather than allowed to panic dgst.Verifier().
Fixes GHSA-685w-q87j-wqw3.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This PR changes the code based on the `go fix` suggestions
to modernize the codebase and keep up with the latest Go features.
Signed-off-by: Milos Gajdos <milosthegajdos@gmail.com>
bind proxy-mode bearer realms to the upstream trust boundary before sending credentials, move challenge filtering behind the auth manager, and use golang.org/x/net/publicsuffix for registrable-domain handling.
The manifest Exists() client call issued a HEAD without any Accept
headers. Some OCI-focused registries require an explicit Accept for
manifest content negotiation, causing HEAD to fail (404/406) even
when the manifest exists. The Get() path already sets Accept;
Exists() did not.
This change adds all supported manifest media types from
distribution.ManifestMediaTypes() as Accept headers to the Exists()
HEAD request, aligning behavior with Get() and improving OCI
interoperability.
Tests:
- Regression: Exists() returns true when Accept is present and
false when stripped (negative path), mirroring real-world
behavior.
Risk/compatibility:
- Low. Registries that ignore Accept on HEAD continue to work.
- Redirect handling is unchanged; existing CheckRedirect preserves
Accept.
Signed-off-by: Artem Tkachuk <artemtkachuk@yahoo.com>
HEAD requests for instance return no body while still having all the relevant Content-Type headers set, causing unnecessary parsing errors. This skips further parsing for all requests that don't have any body to begin with.
Signed-off-by: Markus Thömmes <markusthoemmes@me.com>
We make sure they're not hiding at the bottom or in the middle
which makes debugging an utter nightmare!
Signed-off-by: Milos Gajdos <milosthegajdos@gmail.com>
the `uuid` package is not used in the code base,
so it can be safely remove.
Signed-off-by: Alex Gotgelf <gotgelf@gmail.com>
Signed-off-by: gotgelf <gotgelf@gmail.com>
The RemoteAddr and RemoteIP functions operate on *http.Request values,
not contexts. They have very low cohesion with the rest of the package.
Signed-off-by: Cory Snider <csnider@mirantis.com>
Our context package predates the establishment of current best practices
regarding context usage and it shows. It encourages bad practices such
as using contexts to propagate non-request-scoped values like the
application version and using string-typed keys for context values. Move
the package internal to remove it from the API surface of
distribution/v3@v3.0.0 so we are free to iterate on it without being
constrained by compatibility.
Signed-off-by: Cory Snider <csnider@mirantis.com>
Nowadays there are much, much better UUID implementations to choose
from, such as github.com/google/uuid. Prevent external users from
importing our bespoke implementation so that we can change or migrate
away from it internally without introducing breaking changes.
Signed-off-by: Cory Snider <csnider@mirantis.com>
Our registry client is not currently in a good place to be used as the
reference OCI Distribution client implementation. But the registry proxy
currently depends on it. Make the registry client internal to the
distribution application to remove it from the API surface area (and any
implied compatibility promises) of distribution/v3@v3.0.0 without
breaking the proxy.
Signed-off-by: Cory Snider <csnider@mirantis.com>