Documentation
¶
Overview ¶
Package docker serves the registry protocol, the OCI Distribution Specification v1.1 with Docker's extensions, for docker, oci and helmoci repositories (decisions 0003 and 0031). It answers three addressing forms:
- the repository path, /v2/<repo>/<image>/..., the native default, which needs no reverse proxy;
- Artifactory's own prefix, /artifactory/api/docker/<repo>/v2/<image>/...;
- the subdomain, <repo>.<base_url host>/v2/<image>/..., when docker.subdomain_match is on.
The router is hand-written and mounted before the generated servers (decision 0002). It parses each path into a Request and hands it to the endpoint a feature registered for its kind and method; an operation the specification defines that no feature has registered yet answers 405 UNSUPPORTED. This package never imports internal/server.
Index ¶
- Constants
- func APIVersion(next http.Handler) http.Handler
- func ChallengesAnonymous(path string) bool
- func Errorf(status int, code, format string, args ...any) *apierror.Error
- func GrantsCatalog(r *http.Request) bool
- func IsRegistryPath(path string) bool
- func Lookup(ctx context.Context, st store.Store, key string) (repo.Config, bool, error)
- func Serves(t repo.PackageType) bool
- func ValidName(name string) bool
- func Write(w http.ResponseWriter, err error)
- func WriteAll(w http.ResponseWriter, status int, errs ...*apierror.Error)
- type Endpoint
- type Kind
- type Options
- type Registry
- type Request
- type TokenIssuer
Constants ¶
const ( CodeBlobUnknown = "BLOB_UNKNOWN" CodeBlobUploadInvalid = "BLOB_UPLOAD_INVALID" CodeBlobUploadUnknown = "BLOB_UPLOAD_UNKNOWN" CodeDigestInvalid = "DIGEST_INVALID" CodeManifestBlobUnknown = "MANIFEST_BLOB_UNKNOWN" CodeManifestInvalid = "MANIFEST_INVALID" CodeManifestUnknown = "MANIFEST_UNKNOWN" CodeNameInvalid = "NAME_INVALID" CodeNameUnknown = "NAME_UNKNOWN" CodeSizeInvalid = "SIZE_INVALID" CodeDenied = "DENIED" CodeUnsupported = "UNSUPPORTED" CodeTooManyRequests = "TOOMANYREQUESTS" // CodeTagInvalid is the one code outside the specification's list: a // push to a tag that would collide with the layout's own folders // (decision 0031). CodeTagInvalid = "TAG_INVALID" )
The error codes of the OCI Distribution Specification v1.1 (code-1 to code-14). Docker clients branch on the code, not the message, so every registry error carries one of these.
const (
APIVersionHeader = "Docker-Distribution-API-Version"
)
APIVersionHeader is the header every registry response carries. Docker clients read it from the /v2/ probe, the 401 included, to know that they reached a v2 registry.
const RegistryHeader = "X-Artifactory-Docker-Registry"
RegistryHeader names, on a manifest read, the repository that holds the manifest, by its stored key. jf docker push and pull HEAD the manifest through the registry after the docker client finishes and read the key from here; without it they fail before collecting build-info (jfrog-cli-artifactory ocicontainer/image.go, GetRemoteRepo).
Variables ¶
This section is empty.
Functions ¶
func APIVersion ¶
APIVersion sets the version header on every registry response, before authentication can answer one.
func ChallengesAnonymous ¶
ChallengesAnonymous reports whether a request to path without credentials is challenged even while anonymous access is on: every registry path but the token endpoint, from which an anonymous client fetches the anonymous token it then pulls with (decision 0031).
func Errorf ¶
Errorf builds a registry error: the status, the specification's code and a message for people. Write renders it in the OCI envelope.
func GrantsCatalog ¶
GrantsCatalog reports whether the request's credential may list the catalog: any but a registry token without registry:catalog:*.
func IsRegistryPath ¶
IsRegistryPath reports whether path is under /v2 or a repository's /artifactory/api/docker/<repo>/v2.
func Lookup ¶
Lookup finds the Docker, OCI or Helm OCI repository key names in st, compared without regard to case: keys are unique that way, and Docker clients send references in lower case only (decision 0003). found is false for a missing repository and for one of another package type.
func Serves ¶
func Serves(t repo.PackageType) bool
Serves reports whether the registry serves repositories of package type t: docker, and the oci and helmoci types that share its protocol (research 04).
func Write ¶
func Write(w http.ResponseWriter, err error)
Write renders err in the OCI envelope. An error that is not an *apierror.Error becomes a 500 without its detail, as everywhere else.
Types ¶
type Endpoint ¶
type Endpoint func(w http.ResponseWriter, r *http.Request, q Request)
Endpoint serves one registry operation for a parsed request.
type Kind ¶
type Kind int
Kind is the registry operation a path addresses, before its method picks the endpoint.
const ( // KindBase is the empty path, the version probe clients send first. KindBase Kind = iota + 1 // KindCatalog is _catalog, Docker's listing of image names: of every // repository the caller can read on the repository path, of one // repository under a subdomain, as <repo>/_catalog or under the // Artifactory prefix (decision 0003). KindCatalog // KindToken is token, the registry token endpoint. KindToken // KindAuth is auth under the Artifactory prefix, which answers the // config.json entry. KindAuth // KindBlob is <name>/blobs/<digest>. KindBlob // KindUploads is <name>/blobs/uploads/, which starts an upload. KindUploads // KindUpload is <name>/blobs/uploads/<session>, one upload in progress. KindUpload // KindManifest is <name>/manifests/<tag or digest>. KindManifest // KindTags is <name>/tags/list. KindTags // KindReferrers is <name>/referrers/<digest>. KindReferrers )
The kinds of registry path. Their comments show the path below /v2/, where <name> is the image name and, on the repository-path method, begins with the repository key.
type Options ¶
type Options struct {
// Store resolves repositories. Nil serves no repository, for tests of
// the router alone.
Store store.Store
// SubdomainMatch turns on the subdomain method. BaseURL must then be
// set: its host is the parent the repository subdomains sit under.
SubdomainMatch bool
BaseURL string
// Fault records an unexpected error for the access log, as the server's
// handlers do; nil drops it.
Fault func(*http.Request, error)
// Blobs is the blob store behind Store. Nil leaves blobs and uploads
// unimplemented, for tests of the router alone.
Blobs blob.Store
// ServeBlob answers a GET of a blob's item in a repository with the
// server's download, which applies the download redirect policy
// (decision 0029) and counts the download. Nil streams it from Blobs.
ServeBlob func(w http.ResponseWriter, r *http.Request, c repo.Config, it types.Item)
// RedirectManifest answers a GET of a manifest's item, whose media type
// is mediaType, with the server's download redirect when the policy says
// so (decision 0029), and reports whether it wrote a response. Nil
// streams every manifest.
RedirectManifest func(
w http.ResponseWriter, r *http.Request, c repo.Config, it types.Item, mediaType string,
) bool
// Now supplies the time to upload sessions; nil means time.Now.
Now func() time.Time
// Tokens signs registry tokens; nil leaves the token endpoint
// unimplemented.
Tokens TokenIssuer
}
Options configures a Registry.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry routes registry requests to the endpoints features register.
func (*Registry) Challenge ¶
Challenge gives every 401 from the registry the Bearer challenge Docker clients follow to the token endpoint (decision 0005), whoever wrote it: the authentication middleware, a handler's Require, or a later feature. A 401 written with apierror's default Basic challenge, or none, gets the registry's; one a handler challenged itself (a mount's second scope) keeps its own. It must run after the base-URL middleware.
func (*Registry) Register ¶
Register mounts the registry on r for every method, so that the registry answers 405 itself, in its own envelope. Under the Artifactory prefix chi prefers the generated JFrog operations' literal segments (POST parentManifests, POST promote, DELETE delete) to these catch-alls, so those keep their generated handlers (decision 0003). The JFrog catalog and tags list are the registry's own operations, marked x-handwritten in the specification; they are registered under the patterns the specification gives them as well, so that the server's stubs for unimplemented hand-written operations never claim them.
type Request ¶
type Request struct {
Kind Kind
// RepoKey is the repository the request addressed: the subdomain, or
// the key in /artifactory/api/docker/<key>/v2. It is empty for /v2/,
// /v2/_catalog and /v2/token on the repository path, which address no
// repository, and may be "null", which the token realm uses for that
// (research 17). Only an operation on an image resolves it into Repo.
RepoKey string
// Repo is the resolved repository, set when Kind is an image operation.
Repo repo.Config
// Name is the image name inside the repository.
Name string
// Reference is the digest, tag or upload session the path ends in.
Reference string
// contains filtered or unexported fields
}
Request is a registry request with its operation parsed and, for an operation on an image, its repository resolved and its name validated.
func (Request) Path ¶
Path returns the absolute path of an operation on the request's image in the addressing form the client used, for Location headers: the client may only know the registry by that form. Path("blobs", "uploads", id) is .../<name>/blobs/uploads/<id>.
func (Request) Require ¶
Require answers nil when the caller holds every action in want on path, a path inside the repository. Otherwise it answers what the registry tells a client: UNAUTHORIZED to an anonymous caller, so that it sends credentials, and DENIED to anyone else. A registry token must also grant the actions for the image as this request names it; one that does not gets UNAUTHORIZED, whose challenge (Challenge) names the scope the client then fetches a token for, as Docker's registry answers an insufficient scope. A request without a principal reached the handler only on a server built without authentication, which only tests build, and is allowed.
type TokenIssuer ¶
type TokenIssuer interface {
IssueRegistry(ctx context.Context, r token.RegistryRequest) (token.Issued, error)
}
TokenIssuer signs registry tokens; internal/auth/token implements it.