Merge pull request #3489 from aojea/ipv6_domains

Ipv6 registries
pull/3481/head
Milos Gajdos 2022-07-25 14:31:11 +01:00 committed by GitHub
commit 4bf3547399
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 181 additions and 7 deletions

View File

@ -22,7 +22,14 @@ 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
@ -40,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",
}

View File

@ -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]*

View File

@ -171,6 +171,101 @@ func TestReferenceParse(t *testing.T) {
repository: "foo/foo_bar.com",
tag: "8080",
},
{
input: "192.168.1.1",
repository: "192.168.1.1",
},
{
input: "192.168.1.1:tag",
repository: "192.168.1.1",
tag: "tag",
},
{
input: "192.168.1.1:5000",
repository: "192.168.1.1",
tag: "5000",
},
{
input: "192.168.1.1/repo",
domain: "192.168.1.1",
repository: "192.168.1.1/repo",
},
{
input: "192.168.1.1:5000/repo",
domain: "192.168.1.1:5000",
repository: "192.168.1.1:5000/repo",
},
{
input: "192.168.1.1:5000/repo:5050",
domain: "192.168.1.1:5000",
repository: "192.168.1.1:5000/repo",
tag: "5050",
},
{
input: "[2001:db8::1]",
err: ErrReferenceInvalidFormat,
},
{
input: "[2001:db8::1]:5000",
err: ErrReferenceInvalidFormat,
},
{
input: "[2001:db8::1]:tag",
err: ErrReferenceInvalidFormat,
},
{
input: "[2001:db8::1]/repo",
domain: "[2001:db8::1]",
repository: "[2001:db8::1]/repo",
},
{
input: "[2001:db8:1:2:3:4:5:6]/repo:tag",
domain: "[2001:db8:1:2:3:4:5:6]",
repository: "[2001:db8:1:2:3:4:5:6]/repo",
tag: "tag",
},
{
input: "[2001:db8::1]:5000/repo",
domain: "[2001:db8::1]:5000",
repository: "[2001:db8::1]:5000/repo",
},
{
input: "[2001:db8::1]:5000/repo:tag",
domain: "[2001:db8::1]:5000",
repository: "[2001:db8::1]:5000/repo",
tag: "tag",
},
{
input: "[2001:db8::1]:5000/repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
domain: "[2001:db8::1]:5000",
repository: "[2001:db8::1]:5000/repo",
digest: "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
},
{
input: "[2001:db8::1]:5000/repo:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
domain: "[2001:db8::1]:5000",
repository: "[2001:db8::1]:5000/repo",
tag: "tag",
digest: "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
},
{
input: "[2001:db8::]:5000/repo",
domain: "[2001:db8::]:5000",
repository: "[2001:db8::]:5000/repo",
},
{
input: "[::1]:5000/repo",
domain: "[::1]:5000",
repository: "[::1]:5000/repo",
},
{
input: "[fe80::1%eth0]:5000/repo",
err: ErrReferenceInvalidFormat,
},
{
input: "[fe80::1%@invalidzone]:5000/repo",
err: ErrReferenceInvalidFormat,
},
}
for _, testcase := range referenceTestcases {
failf := func(format string, v ...interface{}) {

View File

@ -23,15 +23,40 @@ var (
alphaNumeric,
optional(repeated(separator, alphaNumeric)))
// domainComponent restricts the registry domain component of a
// repository name to start with a component as defined by DomainRegexp
// and followed by an optional port.
domainComponent = `(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`
// domainNameComponent restricts the registry domain component of a
// repository name to start with a component as defined by DomainRegexp.
domainNameComponent = `(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`
// ipv6address are enclosed between square brackets and may be represented
// in many ways, see rfc5952. Only IPv6 in compressed or uncompressed format
// are allowed, IPv6 zone identifiers (rfc6874) or Special addresses such as
// IPv4-Mapped are deliberately excluded.
ipv6address = expression(
literal(`[`), `(?:[a-fA-F0-9:]+)`, literal(`]`),
)
// domainName 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. This includes IPv4 addresses on decimal format.
domainName = expression(
domainNameComponent,
optional(repeated(literal(`.`), domainNameComponent)),
)
// host defines the structure of potential domains based on the URI
// Host subcomponent on rfc3986. It may be a subset of DNS domain name,
// or an IPv4 address in decimal format, or an IPv6 address between square
// brackets (excluding zone identifiers as defined by rfc6874 or special
// addresses such as IPv4-Mapped).
host = `(?:` + domainName + `|` + ipv6address + `)`
// allowed by the URI Host subcomponent on rfc3986 to ensure backwards
// compatibility with Docker image names.
domain = expression(
domainComponent,
optional(repeated(literal(`.`), domainComponent)),
host,
optional(literal(`:`), `[0-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

View File

@ -115,6 +115,46 @@ func TestDomainRegexp(t *testing.T) {
input: "Asdf.com", // uppercase character
match: true,
},
{
input: "192.168.1.1:75050", // ipv4
match: true,
},
{
input: "192.168.1.1:750050", // port with more than 5 digits, it will fail on validation
match: true,
},
{
input: "[fd00:1:2::3]:75050", // ipv6 compressed
match: true,
},
{
input: "[fd00:1:2::3]75050", // ipv6 wrong port separator
match: false,
},
{
input: "[fd00:1:2::3]::75050", // ipv6 wrong port separator
match: false,
},
{
input: "[fd00:1:2::3%eth0]:75050", // ipv6 with zone
match: false,
},
{
input: "[fd00123123123]:75050", // ipv6 wrong format, will fail in validation
match: true,
},
{
input: "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:75050", // ipv6 long format
match: true,
},
{
input: "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:750505", // ipv6 long format and invalid port, it will fail in validation
match: true,
},
{
input: "fd00:1:2::3:75050", // bad ipv6 without square brackets
match: false,
},
}
r := regexp.MustCompile(`^` + DomainRegexp.String() + `$`)
for i := range hostcases {