From 2807bce77a329757ba1f20f3e9c9c11efc8c74b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Vl=C3=A9rick?= Date: Tue, 10 Oct 2023 14:56:32 +0200 Subject: [PATCH] add a check on the position of the image in the index before deleting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Vlérick --- .../delete_image_only_one_image/index.json | 2 +- ...e402ae2e97119c6007b6e52146419985ec1f0092dc | 1 + ...a9f52b17b187642269d84c044538523c5b69a660b3 | 16 +++++ ...2b8637b47ce96c838ba2aa0de66d14f45cedc11423 | 30 ++++++++ ...46613b6b49811f79e38b5b0ce666268ba4b6c68e41 | 30 ++++++++ ...dc4df81d4785d5d6373027c488a2db8a6e76fe88ed | 16 +++++ ...54d2a840020592530a8d4e8de9888b9e9a533419d8 | 1 + .../index.json | 21 ++++++ .../oci-layout | 1 + oci/layout/oci_delete.go | 11 +-- oci/layout/oci_delete_test.go | 35 ++++++++-- oci/layout/oci_src.go | 2 +- oci/layout/oci_transport.go | 19 ++--- oci/layout/oci_transport_test.go | 69 ++++++++++++------- 14 files changed, 211 insertions(+), 43 deletions(-) create mode 100644 oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc create mode 100644 oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/49d1584496c6e196f512c4a9f52b17b187642269d84c044538523c5b69a660b3 create mode 100644 oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 create mode 100644 oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/ce229a4eb5797ecd3a3a1846613b6b49811f79e38b5b0ce666268ba4b6c68e41 create mode 100644 oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/ecfa463536cb5472e238aadc4df81d4785d5d6373027c488a2db8a6e76fe88ed create mode 100644 oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/fa00bb4e2adbc73a5da1fd54d2a840020592530a8d4e8de9888b9e9a533419d8 create mode 100644 oci/layout/fixtures/delete_image_two_identical_references/index.json create mode 100644 oci/layout/fixtures/delete_image_two_identical_references/oci-layout diff --git a/oci/layout/fixtures/delete_image_only_one_image/index.json b/oci/layout/fixtures/delete_image_only_one_image/index.json index 49925c19ae..b0a0c98478 100644 --- a/oci/layout/fixtures/delete_image_only_one_image/index.json +++ b/oci/layout/fixtures/delete_image_only_one_image/index.json @@ -4,7 +4,7 @@ { "mediaType": "application/vnd.oci.image.manifest.v1+json", "digest": "sha256:eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18", - "size": 405, + "size": 476, "annotations": { "org.opencontainers.image.ref.name": "latest" } diff --git a/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc b/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc new file mode 100644 index 0000000000..e7e64ba41b --- /dev/null +++ b/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc @@ -0,0 +1 @@ +insert binary content here #9671 diff --git a/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/49d1584496c6e196f512c4a9f52b17b187642269d84c044538523c5b69a660b3 b/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/49d1584496c6e196f512c4a9f52b17b187642269d84c044538523c5b69a660b3 new file mode 100644 index 0000000000..e59a5f804a --- /dev/null +++ b/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/49d1584496c6e196f512c4a9f52b17b187642269d84c044538523c5b69a660b3 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423", + "size": 740 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc", + "size": 33 + } + ] +} diff --git a/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 b/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 new file mode 100644 index 0000000000..f0f06201be --- /dev/null +++ b/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 @@ -0,0 +1,30 @@ +{ + "created": "2019-08-20T20:19:55.211423266Z", + "architecture": "amd64", + "os": "linux", + "config": { + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ], + "Cmd": [ + "/bin/sh" + ] + }, + "rootfs": { + "type": "layers", + "diff_ids": [ + "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" + ] + }, + "history": [ + { + "created": "2019-08-20T20:19:55.062606894Z", + "created_by": "/bin/sh -c #(nop) ADD file:fe64057fbb83dccb960efabbf1cd8777920ef279a7fa8dbca0a8801c651bdf7c in / " + }, + { + "created": "2019-08-20T20:19:55.211423266Z", + "created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]", + "empty_layer": true + } + ] +} diff --git a/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/ce229a4eb5797ecd3a3a1846613b6b49811f79e38b5b0ce666268ba4b6c68e41 b/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/ce229a4eb5797ecd3a3a1846613b6b49811f79e38b5b0ce666268ba4b6c68e41 new file mode 100644 index 0000000000..9578f7d9ec --- /dev/null +++ b/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/ce229a4eb5797ecd3a3a1846613b6b49811f79e38b5b0ce666268ba4b6c68e41 @@ -0,0 +1,30 @@ +{ + "created": "2019-08-20T20:20:55.211423266Z", + "architecture": "amd64", + "os": "linux", + "config": { + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ], + "Cmd": [ + "/bin/sh" + ] + }, + "rootfs": { + "type": "layers", + "diff_ids": [ + "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" + ] + }, + "history": [ + { + "created": "2019-08-20T20:19:55.062606894Z", + "created_by": "/bin/sh -c #(nop) ADD file:fe64057fbb83dccb960efabbf1cd8777920ef279a7fa8dbca0a8801c651bdf7c in / " + }, + { + "created": "2019-08-20T20:19:55.211423266Z", + "created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]", + "empty_layer": true + } + ] +} diff --git a/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/ecfa463536cb5472e238aadc4df81d4785d5d6373027c488a2db8a6e76fe88ed b/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/ecfa463536cb5472e238aadc4df81d4785d5d6373027c488a2db8a6e76fe88ed new file mode 100644 index 0000000000..16b7c27bd4 --- /dev/null +++ b/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/ecfa463536cb5472e238aadc4df81d4785d5d6373027c488a2db8a6e76fe88ed @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:ce229a4eb5797ecd3a3a1846613b6b49811f79e38b5b0ce666268ba4b6c68e41", + "size": 740 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:fa00bb4e2adbc73a5da1fd54d2a840020592530a8d4e8de9888b9e9a533419d8", + "size": 33 + } + ] +} diff --git a/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/fa00bb4e2adbc73a5da1fd54d2a840020592530a8d4e8de9888b9e9a533419d8 b/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/fa00bb4e2adbc73a5da1fd54d2a840020592530a8d4e8de9888b9e9a533419d8 new file mode 100644 index 0000000000..3badd42d29 --- /dev/null +++ b/oci/layout/fixtures/delete_image_two_identical_references/blobs/sha256/fa00bb4e2adbc73a5da1fd54d2a840020592530a8d4e8de9888b9e9a533419d8 @@ -0,0 +1 @@ +insert binary content here 32515 diff --git a/oci/layout/fixtures/delete_image_two_identical_references/index.json b/oci/layout/fixtures/delete_image_two_identical_references/index.json new file mode 100644 index 0000000000..80850d4b91 --- /dev/null +++ b/oci/layout/fixtures/delete_image_two_identical_references/index.json @@ -0,0 +1,21 @@ +{ + "schemaVersion": 2, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:49d1584496c6e196f512c4a9f52b17b187642269d84c044538523c5b69a660b3", + "size": 476, + "annotations": { + "org.opencontainers.image.ref.name": "1.0.0" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:ecfa463536cb5472e238aadc4df81d4785d5d6373027c488a2db8a6e76fe88ed", + "size": 476, + "annotations": { + "org.opencontainers.image.ref.name": "1.0.0" + } + } + ] +} diff --git a/oci/layout/fixtures/delete_image_two_identical_references/oci-layout b/oci/layout/fixtures/delete_image_two_identical_references/oci-layout new file mode 100644 index 0000000000..21b1439d1c --- /dev/null +++ b/oci/layout/fixtures/delete_image_two_identical_references/oci-layout @@ -0,0 +1 @@ +{"imageLayoutVersion": "1.0.0"} \ No newline at end of file diff --git a/oci/layout/oci_delete.go b/oci/layout/oci_delete.go index bde83eafb8..a8285ea097 100644 --- a/oci/layout/oci_delete.go +++ b/oci/layout/oci_delete.go @@ -21,7 +21,7 @@ func (ref ociReference) DeleteImage(ctx context.Context, sys *types.SystemContex sharedBlobsDir = sys.OCISharedBlobDirPath } - descriptor, err := ref.getManifestDescriptor() + descriptor, descriptorIndex, err := ref.getManifestDescriptor() if err != nil { return err } @@ -50,7 +50,7 @@ func (ref ociReference) DeleteImage(ctx context.Context, sys *types.SystemContex return err } - return ref.deleteReferenceFromIndex() + return ref.deleteReferenceFromIndex(descriptorIndex) } func (ref ociReference) getBlobsUsedInSingleImage(descriptor *imgspecv1.Descriptor, sharedBlobsDir string) (map[digest.Digest]int, error) { @@ -184,7 +184,7 @@ func deleteBlob(blobPath string) error { } } -func (ref ociReference) deleteReferenceFromIndex() error { +func (ref ociReference) deleteReferenceFromIndex(referenceIndex int) error { index, err := ref.getIndex() if err != nil { return err @@ -196,8 +196,9 @@ func (ref ociReference) deleteReferenceFromIndex() error { } newDescriptors := make([]imgspecv1.Descriptor, 0, len(index.Manifests)-1) - for _, descriptor := range index.Manifests { - if descriptor.Annotations[imgspecv1.AnnotationRefName] != ref.image { + for i, descriptor := range index.Manifests { + // Double check: same image reference name and same position in the index + if descriptor.Annotations[imgspecv1.AnnotationRefName] != ref.image || referenceIndex != i { newDescriptors = append(newDescriptors, descriptor) } } diff --git a/oci/layout/oci_delete_test.go b/oci/layout/oci_delete_test.go index 2ddc5de4ae..7e06456ffd 100644 --- a/oci/layout/oci_delete_test.go +++ b/oci/layout/oci_delete_test.go @@ -100,7 +100,7 @@ func TestReferenceDeleteImage_multipleImages(t *testing.T) { err = ref.DeleteImage(context.Background(), nil) require.NoError(t, err) - // Check that the relevant blobs were deleted/preservend + // Check that the relevant blobs were deleted/preserved blobsDir := filepath.Join(tmpDir, "blobs") files, err := os.ReadDir(filepath.Join(blobsDir, "sha256")) require.NoError(t, err) @@ -136,7 +136,7 @@ func TestReferenceDeleteImage_multipleImages_blobsUsedByOtherImages(t *testing.T err = ref.DeleteImage(context.Background(), nil) require.NoError(t, err) - // Check that the relevant blobs were deleted/preservend + // Check that the relevant blobs were deleted/preserved blobsDir := filepath.Join(tmpDir, "blobs") files, err := os.ReadDir(filepath.Join(blobsDir, "sha256")) require.NoError(t, err) @@ -192,7 +192,7 @@ func TestReferenceDeleteImage_multipleImages_nestedIndexImage(t *testing.T) { err = ref.DeleteImage(context.Background(), nil) require.NoError(t, err) - // Check that the relevant blobs were deleted/preservend + // Check that the relevant blobs were deleted/preserved blobsDir := filepath.Join(tmpDir, "blobs") files, err := os.ReadDir(filepath.Join(blobsDir, "sha256")) require.NoError(t, err) @@ -232,7 +232,7 @@ func TestReferenceDeleteImage_multipleImages_nestedIndexImage_refWithSameContent err = ref.DeleteImage(context.Background(), nil) require.NoError(t, err) - // Check that the relevant blobs were deleted/preservend + // Check that the relevant blobs were deleted/preserved blobsDir := filepath.Join(tmpDir, "blobs") files, err := os.ReadDir(filepath.Join(blobsDir, "sha256")) require.NoError(t, err) @@ -247,6 +247,33 @@ func TestReferenceDeleteImage_multipleImages_nestedIndexImage_refWithSameContent require.Equal(t, 6, len(index.Manifests)) } +func TestReferenceDeleteImage_multipleImages_twoIdenticalReferences(t *testing.T) { + tmpDir := loadFixture(t, "delete_image_two_identical_references") + + ref, err := NewReference(tmpDir, "1.0.0") + require.NoError(t, err) + + err = ref.DeleteImage(context.Background(), nil) + require.NoError(t, err) + + // Check that the relevant blobs were deleted/preserved - in this case only the first reference should be deleted + blobsDir := filepath.Join(tmpDir, "blobs") + files, err := os.ReadDir(filepath.Join(blobsDir, "sha256")) + require.NoError(t, err) + require.Equal(t, 3, len(files)) + assertBlobExists(t, blobsDir, "sha256:ecfa463536cb5472e238aadc4df81d4785d5d6373027c488a2db8a6e76fe88ed") + assertBlobExists(t, blobsDir, "sha256:ce229a4eb5797ecd3a3a1846613b6b49811f79e38b5b0ce666268ba4b6c68e41") + assertBlobExists(t, blobsDir, "sha256:fa00bb4e2adbc73a5da1fd54d2a840020592530a8d4e8de9888b9e9a533419d8") + + // Check the index + ociRef, ok := ref.(ociReference) + require.True(t, ok) + // .. Check that the index has been reduced to the correct size + index, err := ociRef.getIndex() + require.NoError(t, err) + require.Equal(t, 1, len(index.Manifests)) +} + func loadFixture(t *testing.T, fixtureName string) string { tmpDir := t.TempDir() err := cp.Copy(fmt.Sprintf("fixtures/%v/", fixtureName), tmpDir) diff --git a/oci/layout/oci_src.go b/oci/layout/oci_src.go index 6b423f3b05..f5f1debc9f 100644 --- a/oci/layout/oci_src.go +++ b/oci/layout/oci_src.go @@ -60,7 +60,7 @@ func newImageSource(sys *types.SystemContext, ref ociReference) (private.ImageSo client := &http.Client{} client.Transport = tr - descriptor, err := ref.getManifestDescriptor() + descriptor, _, err := ref.getManifestDescriptor() if err != nil { return nil, err } diff --git a/oci/layout/oci_transport.go b/oci/layout/oci_transport.go index 4b11964e6f..1e26dc5244 100644 --- a/oci/layout/oci_transport.go +++ b/oci/layout/oci_transport.go @@ -181,35 +181,35 @@ func parseJSON[T any](path string) (*T, error) { return obj, nil } -func (ref ociReference) getManifestDescriptor() (imgspecv1.Descriptor, error) { +func (ref ociReference) getManifestDescriptor() (imgspecv1.Descriptor, int, error) { index, err := ref.getIndex() if err != nil { - return imgspecv1.Descriptor{}, err + return imgspecv1.Descriptor{}, -1, err } if ref.image == "" { // return manifest if only one image is in the oci directory if len(index.Manifests) != 1 { // ask user to choose image when more than one image in the oci directory - return imgspecv1.Descriptor{}, ErrMoreThanOneImage + return imgspecv1.Descriptor{}, -1, ErrMoreThanOneImage } - return index.Manifests[0], nil + return index.Manifests[0], 0, nil } else { // if image specified, look through all manifests for a match var unsupportedMIMETypes []string - for _, md := range index.Manifests { + for i, md := range index.Manifests { if refName, ok := md.Annotations[imgspecv1.AnnotationRefName]; ok && refName == ref.image { if md.MediaType == imgspecv1.MediaTypeImageManifest || md.MediaType == imgspecv1.MediaTypeImageIndex { - return md, nil + return md, i, nil } unsupportedMIMETypes = append(unsupportedMIMETypes, md.MediaType) } } if len(unsupportedMIMETypes) != 0 { - return imgspecv1.Descriptor{}, fmt.Errorf("reference %q matches unsupported manifest MIME types %q", ref.image, unsupportedMIMETypes) + return imgspecv1.Descriptor{}, -1, fmt.Errorf("reference %q matches unsupported manifest MIME types %q", ref.image, unsupportedMIMETypes) } } - return imgspecv1.Descriptor{}, ImageNotFoundError{ref} + return imgspecv1.Descriptor{}, -1, ImageNotFoundError{ref} } // LoadManifestDescriptor loads the manifest descriptor to be used to retrieve the image name @@ -219,7 +219,8 @@ func LoadManifestDescriptor(imgRef types.ImageReference) (imgspecv1.Descriptor, if !ok { return imgspecv1.Descriptor{}, errors.New("error typecasting, need type ociRef") } - return ociRef.getManifestDescriptor() + md, _, err := ociRef.getManifestDescriptor() + return md, err } // NewImageSource returns a types.ImageSource for this reference. diff --git a/oci/layout/oci_transport_test.go b/oci/layout/oci_transport_test.go index ae56a3d004..3595b0d309 100644 --- a/oci/layout/oci_transport_test.go +++ b/oci/layout/oci_transport_test.go @@ -18,9 +18,12 @@ func TestGetManifestDescriptor(t *testing.T) { for _, c := range []struct { dir, image string - expected *imgspecv1.Descriptor // nil if a failure ie expected. errorIs / errorAs allows more specific checks. - errorIs error - errorAs any + expected *struct { + descriptor *imgspecv1.Descriptor + index int + } // nil if a failure ie expected. errorIs / errorAs allows more specific checks. + errorIs error + errorAs any }{ { // Index is missing dir: emptyDir, @@ -30,15 +33,21 @@ func TestGetManifestDescriptor(t *testing.T) { { // A valid reference to the only manifest dir: "fixtures/manifest", image: "", - expected: &imgspecv1.Descriptor{ - MediaType: "application/vnd.oci.image.manifest.v1+json", - Digest: "sha256:84afb6189c4d69f2d040c5f1dc4e0a16fed9b539ce9cfb4ac2526ae4e0576cc0", - Size: 496, - Annotations: map[string]string{"org.opencontainers.image.ref.name": "v0.1.1"}, - Platform: &imgspecv1.Platform{ - Architecture: "amd64", - OS: "linux", + expected: &struct { + descriptor *imgspecv1.Descriptor + index int + }{ + descriptor: &imgspecv1.Descriptor{ + MediaType: "application/vnd.oci.image.manifest.v1+json", + Digest: "sha256:84afb6189c4d69f2d040c5f1dc4e0a16fed9b539ce9cfb4ac2526ae4e0576cc0", + Size: 496, + Annotations: map[string]string{"org.opencontainers.image.ref.name": "v0.1.1"}, + Platform: &imgspecv1.Platform{ + Architecture: "amd64", + OS: "linux", + }, }, + index: 0, }, }, { // An ambiguous reference to a multi-manifest directory @@ -50,21 +59,33 @@ func TestGetManifestDescriptor(t *testing.T) { { // A valid reference in a multi-manifest directory dir: "fixtures/name_lookups", image: "a", - expected: &imgspecv1.Descriptor{ - MediaType: "application/vnd.oci.image.manifest.v1+json", - Digest: "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - Size: 1, - Annotations: map[string]string{"org.opencontainers.image.ref.name": "a"}, + expected: &struct { + descriptor *imgspecv1.Descriptor + index int + }{ + descriptor: &imgspecv1.Descriptor{ + MediaType: "application/vnd.oci.image.manifest.v1+json", + Digest: "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + Size: 1, + Annotations: map[string]string{"org.opencontainers.image.ref.name": "a"}, + }, + index: 0, }, }, { // A valid reference in a multi-manifest directory dir: "fixtures/name_lookups", image: "b", - expected: &imgspecv1.Descriptor{ - MediaType: "application/vnd.oci.image.manifest.v1+json", - Digest: "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", - Size: 2, - Annotations: map[string]string{"org.opencontainers.image.ref.name": "b"}, + expected: &struct { + descriptor *imgspecv1.Descriptor + index int + }{ + descriptor: &imgspecv1.Descriptor{ + MediaType: "application/vnd.oci.image.manifest.v1+json", + Digest: "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + Size: 2, + Annotations: map[string]string{"org.opencontainers.image.ref.name": "b"}, + }, + index: 0, }, }, { // No entry found @@ -82,11 +103,13 @@ func TestGetManifestDescriptor(t *testing.T) { ref, err := NewReference(c.dir, c.image) require.NoError(t, err) - res, err := ref.(ociReference).getManifestDescriptor() + res, i, err := ref.(ociReference).getManifestDescriptor() if c.expected != nil { require.NoError(t, err) - assert.Equal(t, *c.expected, res) + assert.Equal(t, 0, c.expected.index) + assert.Equal(t, *c.expected.descriptor, res) } else { + assert.Equal(t, -1, i) require.Error(t, err) if c.errorIs != nil { assert.ErrorIs(t, err, c.errorIs)