diff --git a/go.mod b/go.mod index bbfdcc8fa7f..e8f6fdc2ba3 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,9 @@ exclude ( github.com/opencontainers/image-spec v1.1.0-rc4 ) +// Unit tests fail due to a breaking change in reference.Parse() from this version. +exclude github.com/docker/distribution v2.8.3+incompatible + // this version requires code change may remove these later exclude go.opentelemetry.io/otel/metric v0.37.0 @@ -34,7 +37,7 @@ require ( github.com/cenkalti/backoff/v4 v4.2.1 github.com/containerd/containerd v1.7.13 github.com/docker/cli v25.0.3+incompatible - github.com/docker/distribution v2.8.3+incompatible + github.com/docker/distribution v2.8.2+incompatible github.com/docker/docker v25.0.5+incompatible github.com/docker/go-connections v0.5.0 github.com/dustin/go-humanize v1.0.1 diff --git a/go.sum b/go.sum index ff5d8230cd7..e52ab687c9f 100644 --- a/go.sum +++ b/go.sum @@ -316,8 +316,8 @@ github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5 github.com/docker/cli v25.0.3+incompatible h1:KLeNs7zws74oFuVhgZQ5ONGZiXUUdgsdy6/EsX/6284= github.com/docker/cli v25.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= -github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE= github.com/docker/docker v25.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= diff --git a/vendor/github.com/docker/distribution/.golangci.yml b/vendor/github.com/docker/distribution/.golangci.yml index 61dd0e00eb7..36c083b0fc4 100644 --- a/vendor/github.com/docker/distribution/.golangci.yml +++ b/vendor/github.com/docker/distribution/.golangci.yml @@ -1,5 +1,7 @@ linters: enable: + - structcheck + - varcheck - staticcheck - unconvert - gofmt @@ -12,14 +14,6 @@ linters: disable: - errcheck -linters-settings: - revive: - rules: - # TODO(thaJeztah): temporarily disabled the "unused-parameter" check. - # It produces many warnings, and some of those may need to be looked at. - - name: unused-parameter - disabled: true - run: deadline: 2m skip-dirs: diff --git a/vendor/github.com/docker/distribution/.mailmap b/vendor/github.com/docker/distribution/.mailmap index d7b832d9ea0..d94c3936e02 100644 --- a/vendor/github.com/docker/distribution/.mailmap +++ b/vendor/github.com/docker/distribution/.mailmap @@ -49,6 +49,3 @@ Hayley Swimelar Jose D. Gomez R Shengjing Zhu Silvin Lubecki <31478878+silvin-lubecki@users.noreply.github.com> -James Hewitt -Marcus Pettersen Irgens -Ben Manuel diff --git a/vendor/github.com/docker/distribution/BUILDING.md b/vendor/github.com/docker/distribution/BUILDING.md index 4c43b03cb7a..2981d016b0d 100644 --- a/vendor/github.com/docker/distribution/BUILDING.md +++ b/vendor/github.com/docker/distribution/BUILDING.md @@ -114,4 +114,4 @@ the registry binary generated in the "./bin" directory: ### Optional build tags Optional [build tags](http://golang.org/pkg/go/build/) can be provided using -the environment variable `BUILDTAGS`. +the environment variable `DOCKER_BUILDTAGS`. diff --git a/vendor/github.com/docker/distribution/Dockerfile b/vendor/github.com/docker/distribution/Dockerfile index ebd42c242be..fb54b68138d 100644 --- a/vendor/github.com/docker/distribution/Dockerfile +++ b/vendor/github.com/docker/distribution/Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 -ARG GO_VERSION=1.20.8 -ARG ALPINE_VERSION=3.18 +ARG GO_VERSION=1.19.9 +ARG ALPINE_VERSION=3.16 ARG XX_VERSION=1.2.1 FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx @@ -22,12 +22,12 @@ RUN --mount=target=. \ FROM base AS build ARG TARGETPLATFORM ARG LDFLAGS="-s -w" -ARG BUILDTAGS="include_oss,include_gcs" +ARG BUILDTAGS="include_oss include_gcs" RUN --mount=type=bind,target=/go/src/github.com/docker/distribution,rw \ --mount=type=cache,target=/root/.cache/go-build \ --mount=target=/go/pkg/mod,type=cache \ --mount=type=bind,source=/tmp/.ldflags,target=/tmp/.ldflags,from=version \ - set -x ; xx-go build -tags "${BUILDTAGS}" -trimpath -ldflags "$(cat /tmp/.ldflags) ${LDFLAGS}" -o /usr/bin/registry ./cmd/registry \ + set -x ; xx-go build -trimpath -ldflags "$(cat /tmp/.ldflags) ${LDFLAGS}" -o /usr/bin/registry ./cmd/registry \ && xx-verify --static /usr/bin/registry FROM scratch AS binary diff --git a/vendor/github.com/docker/distribution/Makefile b/vendor/github.com/docker/distribution/Makefile index dcdbcb54799..75e11820152 100644 --- a/vendor/github.com/docker/distribution/Makefile +++ b/vendor/github.com/docker/distribution/Makefile @@ -50,7 +50,7 @@ version/version.go: check: ## run all linters (TODO: enable "unused", "varcheck", "ineffassign", "unconvert", "staticheck", "goimports", "structcheck") @echo "$(WHALE) $@" - @GO111MODULE=off golangci-lint --build-tags "${BUILDTAGS}" run + @GO111MODULE=off golangci-lint run test: ## run tests, except integration test with test.short @echo "$(WHALE) $@" diff --git a/vendor/github.com/docker/distribution/blobs.go b/vendor/github.com/docker/distribution/blobs.go index 671372abf4e..2a659eaa368 100644 --- a/vendor/github.com/docker/distribution/blobs.go +++ b/vendor/github.com/docker/distribution/blobs.go @@ -8,7 +8,7 @@ import ( "net/http" "time" - "github.com/distribution/reference" + "github.com/docker/distribution/reference" "github.com/opencontainers/go-digest" v1 "github.com/opencontainers/image-spec/specs-go/v1" ) diff --git a/vendor/github.com/opencontainers/go-digest/digestset/set.go b/vendor/github.com/docker/distribution/digestset/set.go similarity index 91% rename from vendor/github.com/opencontainers/go-digest/digestset/set.go rename to vendor/github.com/docker/distribution/digestset/set.go index 71f24184ca2..71327dca720 100644 --- a/vendor/github.com/opencontainers/go-digest/digestset/set.go +++ b/vendor/github.com/docker/distribution/digestset/set.go @@ -1,18 +1,3 @@ -// Copyright 2020, 2020 OCI Contributors -// Copyright 2017 Docker, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package digestset import ( diff --git a/vendor/github.com/docker/distribution/reference/helpers.go b/vendor/github.com/docker/distribution/reference/helpers.go new file mode 100644 index 00000000000..978df7eabbf --- /dev/null +++ b/vendor/github.com/docker/distribution/reference/helpers.go @@ -0,0 +1,42 @@ +package reference + +import "path" + +// IsNameOnly returns true if reference only contains a repo name. +func IsNameOnly(ref Named) bool { + if _, ok := ref.(NamedTagged); ok { + return false + } + if _, ok := ref.(Canonical); ok { + return false + } + return true +} + +// FamiliarName returns the familiar name string +// for the given named, familiarizing if needed. +func FamiliarName(ref Named) string { + if nn, ok := ref.(normalizedNamed); ok { + return nn.Familiar().Name() + } + return ref.Name() +} + +// FamiliarString returns the familiar string representation +// for the given reference, familiarizing if needed. +func FamiliarString(ref Reference) string { + if nn, ok := ref.(normalizedNamed); ok { + return nn.Familiar().String() + } + return ref.String() +} + +// FamiliarMatch reports whether ref matches the specified pattern. +// See https://godoc.org/path#Match for supported patterns. +func FamiliarMatch(pattern string, ref Reference) (bool, error) { + matched, err := path.Match(pattern, FamiliarString(ref)) + if namedRef, isNamed := ref.(Named); isNamed && !matched { + matched, _ = path.Match(pattern, FamiliarName(namedRef)) + } + return matched, err +} diff --git a/vendor/github.com/docker/distribution/reference/helpers_deprecated.go b/vendor/github.com/docker/distribution/reference/helpers_deprecated.go deleted file mode 100644 index cbd119250ad..00000000000 --- a/vendor/github.com/docker/distribution/reference/helpers_deprecated.go +++ /dev/null @@ -1,34 +0,0 @@ -package reference - -import "github.com/distribution/reference" - -// IsNameOnly returns true if reference only contains a repo name. -// -// Deprecated: use [reference.IsNameOnly]. -func IsNameOnly(ref reference.Named) bool { - return reference.IsNameOnly(ref) -} - -// FamiliarName returns the familiar name string -// for the given named, familiarizing if needed. -// -// Deprecated: use [reference.FamiliarName]. -func FamiliarName(ref reference.Named) string { - return reference.FamiliarName(ref) -} - -// FamiliarString returns the familiar string representation -// for the given reference, familiarizing if needed. -// -// Deprecated: use [reference.FamiliarString]. -func FamiliarString(ref reference.Reference) string { - return reference.FamiliarString(ref) -} - -// FamiliarMatch reports whether ref matches the specified pattern. -// See [path.Match] for supported patterns. -// -// Deprecated: use [reference.FamiliarMatch]. -func FamiliarMatch(pattern string, ref reference.Reference) (bool, error) { - return reference.FamiliarMatch(pattern, ref) -} diff --git a/vendor/github.com/docker/distribution/reference/normalize.go b/vendor/github.com/docker/distribution/reference/normalize.go new file mode 100644 index 00000000000..b3dfb7a6d7e --- /dev/null +++ b/vendor/github.com/docker/distribution/reference/normalize.go @@ -0,0 +1,199 @@ +package reference + +import ( + "errors" + "fmt" + "strings" + + "github.com/docker/distribution/digestset" + "github.com/opencontainers/go-digest" +) + +var ( + legacyDefaultDomain = "index.docker.io" + defaultDomain = "docker.io" + officialRepoName = "library" + defaultTag = "latest" +) + +// normalizedNamed represents a name which has been +// normalized and has a familiar form. A familiar name +// is what is used in Docker UI. An example normalized +// name is "docker.io/library/ubuntu" and corresponding +// familiar name of "ubuntu". +type normalizedNamed interface { + Named + Familiar() Named +} + +// ParseNormalizedNamed parses a string into a named reference +// transforming a familiar name from Docker UI to a fully +// qualified reference. If the value may be an identifier +// use ParseAnyReference. +func ParseNormalizedNamed(s string) (Named, error) { + if ok := anchoredIdentifierRegexp.MatchString(s); ok { + return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s) + } + domain, remainder := splitDockerDomain(s) + var remoteName string + if tagSep := strings.IndexRune(remainder, ':'); tagSep > -1 { + remoteName = remainder[:tagSep] + } else { + remoteName = remainder + } + if strings.ToLower(remoteName) != remoteName { + return nil, errors.New("invalid reference format: repository name must be lowercase") + } + + ref, err := Parse(domain + "/" + remainder) + if err != nil { + return nil, err + } + named, isNamed := ref.(Named) + if !isNamed { + return nil, fmt.Errorf("reference %s has no name", ref.String()) + } + return named, nil +} + +// ParseDockerRef normalizes the image reference following the docker convention. This is added +// mainly for backward compatibility. +// The reference returned can only be either tagged or digested. For reference contains both tag +// and digest, the function returns digested reference, e.g. docker.io/library/busybox:latest@ +// sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa will be returned as +// docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa. +func ParseDockerRef(ref string) (Named, error) { + named, err := ParseNormalizedNamed(ref) + if err != nil { + return nil, err + } + if _, ok := named.(NamedTagged); ok { + if canonical, ok := named.(Canonical); ok { + // The reference is both tagged and digested, only + // return digested. + newNamed, err := WithName(canonical.Name()) + if err != nil { + return nil, err + } + newCanonical, err := WithDigest(newNamed, canonical.Digest()) + if err != nil { + return nil, err + } + return newCanonical, nil + } + } + return TagNameOnly(named), nil +} + +// splitDockerDomain splits a repository name to domain and remotename string. +// If no valid domain is found, the default domain is used. Repository name +// needs to be already validated before. +func splitDockerDomain(name string) (domain, remainder string) { + i := strings.IndexRune(name, '/') + if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") { + domain, remainder = defaultDomain, name + } else { + domain, remainder = name[:i], name[i+1:] + } + if domain == legacyDefaultDomain { + domain = defaultDomain + } + if domain == defaultDomain && !strings.ContainsRune(remainder, '/') { + remainder = officialRepoName + "/" + remainder + } + return +} + +// familiarizeName returns a shortened version of the name familiar +// to to the Docker UI. Familiar names have the default domain +// "docker.io" and "library/" repository prefix removed. +// For example, "docker.io/library/redis" will have the familiar +// name "redis" and "docker.io/dmcgowan/myapp" will be "dmcgowan/myapp". +// Returns a familiarized named only reference. +func familiarizeName(named namedRepository) repository { + repo := repository{ + domain: named.Domain(), + path: named.Path(), + } + + if repo.domain == defaultDomain { + repo.domain = "" + // Handle official repositories which have the pattern "library/" + if split := strings.Split(repo.path, "/"); len(split) == 2 && split[0] == officialRepoName { + repo.path = split[1] + } + } + return repo +} + +func (r reference) Familiar() Named { + return reference{ + namedRepository: familiarizeName(r.namedRepository), + tag: r.tag, + digest: r.digest, + } +} + +func (r repository) Familiar() Named { + return familiarizeName(r) +} + +func (t taggedReference) Familiar() Named { + return taggedReference{ + namedRepository: familiarizeName(t.namedRepository), + tag: t.tag, + } +} + +func (c canonicalReference) Familiar() Named { + return canonicalReference{ + namedRepository: familiarizeName(c.namedRepository), + digest: c.digest, + } +} + +// TagNameOnly adds the default tag "latest" to a reference if it only has +// a repo name. +func TagNameOnly(ref Named) Named { + if IsNameOnly(ref) { + namedTagged, err := WithTag(ref, defaultTag) + if err != nil { + // Default tag must be valid, to create a NamedTagged + // type with non-validated input the WithTag function + // should be used instead + panic(err) + } + return namedTagged + } + return ref +} + +// ParseAnyReference parses a reference string as a possible identifier, +// full digest, or familiar name. +func ParseAnyReference(ref string) (Reference, error) { + if ok := anchoredIdentifierRegexp.MatchString(ref); ok { + return digestReference("sha256:" + ref), nil + } + if dgst, err := digest.Parse(ref); err == nil { + return digestReference(dgst), nil + } + + return ParseNormalizedNamed(ref) +} + +// ParseAnyReferenceWithSet parses a reference string as a possible short +// identifier to be matched in a digest set, a full digest, or familiar name. +func ParseAnyReferenceWithSet(ref string, ds *digestset.Set) (Reference, error) { + if ok := anchoredShortIdentifierRegexp.MatchString(ref); ok { + dgst, err := ds.Lookup(ref) + if err == nil { + return digestReference(dgst), nil + } + } else { + if dgst, err := digest.Parse(ref); err == nil { + return digestReference(dgst), nil + } + } + + return ParseNormalizedNamed(ref) +} diff --git a/vendor/github.com/docker/distribution/reference/normalize_deprecated.go b/vendor/github.com/docker/distribution/reference/normalize_deprecated.go deleted file mode 100644 index 1b4a459d700..00000000000 --- a/vendor/github.com/docker/distribution/reference/normalize_deprecated.go +++ /dev/null @@ -1,92 +0,0 @@ -package reference - -import ( - "regexp" - - "github.com/distribution/reference" - "github.com/opencontainers/go-digest" - "github.com/opencontainers/go-digest/digestset" -) - -// ParseNormalizedNamed parses a string into a named reference -// transforming a familiar name from Docker UI to a fully -// qualified reference. If the value may be an identifier -// use ParseAnyReference. -// -// Deprecated: use [reference.ParseNormalizedNamed]. -func ParseNormalizedNamed(s string) (reference.Named, error) { - return reference.ParseNormalizedNamed(s) -} - -// ParseDockerRef normalizes the image reference following the docker convention, -// which allows for references to contain both a tag and a digest. -// -// Deprecated: use [reference.ParseDockerRef]. -func ParseDockerRef(ref string) (reference.Named, error) { - return reference.ParseDockerRef(ref) -} - -// TagNameOnly adds the default tag "latest" to a reference if it only has -// a repo name. -// -// Deprecated: use [reference.TagNameOnly]. -func TagNameOnly(ref reference.Named) reference.Named { - return reference.TagNameOnly(ref) -} - -// ParseAnyReference parses a reference string as a possible identifier, -// full digest, or familiar name. -// -// Deprecated: use [reference.ParseAnyReference]. -func ParseAnyReference(ref string) (reference.Reference, error) { - return reference.ParseAnyReference(ref) -} - -// Functions and types below have been removed in distribution v3 and -// have not been ported to github.com/distribution/reference. See -// https://github.com/distribution/distribution/pull/3774 - -var ( - // ShortIdentifierRegexp is the format used to represent a prefix - // of an identifier. A prefix may be used to match a sha256 identifier - // within a list of trusted identifiers. - // - // Deprecated: support for short-identifiers is deprecated, and will be removed in v3. - ShortIdentifierRegexp = regexp.MustCompile(shortIdentifier) - - shortIdentifier = `([a-f0-9]{6,64})` - - // anchoredShortIdentifierRegexp is used to check if a value - // is a possible identifier prefix, anchored at start and end - // of string. - anchoredShortIdentifierRegexp = regexp.MustCompile(`^` + shortIdentifier + `$`) -) - -type digestReference digest.Digest - -func (d digestReference) String() string { - return digest.Digest(d).String() -} - -func (d digestReference) Digest() digest.Digest { - return digest.Digest(d) -} - -// ParseAnyReferenceWithSet parses a reference string as a possible short -// identifier to be matched in a digest set, a full digest, or familiar name. -// -// Deprecated: support for short-identifiers is deprecated, and will be removed in v3. -func ParseAnyReferenceWithSet(ref string, ds *digestset.Set) (Reference, error) { - if ok := anchoredShortIdentifierRegexp.MatchString(ref); ok { - dgst, err := ds.Lookup(ref) - if err == nil { - return digestReference(dgst), nil - } - } else { - if dgst, err := digest.Parse(ref); err == nil { - return digestReference(dgst), nil - } - } - - return reference.ParseNormalizedNamed(ref) -} diff --git a/vendor/github.com/docker/distribution/reference/reference.go b/vendor/github.com/docker/distribution/reference/reference.go new file mode 100644 index 00000000000..b7cd00b0d68 --- /dev/null +++ b/vendor/github.com/docker/distribution/reference/reference.go @@ -0,0 +1,433 @@ +// Package reference provides a general type to represent any way of referencing images within the registry. +// Its main purpose is to abstract tags and digests (content-addressable hash). +// +// Grammar +// +// reference := name [ ":" tag ] [ "@" digest ] +// name := [domain '/'] path-component ['/' path-component]* +// domain := domain-component ['.' domain-component]* [':' port-number] +// domain-component := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/ +// port-number := /[0-9]+/ +// path-component := alpha-numeric [separator alpha-numeric]* +// alpha-numeric := /[a-z0-9]+/ +// separator := /[_.]|__|[-]*/ +// +// tag := /[\w][\w.-]{0,127}/ +// +// digest := digest-algorithm ":" digest-hex +// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]* +// digest-algorithm-separator := /[+.-_]/ +// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/ +// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value +// +// identifier := /[a-f0-9]{64}/ +// short-identifier := /[a-f0-9]{6,64}/ +package reference + +import ( + "errors" + "fmt" + "strings" + + "github.com/opencontainers/go-digest" +) + +const ( + // NameTotalLengthMax is the maximum total number of characters in a repository name. + NameTotalLengthMax = 255 +) + +var ( + // ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference. + ErrReferenceInvalidFormat = errors.New("invalid reference format") + + // ErrTagInvalidFormat represents an error while trying to parse a string as a tag. + ErrTagInvalidFormat = errors.New("invalid tag format") + + // ErrDigestInvalidFormat represents an error while trying to parse a string as a tag. + ErrDigestInvalidFormat = errors.New("invalid digest format") + + // ErrNameContainsUppercase is returned for invalid repository names that contain uppercase characters. + ErrNameContainsUppercase = errors.New("repository name must be lowercase") + + // ErrNameEmpty is returned for empty, invalid repository names. + ErrNameEmpty = errors.New("repository name must have at least one component") + + // ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax. + ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax) + + // ErrNameNotCanonical is returned when a name is not canonical. + ErrNameNotCanonical = errors.New("repository name must be canonical") +) + +// Reference is an opaque object reference identifier that may include +// modifiers such as a hostname, name, tag, and digest. +type Reference interface { + // String returns the full reference + String() string +} + +// Field provides a wrapper type for resolving correct reference types when +// working with encoding. +type Field struct { + reference Reference +} + +// AsField wraps a reference in a Field for encoding. +func AsField(reference Reference) Field { + return Field{reference} +} + +// Reference unwraps the reference type from the field to +// return the Reference object. This object should be +// of the appropriate type to further check for different +// reference types. +func (f Field) Reference() Reference { + return f.reference +} + +// MarshalText serializes the field to byte text which +// is the string of the reference. +func (f Field) MarshalText() (p []byte, err error) { + return []byte(f.reference.String()), nil +} + +// UnmarshalText parses text bytes by invoking the +// reference parser to ensure the appropriately +// typed reference object is wrapped by field. +func (f *Field) UnmarshalText(p []byte) error { + r, err := Parse(string(p)) + if err != nil { + return err + } + + f.reference = r + return nil +} + +// Named is an object with a full name +type Named interface { + Reference + Name() string +} + +// Tagged is an object which has a tag +type Tagged interface { + Reference + Tag() string +} + +// NamedTagged is an object including a name and tag. +type NamedTagged interface { + Named + Tag() string +} + +// Digested is an object which has a digest +// in which it can be referenced by +type Digested interface { + Reference + Digest() digest.Digest +} + +// Canonical reference is an object with a fully unique +// name including a name with domain and digest +type Canonical interface { + Named + Digest() digest.Digest +} + +// namedRepository is a reference to a repository with a name. +// A namedRepository has both domain and path components. +type namedRepository interface { + Named + Domain() string + Path() string +} + +// Domain returns the domain part of the Named reference +func Domain(named Named) string { + if r, ok := named.(namedRepository); ok { + return r.Domain() + } + domain, _ := splitDomain(named.Name()) + return domain +} + +// Path returns the name without the domain part of the Named reference +func Path(named Named) (name string) { + if r, ok := named.(namedRepository); ok { + return r.Path() + } + _, path := splitDomain(named.Name()) + return path +} + +func splitDomain(name string) (string, string) { + match := anchoredNameRegexp.FindStringSubmatch(name) + if len(match) != 3 { + return "", name + } + return match[1], match[2] +} + +// SplitHostname splits a named reference into a +// hostname and name string. If no valid hostname is +// found, the hostname is empty and the full value +// is returned as name +// DEPRECATED: Use Domain or Path +func SplitHostname(named Named) (string, string) { + if r, ok := named.(namedRepository); ok { + return r.Domain(), r.Path() + } + return splitDomain(named.Name()) +} + +// Parse parses s and returns a syntactically valid Reference. +// If an error was encountered it is returned, along with a nil Reference. +// NOTE: Parse will not handle short digests. +func Parse(s string) (Reference, error) { + matches := ReferenceRegexp.FindStringSubmatch(s) + if matches == nil { + if s == "" { + return nil, ErrNameEmpty + } + if ReferenceRegexp.FindStringSubmatch(strings.ToLower(s)) != nil { + return nil, ErrNameContainsUppercase + } + return nil, ErrReferenceInvalidFormat + } + + if len(matches[1]) > NameTotalLengthMax { + return nil, ErrNameTooLong + } + + var repo repository + + nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1]) + if len(nameMatch) == 3 { + repo.domain = nameMatch[1] + repo.path = nameMatch[2] + } else { + repo.domain = "" + repo.path = matches[1] + } + + ref := reference{ + namedRepository: repo, + tag: matches[2], + } + if matches[3] != "" { + var err error + ref.digest, err = digest.Parse(matches[3]) + if err != nil { + return nil, err + } + } + + r := getBestReferenceType(ref) + if r == nil { + return nil, ErrNameEmpty + } + + return r, nil +} + +// ParseNamed parses s and returns a syntactically valid reference implementing +// the Named interface. The reference must have a name and be in the canonical +// form, otherwise an error is returned. +// If an error was encountered it is returned, along with a nil Reference. +// NOTE: ParseNamed will not handle short digests. +func ParseNamed(s string) (Named, error) { + named, err := ParseNormalizedNamed(s) + if err != nil { + return nil, err + } + if named.String() != s { + return nil, ErrNameNotCanonical + } + return named, nil +} + +// WithName returns a named object representing the given string. If the input +// is invalid ErrReferenceInvalidFormat will be returned. +func WithName(name string) (Named, error) { + if len(name) > NameTotalLengthMax { + return nil, ErrNameTooLong + } + + match := anchoredNameRegexp.FindStringSubmatch(name) + if match == nil || len(match) != 3 { + return nil, ErrReferenceInvalidFormat + } + return repository{ + domain: match[1], + path: match[2], + }, nil +} + +// WithTag combines the name from "name" and the tag from "tag" to form a +// reference incorporating both the name and the tag. +func WithTag(name Named, tag string) (NamedTagged, error) { + if !anchoredTagRegexp.MatchString(tag) { + return nil, ErrTagInvalidFormat + } + var repo repository + if r, ok := name.(namedRepository); ok { + repo.domain = r.Domain() + repo.path = r.Path() + } else { + repo.path = name.Name() + } + if canonical, ok := name.(Canonical); ok { + return reference{ + namedRepository: repo, + tag: tag, + digest: canonical.Digest(), + }, nil + } + return taggedReference{ + namedRepository: repo, + tag: tag, + }, nil +} + +// WithDigest combines the name from "name" and the digest from "digest" to form +// a reference incorporating both the name and the digest. +func WithDigest(name Named, digest digest.Digest) (Canonical, error) { + if !anchoredDigestRegexp.MatchString(digest.String()) { + return nil, ErrDigestInvalidFormat + } + var repo repository + if r, ok := name.(namedRepository); ok { + repo.domain = r.Domain() + repo.path = r.Path() + } else { + repo.path = name.Name() + } + if tagged, ok := name.(Tagged); ok { + return reference{ + namedRepository: repo, + tag: tagged.Tag(), + digest: digest, + }, nil + } + return canonicalReference{ + namedRepository: repo, + digest: digest, + }, nil +} + +// TrimNamed removes any tag or digest from the named reference. +func TrimNamed(ref Named) Named { + domain, path := SplitHostname(ref) + return repository{ + domain: domain, + path: path, + } +} + +func getBestReferenceType(ref reference) Reference { + if ref.Name() == "" { + // Allow digest only references + if ref.digest != "" { + return digestReference(ref.digest) + } + return nil + } + if ref.tag == "" { + if ref.digest != "" { + return canonicalReference{ + namedRepository: ref.namedRepository, + digest: ref.digest, + } + } + return ref.namedRepository + } + if ref.digest == "" { + return taggedReference{ + namedRepository: ref.namedRepository, + tag: ref.tag, + } + } + + return ref +} + +type reference struct { + namedRepository + tag string + digest digest.Digest +} + +func (r reference) String() string { + return r.Name() + ":" + r.tag + "@" + r.digest.String() +} + +func (r reference) Tag() string { + return r.tag +} + +func (r reference) Digest() digest.Digest { + return r.digest +} + +type repository struct { + domain string + path string +} + +func (r repository) String() string { + return r.Name() +} + +func (r repository) Name() string { + if r.domain == "" { + return r.path + } + return r.domain + "/" + r.path +} + +func (r repository) Domain() string { + return r.domain +} + +func (r repository) Path() string { + return r.path +} + +type digestReference digest.Digest + +func (d digestReference) String() string { + return digest.Digest(d).String() +} + +func (d digestReference) Digest() digest.Digest { + return digest.Digest(d) +} + +type taggedReference struct { + namedRepository + tag string +} + +func (t taggedReference) String() string { + return t.Name() + ":" + t.tag +} + +func (t taggedReference) Tag() string { + return t.tag +} + +type canonicalReference struct { + namedRepository + digest digest.Digest +} + +func (c canonicalReference) String() string { + return c.Name() + "@" + c.digest.String() +} + +func (c canonicalReference) Digest() digest.Digest { + return c.digest +} diff --git a/vendor/github.com/docker/distribution/reference/reference_deprecated.go b/vendor/github.com/docker/distribution/reference/reference_deprecated.go deleted file mode 100644 index 5b732498ebf..00000000000 --- a/vendor/github.com/docker/distribution/reference/reference_deprecated.go +++ /dev/null @@ -1,172 +0,0 @@ -// Package reference is deprecated, and has moved to github.com/distribution/reference. -// -// Deprecated: use github.com/distribution/reference instead. -package reference - -import ( - "github.com/distribution/reference" - "github.com/opencontainers/go-digest" -) - -const ( - // NameTotalLengthMax is the maximum total number of characters in a repository name. - // - // Deprecated: use [reference.NameTotalLengthMax]. - NameTotalLengthMax = reference.NameTotalLengthMax -) - -var ( - // ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference. - // - // Deprecated: use [reference.ErrReferenceInvalidFormat]. - ErrReferenceInvalidFormat = reference.ErrReferenceInvalidFormat - - // ErrTagInvalidFormat represents an error while trying to parse a string as a tag. - // - // Deprecated: use [reference.ErrTagInvalidFormat]. - ErrTagInvalidFormat = reference.ErrTagInvalidFormat - - // ErrDigestInvalidFormat represents an error while trying to parse a string as a tag. - // - // Deprecated: use [reference.ErrDigestInvalidFormat]. - ErrDigestInvalidFormat = reference.ErrDigestInvalidFormat - - // ErrNameContainsUppercase is returned for invalid repository names that contain uppercase characters. - // - // Deprecated: use [reference.ErrNameContainsUppercase]. - ErrNameContainsUppercase = reference.ErrNameContainsUppercase - - // ErrNameEmpty is returned for empty, invalid repository names. - // - // Deprecated: use [reference.ErrNameEmpty]. - ErrNameEmpty = reference.ErrNameEmpty - - // ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax. - // - // Deprecated: use [reference.ErrNameTooLong]. - ErrNameTooLong = reference.ErrNameTooLong - - // ErrNameNotCanonical is returned when a name is not canonical. - // - // Deprecated: use [reference.ErrNameNotCanonical]. - ErrNameNotCanonical = reference.ErrNameNotCanonical -) - -// Reference is an opaque object reference identifier that may include -// modifiers such as a hostname, name, tag, and digest. -// -// Deprecated: use [reference.Reference]. -type Reference = reference.Reference - -// Field provides a wrapper type for resolving correct reference types when -// working with encoding. -// -// Deprecated: use [reference.Field]. -type Field = reference.Field - -// AsField wraps a reference in a Field for encoding. -// -// Deprecated: use [reference.AsField]. -func AsField(ref reference.Reference) reference.Field { - return reference.AsField(ref) -} - -// Named is an object with a full name -// -// Deprecated: use [reference.Named]. -type Named = reference.Named - -// Tagged is an object which has a tag -// -// Deprecated: use [reference.Tagged]. -type Tagged = reference.Tagged - -// NamedTagged is an object including a name and tag. -// -// Deprecated: use [reference.NamedTagged]. -type NamedTagged reference.NamedTagged - -// Digested is an object which has a digest -// in which it can be referenced by -// -// Deprecated: use [reference.Digested]. -type Digested reference.Digested - -// Canonical reference is an object with a fully unique -// name including a name with domain and digest -// -// Deprecated: use [reference.Canonical]. -type Canonical reference.Canonical - -// Domain returns the domain part of the [Named] reference. -// -// Deprecated: use [reference.Domain]. -func Domain(named reference.Named) string { - return reference.Domain(named) -} - -// Path returns the name without the domain part of the [Named] reference. -// -// Deprecated: use [reference.Path]. -func Path(named reference.Named) (name string) { - return reference.Path(named) -} - -// SplitHostname splits a named reference into a -// hostname and name string. If no valid hostname is -// found, the hostname is empty and the full value -// is returned as name -// -// Deprecated: Use [reference.Domain] or [reference.Path]. -func SplitHostname(named reference.Named) (string, string) { - return reference.SplitHostname(named) -} - -// Parse parses s and returns a syntactically valid Reference. -// If an error was encountered it is returned, along with a nil Reference. -// -// Deprecated: use [reference.Parse]. -func Parse(s string) (reference.Reference, error) { - return reference.Parse(s) -} - -// ParseNamed parses s and returns a syntactically valid reference implementing -// the Named interface. The reference must have a name and be in the canonical -// form, otherwise an error is returned. -// If an error was encountered it is returned, along with a nil Reference. -// -// Deprecated: use [reference.ParseNamed]. -func ParseNamed(s string) (reference.Named, error) { - return reference.ParseNamed(s) -} - -// WithName returns a named object representing the given string. If the input -// is invalid ErrReferenceInvalidFormat will be returned. -// -// Deprecated: use [reference.WithName]. -func WithName(name string) (reference.Named, error) { - return reference.WithName(name) -} - -// WithTag combines the name from "name" and the tag from "tag" to form a -// reference incorporating both the name and the tag. -// -// Deprecated: use [reference.WithTag]. -func WithTag(name reference.Named, tag string) (reference.NamedTagged, error) { - return reference.WithTag(name, tag) -} - -// WithDigest combines the name from "name" and the digest from "digest" to form -// a reference incorporating both the name and the digest. -// -// Deprecated: use [reference.WithDigest]. -func WithDigest(name reference.Named, digest digest.Digest) (reference.Canonical, error) { - return reference.WithDigest(name, digest) -} - -// TrimNamed removes any tag or digest from the named reference. -// -// Deprecated: use [reference.TrimNamed]. -func TrimNamed(ref reference.Named) reference.Named { - return reference.TrimNamed(ref) -} diff --git a/vendor/github.com/docker/distribution/reference/regexp.go b/vendor/github.com/docker/distribution/reference/regexp.go new file mode 100644 index 00000000000..78603493203 --- /dev/null +++ b/vendor/github.com/docker/distribution/reference/regexp.go @@ -0,0 +1,143 @@ +package reference + +import "regexp" + +var ( + // alphaNumericRegexp defines the alpha numeric atom, typically a + // component of names. This only allows lower case characters and digits. + alphaNumericRegexp = match(`[a-z0-9]+`) + + // separatorRegexp defines the separators allowed to be embedded in name + // components. This allow one period, one or two underscore and multiple + // dashes. + separatorRegexp = match(`(?:[._]|__|[-]*)`) + + // nameComponentRegexp restricts registry path component names to start + // with at least one letter or number, with following parts able to be + // separated by one period, one or two underscore and multiple dashes. + nameComponentRegexp = expression( + alphaNumericRegexp, + optional(repeated(separatorRegexp, alphaNumericRegexp))) + + // domainComponentRegexp restricts the registry domain component of a + // repository name to start with a component as defined by DomainRegexp + // and followed by an optional port. + domainComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`) + + // DomainRegexp defines the structure of potential domain components + // that may be part of image names. This is purposely a subset of what is + // allowed by DNS to ensure backwards compatibility with Docker image + // names. + DomainRegexp = expression( + domainComponentRegexp, + optional(repeated(literal(`.`), domainComponentRegexp)), + optional(literal(`:`), match(`[0-9]+`))) + + // TagRegexp matches valid tag names. From docker/docker:graph/tags.go. + TagRegexp = match(`[\w][\w.-]{0,127}`) + + // anchoredTagRegexp matches valid tag names, anchored at the start and + // end of the matched string. + anchoredTagRegexp = anchored(TagRegexp) + + // DigestRegexp matches valid digests. + DigestRegexp = match(`[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`) + + // anchoredDigestRegexp matches valid digests, anchored at the start and + // end of the matched string. + anchoredDigestRegexp = anchored(DigestRegexp) + + // NameRegexp is the format for the name component of references. The + // regexp has capturing groups for the domain and name part omitting + // the separating forward slash from either. + NameRegexp = expression( + optional(DomainRegexp, literal(`/`)), + nameComponentRegexp, + optional(repeated(literal(`/`), nameComponentRegexp))) + + // anchoredNameRegexp is used to parse a name value, capturing the + // domain and trailing components. + anchoredNameRegexp = anchored( + optional(capture(DomainRegexp), literal(`/`)), + capture(nameComponentRegexp, + optional(repeated(literal(`/`), nameComponentRegexp)))) + + // ReferenceRegexp is the full supported format of a reference. The regexp + // is anchored and has capturing groups for name, tag, and digest + // components. + ReferenceRegexp = anchored(capture(NameRegexp), + optional(literal(":"), capture(TagRegexp)), + optional(literal("@"), capture(DigestRegexp))) + + // IdentifierRegexp is the format for string identifier used as a + // content addressable identifier using sha256. These identifiers + // are like digests without the algorithm, since sha256 is used. + IdentifierRegexp = match(`([a-f0-9]{64})`) + + // ShortIdentifierRegexp is the format used to represent a prefix + // of an identifier. A prefix may be used to match a sha256 identifier + // within a list of trusted identifiers. + ShortIdentifierRegexp = match(`([a-f0-9]{6,64})`) + + // anchoredIdentifierRegexp is used to check or match an + // identifier value, anchored at start and end of string. + anchoredIdentifierRegexp = anchored(IdentifierRegexp) + + // anchoredShortIdentifierRegexp is used to check if a value + // is a possible identifier prefix, anchored at start and end + // of string. + anchoredShortIdentifierRegexp = anchored(ShortIdentifierRegexp) +) + +// match compiles the string to a regular expression. +var match = regexp.MustCompile + +// literal compiles s into a literal regular expression, escaping any regexp +// reserved characters. +func literal(s string) *regexp.Regexp { + re := match(regexp.QuoteMeta(s)) + + if _, complete := re.LiteralPrefix(); !complete { + panic("must be a literal") + } + + return re +} + +// expression defines a full expression, where each regular expression must +// follow the previous. +func expression(res ...*regexp.Regexp) *regexp.Regexp { + var s string + for _, re := range res { + s += re.String() + } + + return match(s) +} + +// optional wraps the expression in a non-capturing group and makes the +// production optional. +func optional(res ...*regexp.Regexp) *regexp.Regexp { + return match(group(expression(res...)).String() + `?`) +} + +// repeated wraps the regexp in a non-capturing group to get one or more +// matches. +func repeated(res ...*regexp.Regexp) *regexp.Regexp { + return match(group(expression(res...)).String() + `+`) +} + +// group wraps the regexp in a non-capturing group. +func group(res ...*regexp.Regexp) *regexp.Regexp { + return match(`(?:` + expression(res...).String() + `)`) +} + +// capture wraps the expression in a capturing group. +func capture(res ...*regexp.Regexp) *regexp.Regexp { + return match(`(` + expression(res...).String() + `)`) +} + +// anchored anchors the regular expression by adding start and end delimiters. +func anchored(res ...*regexp.Regexp) *regexp.Regexp { + return match(`^` + expression(res...).String() + `$`) +} diff --git a/vendor/github.com/docker/distribution/reference/regexp_deprecated.go b/vendor/github.com/docker/distribution/reference/regexp_deprecated.go deleted file mode 100644 index 4b9c1b58eba..00000000000 --- a/vendor/github.com/docker/distribution/reference/regexp_deprecated.go +++ /dev/null @@ -1,50 +0,0 @@ -package reference - -import ( - "github.com/distribution/reference" -) - -// DigestRegexp matches well-formed digests, including algorithm (e.g. "sha256:"). -// -// Deprecated: use [reference.DigestRegexp]. -var DigestRegexp = reference.DigestRegexp - -// DomainRegexp matches hostname or IP-addresses, optionally including a port -// number. It defines the structure of potential domain components that may be -// part of image names. This is purposely a subset of what is allowed by DNS to -// ensure backwards compatibility with Docker image names. It may be a subset of -// DNS domain name, an IPv4 address in decimal format, or an IPv6 address between -// square brackets (excluding zone identifiers as defined by [RFC 6874] or special -// addresses such as IPv4-Mapped). -// -// Deprecated: use [reference.DomainRegexp]. -// -// [RFC 6874]: https://www.rfc-editor.org/rfc/rfc6874. -var DomainRegexp = reference.DigestRegexp - -// IdentifierRegexp is the format for string identifier used as a -// content addressable identifier using sha256. These identifiers -// are like digests without the algorithm, since sha256 is used. -// -// Deprecated: use [reference.IdentifierRegexp]. -var IdentifierRegexp = reference.IdentifierRegexp - -// NameRegexp is the format for the name component of references, including -// an optional domain and port, but without tag or digest suffix. -// -// Deprecated: use [reference.NameRegexp]. -var NameRegexp = reference.NameRegexp - -// ReferenceRegexp is the full supported format of a reference. The regexp -// is anchored and has capturing groups for name, tag, and digest -// components. -// -// Deprecated: use [reference.ReferenceRegexp]. -var ReferenceRegexp = reference.ReferenceRegexp - -// TagRegexp matches valid tag names. From [docker/docker:graph/tags.go]. -// -// Deprecated: use [reference.TagRegexp]. -// -// [docker/docker:graph/tags.go]: https://github.com/moby/moby/blob/v1.6.0/graph/tags.go#L26-L28 -var TagRegexp = reference.TagRegexp diff --git a/vendor/github.com/docker/distribution/reference/sort_deprecated.go b/vendor/github.com/docker/distribution/reference/sort_deprecated.go deleted file mode 100644 index a73251b6f5d..00000000000 --- a/vendor/github.com/docker/distribution/reference/sort_deprecated.go +++ /dev/null @@ -1,10 +0,0 @@ -package reference - -import "github.com/distribution/reference" - -// Sort sorts string references preferring higher information references. -// -// Deprecated: use [reference.Sort]. -func Sort(references []string) []string { - return reference.Sort(references) -} diff --git a/vendor/github.com/docker/distribution/registry.go b/vendor/github.com/docker/distribution/registry.go index d0deee65d7b..6c32109894d 100644 --- a/vendor/github.com/docker/distribution/registry.go +++ b/vendor/github.com/docker/distribution/registry.go @@ -3,7 +3,7 @@ package distribution import ( "context" - "github.com/distribution/reference" + "github.com/docker/distribution/reference" ) // Scope defines the set of items that match a namespace. diff --git a/vendor/github.com/docker/distribution/registry/api/v2/descriptors.go b/vendor/github.com/docker/distribution/registry/api/v2/descriptors.go index 7fceefbc64a..c3bf90f71d0 100644 --- a/vendor/github.com/docker/distribution/registry/api/v2/descriptors.go +++ b/vendor/github.com/docker/distribution/registry/api/v2/descriptors.go @@ -4,7 +4,7 @@ import ( "net/http" "regexp" - "github.com/distribution/reference" + "github.com/docker/distribution/reference" "github.com/docker/distribution/registry/api/errcode" "github.com/opencontainers/go-digest" ) diff --git a/vendor/github.com/docker/distribution/registry/api/v2/urls.go b/vendor/github.com/docker/distribution/registry/api/v2/urls.go index ab640633592..3c3ec989330 100644 --- a/vendor/github.com/docker/distribution/registry/api/v2/urls.go +++ b/vendor/github.com/docker/distribution/registry/api/v2/urls.go @@ -6,7 +6,7 @@ import ( "net/url" "strings" - "github.com/distribution/reference" + "github.com/docker/distribution/reference" "github.com/gorilla/mux" ) diff --git a/vendor/github.com/docker/distribution/registry/client/blob_writer.go b/vendor/github.com/docker/distribution/registry/client/blob_writer.go index dac030c7382..695bf852f16 100644 --- a/vendor/github.com/docker/distribution/registry/client/blob_writer.go +++ b/vendor/github.com/docker/distribution/registry/client/blob_writer.go @@ -42,8 +42,6 @@ func (hbu *httpBlobUpload) ReadFrom(r io.Reader) (n int64, err error) { } defer req.Body.Close() - req.Header.Set("Content-Type", "application/octet-stream") - resp, err := hbu.client.Do(req) if err != nil { return 0, err diff --git a/vendor/github.com/docker/distribution/registry/client/errors.go b/vendor/github.com/docker/distribution/registry/client/errors.go index ce9902034d3..024df43dd92 100644 --- a/vendor/github.com/docker/distribution/registry/client/errors.go +++ b/vendor/github.com/docker/distribution/registry/client/errors.go @@ -4,8 +4,8 @@ import ( "encoding/json" "errors" "fmt" + "io" "io/ioutil" - "mime" "net/http" "github.com/docker/distribution/registry/api/errcode" @@ -38,29 +38,13 @@ func (e *UnexpectedHTTPResponseError) Error() string { return fmt.Sprintf("error parsing HTTP %d response body: %s: %q", e.StatusCode, e.ParseErr.Error(), string(e.Response)) } -func parseHTTPErrorResponse(resp *http.Response) error { +func parseHTTPErrorResponse(statusCode int, r io.Reader) error { var errors errcode.Errors - body, err := ioutil.ReadAll(resp.Body) + body, err := ioutil.ReadAll(r) if err != nil { return err } - statusCode := resp.StatusCode - ctHeader := resp.Header.Get("Content-Type") - - if ctHeader == "" { - return makeError(statusCode, string(body)) - } - - contentType, _, err := mime.ParseMediaType(ctHeader) - if err != nil { - return fmt.Errorf("failed parsing content-type: %w", err) - } - - if contentType != "application/json" && contentType != "application/vnd.api+json" { - return makeError(statusCode, string(body)) - } - // For backward compatibility, handle irregularly formatted // messages that contain a "details" field. var detailsErr struct { @@ -68,7 +52,16 @@ func parseHTTPErrorResponse(resp *http.Response) error { } err = json.Unmarshal(body, &detailsErr) if err == nil && detailsErr.Details != "" { - return makeError(statusCode, detailsErr.Details) + switch statusCode { + case http.StatusUnauthorized: + return errcode.ErrorCodeUnauthorized.WithMessage(detailsErr.Details) + case http.StatusForbidden: + return errcode.ErrorCodeDenied.WithMessage(detailsErr.Details) + case http.StatusTooManyRequests: + return errcode.ErrorCodeTooManyRequests.WithMessage(detailsErr.Details) + default: + return errcode.ErrorCodeUnknown.WithMessage(detailsErr.Details) + } } if err := json.Unmarshal(body, &errors); err != nil { @@ -92,19 +85,6 @@ func parseHTTPErrorResponse(resp *http.Response) error { return errors } -func makeError(statusCode int, details string) error { - switch statusCode { - case http.StatusUnauthorized: - return errcode.ErrorCodeUnauthorized.WithMessage(details) - case http.StatusForbidden: - return errcode.ErrorCodeDenied.WithMessage(details) - case http.StatusTooManyRequests: - return errcode.ErrorCodeTooManyRequests.WithMessage(details) - default: - return errcode.ErrorCodeUnknown.WithMessage(details) - } -} - func makeErrorList(err error) []error { if errL, ok := err.(errcode.Errors); ok { return []error(errL) @@ -141,10 +121,11 @@ func HandleErrorResponse(resp *http.Response) error { } else { err.Message = err.Code.Message() } - return mergeErrors(err, parseHTTPErrorResponse(resp)) + + return mergeErrors(err, parseHTTPErrorResponse(resp.StatusCode, resp.Body)) } } - err := parseHTTPErrorResponse(resp) + err := parseHTTPErrorResponse(resp.StatusCode, resp.Body) if uErr, ok := err.(*UnexpectedHTTPResponseError); ok && resp.StatusCode == 401 { return errcode.ErrorCodeUnauthorized.WithDetail(uErr.Response) } diff --git a/vendor/github.com/docker/distribution/registry/client/repository.go b/vendor/github.com/docker/distribution/registry/client/repository.go index fd42a1e66fd..04e5a3ba01f 100644 --- a/vendor/github.com/docker/distribution/registry/client/repository.go +++ b/vendor/github.com/docker/distribution/registry/client/repository.go @@ -14,8 +14,8 @@ import ( "strings" "time" - "github.com/distribution/reference" "github.com/docker/distribution" + "github.com/docker/distribution/reference" v2 "github.com/docker/distribution/registry/api/v2" "github.com/docker/distribution/registry/client/transport" "github.com/docker/distribution/registry/storage/cache" diff --git a/vendor/github.com/docker/distribution/registry/storage/cache/memory/memory.go b/vendor/github.com/docker/distribution/registry/storage/cache/memory/memory.go index f2953b02c2c..42d94d9bde6 100644 --- a/vendor/github.com/docker/distribution/registry/storage/cache/memory/memory.go +++ b/vendor/github.com/docker/distribution/registry/storage/cache/memory/memory.go @@ -4,8 +4,8 @@ import ( "context" "sync" - "github.com/distribution/reference" "github.com/docker/distribution" + "github.com/docker/distribution/reference" "github.com/docker/distribution/registry/storage/cache" "github.com/opencontainers/go-digest" ) diff --git a/vendor/github.com/docker/distribution/vendor.conf b/vendor/github.com/docker/distribution/vendor.conf index 20818428ffd..bd1b4bff61c 100644 --- a/vendor/github.com/docker/distribution/vendor.conf +++ b/vendor/github.com/docker/distribution/vendor.conf @@ -9,7 +9,6 @@ github.com/bugsnag/osext 0dd3f918b21bec95ace9dc86c7e70266cfc5c702 github.com/bugsnag/panicwrap e2c28503fcd0675329da73bf48b33404db873782 github.com/denverdino/aliyungo afedced274aa9a7fcdd47ac97018f0f8db4e5de2 github.com/dgrijalva/jwt-go 4bbdd8ac624fc7a9ef7aec841c43d99b5fe65a29 https://github.com/golang-jwt/jwt.git # v3.2.2 -github.com/distribution/reference 49c28499d219290c3226822e9cfcd4ede6d75379 # v0.5.0 github.com/docker/go-metrics 399ea8c73916000c64c2c76e8da00ca82f8387ab github.com/docker/libtrust fa567046d9b14f6aa788882a950d69651d230b21 github.com/garyburd/redigo 535138d7bcd717d6531c701ef5933d98b1866257 @@ -48,5 +47,5 @@ gopkg.in/check.v1 64131543e7896d5bcc6bd5a76287eb75ea96c673 gopkg.in/square/go-jose.v1 40d457b439244b546f023d056628e5184136899b gopkg.in/yaml.v2 v2.2.1 rsc.io/letsencrypt e770c10b0f1a64775ae91d240407ce00d1a5bdeb https://github.com/dmcgowan/letsencrypt.git -github.com/opencontainers/go-digest ea51bea511f75cfa3ef6098cc253c5c3609b037a # v1.0.0 +github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb github.com/opencontainers/image-spec 67d2d5658fe0476ab9bf414cec164077ebff3920 # v1.0.2 diff --git a/vendor/modules.txt b/vendor/modules.txt index 01899c7aa69..3f9c2f50b9a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -423,9 +423,10 @@ github.com/docker/cli/cli/config/types github.com/docker/cli/cli/connhelper github.com/docker/cli/cli/connhelper/commandconn github.com/docker/cli/cli/connhelper/ssh -# github.com/docker/distribution v2.8.3+incompatible +# github.com/docker/distribution v2.8.2+incompatible ## explicit github.com/docker/distribution +github.com/docker/distribution/digestset github.com/docker/distribution/metrics github.com/docker/distribution/reference github.com/docker/distribution/registry/api/errcode @@ -1011,7 +1012,6 @@ github.com/oklog/ulid # github.com/opencontainers/go-digest v1.0.0 ## explicit; go 1.13 github.com/opencontainers/go-digest -github.com/opencontainers/go-digest/digestset # github.com/opencontainers/image-spec v1.1.0-rc5 ## explicit; go 1.18 github.com/opencontainers/image-spec/specs-go