Documentation
¶
Overview ¶
Package oci provides the OCI distribution registry client used by the conformance suite. `New` and the `*HTTPError` envelope are the Step 1 base; Step 1 also adds the Docker Registry HTTP API V2 token-exchange machinery (auth.go). Per-operation methods are introduced starting at S07 Step 2: the blob lifecycle (blob.go). Manifest, tag, and referrers operations follow in later steps.
Spec anchors:
- S04 §HTTPError block: ResponseBody is truncated to 4 KiB.
- S04 §per-format Client block: constructor takes baseURL, a Credential, and an *http.Client (nil ⇒ http.DefaultClient).
- S04 AC #32: `*HTTPError` round-trips through `errors.As`.
- S04 AC #33: 4 KiB tail truncation marker ends ResponseBody.
- Plan extra: the Authorization request header is scrubbed via the shared `pkg/conformance/redact` primitives before any error surface or log line is rendered.
Index ¶
- Constants
- Variables
- func ComputeSHA256(body []byte) string
- func ParseDigest(s string) (algo, encoded string, err error)
- func ReferrersTagSchema(subjectDigest string) (string, error)
- func ValidateName(name string) error
- func ValidateTag(tag string) error
- type BlobResponse
- type BlobUploadResult
- type BlobUploadSession
- type Client
- func (c *Client) CancelBlobUpload(ctx context.Context, location string) *HTTPError
- func (c *Client) CompleteBlobUpload(ctx context.Context, location, digest string, body []byte) (*BlobUploadResult, *HTTPError)
- func (c *Client) CompleteBlobUploadWithContentRange(ctx context.Context, location, digest string, start, end int64, body []byte) (*BlobUploadResult, *HTTPError)
- func (c *Client) DeleteBlob(ctx context.Context, name, digest string) *HTTPError
- func (c *Client) DeleteManifest(ctx context.Context, name, reference string) *HTTPError
- func (c *Client) GetBlob(ctx context.Context, name, digest string) (*BlobResponse, *HTTPError)
- func (c *Client) GetBlobRange(ctx context.Context, name, digest string, start, end int64) (*BlobResponse, *HTTPError)
- func (c *Client) GetBlobUploadStatus(ctx context.Context, location string) (*BlobUploadSession, *HTTPError)
- func (c *Client) GetManifest(ctx context.Context, name, reference string, acceptList []string) (*ManifestResponse, *HTTPError)
- func (c *Client) HeadBlob(ctx context.Context, name, digest string) (*BlobResponse, *HTTPError)
- func (c *Client) HeadManifest(ctx context.Context, name, reference string, acceptList []string) (*ManifestResponse, *HTTPError)
- func (c *Client) InitBlobUpload(ctx context.Context, name string) (*BlobUploadSession, *HTTPError)
- func (c *Client) ListReferrers(ctx context.Context, name, subjectDigest string, artifactTypes []string) (*ReferrersResponse, *HTTPError)
- func (c *Client) ListTags(ctx context.Context, name string) (*TagListResponse, *HTTPError)
- func (c *Client) ListTagsPaginated(ctx context.Context, name string, n int, last string) (*TagListResponse, *HTTPError)
- func (c *Client) MountBlob(ctx context.Context, name, fromName, digest string) (*BlobUploadResult, *HTTPError)
- func (c *Client) PatchBlobChunk(ctx context.Context, location string, start, end int64, body []byte) (*BlobUploadSession, *HTTPError)
- func (c *Client) PutManifest(ctx context.Context, name, reference, mediaType string, body []byte) (*PutManifestResponse, *HTTPError)
- func (c *Client) UploadBlobSingle(ctx context.Context, name, digest string, body []byte) (*BlobUploadResult, *HTTPError)
- func (c *Client) VersionCheck(ctx context.Context) *HTTPError
- type DigestVerdict
- type HTTPError
- type ImageIndex
- type ManifestResponse
- type PutManifestResponse
- type ReferrerDescriptor
- type ReferrersResponse
- type TagListResponse
Constants ¶
const ( // ManifestMediaType is the OCI image manifest media type. ManifestMediaType = "application/vnd.oci.image.manifest.v1+json" // ConfigMediaType is the OCI image config media type. ConfigMediaType = "application/vnd.oci.image.config.v1+json" // LayerMediaType is the OCI image layer media type (gzipped tar). LayerMediaType = "application/vnd.oci.image.layer.v1.tar+gzip" // IndexMediaType is the OCI image index (manifest list) media type. IndexMediaType = "application/vnd.oci.image.index.v1+json" )
const BlobUploadMediaType = "application/octet-stream"
BlobUploadMediaType is the Content-Type a blob upload carries on the single POST, the chunk PATCH, and the completion PUT (S07 §Common request semantics: "blob `PUT` and `PATCH` set `application/octet-stream`"; §Operation: blob upload single POST). It is fixed regardless of the layer's logical media type: the registry stores blob bytes opaquely and addresses them by digest.
Variables ¶
var ErrInvalidDigest = errors.New("oci: invalid digest")
ErrInvalidDigest is returned by ParseDigest when the input does not match the `<algorithm>:<hex>` grammar for a supported algorithm.
var ErrInvalidName = errors.New("oci: invalid repository name")
ErrInvalidName is returned by ValidateName when the input does not match the OCI distribution-spec `<name>` grammar.
var ErrInvalidTag = errors.New("oci: invalid tag")
ErrInvalidTag is returned by ValidateTag when the input does not match the tag grammar `[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}`.
var ErrLocationOriginMismatch = errors.New("oci: Location resolved to a different origin than the configured registry")
ErrLocationOriginMismatch is wrapped into the error resolveAndValidateLocation returns when a resolved Location's origin differs from the configured registry's (S07 §Security Considerations).
Functions ¶
func ComputeSHA256 ¶
ComputeSHA256 returns the canonical `sha256:<hex>` digest of body, where <hex> is the lowercase hex encoding of the SHA-256 sum.
func ParseDigest ¶
ParseDigest splits a digest string of the form `<algorithm>:<hex>` into its algorithm and hex-encoded digest components. It accepts the `sha256` (64 lowercase hex characters) and `sha512` (128 lowercase hex characters) algorithms per S07 §Tag and digest references. On a grammar violation it returns ErrInvalidDigest.
func ReferrersTagSchema ¶ added in v1.52.0
ReferrersTagSchema builds the OCI referrers tag-schema fallback tag for subjectDigest (S07 §Referrers API (v1.1) / Tag-schema fallback: `<algorithm>-<hex>`), consumed by oci.referrers.tag-schema-fallback (AC #24) when the referrers API itself returns 404. Returns ErrInvalidDigest when subjectDigest does not match the `<algorithm>:<hex>` grammar (digest.go's ParseDigest).
func ValidateName ¶
ValidateName reports whether name matches the OCI distribution-spec `<name>` grammar: one or more lowercase alphanumeric segments separated by `.`, `_`, `__`, or `-`, joined into a path by `/`. It returns ErrInvalidName on a violation. An empty name and an empty path component both fail nameComponentRE, which requires a leading alphanumeric run.
func ValidateTag ¶
ValidateTag reports whether tag matches the grammar `[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}` (1-128 characters, first character alphanumeric or underscore) per S07 §Tag and digest references. It returns ErrInvalidTag on a violation.
Types ¶
type BlobResponse ¶ added in v1.39.0
type BlobResponse struct {
// StatusCode is the HTTP status of the accepted (2xx) response
// (200 full body, 206 partial on a Range request).
StatusCode int
// Body is the blob bytes verbatim. Populated by GetBlob; empty for
// HeadBlob (RFC 9110 §9.3.2).
Body []byte
// DockerContentDigest is the `Docker-Content-Digest` response header
// (`<algorithm>:<hex>`), present on a successful blob GET and HEAD
// (S07 §`Docker-Content-Digest` response header; AC #5, #6, #26).
DockerContentDigest string
// ContentType is the response Content-Type header, verbatim.
ContentType string
// ContentLength is the response Content-Length. -1 when the server
// did not declare one (net/http's sentinel for unknown length).
ContentLength int64
// ContentRange is the `Content-Range` response header, present on a
// 206 Partial Content reply to a Range request (AC #29).
ContentRange string
// Digest is the S07 AC #26 Docker-Content-Digest verdict (plan
// Step 28). For GetBlob, Expected is the digest of the received
// Body. For HeadBlob, Expected is the digest argument (the caller
// already supplies it; HeadBlob has no body to hash). For
// GetBlobRange, Expected is left empty (zero DigestVerdict): a
// partial (206) response's bytes cannot hash to the full-content
// digest the header advertises, and AC #26 scopes the always-on GET
// check to the full body (see DigestVerdict's doc).
Digest DigestVerdict
}
BlobResponse is the result of a blob GET or HEAD (S07 §Operation: blob GET / HEAD).
type BlobUploadResult ¶ added in v1.39.0
type BlobUploadResult struct {
// StatusCode is the HTTP status of the accepted (2xx) response.
// Callers inspect it to distinguish 201 (created / mounted) from
// 202 (fallback to two-phase upload).
StatusCode int
// Location is the blob URL on 201, or the upload-session URL on a
// 202 fallback: always absolute and same-origin with baseURL,
// whatever form the registry's own Location header took
// (resolveAndValidateLocation).
Location string
}
BlobUploadResult is the result of an operation that produces a pullable blob or selects an upload path: single-request upload, completion PUT, or cross-repository mount. On 201 Location points at the pullable blob URL (`/v2/<name>/blobs/<digest>`); on a 202 fallback Location is the upload-session URL (S07 §Operation: blob upload single POST / complete / mount).
type BlobUploadSession ¶ added in v1.39.0
type BlobUploadSession struct {
// StatusCode is the HTTP status of the accepted (2xx) response.
StatusCode int
// Location is the upload-session URL: always absolute and
// same-origin with baseURL, whatever form the registry's own
// Location header took (resolveAndValidateLocation). Used as the
// target of subsequent PATCH / PUT / GET / DELETE on the session.
Location string
// Range is the registry's cumulative write-position header
// (`0-0` on init, `0-<end>` after a chunk, `0-<offset>` on status).
Range string
}
BlobUploadSession is the result of an operation that opens or advances an upload session: init (POST .../uploads/), a chunk PATCH, or a status GET. Location is the opaque session URL the caller passes back verbatim; Range echoes the registry's cumulative write position (S07 §Operation: blob upload init / chunk / status).
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the OCI distribution protocol client. Per-operation methods are introduced in S07 Step 2+; Step 1 adds the Docker Registry HTTP API V2 token-exchange machinery (credential dispatch, realm-URL HTTPS pre-check, scope-keyed token cache, single-retry refresh).
func New ¶
func New(baseURL string, cred conformance.Credential, hc *http.Client) *Client
New returns an OCI client. baseURL is the registry root; cred is the user-supplied secret carried into protocol exchanges; hc is the transport (nil ⇒ http.DefaultClient). The constructor does not perform I/O; connection is lazy.
func (*Client) CancelBlobUpload ¶ added in v1.39.0
CancelBlobUpload issues `DELETE <location>` to abandon an in-flight session (S07 §Operation: blob upload cancel). On 204 it returns a nil *HTTPError; any non-2xx maps to *HTTPError (AC #31). location is already absolute and same-origin (resolveAndValidateLocation ran when it was first read) and is used as-is.
func (*Client) CompleteBlobUpload ¶ added in v1.39.0
func (c *Client) CompleteBlobUpload(ctx context.Context, location, digest string, body []byte) (*BlobUploadResult, *HTTPError)
CompleteBlobUpload issues `PUT <location>?digest=<digest>` with an empty body (after a chunked upload) or the final blob bytes (after init-only) to close the session (S07 §Operation: blob upload complete). On 201 it returns the pullable blob Location; a mismatched digest yields 400 DIGEST_INVALID, mapped to *HTTPError. AC #44 pins this shape on the single-POST path (UploadBlobSingle); the completion PUT's non-2xx mapping is covered by the generic *HTTPError contract (AC #48). location is already absolute and same-origin (resolveAndValidateLocation ran when it was first read); the digest query parameter is appended to it as-is.
func (*Client) CompleteBlobUploadWithContentRange ¶ added in v1.62.0
func (c *Client) CompleteBlobUploadWithContentRange( ctx context.Context, location, digest string, start, end int64, body []byte, ) (*BlobUploadResult, *HTTPError)
CompleteBlobUploadWithContentRange issues `PUT <location>?digest=<digest>` exactly as CompleteBlobUpload does, but additionally carries a `Content-Range: <start>-<end>` header on the request (mirroring PatchBlobChunk's own Content-Range construction below), for the closing PUT's trailing-chunk shape the upstream OCI distribution-spec's "close the session" operation allows (S07 §Operation: blob upload complete does not itself document the header, but AC #45's second arm requires driving exactly this request shape: "a final PUT <session-url>?digest=<digest> whose Content-Range is mismatched"). On 201 it returns the pullable blob Location; a mismatched Content-Range (a start offset past the registry's current write position) yields 416 BLOB_UPLOAD_INVALID, mapped to *HTTPError (AC #45); a mismatched digest still yields 400 DIGEST_INVALID as CompleteBlobUpload does.
Added as a plan amendment for Step 26e (docs/plans/2026-05-26-oci-format.md): Step 2 pinned CompleteBlobUpload's exact signature with no Content-Range parameter, and that signature is already consumed by Steps 13/14/16's committed call sites, so this is a new, additive sibling rather than a change to CompleteBlobUpload itself, the same "within this plan's own authority" scope Step 26b's WWWAuthenticate() accessor and Step 12's version-check method used, applied here to a new method rather than a new accessor.
func (*Client) DeleteBlob ¶ added in v1.39.0
DeleteBlob issues `DELETE /v2/<name>/blobs/<digest>` (S07 §Operation: blob DELETE). On 202 it returns a nil *HTTPError (AC #18); a deletion-disabled registry yields 400 or 405 with UNSUPPORTED and a missing blob yields 404 BLOB_UNKNOWN, both mapped to *HTTPError.
func (*Client) DeleteManifest ¶ added in v1.42.0
DeleteManifest issues `DELETE /v2/<name>/manifests/<reference>` (S07 §Operation: manifest DELETE). reference is a digest (AC #16) or a tag (AC #17); both address the same endpoint. On 202 it returns a nil *HTTPError; a deletion-disabled registry yields 400 or 405 with UNSUPPORTED (AC #46) and a delete against a repository with no manifests yields 404 (AC #41), both mapped to *HTTPError.
func (*Client) GetBlob ¶ added in v1.39.0
GetBlob issues `GET /v2/<name>/blobs/<digest>` for the full blob (S07 §Operation: blob GET). On 200 it returns the blob bytes verbatim with the Docker-Content-Digest, Content-Type, and Content-Length headers (AC #5). A missing blob yields 404 BLOB_UNKNOWN, mapped to *HTTPError (AC #40).
func (*Client) GetBlobRange ¶ added in v1.39.0
func (c *Client) GetBlobRange(ctx context.Context, name, digest string, start, end int64) (*BlobResponse, *HTTPError)
GetBlobRange issues `GET /v2/<name>/blobs/<digest>` with `Range: bytes=<start>-<end>` (S07 §Operation: blob GET / `Range` support; AC #29). A registry that honors the range returns 206 with Content-Range and the requested byte window; one that ignores it returns 200 with the full body (both are conformant, so the per-slug oci.blob.range-request layer reads the returned StatusCode to decide pass-vs-skip). A missing blob yields 404 BLOB_UNKNOWN, mapped to *HTTPError.
func (*Client) GetBlobUploadStatus ¶ added in v1.39.0
func (c *Client) GetBlobUploadStatus(ctx context.Context, location string) (*BlobUploadSession, *HTTPError)
GetBlobUploadStatus issues `GET <location>` against an in-flight session (S07 §Operation: blob upload status). On 204 it returns the session Location and the `Range: 0-<offset>` header showing the current write position (AC #30); any non-2xx maps to *HTTPError. location is already absolute and same-origin (resolveAndValidateLocation ran when it was first read) and is used as-is.
func (*Client) GetManifest ¶ added in v1.42.0
func (c *Client) GetManifest(ctx context.Context, name, reference string, acceptList []string) (*ManifestResponse, *HTTPError)
GetManifest issues `GET /v2/<name>/manifests/<reference>` (S07 §Operation: manifest GET). acceptList is joined into the request `Accept` header per S07 §Common request semantics (a comma-separated list of OCI image-manifest and image-index media types the caller understands); an empty acceptList omits the header. On 200 it returns the manifest bytes verbatim plus the parsed Content-Type and Docker-Content-Digest headers (AC #9, #10, #25, #26, #27, #34); a manifest that was never pushed yields 404 MANIFEST_UNKNOWN, mapped to *HTTPError (AC #39).
func (*Client) HeadBlob ¶ added in v1.39.0
HeadBlob issues `HEAD /v2/<name>/blobs/<digest>` (S07 §Operation: blob HEAD). On 200 it returns an empty Body with the Content-Length and Docker-Content-Digest the corresponding GET carries (AC #6); a missing blob yields 404, mapped to *HTTPError.
func (*Client) HeadManifest ¶ added in v1.42.0
func (c *Client) HeadManifest(ctx context.Context, name, reference string, acceptList []string) (*ManifestResponse, *HTTPError)
HeadManifest issues `HEAD /v2/<name>/manifests/<reference>` (S07 §Operation: manifest HEAD). reference is a bare tag or digest with no expected-digest parameter; see this file's package doc for the HEAD-by-tag validation split with the test layer. acceptList sets the `Accept` header the same way GetManifest does (S07 §Common request semantics pins `Accept` on both manifest GET and HEAD). On 200 it returns an empty Body with the Content-Length and Docker-Content-Digest the corresponding GET carries (AC #11, #26); a manifest that was never pushed yields 404, mapped to *HTTPError.
func (*Client) InitBlobUpload ¶ added in v1.39.0
InitBlobUpload issues `POST /v2/<name>/blobs/uploads/` to open a monolithic or chunked upload session (S07 §Operation: blob upload init). On 202 it returns the opaque session Location and the `Range: 0-0` header; any non-2xx maps to *HTTPError.
func (*Client) ListReferrers ¶ added in v1.52.0
func (c *Client) ListReferrers(ctx context.Context, name, subjectDigest string, artifactTypes []string) (*ReferrersResponse, *HTTPError)
ListReferrers issues `GET /v2/<name>/referrers/<digest>` (S07 §Operation: referrers list (v1.1)). artifactTypes, when non-empty, is sent as one repeated `artifactType=<type>` query parameter per entry; a registry that applies the filter echoes `OCI-Filters-Applied` in the response (AC #23). On 200 the response body decodes into an ImageIndex (AC #22); any other status maps to *HTTPError like every other client method — see this file's package doc for the v1.0-vs-v1.1 distinction callers draw from herr.StatusCode.
func (*Client) ListTags ¶ added in v1.46.0
ListTags issues `GET /v2/<name>/tags/list` with no pagination parameters (S07 §Operation: tag list; AC #12).
func (*Client) ListTagsPaginated ¶ added in v1.46.0
func (c *Client) ListTagsPaginated(ctx context.Context, name string, n int, last string) (*TagListResponse, *HTTPError)
ListTagsPaginated issues `GET /v2/<name>/tags/list?n=<n>&last=<last>` (S07 §Operation: tag list / Pagination; AC #13). last is omitted from the query when empty. A registry MAY include an RFC 5988 `Link: <url>; rel="next"` response header when more tags exist beyond the returned page; ListTagsPaginated parses it into NextLink. n=0 returns an empty Tags slice and no NextLink.
func (*Client) MountBlob ¶ added in v1.39.0
func (c *Client) MountBlob(ctx context.Context, name, fromName, digest string) (*BlobUploadResult, *HTTPError)
MountBlob issues `POST /v2/<name>/blobs/uploads/?mount=<digest>&from=<fromName>`, constructing the cross-repository mount URL inline (S07 §Operation: cross-repository blob mount). A registry that supports mount returns 201 with the blob Location; one that does not returns 202 with a session Location for fallback. Both are conformant (AC #15); any non-2xx maps to *HTTPError.
func (*Client) PatchBlobChunk ¶ added in v1.39.0
func (c *Client) PatchBlobChunk(ctx context.Context, location string, start, end int64, body []byte) (*BlobUploadSession, *HTTPError)
PatchBlobChunk issues `PATCH <location>` with `Content-Range: <start>-<end>` and the chunk bytes (S07 §Operation: blob upload chunk). On 202 it returns the updated session Location and the `Range: 0-<end>` header; an out-of-order range yields 416 with BLOB_UPLOAD_INVALID, mapped to *HTTPError (AC #14, #45). location is already absolute and same-origin (resolveAndValidateLocation ran when it was first read) and is used as-is.
func (*Client) PutManifest ¶ added in v1.42.0
func (c *Client) PutManifest(ctx context.Context, name, reference, mediaType string, body []byte) (*PutManifestResponse, *HTTPError)
PutManifest issues `PUT /v2/<name>/manifests/<reference>` with the manifest bytes verbatim, setting `Content-Type: <mediaType>` per S07 §Common request semantics (S07 §Operation: manifest PUT). reference may be a tag or a digest (S07 §Tag and digest references); on a digest reference the request URL's digest MUST equal the digest of body, or the registry returns 400 DIGEST_INVALID (AC #8). On 201 it returns the Location, Docker-Content-Digest, and OCI-Subject (when present) response headers; a manifest exceeding the registry's enforced max yields 413 (AC #28); a manifest referencing missing blobs yields one or more MANIFEST_BLOB_UNKNOWN errors when the registry validates push-time blob references (AC #21, #43); any other non-2xx maps to *HTTPError.
func (*Client) UploadBlobSingle ¶ added in v1.39.0
func (c *Client) UploadBlobSingle(ctx context.Context, name, digest string, body []byte) (*BlobUploadResult, *HTTPError)
UploadBlobSingle issues `POST /v2/<name>/blobs/uploads/?digest=<digest>` with the blob body in one request (S07 §Operation: blob upload single POST). A registry that supports the path returns 201 with the blob Location; one that does not returns 202 with a session Location and the caller falls back to two-phase. Both are conformant (AC #3); a body that doesn't hash to the URL digest yields 400 DIGEST_INVALID, mapped to *HTTPError (AC #44); any other non-2xx also maps to *HTTPError.
func (*Client) VersionCheck ¶ added in v1.53.0
VersionCheck issues `GET /v2/` (S07 §Operation: version check; AC #1). Returns nil on `200 OK`; any other status maps to *HTTPError through the shared do/statusIs path, the same envelope every other operation method in this package uses. The response body is never inspected: AC #1 pins the assertion on status alone.
type DigestVerdict ¶ added in v1.54.0
type DigestVerdict struct {
// Advertised is the raw `Docker-Content-Digest` response header
// value, exactly as the registry sent it (no normalization).
Advertised string
// Expected is the digest the client independently knows for this
// response (GET: digest of the received body; PUT: digest of the
// pushed body; HEAD: the digest from the request path), or empty
// when the client holds none (see type doc).
Expected string
// Match reports whether Advertised equals Expected byte-for-byte.
// Always false when Expected is empty.
Match bool
}
DigestVerdict is the S07 AC #26 (`oci.http.docker-content-digest`) validation outcome the client computes on every manifest GET/HEAD/PUT and blob GET/HEAD response in scope (S07 §Docker-Content- Digest response header). It is carried on the operation's own response value (`ManifestResponse.Digest`, `PutManifestResponse.Digest`, `BlobResponse.Digest`), never on a shared *Client field, so verdicts from concurrent responses cannot clobber each other (plan Step 28).
Expected is empty and Match is always false when the client holds no independently-known digest to compare Advertised against:
- HeadManifest by tag: the client signature carries no expected digest for a tag reference (Step 21's per-slug Fn validates that case at the test layer against its own setup-known digest, per this file's manifest.go package doc).
- GetBlobRange: a partial (206) response's bytes cannot hash to the full-content digest the header advertises, and AC #26 scopes the always-on GET check to the full body; the partial-content shape is AC #29's (`oci.blob.range-request`) concern, not this validator's.
A syntactically-present but unverified Advertised value must never report Match=true: this is a deliberate "unverified pass is worse than no verdict" design (plan Step 28 rationale for HeadManifest).
type HTTPError ¶
type HTTPError struct {
// Method is the HTTP method of the failing request (e.g., "GET").
Method string
// URL is the absolute URL the client attempted.
URL string
// StatusCode is the HTTP status code observed. Zero for
// transport-level failures that never received a status line.
StatusCode int
// ResponseBody is the body the server returned, truncated to
// 4 KiB inclusive of the `... [truncated]` marker when the wire
// body exceeded that limit. See S04 AC #33.
ResponseBody string
// contains filtered or unexported fields
}
HTTPError is returned by client methods when the registry responds with an unexpected status, or when the request fails at the transport layer in a way that yields a partial response. The fields mirror the spec block in `docs/specs/S04-contracts.md` §HTTPError.
ResponseBody must only ever be populated via one of this file's newHTTPErrorFrom* constructors (newHTTPErrorFromRequestError, newHTTPErrorFromResponse, newHTTPErrorFromBody); each of them runs the raw registry body through redact.ScanContent and redact.RedactURLUserinfo before assignment. Constructing an HTTPError directly with an unscrubbed body bypasses that pipeline, and any credential-bearing content the body carries becomes reachable through every body-derived accessor: Code(), HasCode(), and Codes(). Error() is not one of them — it renders only Method, scrubURL(URL) and StatusCode, so it is an egress route for URL userinfo, not for the body.
func (*HTTPError) Code ¶ added in v1.54.0
Code extracts the first error's `code` field from ResponseBody's OCI error envelope (see Codes). Returns "" when ResponseBody does not parse as that shape or carries no errors. A protocol-level response parser belongs at this layer, not the test layer (docs/dev/architecture.md §Code placement), so callers compare against the pinned error-code constants here rather than parsing ResponseBody themselves.
func (*HTTPError) Codes ¶ added in v1.64.0
Codes reports every entry's `code` field from ResponseBody's OCI error envelope (S07 §Error response format: `{"errors":[{"code":"...","message":"..."}]}`), in order, alongside whether ResponseBody decoded as JSON compatible with that shape.
ok is true for any JSON that decodes into the envelope, which includes JSON carrying no `errors` array at all: `{}`, `{"foo":1}`, `{"errors":null}`, and the literal `null` each yield ok == true with an empty, non-nil codes. ok is false wherever encoding/json rejects ResponseBody. Only `code` is declared, so an entry whose `message` is not a string still decodes rather than failing the parse — the one classification this method does not inherit from the conformance-layer parser it replaced (plan Step 26a amendment).
Unlike Code and HasCode, which collapse "did not decode" and "decoded but carries no errors[] entry" into the same empty/false result, Codes lets a caller distinguish the two — needed where a spec AC treats a non-JSON body and a JSON-but-empty-envelope body differently (e.g. S07 AC #42's non-JSON carve-out). Plan Step 26a amendment (docs/plans/2026-05-26-oci-format.md).
ResponseBody must have been set via one of this file's newHTTPErrorFrom* constructors; direct construction of HTTPError with a raw registry response body bypasses the scrubbing pipeline (see HTTPError's doc) and may expose credential-bearing content through the returned codes.
func (*HTTPError) Error ¶
Error implements the error interface for *HTTPError. The format is stable for end-user display; it must not include any value drawn from the Authorization request header.
func (*HTTPError) HasBearerRealmChallenge ¶ added in v1.62.0
HasBearerRealmChallenge reports whether the captured WWW-Authenticate header (see WWWAuthenticate above) is a well-formed RFC 6750 Bearer challenge carrying a non-empty realm parameter, reusing this package's own parseWWWAuthenticate (auth.go) rather than making every caller re-parse the header itself. A protocol-level response parser belongs at this layer, not the test layer (docs/dev/architecture.md §Code placement), mirroring Code()'s identical rationale.
func (*HTTPError) HasCode ¶ added in v1.58.0
HasCode reports whether any error in ResponseBody's OCI error envelope (see Codes) carries the given code. Unlike Code, which only inspects the first entry, HasCode lets a caller accept a registry that reports multiple errors in one response — needed where a spec AC requires "one or more" errors of a given code rather than pinning the code to a specific position in the list.
func (*HTTPError) WWWAuthenticate ¶ added in v1.62.0
WWWAuthenticate returns the raw WWW-Authenticate response header value captured from the 401 response that produced this error, or "" when none was captured (a non-401 error, or a 401 whose response carried no such header). Exposed so a caller outside pkg/client/oci can check S07 AC #47's RFC 6750 alternative (`WWW-Authenticate: Bearer realm="…"`) for oci.negative.unauthenticated: unlike Error() and ResponseBody, which deliberately never render this value (see the wwwAuthenticate field doc above), this accessor is the one sanctioned egress route for it. A caller that surfaces the returned value further (a TestCase message, an HTTPDetail) must not re-introduce the channels S07 §Authentication forbids. Plan Step 26b amendment (docs/plans/2026-05-26-oci-format.md).
type ImageIndex ¶ added in v1.52.0
type ImageIndex struct {
// SchemaVersion is the image index schema version (2 for every
// Phase 1 registry).
SchemaVersion int `json:"schemaVersion"`
// MediaType is the image index media type
// (`application/vnd.oci.image.index.v1+json`).
MediaType string `json:"mediaType"`
// Manifests lists every referrer the registry returned. Empty
// (non-nil after a successful decode of a spec-shaped `[]` body)
// when the subject digest has no referrers.
Manifests []ReferrerDescriptor `json:"manifests"`
}
ImageIndex is the OCI image index body a referrers-list response carries (S07 §Referrers API (v1.1); OCI Image Format Specification §Image Index).
type ManifestResponse ¶ added in v1.42.0
type ManifestResponse struct {
// StatusCode is the HTTP status of the accepted (200) response.
StatusCode int
// Body is the manifest bytes verbatim, exactly as GetManifest read
// them off the wire (no JSON re-marshaling), so callers can assert
// byte-exact storage (AC #34). Empty for HeadManifest (RFC 9110
// §9.3.2: a HEAD response carries no body).
Body []byte
// ContentType is the response Content-Type header, verbatim
// (S07 §`http.content-type`; AC #27).
ContentType string
// ContentLength is the response Content-Length. -1 when the server
// did not declare one (net/http's sentinel for unknown length).
ContentLength int64
// DockerContentDigest is the `Docker-Content-Digest` response header
// (S07 §`Docker-Content-Digest` response header; AC #10, #11, #26).
DockerContentDigest string
// Digest is the S07 AC #26 Docker-Content-Digest verdict (plan
// Step 28). For GetManifest, Expected is the digest of the received
// Body. For HeadManifest, Expected is the digest from the request
// path when reference is a digest, and empty when reference is a
// tag (HeadManifest carries no expected digest for a tag reference;
// see this file's package doc and DigestVerdict's doc for the
// HEAD-by-tag test-layer split).
Digest DigestVerdict
}
ManifestResponse is the result of a manifest GET or HEAD (S07 §Operation: manifest GET / HEAD).
type PutManifestResponse ¶ added in v1.42.0
type PutManifestResponse struct {
// StatusCode is the HTTP status of the accepted (201) response.
StatusCode int
// Location is the canonical `/v2/<name>/manifests/<digest>` URL the
// registry echoes back, populated on both push-by-tag and
// push-by-digest.
Location string
// DockerContentDigest is the `Docker-Content-Digest` response header;
// it MUST equal the digest the client computed locally over the
// pushed bytes (S07 §`Docker-Content-Digest` response header; AC #7,
// #8, #26).
DockerContentDigest string
// OCISubject is the `OCI-Subject` response header, present when the
// pushed manifest carries a `subject` field and the registry
// implements OCI v1.1 (S07 §`subject` field (v1.1); AC #19, #20).
// Empty when the response omits the header (v1.0 registry, or the
// pushed manifest carried no `subject` field).
OCISubject string
// Digest is the S07 AC #26 Docker-Content-Digest verdict: Expected
// is the digest of the pushed body (the client already has it),
// compared against the DockerContentDigest header above (plan
// Step 28; see DigestVerdict's doc for the zero-verdict cases).
Digest DigestVerdict
}
PutManifestResponse is the result of a manifest PUT (S07 §Operation: manifest PUT).
type ReferrerDescriptor ¶ added in v1.52.0
type ReferrerDescriptor struct {
// MediaType is the referrer manifest's media type.
MediaType string `json:"mediaType"`
// Digest is the referrer manifest's content digest.
Digest string `json:"digest"`
// Size is the referrer manifest's byte size.
Size int64 `json:"size"`
// ArtifactType is the referrer's artifact type, when the manifest
// carries one. Empty when absent (S07 AC #23's `artifactType`
// filter matches against this field).
ArtifactType string `json:"artifactType,omitempty"`
// Annotations is the referrer's annotations map, when present. Nil
// when absent.
Annotations map[string]string `json:"annotations,omitempty"`
}
ReferrerDescriptor is one entry in an OCI image index's `manifests` array (S07 §Referrers API (v1.1); OCI Image Format Specification §Image Index).
type ReferrersResponse ¶ added in v1.52.0
type ReferrersResponse struct {
// StatusCode is the HTTP status of the accepted (200) response.
StatusCode int
// ContentType is the response Content-Type header, verbatim (S07
// §Referrers API (v1.1) / "Probe to distinguish v1.1 from v1.0": a
// v1.1 registry's 200 response carries
// "application/vnd.oci.image.index.v1+json"; callers distinguishing
// v1.1 from a 200 that isn't actually an image index compare this
// against client.IndexMediaType.
ContentType string
// Index is the decoded image index body (AC #22).
Index ImageIndex
// FiltersApplied is the parsed `OCI-Filters-Applied` response
// header (S07 §Referrers API (v1.1); AC #23): the header value
// split on `,` with surrounding whitespace trimmed from each
// entry. Nil when the header is absent (no filter applied, or the
// registry ignores the filter).
FiltersApplied []string
}
ReferrersResponse is the result of a referrers-list operation (S07 §Operation: referrers list (v1.1)).
type TagListResponse ¶ added in v1.46.0
type TagListResponse struct {
// Name is the repository name echoed back in the response body.
Name string
// Tags is the tag list returned by the registry, in the order the
// response body carried it. The registry sorts tags lexically per
// S07 §Tags (AC #12); the client does not re-sort.
Tags []string
// NextLink is the target URL of an RFC 5988
// `Link: <url>; rel="next"` response header, or empty when the
// header is absent or carries no `rel="next"` entry (S07
// §Operation: tag list / `Link` header; AC #13).
NextLink string
}
TagListResponse is the parsed result of a tag-list operation (S07 §Operation: tag list).