commit
						4bf3547399
					
				|  | @ -22,7 +22,14 @@ func TestValidateReferenceName(t *testing.T) { | ||||||
| 		"127.0.0.1:5000/docker/docker", | 		"127.0.0.1:5000/docker/docker", | ||||||
| 		"127.0.0.1:5000/library/debian", | 		"127.0.0.1:5000/library/debian", | ||||||
| 		"127.0.0.1:5000/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", | 		"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
 | 		// 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
 | 		// when specified with a hostname, it removes the ambiguity from about
 | ||||||
|  | @ -40,6 +47,11 @@ func TestValidateReferenceName(t *testing.T) { | ||||||
| 		"docker///docker", | 		"docker///docker", | ||||||
| 		"docker.io/docker/Docker", | 		"docker.io/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", | 		"1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a", | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5,7 +5,9 @@ | ||||||
| //
 | //
 | ||||||
| // 	reference                       := name [ ":" tag ] [ "@" digest ]
 | // 	reference                       := name [ ":" tag ] [ "@" digest ]
 | ||||||
| //	name                            := [domain '/'] path-component ['/' path-component]*
 | //	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])/
 | //	domain-component                := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
 | ||||||
| //	port-number                     := /[0-9]+/
 | //	port-number                     := /[0-9]+/
 | ||||||
| //	path-component                  := alpha-numeric [separator alpha-numeric]*
 | //	path-component                  := alpha-numeric [separator alpha-numeric]*
 | ||||||
|  |  | ||||||
|  | @ -171,6 +171,101 @@ func TestReferenceParse(t *testing.T) { | ||||||
| 			repository: "foo/foo_bar.com", | 			repository: "foo/foo_bar.com", | ||||||
| 			tag:        "8080", | 			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 { | 	for _, testcase := range referenceTestcases { | ||||||
| 		failf := func(format string, v ...interface{}) { | 		failf := func(format string, v ...interface{}) { | ||||||
|  |  | ||||||
|  | @ -23,15 +23,40 @@ var ( | ||||||
| 		alphaNumeric, | 		alphaNumeric, | ||||||
| 		optional(repeated(separator, alphaNumeric))) | 		optional(repeated(separator, alphaNumeric))) | ||||||
| 
 | 
 | ||||||
| 	// domainComponent restricts the registry domain component of a
 | 	// domainNameComponent restricts the registry domain component of a
 | ||||||
| 	// repository name to start with a component as defined by DomainRegexp
 | 	// repository name to start with a component as defined by DomainRegexp.
 | ||||||
| 	// and followed by an optional port.
 | 	domainNameComponent = `(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])` | ||||||
| 	domainComponent = `(?:[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( | 	domain = expression( | ||||||
| 		domainComponent, | 		host, | ||||||
| 		optional(repeated(literal(`.`), domainComponent)), |  | ||||||
| 		optional(literal(`:`), `[0-9]+`)) | 		optional(literal(`:`), `[0-9]+`)) | ||||||
|  | 
 | ||||||
| 	// DomainRegexp defines the structure of potential domain components
 | 	// DomainRegexp defines the structure of potential domain components
 | ||||||
| 	// that may be part of image names. This is purposely a subset of what is
 | 	// 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
 | 	// allowed by DNS to ensure backwards compatibility with Docker image
 | ||||||
|  |  | ||||||
|  | @ -115,6 +115,46 @@ func TestDomainRegexp(t *testing.T) { | ||||||
| 			input: "Asdf.com", // uppercase character
 | 			input: "Asdf.com", // uppercase character
 | ||||||
| 			match: true, | 			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() + `$`) | 	r := regexp.MustCompile(`^` + DomainRegexp.String() + `$`) | ||||||
| 	for i := range hostcases { | 	for i := range hostcases { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue