Validate digest length on parsing
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>master
							parent
							
								
									329c353411
								
							
						
					
					
						commit
						f015982f0f
					
				|  | @ -58,6 +58,9 @@ var ( | |||
| 	// ErrDigestInvalidFormat returned when digest format invalid.
 | ||||
| 	ErrDigestInvalidFormat = fmt.Errorf("invalid checksum digest format") | ||||
| 
 | ||||
| 	// ErrDigestInvalidLength returned when digest has invalid length.
 | ||||
| 	ErrDigestInvalidLength = fmt.Errorf("invalid checksum digest length") | ||||
| 
 | ||||
| 	// ErrDigestUnsupported returned when the digest algorithm is unsupported.
 | ||||
| 	ErrDigestUnsupported = fmt.Errorf("unsupported digest algorithm") | ||||
| ) | ||||
|  | @ -126,8 +129,11 @@ func (d Digest) Validate() error { | |||
| 		return ErrDigestInvalidFormat | ||||
| 	} | ||||
| 
 | ||||
| 	switch Algorithm(s[:i]) { | ||||
| 	switch algorithm := Algorithm(s[:i]); algorithm { | ||||
| 	case SHA256, SHA384, SHA512: | ||||
| 		if algorithm.Size()*2 != len(s[i+1:]) { | ||||
| 			return ErrDigestInvalidLength | ||||
| 		} | ||||
| 		break | ||||
| 	default: | ||||
| 		return ErrDigestUnsupported | ||||
|  |  | |||
|  | @ -53,6 +53,16 @@ func TestParseDigest(t *testing.T) { | |||
| 			input: "sha256:d41d8cd98f00b204e9800m98ecf8427e", | ||||
| 			err:   ErrDigestInvalidFormat, | ||||
| 		}, | ||||
| 		{ | ||||
| 			// too short
 | ||||
| 			input: "sha256:abcdef0123456789", | ||||
| 			err:   ErrDigestInvalidLength, | ||||
| 		}, | ||||
| 		{ | ||||
| 			// too short (from different algorithm)
 | ||||
| 			input: "sha512:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789", | ||||
| 			err:   ErrDigestInvalidLength, | ||||
| 		}, | ||||
| 		{ | ||||
| 			input: "foo:d41d8cd98f00b204e9800998ecf8427e", | ||||
| 			err:   ErrDigestUnsupported, | ||||
|  |  | |||
|  | @ -54,6 +54,15 @@ func (a Algorithm) String() string { | |||
| 	return string(a) | ||||
| } | ||||
| 
 | ||||
| // Size returns number of bytes returned by the hash.
 | ||||
| func (a Algorithm) Size() int { | ||||
| 	h, ok := algorithms[a] | ||||
| 	if !ok { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return h.Size() | ||||
| } | ||||
| 
 | ||||
| // Set implemented to allow use of Algorithm as a command line flag.
 | ||||
| func (a *Algorithm) Set(value string) error { | ||||
| 	if value == "" { | ||||
|  |  | |||
|  | @ -15,14 +15,14 @@ func assertEqualDigests(t *testing.T, d1, d2 Digest) { | |||
| 
 | ||||
| func TestLookup(t *testing.T) { | ||||
| 	digests := []Digest{ | ||||
| 		"sha256:12345", | ||||
| 		"sha256:1234", | ||||
| 		"sha256:12346", | ||||
| 		"sha256:54321", | ||||
| 		"sha256:65431", | ||||
| 		"sha256:64321", | ||||
| 		"sha256:65421", | ||||
| 		"sha256:65321", | ||||
| 		"sha256:1234511111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:1234111111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:1234611111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:5432111111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:6543111111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:6432111111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:6542111111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:6532111111111111111111111111111111111111111111111111111111111111", | ||||
| 	} | ||||
| 
 | ||||
| 	dset := NewSet() | ||||
|  | @ -55,10 +55,12 @@ func TestLookup(t *testing.T) { | |||
| 	} | ||||
| 
 | ||||
| 	dgst, err = dset.Lookup("sha256:1234") | ||||
| 	if err != nil { | ||||
| 	if err == nil { | ||||
| 		t.Fatal("Expected ambiguous error looking up: sha256:1234") | ||||
| 	} | ||||
| 	if err != ErrDigestAmbiguous { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	assertEqualDigests(t, dgst, digests[1]) | ||||
| 
 | ||||
| 	dgst, err = dset.Lookup("sha256:12345") | ||||
| 	if err != nil { | ||||
|  | @ -87,14 +89,14 @@ func TestLookup(t *testing.T) { | |||
| 
 | ||||
| func TestAddDuplication(t *testing.T) { | ||||
| 	digests := []Digest{ | ||||
| 		"sha256:1234", | ||||
| 		"sha256:12345", | ||||
| 		"sha256:12346", | ||||
| 		"sha256:54321", | ||||
| 		"sha256:65431", | ||||
| 		"sha512:65431", | ||||
| 		"sha512:65421", | ||||
| 		"sha512:65321", | ||||
| 		"sha256:1234111111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:1234511111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:1234611111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:5432111111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:6543111111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha512:65431111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha512:65421111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha512:65321111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", | ||||
| 	} | ||||
| 
 | ||||
| 	dset := NewSet() | ||||
|  | @ -108,7 +110,7 @@ func TestAddDuplication(t *testing.T) { | |||
| 		t.Fatal("Invalid dset size") | ||||
| 	} | ||||
| 
 | ||||
| 	if err := dset.Add(Digest("sha256:12345")); err != nil { | ||||
| 	if err := dset.Add(Digest("sha256:1234511111111111111111111111111111111111111111111111111111111111")); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
|  | @ -116,7 +118,7 @@ func TestAddDuplication(t *testing.T) { | |||
| 		t.Fatal("Duplicate digest insert allowed") | ||||
| 	} | ||||
| 
 | ||||
| 	if err := dset.Add(Digest("sha384:12345")); err != nil { | ||||
| 	if err := dset.Add(Digest("sha384:123451111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111")); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
|  | @ -193,14 +195,14 @@ func assertEqualShort(t *testing.T, actual, expected string) { | |||
| 
 | ||||
| func TestShortCodeTable(t *testing.T) { | ||||
| 	digests := []Digest{ | ||||
| 		"sha256:1234", | ||||
| 		"sha256:12345", | ||||
| 		"sha256:12346", | ||||
| 		"sha256:54321", | ||||
| 		"sha256:65431", | ||||
| 		"sha256:64321", | ||||
| 		"sha256:65421", | ||||
| 		"sha256:65321", | ||||
| 		"sha256:1234111111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:1234511111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:1234611111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:5432111111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:6543111111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:6432111111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:6542111111111111111111111111111111111111111111111111111111111111", | ||||
| 		"sha256:6532111111111111111111111111111111111111111111111111111111111111", | ||||
| 	} | ||||
| 
 | ||||
| 	dset := NewSet() | ||||
|  | @ -215,10 +217,9 @@ func TestShortCodeTable(t *testing.T) { | |||
| 	if len(dump) < len(digests) { | ||||
| 		t.Fatalf("Error unexpected size: %d, expecting %d", len(dump), len(digests)) | ||||
| 	} | ||||
| 
 | ||||
| 	assertEqualShort(t, dump[digests[0]], "sha256:1234") | ||||
| 	assertEqualShort(t, dump[digests[1]], "sha256:12345") | ||||
| 	assertEqualShort(t, dump[digests[2]], "sha256:12346") | ||||
| 	assertEqualShort(t, dump[digests[0]], "12341") | ||||
| 	assertEqualShort(t, dump[digests[1]], "12345") | ||||
| 	assertEqualShort(t, dump[digests[2]], "12346") | ||||
| 	assertEqualShort(t, dump[digests[3]], "54") | ||||
| 	assertEqualShort(t, dump[digests[4]], "6543") | ||||
| 	assertEqualShort(t, dump[digests[5]], "64") | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ | |||
| //
 | ||||
| //	// repository.go
 | ||||
| //	repository			:= hostname ['/' component]+
 | ||||
| //	hostname 			:= hostcomponent [':' port-number]
 | ||||
| //	hostname			:= hostcomponent [':' port-number]
 | ||||
| //	component			:= subcomponent [separator subcomponent]*
 | ||||
| //	subcomponent			:= alpha-numeric ['-'* alpha-numeric]*
 | ||||
| //	hostcomponent                   := [hostpart '.']* hostpart
 | ||||
|  | @ -24,7 +24,7 @@ | |||
| //	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,}/ ; Atleast 128 bit digest value
 | ||||
| //	digest-hex                      := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value
 | ||||
| package reference | ||||
| 
 | ||||
| import ( | ||||
|  |  | |||
|  | @ -87,6 +87,10 @@ func TestReferenceParse(t *testing.T) { | |||
| 			input: "@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", | ||||
| 			err:   ErrReferenceInvalidFormat, | ||||
| 		}, | ||||
| 		{ | ||||
| 			input: "repo@sha256:ffffffffffffffffffffffffffffffffff", | ||||
| 			err:   digest.ErrDigestInvalidLength, | ||||
| 		}, | ||||
| 		{ | ||||
| 			input: "validname@invaliddigest:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", | ||||
| 			err:   digest.ErrDigestUnsupported, | ||||
|  | @ -129,11 +133,11 @@ func TestReferenceParse(t *testing.T) { | |||
| 			tag:        "xn--n3h.com", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:      "xn--7o8h.com/myimage:xn--7o8h.com@sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // 🐳.com in punycode
 | ||||
| 			input:      "xn--7o8h.com/myimage:xn--7o8h.com@sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // 🐳.com in punycode
 | ||||
| 			hostname:   "xn--7o8h.com", | ||||
| 			repository: "xn--7o8h.com/myimage", | ||||
| 			tag:        "xn--7o8h.com", | ||||
| 			digest:     "sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", | ||||
| 			digest:     "sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:      "foo_bar.com:8080", | ||||
|  | @ -343,9 +347,9 @@ func TestSerialization(t *testing.T) { | |||
| 		}, | ||||
| 		{ | ||||
| 			description: "name with digest", | ||||
| 			input:       "other.com/named@sha256:1234567890098765432112345667890098765", | ||||
| 			input:       "other.com/named@sha256:1234567890098765432112345667890098765432112345667890098765432112", | ||||
| 			name:        "other.com/named", | ||||
| 			digest:      "sha256:1234567890098765432112345667890098765", | ||||
| 			digest:      "sha256:1234567890098765432112345667890098765432112345667890098765432112", | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, testcase := range testcases { | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ func CheckBlobDescriptorCache(t *testing.T, provider cache.BlobDescriptorCachePr | |||
| } | ||||
| 
 | ||||
| func checkBlobDescriptorCacheEmptyRepository(t *testing.T, ctx context.Context, provider cache.BlobDescriptorCacheProvider) { | ||||
| 	if _, err := provider.Stat(ctx, "sha384:abc"); err != distribution.ErrBlobUnknown { | ||||
| 	if _, err := provider.Stat(ctx, "sha384:abc111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); err != distribution.ErrBlobUnknown { | ||||
| 		t.Fatalf("expected unknown blob error with empty store: %v", err) | ||||
| 	} | ||||
| 
 | ||||
|  | @ -41,7 +41,7 @@ func checkBlobDescriptorCacheEmptyRepository(t *testing.T, ctx context.Context, | |||
| 		t.Fatalf("expected error with invalid digest: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if err := cache.SetDescriptor(ctx, "sha384:abc", distribution.Descriptor{ | ||||
| 	if err := cache.SetDescriptor(ctx, "sha384:abc111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", distribution.Descriptor{ | ||||
| 		Digest:    "", | ||||
| 		Size:      10, | ||||
| 		MediaType: "application/octet-stream"}); err == nil { | ||||
|  | @ -52,15 +52,15 @@ func checkBlobDescriptorCacheEmptyRepository(t *testing.T, ctx context.Context, | |||
| 		t.Fatalf("expected error checking for cache item with empty digest: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if _, err := cache.Stat(ctx, "sha384:abc"); err != distribution.ErrBlobUnknown { | ||||
| 	if _, err := cache.Stat(ctx, "sha384:abc111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); err != distribution.ErrBlobUnknown { | ||||
| 		t.Fatalf("expected unknown blob error with empty repo: %v", err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func checkBlobDescriptorCacheSetAndRead(t *testing.T, ctx context.Context, provider cache.BlobDescriptorCacheProvider) { | ||||
| 	localDigest := digest.Digest("sha384:abc") | ||||
| 	localDigest := digest.Digest("sha384:abc111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") | ||||
| 	expected := distribution.Descriptor{ | ||||
| 		Digest:    "sha256:abc", | ||||
| 		Digest:    "sha256:abc1111111111111111111111111111111111111111111111111111111111111", | ||||
| 		Size:      10, | ||||
| 		MediaType: "application/octet-stream"} | ||||
| 
 | ||||
|  |  | |||
|  | @ -385,15 +385,15 @@ func TestLinkPathFuncs(t *testing.T) { | |||
| 	}{ | ||||
| 		{ | ||||
| 			repo:       "foo/bar", | ||||
| 			digest:     "sha256:deadbeaf", | ||||
| 			digest:     "sha256:deadbeaf98fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", | ||||
| 			linkPathFn: blobLinkPath, | ||||
| 			expected:   "/docker/registry/v2/repositories/foo/bar/_layers/sha256/deadbeaf/link", | ||||
| 			expected:   "/docker/registry/v2/repositories/foo/bar/_layers/sha256/deadbeaf98fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/link", | ||||
| 		}, | ||||
| 		{ | ||||
| 			repo:       "foo/bar", | ||||
| 			digest:     "sha256:deadbeaf", | ||||
| 			digest:     "sha256:deadbeaf98fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", | ||||
| 			linkPathFn: manifestRevisionLinkPath, | ||||
| 			expected:   "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/deadbeaf/link", | ||||
| 			expected:   "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/deadbeaf98fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/link", | ||||
| 		}, | ||||
| 	} { | ||||
| 		p, err := testcase.linkPathFn(testcase.repo, testcase.digest) | ||||
|  |  | |||
|  | @ -15,31 +15,31 @@ func TestPathMapper(t *testing.T) { | |||
| 		{ | ||||
| 			spec: manifestRevisionPathSpec{ | ||||
| 				name:     "foo/bar", | ||||
| 				revision: "sha256:abcdef0123456789", | ||||
| 				revision: "sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789", | ||||
| 			}, | ||||
| 			expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789", | ||||
| 			expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789", | ||||
| 		}, | ||||
| 		{ | ||||
| 			spec: manifestRevisionLinkPathSpec{ | ||||
| 				name:     "foo/bar", | ||||
| 				revision: "sha256:abcdef0123456789", | ||||
| 				revision: "sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789", | ||||
| 			}, | ||||
| 			expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789/link", | ||||
| 			expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789/link", | ||||
| 		}, | ||||
| 		{ | ||||
| 			spec: manifestSignatureLinkPathSpec{ | ||||
| 				name:      "foo/bar", | ||||
| 				revision:  "sha256:abcdef0123456789", | ||||
| 				signature: "sha256:abcdef0123456789", | ||||
| 				revision:  "sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789", | ||||
| 				signature: "sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789", | ||||
| 			}, | ||||
| 			expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789/signatures/sha256/abcdef0123456789/link", | ||||
| 			expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789/signatures/sha256/abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789/link", | ||||
| 		}, | ||||
| 		{ | ||||
| 			spec: manifestSignaturesPathSpec{ | ||||
| 				name:     "foo/bar", | ||||
| 				revision: "sha256:abcdef0123456789", | ||||
| 				revision: "sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789", | ||||
| 			}, | ||||
| 			expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789/signatures", | ||||
| 			expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789/signatures", | ||||
| 		}, | ||||
| 		{ | ||||
| 			spec: manifestTagsPathSpec{ | ||||
|  | @ -72,17 +72,17 @@ func TestPathMapper(t *testing.T) { | |||
| 			spec: manifestTagIndexEntryPathSpec{ | ||||
| 				name:     "foo/bar", | ||||
| 				tag:      "thetag", | ||||
| 				revision: "sha256:abcdef0123456789", | ||||
| 				revision: "sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789", | ||||
| 			}, | ||||
| 			expected: "/docker/registry/v2/repositories/foo/bar/_manifests/tags/thetag/index/sha256/abcdef0123456789", | ||||
| 			expected: "/docker/registry/v2/repositories/foo/bar/_manifests/tags/thetag/index/sha256/abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789", | ||||
| 		}, | ||||
| 		{ | ||||
| 			spec: manifestTagIndexEntryLinkPathSpec{ | ||||
| 				name:     "foo/bar", | ||||
| 				tag:      "thetag", | ||||
| 				revision: "sha256:abcdef0123456789", | ||||
| 				revision: "sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789", | ||||
| 			}, | ||||
| 			expected: "/docker/registry/v2/repositories/foo/bar/_manifests/tags/thetag/index/sha256/abcdef0123456789/link", | ||||
| 			expected: "/docker/registry/v2/repositories/foo/bar/_manifests/tags/thetag/index/sha256/abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789/link", | ||||
| 		}, | ||||
| 		{ | ||||
| 			spec: layerLinkPathSpec{ | ||||
|  | @ -93,15 +93,15 @@ func TestPathMapper(t *testing.T) { | |||
| 		}, | ||||
| 		{ | ||||
| 			spec: blobDataPathSpec{ | ||||
| 				digest: digest.Digest("tarsum.dev+sha512:abcdefabcdefabcdef908909909"), | ||||
| 				digest: digest.Digest("tarsum.dev+sha512:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"), | ||||
| 			}, | ||||
| 			expected: "/docker/registry/v2/blobs/tarsum/dev/sha512/ab/abcdefabcdefabcdef908909909/data", | ||||
| 			expected: "/docker/registry/v2/blobs/tarsum/dev/sha512/ab/abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789/data", | ||||
| 		}, | ||||
| 		{ | ||||
| 			spec: blobDataPathSpec{ | ||||
| 				digest: digest.Digest("tarsum.v1+sha256:abcdefabcdefabcdef908909909"), | ||||
| 				digest: digest.Digest("tarsum.v1+sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"), | ||||
| 			}, | ||||
| 			expected: "/docker/registry/v2/blobs/tarsum/v1/sha256/ab/abcdefabcdefabcdef908909909/data", | ||||
| 			expected: "/docker/registry/v2/blobs/tarsum/v1/sha256/ab/abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789/data", | ||||
| 		}, | ||||
| 
 | ||||
| 		{ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue