Skip to content

Commit

Permalink
Update to distribution/distribtion in master branch
Browse files Browse the repository at this point in the history
Improvements on containers/podman#16205

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
  • Loading branch information
rhatdan committed Nov 21, 2022
1 parent d8eb9dd commit 355a56f
Show file tree
Hide file tree
Showing 6 changed files with 1,047 additions and 675 deletions.
27 changes: 19 additions & 8 deletions docker/reference/normalize.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package reference

import (
"errors"
"fmt"
"strings"

"github.com/opencontainers/go-digest"
)

var (
const (
legacyDefaultDomain = "index.docker.io"
defaultDomain = "docker.io"
officialRepoName = "library"
officialRepoPrefix = "library/"
defaultTag = "latest"
)

Expand Down Expand Up @@ -41,7 +40,7 @@ func ParseNormalizedNamed(s string) (Named, error) {
remoteName = remainder
}
if strings.ToLower(remoteName) != remoteName {
return nil, errors.New("invalid reference format: repository name must be lowercase")
return nil, fmt.Errorf("invalid reference format: repository name (%s) must be lowercase", remoteName)
}

ref, err := Parse(domain + "/" + remainder)
Expand Down Expand Up @@ -89,16 +88,21 @@ func ParseDockerRef(ref string) (Named, error) {
// 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") {
if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost" && strings.ToLower(name[:i]) == name[:i]) {
domain, remainder = defaultDomain, name
} else {
domain, remainder = name[:i], name[i+1:]
}
if domain == legacyDefaultDomain {
domain = defaultDomain
}
// TODO(thaJeztah): this check may be too strict, as it assumes the
// "library/" namespace does not have nested namespaces. While this
// is true (currently), technically it would be possible for Docker
// Hub to use those (e.g. "library/distros/ubuntu:latest").
// See https://github.com/distribution/distribution/pull/3769#issuecomment-1302031785.
if domain == defaultDomain && !strings.ContainsRune(remainder, '/') {
remainder = officialRepoName + "/" + remainder
remainder = officialRepoPrefix + remainder
}
return
}
Expand All @@ -118,8 +122,15 @@ func familiarizeName(named namedRepository) repository {
if repo.domain == defaultDomain {
repo.domain = ""
// Handle official repositories which have the pattern "library/<official repo name>"
if split := strings.Split(repo.path, "/"); len(split) == 2 && split[0] == officialRepoName {
repo.path = split[1]
if strings.HasPrefix(repo.path, officialRepoPrefix) {
// TODO(thaJeztah): this check may be too strict, as it assumes the
// "library/" namespace does not have nested namespaces. While this
// is true (currently), technically it would be possible for Docker
// Hub to use those (e.g. "library/distros/ubuntu:latest").
// See https://github.com/distribution/distribution/pull/3769#issuecomment-1302031785.
if remainder := strings.TrimPrefix(repo.path, officialRepoPrefix); !strings.ContainsRune(remainder, '/') {
repo.path = remainder
}
}
}
return repo
Expand Down
49 changes: 46 additions & 3 deletions docker/reference/normalize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
)

func TestValidateReferenceName(t *testing.T) {
t.Parallel()
validRepoNames := []string{
"docker/docker",
"library/debian",
Expand All @@ -21,12 +22,21 @@ func TestValidateReferenceName(t *testing.T) {
"127.0.0.1:5000/docker/docker",
"127.0.0.1:5000/library/debian",
"127.0.0.1:5000/debian",
"192.168.0.1",
"192.168.0.1:80",
"192.168.0.1:8/debian",
"192.168.0.2:25000/debian",
"thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev",
"[fc00::1]:5000/docker",
"[fc00::1]:5000/docker/docker",
"[fc00:1:2:3:4:5:6:7]:5000/library/debian",

// This test case was moved from invalid to valid since it is valid input
// when specified with a hostname, it removes the ambiguity from about
// whether the value is an identifier or repository name
"docker.io/1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
"Docker/docker",
"DOCKER/docker",
}
invalidRepoNames := []string{
"https://github.com/docker/docker",
Expand All @@ -37,6 +47,11 @@ func TestValidateReferenceName(t *testing.T) {
"docker///docker",
"docker.io/docker/Docker",
"docker.io/docker///docker",
"[fc00::1]",
"[fc00::1]:5000",
"fc00::1:5000/debian",
"[fe80::1%eth0]:5000/debian",
"[2001:db8:3:4::192.0.2.33]:5000/debian",
"1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
}

Expand All @@ -56,6 +71,7 @@ func TestValidateReferenceName(t *testing.T) {
}

func TestValidateRemoteName(t *testing.T) {
t.Parallel()
validRepositoryNames := []string{
// Sanity check.
"docker/docker",
Expand All @@ -69,7 +85,7 @@ func TestValidateRemoteName(t *testing.T) {
// Allow multiple hyphens as well.
"docker---rules/docker",

//Username doc and image name docker being tested.
// Username doc and image name docker being tested.
"doc/docker",

// single character names are now allowed.
Expand Down Expand Up @@ -114,8 +130,8 @@ func TestValidateRemoteName(t *testing.T) {
// No repository.
"docker/",

//namespace too long
"this_is_not_a_valid_namespace_because_its_length_is_greater_than_255_this_is_not_a_valid_namespace_because_its_length_is_greater_than_255_this_is_not_a_valid_namespace_because_its_length_is_greater_than_255_this_is_not_a_valid_namespace_because_its_length_is_greater_than_255/docker",
// namespace too long
"this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255/docker",
}
for _, repositoryName := range invalidRepositoryNames {
if _, err := ParseNormalizedNamed(repositoryName); err == nil {
Expand All @@ -125,6 +141,7 @@ func TestValidateRemoteName(t *testing.T) {
}

func TestParseRepositoryInfo(t *testing.T) {
t.Parallel()
type tcase struct {
RemoteName, FamiliarName, FullName, AmbiguousName, Domain string
}
Expand Down Expand Up @@ -228,6 +245,20 @@ func TestParseRepositoryInfo(t *testing.T) {
AmbiguousName: "",
Domain: "docker.io",
},
{
RemoteName: "bar",
FamiliarName: "Foo/bar",
FullName: "Foo/bar",
AmbiguousName: "",
Domain: "Foo",
},
{
RemoteName: "bar",
FamiliarName: "FOO/bar",
FullName: "FOO/bar",
AmbiguousName: "",
Domain: "FOO",
},
}

for _, tcase := range tcases {
Expand Down Expand Up @@ -264,6 +295,7 @@ func TestParseRepositoryInfo(t *testing.T) {
}

func TestParseReferenceWithTagAndDigest(t *testing.T) {
t.Parallel()
shortRef := "busybox:latest@sha256:86e0e091d0da6bde2456dbb48306f3956bbeb2eae1b5b9a43045843f69fe4aaa"
ref, err := ParseNormalizedNamed(shortRef)
if err != nil {
Expand All @@ -285,6 +317,7 @@ func TestParseReferenceWithTagAndDigest(t *testing.T) {
}

func TestInvalidReferenceComponents(t *testing.T) {
t.Parallel()
if _, err := ParseNormalizedNamed("-foo"); err == nil {
t.Fatal("Expected WithName to detect invalid name")
}
Expand Down Expand Up @@ -327,6 +360,7 @@ func equalReference(r1, r2 Reference) bool {
}

func TestParseAnyReference(t *testing.T) {
t.Parallel()
tcases := []struct {
Reference string
Equivalent string
Expand Down Expand Up @@ -386,6 +420,10 @@ func TestParseAnyReference(t *testing.T) {
Reference: "dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9",
Equivalent: "docker.io/library/dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9",
},
{
Reference: "dbcc1",
Equivalent: "docker.io/library/dbcc1",
},
}

for _, tcase := range tcases {
Expand Down Expand Up @@ -413,6 +451,7 @@ func TestParseAnyReference(t *testing.T) {
}

func TestNormalizedSplitHostname(t *testing.T) {
t.Parallel()
testcases := []struct {
input string
domain string
Expand Down Expand Up @@ -495,6 +534,7 @@ func TestNormalizedSplitHostname(t *testing.T) {
}

func TestMatchError(t *testing.T) {
t.Parallel()
named, err := ParseAnyReference("foo")
if err != nil {
t.Fatal(err)
Expand All @@ -506,6 +546,7 @@ func TestMatchError(t *testing.T) {
}

func TestMatch(t *testing.T) {
t.Parallel()
matchCases := []struct {
reference string
pattern string
Expand Down Expand Up @@ -573,6 +614,7 @@ func TestMatch(t *testing.T) {
}

func TestParseDockerRef(t *testing.T) {
t.Parallel()
testcases := []struct {
name string
input string
Expand Down Expand Up @@ -636,6 +678,7 @@ func TestParseDockerRef(t *testing.T) {
}
for _, test := range testcases {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
normalized, err := ParseDockerRef(test.input)
if err != nil {
t.Fatal(err)
Expand Down
17 changes: 11 additions & 6 deletions docker/reference/reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
//
// reference := name [ ":" tag ] [ "@" digest ]
// name := [domain '/'] path-component ['/' path-component]*
// domain := domain-component ['.' domain-component]* [':' port-number]
// domain := host [':' port-number]
// host := domain-name | IPv4address | \[ IPv6address \] ; rfc3986 appendix-A
// domain-name := domain-component ['.' domain-component]*
// 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]*
Expand Down Expand Up @@ -175,7 +177,8 @@ func splitDomain(name string) (string, string) {
// 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
//
// Deprecated: Use [Domain] or [Path].
func SplitHostname(named Named) (string, string) {
if r, ok := named.(namedRepository); ok {
return r.Domain(), r.Path()
Expand Down Expand Up @@ -320,11 +323,13 @@ func WithDigest(name Named, digest digest.Digest) (Canonical, error) {

// 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,
repo := repository{}
if r, ok := ref.(namedRepository); ok {
repo.domain, repo.path = r.Domain(), r.Path()
} else {
repo.domain, repo.path = splitDomain(ref.Name())
}
return repo
}

func getBestReferenceType(ref reference) Reference {
Expand Down
Loading

0 comments on commit 355a56f

Please sign in to comment.