commit
						4bf3547399
					
				|  | @ -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", | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -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]*
 | ||||
|  |  | |||
|  | @ -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{}) { | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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 { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue