Skip to content

Commit 79a08b4

Browse files
authored
fix: check content-type when using referrers API (#635)
When accessing the referrer's API, this adds a check to make sure the content-type is an OCI index. Also fixes the tests to properly set the content-type header in the response. Closes #633 Signed-off-by: Kyle M. Tarplee <[email protected]>
1 parent 3776676 commit 79a08b4

File tree

5 files changed

+270
-130
lines changed

5 files changed

+270
-130
lines changed

example_copy_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ func TestMain(m *testing.M) {
144144
MediaType: ocispec.MediaTypeImageIndex,
145145
Manifests: referrers,
146146
}
147+
w.Header().Set("Content-Type", ocispec.MediaTypeImageIndex)
147148
if err := json.NewEncoder(w).Encode(result); err != nil {
148149
panic(err)
149150
}

extendedcopy_test.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,15 +1031,20 @@ func TestExtendedCopyGraph_FilterAnnotationWithMultipleRegex_Referrers(t *testin
10311031
// set up test server
10321032
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
10331033
p := r.URL.Path
1034+
var manifests []ocispec.Descriptor
10341035
switch {
10351036
case p == "/v2/test/referrers/"+descs[0].Digest.String():
1037+
manifests = descs[1:]
1038+
fallthrough
1039+
case strings.HasPrefix(p, "/v2/test/referrers/"):
10361040
result := ocispec.Index{
10371041
Versioned: specs.Versioned{
10381042
SchemaVersion: 2, // historical value. does not pertain to OCI or docker version
10391043
},
10401044
MediaType: ocispec.MediaTypeImageIndex,
1041-
Manifests: descs[1:],
1045+
Manifests: manifests,
10421046
}
1047+
w.Header().Set("Content-Type", ocispec.MediaTypeImageIndex)
10431048
if err := json.NewEncoder(w).Encode(result); err != nil {
10441049
t.Errorf("failed to write response: %v", err)
10451050
}
@@ -1076,7 +1081,6 @@ func TestExtendedCopyGraph_FilterAnnotationWithMultipleRegex_Referrers(t *testin
10761081
default:
10771082
t.Errorf("unexpected access: %s %s", r.Method, r.URL)
10781083
w.WriteHeader(http.StatusNotFound)
1079-
return
10801084
}
10811085
}))
10821086
defer ts.Close()
@@ -1454,15 +1458,20 @@ func TestExtendedCopyGraph_FilterArtifactTypeWithMultipleRegex_Referrers(t *test
14541458
// set up test server
14551459
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
14561460
p := r.URL.Path
1461+
var manifests []ocispec.Descriptor
14571462
switch {
14581463
case p == "/v2/test/referrers/"+descs[0].Digest.String():
1464+
manifests = descs[1:]
1465+
fallthrough
1466+
case strings.HasPrefix(p, "/v2/test/referrers/"):
14591467
result := ocispec.Index{
14601468
Versioned: specs.Versioned{
14611469
SchemaVersion: 2, // historical value. does not pertain to OCI or docker version
14621470
},
14631471
MediaType: ocispec.MediaTypeImageIndex,
1464-
Manifests: descs[1:],
1472+
Manifests: manifests,
14651473
}
1474+
w.Header().Set("Content-Type", ocispec.MediaTypeImageIndex)
14661475
if err := json.NewEncoder(w).Encode(result); err != nil {
14671476
t.Errorf("failed to write response: %v", err)
14681477
}
@@ -1695,15 +1704,20 @@ func TestExtendedCopyGraph_FilterArtifactTypeAndAnnotationWithMultipleRegex_Refe
16951704
// set up test server
16961705
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
16971706
p := r.URL.Path
1707+
var manifests []ocispec.Descriptor
16981708
switch {
16991709
case p == "/v2/test/referrers/"+descs[0].Digest.String():
1710+
manifests = descs[1:]
1711+
fallthrough
1712+
case strings.HasPrefix(p, "/v2/test/referrers/"):
17001713
result := ocispec.Index{
17011714
Versioned: specs.Versioned{
17021715
SchemaVersion: 2, // historical value. does not pertain to OCI or docker version
17031716
},
17041717
MediaType: ocispec.MediaTypeImageIndex,
1705-
Manifests: descs[1:],
1718+
Manifests: manifests,
17061719
}
1720+
w.Header().Set("Content-Type", ocispec.MediaTypeImageIndex)
17071721
if err := json.NewEncoder(w).Encode(result); err != nil {
17081722
t.Errorf("failed to write response: %v", err)
17091723
}

registry/remote/example_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,17 @@ func TestMain(m *testing.M) {
174174
w.Header().Set("Content-Digest", string(blobDescriptor.Digest))
175175
w.Header().Set("Content-Length", strconv.Itoa(len(blobContent)))
176176
w.Write([]byte(blobContent))
177+
case p == fmt.Sprintf("/v2/%s/referrers/%s", exampleRepositoryName, "sha256:0000000000000000000000000000000000000000000000000000000000000000"):
178+
result := ocispec.Index{
179+
Versioned: specs.Versioned{
180+
SchemaVersion: 2, // historical value. does not pertain to OCI or docker version
181+
},
182+
MediaType: ocispec.MediaTypeImageIndex,
183+
}
184+
w.Header().Set("Content-Type", ocispec.MediaTypeImageIndex)
185+
if err := json.NewEncoder(w).Encode(result); err != nil {
186+
panic(err)
187+
}
177188
case p == fmt.Sprintf("/v2/%s/referrers/%s", exampleRepositoryName, exampleManifestDescriptor.Digest.String()):
178189
q := r.URL.Query()
179190
var referrers []ocispec.Descriptor
@@ -191,6 +202,7 @@ func TestMain(m *testing.M) {
191202
MediaType: ocispec.MediaTypeImageIndex,
192203
Manifests: referrers,
193204
}
205+
w.Header().Set("Content-Type", ocispec.MediaTypeImageIndex)
194206
if err := json.NewEncoder(w).Encode(result); err != nil {
195207
panic(err)
196208
}

registry/remote/repository.go

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -483,18 +483,12 @@ func (r *Repository) Referrers(ctx context.Context, desc ocispec.Descriptor, art
483483

484484
// The referrers state is unknown.
485485
if err != nil {
486-
var errResp *errcode.ErrorResponse
487-
if !errors.As(err, &errResp) || errResp.StatusCode != http.StatusNotFound {
488-
return err
489-
}
490-
if errutil.IsErrorCode(errResp, errcode.ErrorCodeNameUnknown) {
491-
// The repository is not found, no fallback.
492-
return err
486+
if errors.Is(err, errdef.ErrUnsupported) {
487+
// Referrers API is not supported, fallback to referrers tag schema.
488+
r.SetReferrersCapability(false)
489+
return r.referrersByTagSchema(ctx, desc, artifactType, fn)
493490
}
494-
// A 404 returned by Referrers API indicates that Referrers API is
495-
// not supported. Fallback to referrers tag schema.
496-
r.SetReferrersCapability(false)
497-
return r.referrersByTagSchema(ctx, desc, artifactType, fn)
491+
return err
498492
}
499493

500494
r.SetReferrersCapability(true)
@@ -544,10 +538,24 @@ func (r *Repository) referrersPageByAPI(ctx context.Context, artifactType string
544538
}
545539
defer resp.Body.Close()
546540

547-
if resp.StatusCode != http.StatusOK {
541+
switch resp.StatusCode {
542+
case http.StatusOK:
543+
case http.StatusNotFound:
544+
if errResp := errutil.ParseErrorResponse(resp); errutil.IsErrorCode(errResp, errcode.ErrorCodeNameUnknown) {
545+
// The repository is not found, Referrers API status is unknown
546+
return "", errResp
547+
}
548+
// Referrers API is not supported.
549+
return "", fmt.Errorf("failed to query referrers API: %w", errdef.ErrUnsupported)
550+
default:
548551
return "", errutil.ParseErrorResponse(resp)
549552
}
550553

554+
// also check the content type
555+
if ct := resp.Header.Get("Content-Type"); ct != ocispec.MediaTypeImageIndex {
556+
return "", fmt.Errorf("unknown content returned (%s), expecting image index: %w", ct, errdef.ErrUnsupported)
557+
}
558+
551559
var index ocispec.Index
552560
lr := limitReader(resp.Body, r.MaxMetadataBytes)
553561
if err := json.NewDecoder(lr).Decode(&index); err != nil {
@@ -657,8 +665,9 @@ func (r *Repository) pingReferrers(ctx context.Context) (bool, error) {
657665

658666
switch resp.StatusCode {
659667
case http.StatusOK:
660-
r.SetReferrersCapability(true)
661-
return true, nil
668+
supported := resp.Header.Get("Content-Type") == ocispec.MediaTypeImageIndex
669+
r.SetReferrersCapability(supported)
670+
return supported, nil
662671
case http.StatusNotFound:
663672
if err := errutil.ParseErrorResponse(resp); errutil.IsErrorCode(err, errcode.ErrorCodeNameUnknown) {
664673
// repository not found

0 commit comments

Comments
 (0)