diff --git a/go.mod b/go.mod index 14661cb977..03054a9ff2 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( github.com/opencontainers/image-spec v1.1.0-rc5 github.com/opencontainers/selinux v1.11.0 github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f + github.com/otiai10/copy v1.12.0 github.com/proglottis/gpgme v0.1.3 github.com/secure-systems-lab/go-securesystemslib v0.7.0 github.com/sigstore/fulcio v1.4.2 diff --git a/go.sum b/go.sum index 822a1adf17..6b2091fede 100644 --- a/go.sum +++ b/go.sum @@ -281,6 +281,9 @@ github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f h1:/UDgs8FGMqwnHagNDPGOlts35QkhAZ8by3DR7nMih7M= github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f/go.mod h1:J6OG6YJVEWopen4avK3VNQSnALmmjvniMmni/YFYAwc= +github.com/otiai10/copy v1.12.0 h1:cLMgSQnXBs1eehF0Wy/FAGsgDTDmAqFR7rQylBb1nDY= +github.com/otiai10/copy v1.12.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww= +github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/02ea786cb1ff44d997661886a4186cbd8a1dc466938712bf7281379209476022 b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/02ea786cb1ff44d997661886a4186cbd8a1dc466938712bf7281379209476022 new file mode 100644 index 0000000000..add1797963 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/02ea786cb1ff44d997661886a4186cbd8a1dc466938712bf7281379209476022 @@ -0,0 +1 @@ +insert binary content here #26559 diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/0dc27f36a618c110ae851662c13283e9fbc1b5a5de003befc4bcefa5a05d2eef b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/0dc27f36a618c110ae851662c13283e9fbc1b5a5de003befc4bcefa5a05d2eef new file mode 100644 index 0000000000..b3a7a96cd0 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/0dc27f36a618c110ae851662c13283e9fbc1b5a5de003befc4bcefa5a05d2eef @@ -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:913cf3a39d377faf89ed388ad913a318a390488c9f34c46e43424795cdabffe8", + "size": 585 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:a6f737ac2b84bc463f2ff721af39588c69646c82f79f3808236178e02e35b922", + "size": 33 + } + ] +} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/39c524417bb4228f9fcb0aef43a680b5fd6b9f3a1df2fd50509d047e47dad8be b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/39c524417bb4228f9fcb0aef43a680b5fd6b9f3a1df2fd50509d047e47dad8be new file mode 100644 index 0000000000..8b7c8e3682 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/39c524417bb4228f9fcb0aef43a680b5fd6b9f3a1df2fd50509d047e47dad8be @@ -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:f732172ad8d2a666550fa3ec37a5153d59acc95744562ae64cf62ded46de101a", + "size": 583 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:02ea786cb1ff44d997661886a4186cbd8a1dc466938712bf7281379209476022", + "size": 34 + } + ] +} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/557ac7d133b7770216a8101268640edf4e88beab1b4e1e1bfc9b1891a1cab861 b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/557ac7d133b7770216a8101268640edf4e88beab1b4e1e1bfc9b1891a1cab861 new file mode 100644 index 0000000000..19c1c1276f --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/557ac7d133b7770216a8101268640edf4e88beab1b4e1e1bfc9b1891a1cab861 @@ -0,0 +1 @@ +insert binary content here #9811 diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/5b2aba4d3c27bc6493633d0ec446b25c8d0a5c9cfe99894bcdff0aee80813805 b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/5b2aba4d3c27bc6493633d0ec446b25c8d0a5c9cfe99894bcdff0aee80813805 new file mode 100644 index 0000000000..aba2333ead --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/5b2aba4d3c27bc6493633d0ec446b25c8d0a5c9cfe99894bcdff0aee80813805 @@ -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:df11bc189adeb50dadb3291a3a7f2c34b36e0efdba0df70f2c8a2d761b215cde", + "size": 585 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:986315a0e599fac2b80eb31db2124dab8d3de04d7ca98b254999bd913c1f73fe", + "size": 33 + } + ] +} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/7ffdfe7d276286b39a203dcc247949cf47c91d2d5e10a53a675c0962ed9e4402 b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/7ffdfe7d276286b39a203dcc247949cf47c91d2d5e10a53a675c0962ed9e4402 new file mode 100644 index 0000000000..f21c274635 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/7ffdfe7d276286b39a203dcc247949cf47c91d2d5e10a53a675c0962ed9e4402 @@ -0,0 +1 @@ +{"created":"2023-08-07T19:38:34.915445772Z","architecture":"386","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:53bfdd548f8566a059cd188348b202a50fb9d39ce80eb5b8f0c670dfa9bc6569"]},"history":[{"created":"2023-08-07T19:38:34.803529816Z","created_by":"/bin/sh -c #(nop) ADD file:c06b4f6991638e506d4d0a4d70c4a78ba30b971767802af4c6b837cdf59d4303 in / "},{"created":"2023-08-07T19:38:34.915445772Z","created_by":"/bin/sh -c #(nop) CMD [\"/bin/sh\"]","empty_layer":true}]} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/861d3c014b0e3edcf80e6221247d6b2921a4f892feb9bafe9515b9975b78c44f b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/861d3c014b0e3edcf80e6221247d6b2921a4f892feb9bafe9515b9975b78c44f new file mode 100644 index 0000000000..85617bd7ac --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/861d3c014b0e3edcf80e6221247d6b2921a4f892feb9bafe9515b9975b78c44f @@ -0,0 +1,24 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.index.v1+json", + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:39c524417bb4228f9fcb0aef43a680b5fd6b9f3a1df2fd50509d047e47dad8be", + "size": 525, + "platform": { + "architecture": "amd64", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:be6036f9b6a4e120a04868c47f1b8674f58b2fe5e410cba9f585a13ca8946cf0", + "size": 525, + "platform": { + "architecture": "386", + "os": "linux" + } + } + ] +} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/913cf3a39d377faf89ed388ad913a318a390488c9f34c46e43424795cdabffe8 b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/913cf3a39d377faf89ed388ad913a318a390488c9f34c46e43424795cdabffe8 new file mode 100644 index 0000000000..ebe323d4df --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/913cf3a39d377faf89ed388ad913a318a390488c9f34c46e43424795cdabffe8 @@ -0,0 +1 @@ +{"created":"2023-08-07T19:20:20.894140623Z","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:4693057ce2364720d39e57e85a5b8e0bd9ac3573716237736d6470ec5b7b7230"]},"history":[{"created":"2023-08-07T19:20:20.71894984Z","created_by":"/bin/sh -c #(nop) ADD file:32ff5e7a78b890996ee4681cc0a26185d3e9acdb4eb1e2aaccb2411f922fed6b in / "},{"created":"2023-08-07T19:20:20.894140623Z","created_by":"/bin/sh -c #(nop) CMD [\"/bin/sh\"]","empty_layer":true}]} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/93cbd11a4f41467a0409b975499ae711bc6f8222de38d9f1b5a4097583195ad5 b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/93cbd11a4f41467a0409b975499ae711bc6f8222de38d9f1b5a4097583195ad5 new file mode 100644 index 0000000000..ccf025c98f --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/93cbd11a4f41467a0409b975499ae711bc6f8222de38d9f1b5a4097583195ad5 @@ -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:913cf3a39d377faf89ed388ad913a318a390488c9f34c46e43424795cdabffe8", + "size": 584 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:557ac7d133b7770216a8101268640edf4e88beab1b4e1e1bfc9b1891a1cab861", + "size": 33 + } + ] +} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/986315a0e599fac2b80eb31db2124dab8d3de04d7ca98b254999bd913c1f73fe b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/986315a0e599fac2b80eb31db2124dab8d3de04d7ca98b254999bd913c1f73fe new file mode 100644 index 0000000000..a0cd5aab0e --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/986315a0e599fac2b80eb31db2124dab8d3de04d7ca98b254999bd913c1f73fe @@ -0,0 +1 @@ +insert binary content here #7959 diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/a2f798327b3f25e3eff54badcb769953de235e62e3e32051d57a5e66246de4a1 b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/a2f798327b3f25e3eff54badcb769953de235e62e3e32051d57a5e66246de4a1 new file mode 100644 index 0000000000..aeecdfac4e --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/a2f798327b3f25e3eff54badcb769953de235e62e3e32051d57a5e66246de4a1 @@ -0,0 +1,24 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.index.v1+json", + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:93cbd11a4f41467a0409b975499ae711bc6f8222de38d9f1b5a4097583195ad5", + "size": 525, + "platform": { + "architecture": "amd64", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:f6d60fd529b234d3e28837e15294d935f55da58ce57c4f9218cad38d0be82ce3", + "size": 525, + "platform": { + "architecture": "386", + "os": "linux" + } + } + ] +} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/a6f737ac2b84bc463f2ff721af39588c69646c82f79f3808236178e02e35b922 b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/a6f737ac2b84bc463f2ff721af39588c69646c82f79f3808236178e02e35b922 new file mode 100644 index 0000000000..f26e504a8e --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/a6f737ac2b84bc463f2ff721af39588c69646c82f79f3808236178e02e35b922 @@ -0,0 +1 @@ +insert binary content here #1234 diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/aab808b283c3f654d84358a40ce8766ecd552249305141de88f0ca61f3d1368f b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/aab808b283c3f654d84358a40ce8766ecd552249305141de88f0ca61f3d1368f new file mode 100644 index 0000000000..e1d45d3569 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/aab808b283c3f654d84358a40ce8766ecd552249305141de88f0ca61f3d1368f @@ -0,0 +1 @@ +{"created":"2023-08-07T19:38:27.007952531Z","architecture":"386","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:f05b0759429ba12d5fda46c196f253cc1cab8f56cd874e9e7be674fc1b8337de"]},"history":[{"created":"2023-08-07T19:38:26.69689892Z","created_by":"/bin/sh -c #(nop) ADD file:4b33c52e11b19fde30197c62ead0b77bde28d34edaa08346a5302cd892d3cebe in / "},{"created":"2023-08-07T19:38:27.007952531Z","created_by":"/bin/sh -c #(nop) CMD [\"/bin/sh\"]","empty_layer":true}]} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/be6036f9b6a4e120a04868c47f1b8674f58b2fe5e410cba9f585a13ca8946cf0 b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/be6036f9b6a4e120a04868c47f1b8674f58b2fe5e410cba9f585a13ca8946cf0 new file mode 100644 index 0000000000..c2d027aa76 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/be6036f9b6a4e120a04868c47f1b8674f58b2fe5e410cba9f585a13ca8946cf0 @@ -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:7ffdfe7d276286b39a203dcc247949cf47c91d2d5e10a53a675c0962ed9e4402", + "size": 583 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:e2f7e0374fd6a03d9c373f4d9a0c7802045cc3ddcc1433e89d83b81fa7007242", + "size": 33 + } + ] +} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/df11bc189adeb50dadb3291a3a7f2c34b36e0efdba0df70f2c8a2d761b215cde b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/df11bc189adeb50dadb3291a3a7f2c34b36e0efdba0df70f2c8a2d761b215cde new file mode 100644 index 0000000000..1ff4ad5415 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/df11bc189adeb50dadb3291a3a7f2c34b36e0efdba0df70f2c8a2d761b215cde @@ -0,0 +1 @@ +{"created":"2023-08-07T19:20:26.426857961Z","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:36b50b131297b8860da51b2d2b24bb4c08dfbdf2789b08e3cc0f187c98637a19"]},"history":[{"created":"2023-08-07T19:20:26.326707843Z","created_by":"/bin/sh -c #(nop) ADD file:6dd87346b8be240b21b4f4d9296253bf0d28b6579aa52d2118872e3936963b6b in / "},{"created":"2023-08-07T19:20:26.426857961Z","created_by":"/bin/sh -c #(nop) CMD [\"/bin/sh\"]","empty_layer":true}]} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/e19729d5a968c71b4b691d60f4a6f85f93c303bb88635dcfef36e23b76cb7b3a b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/e19729d5a968c71b4b691d60f4a6f85f93c303bb88635dcfef36e23b76cb7b3a new file mode 100644 index 0000000000..832c1185d8 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/e19729d5a968c71b4b691d60f4a6f85f93c303bb88635dcfef36e23b76cb7b3a @@ -0,0 +1 @@ +insert binary content here #28017 diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/e2f7e0374fd6a03d9c373f4d9a0c7802045cc3ddcc1433e89d83b81fa7007242 b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/e2f7e0374fd6a03d9c373f4d9a0c7802045cc3ddcc1433e89d83b81fa7007242 new file mode 100644 index 0000000000..a18eab8965 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/e2f7e0374fd6a03d9c373f4d9a0c7802045cc3ddcc1433e89d83b81fa7007242 @@ -0,0 +1 @@ +insert binary content here #4794 diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/f6d60fd529b234d3e28837e15294d935f55da58ce57c4f9218cad38d0be82ce3 b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/f6d60fd529b234d3e28837e15294d935f55da58ce57c4f9218cad38d0be82ce3 new file mode 100644 index 0000000000..fb85ad20ac --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/f6d60fd529b234d3e28837e15294d935f55da58ce57c4f9218cad38d0be82ce3 @@ -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:aab808b283c3f654d84358a40ce8766ecd552249305141de88f0ca61f3d1368f", + "size": 582 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:e19729d5a968c71b4b691d60f4a6f85f93c303bb88635dcfef36e23b76cb7b3a", + "size": 34 + } + ] +} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/f732172ad8d2a666550fa3ec37a5153d59acc95744562ae64cf62ded46de101a b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/f732172ad8d2a666550fa3ec37a5153d59acc95744562ae64cf62ded46de101a new file mode 100644 index 0000000000..016b01bc3d --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/blobs/sha256/f732172ad8d2a666550fa3ec37a5153d59acc95744562ae64cf62ded46de101a @@ -0,0 +1 @@ +{"created":"2023-08-07T19:20:31.99661329Z","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:0e182002b05f2ab123995821ef14f1cda765a0c31f7a6d260221558f6466535e"]},"history":[{"created":"2023-08-07T19:20:31.893185238Z","created_by":"/bin/sh -c #(nop) ADD file:76d829bbce3dd420a8419919b0916c0fda917011d1e6752ca5b9e53d5ca890a6 in / "},{"created":"2023-08-07T19:20:31.99661329Z","created_by":"/bin/sh -c #(nop) CMD [\"/bin/sh\"]","empty_layer":true}]} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_multiple_images/index.json b/oci/layout/fixtures/delete_image_multiple_images/index.json new file mode 100644 index 0000000000..d781143f54 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/index.json @@ -0,0 +1,61 @@ +{ + "schemaVersion": 2, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.index.v1+json", + "digest": "sha256:a2f798327b3f25e3eff54badcb769953de235e62e3e32051d57a5e66246de4a1", + "size": 759, + "annotations": { + "org.opencontainers.image.ref.name": "latest" + } + }, + { + "mediaType": "application/vnd.oci.image.index.v1+json", + "digest": "sha256:a2f798327b3f25e3eff54badcb769953de235e62e3e32051d57a5e66246de4a1", + "size": 759, + "annotations": { + "org.opencontainers.image.ref.name": "3.18.3" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:93cbd11a4f41467a0409b975499ae711bc6f8222de38d9f1b5a4097583195ad5", + "size": 525, + "annotations": { + "org.opencontainers.image.ref.name": "3" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:93cbd11a4f41467a0409b975499ae711bc6f8222de38d9f1b5a4097583195ad5", + "size": 525, + "annotations": { + "org.opencontainers.image.ref.name": "3.18" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:5b2aba4d3c27bc6493633d0ec446b25c8d0a5c9cfe99894bcdff0aee80813805", + "size": 525, + "annotations": { + "org.opencontainers.image.ref.name": "3.17.5" + } + }, + { + "mediaType": "application/vnd.oci.image.index.v1+json", + "digest": "sha256:861d3c014b0e3edcf80e6221247d6b2921a4f892feb9bafe9515b9975b78c44f", + "size": 759, + "annotations": { + "org.opencontainers.image.ref.name": "3.16.7" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:0dc27f36a618c110ae851662c13283e9fbc1b5a5de003befc4bcefa5a05d2eef", + "size": 525, + "annotations": { + "org.opencontainers.image.ref.name": "1.0.0" + } + } + ] +} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_multiple_images/info.txt b/oci/layout/fixtures/delete_image_multiple_images/info.txt new file mode 100644 index 0000000000..4ec2b148c9 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/info.txt @@ -0,0 +1,61 @@ +This is tree representation of the fixture to help writing the tests: + +7 references in the index, 10 descriptors and 19 blobs in the blob directory + +index.json +│ +├── 3.17.5 +│ └── manifest: 5b2aba4d3c27bc6493633d0ec446b25c8d0a5c9cfe99894bcdff0aee80813805 +│ config: df11bc189adeb50dadb3291a3a7f2c34b36e0efdba0df70f2c8a2d761b215cde +│ layers: 986315a0e599fac2b80eb31db2124dab8d3de04d7ca98b254999bd913c1f73fe +│ +├── 3.18 +│ └── manifest: 93cbd11a4f41467a0409b975499ae711bc6f8222de38d9f1b5a4097583195ad5 +│ config: 913cf3a39d377faf89ed388ad913a318a390488c9f34c46e43424795cdabffe8 +│ layers: 557ac7d133b7770216a8101268640edf4e88beab1b4e1e1bfc9b1891a1cab861 +│ +├── 3 +│ └── manifest: 93cbd11a4f41467a0409b975499ae711bc6f8222de38d9f1b5a4097583195ad5 +│ config: 913cf3a39d377faf89ed388ad913a318a390488c9f34c46e43424795cdabffe8 +│ layers: 557ac7d133b7770216a8101268640edf4e88beab1b4e1e1bfc9b1891a1cab861 +│ +├── 1.0.0 +│ └── manifest: 0dc27f36a618c110ae851662c13283e9fbc1b5a5de003befc4bcefa5a05d2eef +│ config: 913cf3a39d377faf89ed388ad913a318a390488c9f34c46e43424795cdabffe8 +│ layers: a6f737ac2b84bc463f2ff721af39588c69646c82f79f3808236178e02e35b922 +│ +├── latest +│ └── index: a2f798327b3f25e3eff54badcb769953de235e62e3e32051d57a5e66246de4a1 +│ ├── linux/am64 +│ │ └── manifest: 93cbd11a4f41467a0409b975499ae711bc6f8222de38d9f1b5a4097583195ad5 +│ │ config: 913cf3a39d377faf89ed388ad913a318a390488c9f34c46e43424795cdabffe8 +│ │ layers: 557ac7d133b7770216a8101268640edf4e88beab1b4e1e1bfc9b1891a1cab861 +│ │ +│ └── linux/386 +│ └── manifest: f6d60fd529b234d3e28837e15294d935f55da58ce57c4f9218cad38d0be82ce3 +│ config: aab808b283c3f654d84358a40ce8766ecd552249305141de88f0ca61f3d1368f +│ layers: e19729d5a968c71b4b691d60f4a6f85f93c303bb88635dcfef36e23b76cb7b3a +│ +├── 3.18.3 +│ └── index: a2f798327b3f25e3eff54badcb769953de235e62e3e32051d57a5e66246de4a1 +│ ├── linux/am64 +│ │ └── manifest: 93cbd11a4f41467a0409b975499ae711bc6f8222de38d9f1b5a4097583195ad5 +│ │ config: 913cf3a39d377faf89ed388ad913a318a390488c9f34c46e43424795cdabffe8 +│ │ layers: 557ac7d133b7770216a8101268640edf4e88beab1b4e1e1bfc9b1891a1cab861 +│ │ +│ └── linux/386 +│ └── manifest: f6d60fd529b234d3e28837e15294d935f55da58ce57c4f9218cad38d0be82ce3 +│ config: aab808b283c3f654d84358a40ce8766ecd552249305141de88f0ca61f3d1368f +│ layers: e19729d5a968c71b4b691d60f4a6f85f93c303bb88635dcfef36e23b76cb7b3a +│ +├── 3.16.7 +│ └── index: 861d3c014b0e3edcf80e6221247d6b2921a4f892feb9bafe9515b9975b78c44f +│ ├── linux/am64 +│ │ └── manifest: 39c524417bb4228f9fcb0aef43a680b5fd6b9f3a1df2fd50509d047e47dad8be +│ │ config: f732172ad8d2a666550fa3ec37a5153d59acc95744562ae64cf62ded46de101a +│ │ layers: 02ea786cb1ff44d997661886a4186cbd8a1dc466938712bf7281379209476022 +│ │ +│ └── linux/386 +│ └── manifest: be6036f9b6a4e120a04868c47f1b8674f58b2fe5e410cba9f585a13ca8946cf0 +│ config: 7ffdfe7d276286b39a203dcc247949cf47c91d2d5e10a53a675c0962ed9e4402 +│ layers: e2f7e0374fd6a03d9c373f4d9a0c7802045cc3ddcc1433e89d83b81fa7007242 diff --git a/oci/layout/fixtures/delete_image_multiple_images/oci-layout b/oci/layout/fixtures/delete_image_multiple_images/oci-layout new file mode 100644 index 0000000000..21b1439d1c --- /dev/null +++ b/oci/layout/fixtures/delete_image_multiple_images/oci-layout @@ -0,0 +1 @@ +{"imageLayoutVersion": "1.0.0"} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_only_one_image/blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc b/oci/layout/fixtures/delete_image_only_one_image/blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc new file mode 100644 index 0000000000..e7e64ba41b --- /dev/null +++ b/oci/layout/fixtures/delete_image_only_one_image/blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc @@ -0,0 +1 @@ +insert binary content here #9671 diff --git a/oci/layout/fixtures/delete_image_only_one_image/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 b/oci/layout/fixtures/delete_image_only_one_image/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 new file mode 100644 index 0000000000..f0f06201be --- /dev/null +++ b/oci/layout/fixtures/delete_image_only_one_image/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_only_one_image/blobs/sha256/eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18 b/oci/layout/fixtures/delete_image_only_one_image/blobs/sha256/eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18 new file mode 100644 index 0000000000..1ff195d0f3 --- /dev/null +++ b/oci/layout/fixtures/delete_image_only_one_image/blobs/sha256/eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18 @@ -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": 585 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc", + "size": 33 + } + ] +} diff --git a/oci/layout/fixtures/delete_image_only_one_image/index.json b/oci/layout/fixtures/delete_image_only_one_image/index.json new file mode 100644 index 0000000000..b0a0c98478 --- /dev/null +++ b/oci/layout/fixtures/delete_image_only_one_image/index.json @@ -0,0 +1,13 @@ +{ + "schemaVersion": 2, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18", + "size": 476, + "annotations": { + "org.opencontainers.image.ref.name": "latest" + } + } + ] +} diff --git a/oci/layout/fixtures/delete_image_only_one_image/oci-layout b/oci/layout/fixtures/delete_image_only_one_image/oci-layout new file mode 100644 index 0000000000..21b1439d1c --- /dev/null +++ b/oci/layout/fixtures/delete_image_only_one_image/oci-layout @@ -0,0 +1 @@ +{"imageLayoutVersion": "1.0.0"} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_shared_blobs_dir/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 b/oci/layout/fixtures/delete_image_shared_blobs_dir/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 new file mode 100644 index 0000000000..f0f06201be --- /dev/null +++ b/oci/layout/fixtures/delete_image_shared_blobs_dir/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_shared_blobs_dir/index.json b/oci/layout/fixtures/delete_image_shared_blobs_dir/index.json new file mode 100644 index 0000000000..49925c19ae --- /dev/null +++ b/oci/layout/fixtures/delete_image_shared_blobs_dir/index.json @@ -0,0 +1,13 @@ +{ + "schemaVersion": 2, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18", + "size": 405, + "annotations": { + "org.opencontainers.image.ref.name": "latest" + } + } + ] +} diff --git a/oci/layout/fixtures/delete_image_shared_blobs_dir/oci-layout b/oci/layout/fixtures/delete_image_shared_blobs_dir/oci-layout new file mode 100644 index 0000000000..21b1439d1c --- /dev/null +++ b/oci/layout/fixtures/delete_image_shared_blobs_dir/oci-layout @@ -0,0 +1 @@ +{"imageLayoutVersion": "1.0.0"} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_shared_blobs_dir/shared_blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc b/oci/layout/fixtures/delete_image_shared_blobs_dir/shared_blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc new file mode 100644 index 0000000000..e7e64ba41b --- /dev/null +++ b/oci/layout/fixtures/delete_image_shared_blobs_dir/shared_blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc @@ -0,0 +1 @@ +insert binary content here #9671 diff --git a/oci/layout/fixtures/delete_image_shared_blobs_dir/shared_blobs/sha256/eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18 b/oci/layout/fixtures/delete_image_shared_blobs_dir/shared_blobs/sha256/eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18 new file mode 100644 index 0000000000..1ff195d0f3 --- /dev/null +++ b/oci/layout/fixtures/delete_image_shared_blobs_dir/shared_blobs/sha256/eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18 @@ -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": 585 + }, + "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/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/fixtures/manifest/index.json b/oci/layout/fixtures/manifest/index.json index fd6930cf1c..7e779082ce 100644 --- a/oci/layout/fixtures/manifest/index.json +++ b/oci/layout/fixtures/manifest/index.json @@ -1 +1,17 @@ -{"schemaVersion":2,"manifests":[{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:84afb6189c4d69f2d040c5f1dc4e0a16fed9b539ce9cfb4ac2526ae4e0576cc0","size":496,"annotations":{"org.opencontainers.image.ref.name":"v0.1.1"},"platform":{"architecture":"amd64","os":"linux"}}]} \ No newline at end of file +{ + "schemaVersion": 2, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:84afb6189c4d69f2d040c5f1dc4e0a16fed9b539ce9cfb4ac2526ae4e0576cc0", + "size": 496, + "annotations": { + "org.opencontainers.image.ref.name": "v0.1.1" + }, + "platform": { + "architecture": "amd64", + "os": "linux" + } + } + ] +} \ No newline at end of file diff --git a/oci/layout/oci_delete.go b/oci/layout/oci_delete.go new file mode 100644 index 0000000000..8dd54f255a --- /dev/null +++ b/oci/layout/oci_delete.go @@ -0,0 +1,240 @@ +package layout + +import ( + "context" + "encoding/json" + "fmt" + "io/fs" + "os" + + "github.com/containers/image/v5/internal/set" + "github.com/containers/image/v5/types" + digest "github.com/opencontainers/go-digest" + imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/sirupsen/logrus" + "golang.org/x/exp/slices" +) + +// DeleteImage deletes the named image from the directory, if supported. +func (ref ociReference) DeleteImage(ctx context.Context, sys *types.SystemContext) error { + sharedBlobsDir := "" + if sys != nil && sys.OCISharedBlobDirPath != "" { + sharedBlobsDir = sys.OCISharedBlobDirPath + } + + descriptor, descriptorIndex, err := ref.getManifestDescriptor() + if err != nil { + return err + } + + var blobsUsedByImage map[digest.Digest]int + + switch descriptor.MediaType { + case imgspecv1.MediaTypeImageManifest: + blobsUsedByImage, err = ref.getBlobsUsedInSingleImage(&descriptor, sharedBlobsDir) + case imgspecv1.MediaTypeImageIndex: + blobsUsedByImage, err = ref.getBlobsUsedInImageIndex(&descriptor, sharedBlobsDir) + default: + return fmt.Errorf("unsupported mediaType in index: %q", descriptor.MediaType) + } + if err != nil { + return err + } + + blobsToDelete, err := ref.getBlobsToDelete(blobsUsedByImage, sharedBlobsDir) + if err != nil { + return err + } + + err = ref.deleteBlobs(blobsToDelete) + if err != nil { + return err + } + + return ref.deleteReferenceFromIndex(descriptorIndex) +} + +func (ref ociReference) getBlobsUsedInSingleImage(descriptor *imgspecv1.Descriptor, sharedBlobsDir string) (map[digest.Digest]int, error) { + manifest, err := ref.getManifest(descriptor, sharedBlobsDir) + if err != nil { + return nil, err + } + blobsUsedInManifest := ref.getBlobsUsedInManifest(manifest) + blobsUsedInManifest[descriptor.Digest]++ // Add the current manifest to the list of blobs used by this reference + + return blobsUsedInManifest, nil +} + +func (ref ociReference) getBlobsUsedInImageIndex(descriptor *imgspecv1.Descriptor, sharedBlobsDir string) (map[digest.Digest]int, error) { + blobPath, err := ref.blobPath(descriptor.Digest, sharedBlobsDir) + if err != nil { + return nil, err + } + index, err := parseIndex(blobPath) + if err != nil { + return nil, err + } + + blobsUsedInImageRefIndex := make(map[digest.Digest]int) + err = ref.addBlobsUsedInIndex(blobsUsedInImageRefIndex, index, sharedBlobsDir) + if err != nil { + return nil, err + } + blobsUsedInImageRefIndex[descriptor.Digest]++ // Add the nested index in the list of blobs used by this reference + + return blobsUsedInImageRefIndex, nil +} + +// Updates a map of digest with the usage count, so a blob that is referenced three times will have 3 in the map +func (ref ociReference) addBlobsUsedInIndex(destination map[digest.Digest]int, index *imgspecv1.Index, sharedBlobsDir string) error { + for _, descriptor := range index.Manifests { + destination[descriptor.Digest]++ + switch descriptor.MediaType { + case imgspecv1.MediaTypeImageManifest: + manifest, err := ref.getManifest(&descriptor, sharedBlobsDir) + if err != nil { + return err + } + for digest, count := range ref.getBlobsUsedInManifest(manifest) { + destination[digest] += count + } + case imgspecv1.MediaTypeImageIndex: + blobPath, err := ref.blobPath(descriptor.Digest, sharedBlobsDir) + if err != nil { + return err + } + index, err := parseIndex(blobPath) + if err != nil { + return err + } + err = ref.addBlobsUsedInIndex(destination, index, sharedBlobsDir) + if err != nil { + return err + } + default: + return fmt.Errorf("unsupported mediaType in index: %q", descriptor.MediaType) + } + } + + return nil +} + +func (ref ociReference) getBlobsUsedInManifest(manifest *imgspecv1.Manifest) map[digest.Digest]int { + blobsUsedInManifest := make(map[digest.Digest]int, 0) + + blobsUsedInManifest[manifest.Config.Digest]++ + for _, layer := range manifest.Layers { + blobsUsedInManifest[layer.Digest]++ + } + + return blobsUsedInManifest +} + +// This takes in a map of the digest and their usage count in the manifest to be deleted +// It will compare it to the digest usage in the root index, and return a set of the blobs that can be safely deleted +func (ref ociReference) getBlobsToDelete(blobsUsedByDescriptorToDelete map[digest.Digest]int, sharedBlobsDir string) (*set.Set[digest.Digest], error) { + rootIndex, err := ref.getIndex() + if err != nil { + return nil, err + } + blobsUsedInRootIndex := make(map[digest.Digest]int) + err = ref.addBlobsUsedInIndex(blobsUsedInRootIndex, rootIndex, sharedBlobsDir) + if err != nil { + return nil, err + } + + blobsToDelete := set.New[digest.Digest]() + + for digest, count := range blobsUsedInRootIndex { + if count-blobsUsedByDescriptorToDelete[digest] == 0 { + blobsToDelete.Add(digest) + } + } + + return blobsToDelete, nil +} + +// This transport never generates layouts where blobs for an image are both in the local blobs directory +// and the shared one; it’s either one or the other, depending on how OCISharedBlobDirPath is set. +// +// But we can’t correctly compute use counts for OCISharedBlobDirPath (because we don't know what +// the other layouts sharing that directory are, and we might not even have permission to read them), +// so we can’t really delete any blobs in that case. +// Checking the _local_ blobs directory, and deleting blobs from there, doesn't really hurt, +// in case the layout was created using some other tool or without OCISharedBlobDirPath set, so let's silently +// check for local blobs (but we should make no noise if the blobs are actually in the shared directory). +// +// So, NOTE: the blobPath() call below hard-codes "" even in calls where OCISharedBlobDirPath is set +func (ref ociReference) deleteBlobs(blobsToDelete *set.Set[digest.Digest]) error { + for _, digest := range blobsToDelete.Values() { + blobPath, err := ref.blobPath(digest, "") //Only delete in the local directory, see comment above + if err != nil { + return err + } + err = deleteBlob(blobPath) + if err != nil { + return err + } + } + + return nil +} + +func deleteBlob(blobPath string) error { + logrus.Debug(fmt.Sprintf("Deleting blob at %q", blobPath)) + + err := os.Remove(blobPath) + if err != nil && !os.IsNotExist(err) { + return err + } else { + return nil + } +} + +func (ref ociReference) deleteReferenceFromIndex(referenceIndex int) error { + index, err := ref.getIndex() + if err != nil { + return err + } + + index.Manifests = slices.Delete(index.Manifests, referenceIndex, referenceIndex+1) + + return saveJSON(ref.indexPath(), index) +} + +func saveJSON(path string, content any) error { + // If the file already exists, get its mode to preserve it + var mode fs.FileMode + existingfi, err := os.Stat(path) + if err != nil { + if !os.IsNotExist(err) { + return err + } else { // File does not exist, use default mode + mode = 0644 + } + } else { + mode = existingfi.Mode() + } + + file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode) + if err != nil { + return err + } + defer file.Close() + + return json.NewEncoder(file).Encode(content) +} + +func (ref ociReference) getManifest(descriptor *imgspecv1.Descriptor, sharedBlobsDir string) (*imgspecv1.Manifest, error) { + manifestPath, err := ref.blobPath(descriptor.Digest, sharedBlobsDir) + if err != nil { + return nil, err + } + + manifest, err := parseJSON[imgspecv1.Manifest](manifestPath) + if err != nil { + return nil, err + } + + return manifest, nil +} diff --git a/oci/layout/oci_delete_test.go b/oci/layout/oci_delete_test.go new file mode 100644 index 0000000000..7e06456ffd --- /dev/null +++ b/oci/layout/oci_delete_test.go @@ -0,0 +1,298 @@ +package layout + +import ( + "context" + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/containers/image/v5/types" + digest "github.com/opencontainers/go-digest" + imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" + cp "github.com/otiai10/copy" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestReferenceDeleteImage_onlyOneImage(t *testing.T) { + tmpDir := loadFixture(t, "delete_image_only_one_image") + + ref, err := NewReference(tmpDir, "latest") + require.NoError(t, err) + + err = ref.DeleteImage(context.Background(), nil) + require.NoError(t, err) + + // Check that all blobs were deleted + blobsDir := filepath.Join(tmpDir, "blobs") + files, err := os.ReadDir(filepath.Join(blobsDir, "sha256")) + require.NoError(t, err) + require.Empty(t, files) + + // Check that the index is empty as there is only one image in the fixture + ociRef, ok := ref.(ociReference) + require.True(t, ok) + index, err := ociRef.getIndex() + require.NoError(t, err) + require.Equal(t, 0, len(index.Manifests)) +} + +func TestReferenceDeleteImage_onlyOneImage_emptyImageName(t *testing.T) { + tmpDir := loadFixture(t, "delete_image_only_one_image") + + ref, err := NewReference(tmpDir, "") + require.NoError(t, err) + + err = ref.DeleteImage(context.Background(), nil) + require.NoError(t, err) + + // Check that all blobs were deleted + blobsDir := filepath.Join(tmpDir, "blobs") + files, err := os.ReadDir(filepath.Join(blobsDir, "sha256")) + require.NoError(t, err) + require.Empty(t, files) + + // Check that the index is empty as there is only one image in the fixture + ociRef, ok := ref.(ociReference) + require.True(t, ok) + index, err := ociRef.getIndex() + require.NoError(t, err) + require.Equal(t, 0, len(index.Manifests)) +} + +func TestReferenceDeleteImage_sharedBlobDir(t *testing.T) { + tmpDir := loadFixture(t, "delete_image_shared_blobs_dir") + + ref, err := NewReference(tmpDir, "latest") + require.NoError(t, err) + + sys := &types.SystemContext{OCISharedBlobDirPath: filepath.Join(tmpDir, "shared_blobs")} + err = ref.DeleteImage(context.Background(), sys) + require.NoError(t, err) + + // Check that the only blob in the local directory was deleted + blobsDir := filepath.Join(tmpDir, "blobs") + files, err := os.ReadDir(filepath.Join(blobsDir, "sha256")) + require.NoError(t, err) + require.Empty(t, files) + + // Check that the blobs in the shared blob directory are still present + sharedBlobsDir := filepath.Join(tmpDir, "shared_blobs") + files, err = os.ReadDir(filepath.Join(sharedBlobsDir, "sha256")) + require.NoError(t, err) + require.Equal(t, 2, len(files)) + + // Check that the index is empty as there is only one image in the fixture + ociRef, ok := ref.(ociReference) + require.True(t, ok) + index, err := ociRef.getIndex() + require.NoError(t, err) + require.Equal(t, 0, len(index.Manifests)) +} + +func TestReferenceDeleteImage_multipleImages(t *testing.T) { + tmpDir := loadFixture(t, "delete_image_multiple_images") + + ref, err := NewReference(tmpDir, "3.17.5") + require.NoError(t, err) + + err = ref.DeleteImage(context.Background(), nil) + require.NoError(t, err) + + // 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) + require.Equal(t, 16, len(files)) + assertBlobDoesNotExist(t, blobsDir, "sha256:5b2aba4d3c27bc6493633d0ec446b25c8d0a5c9cfe99894bcdff0aee80813805") + assertBlobDoesNotExist(t, blobsDir, "sha256:df11bc189adeb50dadb3291a3a7f2c34b36e0efdba0df70f2c8a2d761b215cde") + assertBlobDoesNotExist(t, blobsDir, "sha256:986315a0e599fac2b80eb31db2124dab8d3de04d7ca98b254999bd913c1f73fe") + + // 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, 6, len(index.Manifests)) + // .. Check that the image is not in the index anymore + for _, descriptor := range index.Manifests { + switch descriptor.Annotations[imgspecv1.AnnotationRefName] { + case "3.17.5": + assert.Fail(t, "image still present in the index after deletion") + default: + continue + } + } +} + +func TestReferenceDeleteImage_multipleImages_blobsUsedByOtherImages(t *testing.T) { + tmpDir := loadFixture(t, "delete_image_multiple_images") + + 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 + blobsDir := filepath.Join(tmpDir, "blobs") + files, err := os.ReadDir(filepath.Join(blobsDir, "sha256")) + require.NoError(t, err) + require.Equal(t, 17, len(files)) + assertBlobExists(t, blobsDir, "sha256:df11bc189adeb50dadb3291a3a7f2c34b36e0efdba0df70f2c8a2d761b215cde") + assertBlobDoesNotExist(t, blobsDir, "sha256:0dc27f36a618c110ae851662c13283e9fbc1b5a5de003befc4bcefa5a05d2eef") + assertBlobDoesNotExist(t, blobsDir, "sha256:a6f737ac2b84bc463f2ff721af39588c69646c82f79f3808236178e02e35b922") + + // 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, 6, len(index.Manifests)) + // .. Check that the image is not in the index anymore + for _, descriptor := range index.Manifests { + switch descriptor.Annotations[imgspecv1.AnnotationRefName] { + case "1.0.0": + assert.Fail(t, "image still present in the index after deletion") + default: + continue + } + } +} + +func TestReferenceDeleteImage_multipleImages_imageDoesNotExist(t *testing.T) { + tmpDir := loadFixture(t, "delete_image_multiple_images") + + ref, err := NewReference(tmpDir, "does-not-exist") + assert.NoError(t, err) + + err = ref.DeleteImage(context.Background(), nil) + assert.Error(t, err) +} + +func TestReferenceDeleteImage_multipleImages_emptyImageName(t *testing.T) { + tmpDir := loadFixture(t, "delete_image_multiple_images") + + ref, err := NewReference(tmpDir, "") + require.NoError(t, err) + + err = ref.DeleteImage(context.Background(), nil) + require.Error(t, err) +} + +func TestReferenceDeleteImage_multipleImages_nestedIndexImage(t *testing.T) { + tmpDir := loadFixture(t, "delete_image_multiple_images") + + ref, err := NewReference(tmpDir, "3.16.7") + require.NoError(t, err) + + err = ref.DeleteImage(context.Background(), nil) + require.NoError(t, err) + + // 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) + require.Equal(t, 12, len(files)) + assertBlobDoesNotExist(t, blobsDir, "sha256:861d3c014b0e3edcf80e6221247d6b2921a4f892feb9bafe9515b9975b78c44f") + assertBlobDoesNotExist(t, blobsDir, "sha256:39c524417bb4228f9fcb0aef43a680b5fd6b9f3a1df2fd50509d047e47dad8be") + assertBlobDoesNotExist(t, blobsDir, "sha256:f732172ad8d2a666550fa3ec37a5153d59acc95744562ae64cf62ded46de101a") + assertBlobDoesNotExist(t, blobsDir, "sha256:02ea786cb1ff44d997661886a4186cbd8a1dc466938712bf7281379209476022") + assertBlobDoesNotExist(t, blobsDir, "sha256:be6036f9b6a4e120a04868c47f1b8674f58b2fe5e410cba9f585a13ca8946cf0") + assertBlobDoesNotExist(t, blobsDir, "sha256:7ffdfe7d276286b39a203dcc247949cf47c91d2d5e10a53a675c0962ed9e4402") + assertBlobDoesNotExist(t, blobsDir, "sha256:e2f7e0374fd6a03d9c373f4d9a0c7802045cc3ddcc1433e89d83b81fa7007242") + + // 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, 6, len(index.Manifests)) + // .. Check that the image is not in the index anymore + for _, descriptor := range index.Manifests { + switch descriptor.Annotations[imgspecv1.AnnotationRefName] { + case "3.16.7": + assert.Fail(t, "image still present in the index after deletion") + default: + continue + } + } +} + +func TestReferenceDeleteImage_multipleImages_nestedIndexImage_refWithSameContent(t *testing.T) { + tmpDir := loadFixture(t, "delete_image_multiple_images") + + ref, err := NewReference(tmpDir, "3.18.3") + require.NoError(t, err) + + err = ref.DeleteImage(context.Background(), nil) + require.NoError(t, err) + + // 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) + require.Equal(t, 19, len(files)) + + // 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, 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) + require.NoError(t, err) + return tmpDir +} + +func assertBlobExists(t *testing.T, blobsDir string, blobDigest string) { + digest, err := digest.Parse(blobDigest) + require.NoError(t, err) + blobPath := filepath.Join(blobsDir, digest.Algorithm().String(), digest.Hex()) + _, err = os.Stat(blobPath) + require.NoError(t, err) +} + +func assertBlobDoesNotExist(t *testing.T, blobsDir string, blobDigest string) { + digest, err := digest.Parse(blobDigest) + require.NoError(t, err) + blobPath := filepath.Join(blobsDir, digest.Algorithm().String(), digest.Hex()) + _, err = os.Stat(blobPath) + require.True(t, os.IsNotExist(err)) +} 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 dcb836072e..1e26dc5244 100644 --- a/oci/layout/oci_transport.go +++ b/oci/layout/oci_transport.go @@ -160,48 +160,56 @@ func (ref ociReference) NewImage(ctx context.Context, sys *types.SystemContext) // getIndex returns a pointer to the index references by this ociReference. If an error occurs opening an index nil is returned together // with an error. func (ref ociReference) getIndex() (*imgspecv1.Index, error) { - indexJSON, err := os.Open(ref.indexPath()) + return parseIndex(ref.indexPath()) +} + +func parseIndex(path string) (*imgspecv1.Index, error) { + return parseJSON[imgspecv1.Index](path) +} + +func parseJSON[T any](path string) (*T, error) { + content, err := os.Open(path) if err != nil { return nil, err } - defer indexJSON.Close() + defer content.Close() - index := &imgspecv1.Index{} - if err := json.NewDecoder(indexJSON).Decode(index); err != nil { + obj := new(T) + if err := json.NewDecoder(content).Decode(obj); err != nil { return nil, err } - return index, nil + 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 @@ -211,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. @@ -226,11 +235,6 @@ func (ref ociReference) NewImageDestination(ctx context.Context, sys *types.Syst return newImageDestination(sys, ref) } -// DeleteImage deletes the named image from the registry, if supported. -func (ref ociReference) DeleteImage(ctx context.Context, sys *types.SystemContext) error { - return errors.New("Deleting images not implemented for oci: images") -} - // ociLayoutPath returns a path for the oci-layout within a directory using OCI conventions. func (ref ociReference) ociLayoutPath() string { return filepath.Join(ref.dir, imgspecv1.ImageLayoutFile) diff --git a/oci/layout/oci_transport_test.go b/oci/layout/oci_transport_test.go index fd348deb69..8beb52dd19 100644 --- a/oci/layout/oci_transport_test.go +++ b/oci/layout/oci_transport_test.go @@ -17,20 +17,21 @@ func TestGetManifestDescriptor(t *testing.T) { emptyDir := t.TempDir() 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 + dir, image string + expectedDescriptor *imgspecv1.Descriptor // nil if a failure ie expected. errorIs / errorAs allows more specific checks. + expectedIndex int + errorIs error + errorAs any }{ { // Index is missing - dir: emptyDir, - image: "", - expected: nil, + dir: emptyDir, + image: "", + expectedDescriptor: nil, }, { // A valid reference to the only manifest dir: "fixtures/manifest", image: "", - expected: &imgspecv1.Descriptor{ + expectedDescriptor: &imgspecv1.Descriptor{ MediaType: "application/vnd.oci.image.manifest.v1+json", Digest: "sha256:84afb6189c4d69f2d040c5f1dc4e0a16fed9b539ce9cfb4ac2526ae4e0576cc0", Size: 496, @@ -40,52 +41,56 @@ func TestGetManifestDescriptor(t *testing.T) { OS: "linux", }, }, + expectedIndex: 0, }, { // An ambiguous reference to a multi-manifest directory - dir: "fixtures/two_images_manifest", - image: "", - expected: nil, - errorIs: ErrMoreThanOneImage, + dir: "fixtures/two_images_manifest", + image: "", + expectedDescriptor: nil, + errorIs: ErrMoreThanOneImage, }, { // A valid reference in a multi-manifest directory dir: "fixtures/name_lookups", image: "a", - expected: &imgspecv1.Descriptor{ + expectedDescriptor: &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"}, }, + expectedIndex: 0, }, { // A valid reference in a multi-manifest directory dir: "fixtures/name_lookups", image: "b", - expected: &imgspecv1.Descriptor{ + expectedDescriptor: &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"}, }, + expectedIndex: 1, }, { // No entry found - dir: "fixtures/name_lookups", - image: "this-does-not-exist", - expected: nil, - errorAs: &ImageNotFoundError{}, + dir: "fixtures/name_lookups", + image: "this-does-not-exist", + expectedDescriptor: nil, + errorAs: &ImageNotFoundError{}, }, { // Entries with invalid MIME types found - dir: "fixtures/name_lookups", - image: "invalid-mime", - expected: nil, + dir: "fixtures/name_lookups", + image: "invalid-mime", + expectedDescriptor: nil, }, } { ref, err := NewReference(c.dir, c.image) require.NoError(t, err) - res, err := ref.(ociReference).getManifestDescriptor() - if c.expected != nil { + res, i, err := ref.(ociReference).getManifestDescriptor() + if c.expectedDescriptor != nil { require.NoError(t, err) - assert.Equal(t, *c.expected, res) + assert.Equal(t, c.expectedIndex, i) + assert.Equal(t, *c.expectedDescriptor, res) } else { require.Error(t, err) if c.errorIs != nil { @@ -319,12 +324,6 @@ func TestReferenceNewImageDestination(t *testing.T) { defer dest.Close() } -func TestReferenceDeleteImage(t *testing.T) { - ref, _ := refToTempOCI(t) - err := ref.DeleteImage(context.Background(), nil) - assert.Error(t, err) -} - func TestReferenceOCILayoutPath(t *testing.T) { ref, tmpDir := refToTempOCI(t) ociRef, ok := ref.(ociReference)