From 57acf0cf253450e94b0056bd0fff0ee2657f3937 Mon Sep 17 00:00:00 2001 From: David Trudgian Date: Thu, 23 Jan 2025 11:08:10 +0000 Subject: [PATCH] feat: support cosign signatures in OCI-SIF files Add support for cosign signatures / attestations associated with images and indexes within OCI-SIF files. **Storage within the OCI-SIF** A cosign signature or attestation is an OCI image. It is associated with the image or index it targets using a tag based approach. The signature or attestation has a tag indicating the digest of its target. Within an OCI-SIF file, we will store cosign signatures and annotations so that they have a `org.opencontainers.image.ref.name` annotation in the root index, where the `ref.name` is a placeholder `_cosign` repository followed by the standard cosign tag, e.g.: _cosign:sha256-432f982638b3aefab73cc58ab28f5c16e96fdb504e8c134fc58dff4bae8bf338.sig **SourceSink** The cosign module defines `SignedImage` and `SignedImageIndex` types, which wrap the standard ggcr image / index types. Because signatures / attestations are seperate images, associated with their target by tag, a `SignedImage` or`SignedImageIndex` needs to be able to access blobs outside of the scope of the wrapped image or index, to 'see' the signatures / attestations. This PR introduces a SIF `SourceSink`, which is both a `Source` and a `Sink`. A Source implements `Get()` to return a `Descriptor` that can provide an Image or an Index, depending on the content of the layout and the options that Get() was called with. A `Descriptor` can be upgraded to a `SignedDescriptor`, which provides access to raw cosign signature/attestation images, as well as `cosign.SignedImage/SignedImageIndex` types. A Sink implements `Write()`, accepting a Writable which is either a v1.Image or v1.Index. Options allow the image or index to have a `name.ref` annotation set in the root index when it is written. Note that at this point, cosign signature / attestation images must be explicilty written into the SIF. `Write` does not automatically write associated signatures / attestations if passed a `SignedImage` / `SignedImageIndex`. --- go.mod | 59 ++- go.sum | 169 +++++-- pkg/sourcesink/cosign.go | 77 ++++ pkg/sourcesink/cosign_sif.go | 278 ++++++++++++ pkg/sourcesink/cosign_sif_test.go | 214 +++++++++ pkg/sourcesink/sif.go | 425 ++++++++++++++++++ pkg/sourcesink/sif_test.go | 377 ++++++++++++++++ pkg/sourcesink/sink.go | 42 ++ pkg/sourcesink/source.go | 92 ++++ pkg/sourcesink/sourcesink.go | 34 ++ .../testdata/TestSIFBlob/ImageConfig.golden | 1 + .../testdata/TestSIFBlob/ImageLayer.golden | Bin 0 -> 3208 bytes .../testdata/TestSIFGet/ImageDefaults.golden | 16 + .../testdata/TestSIFGet/ImageDigest.golden | 16 + .../testdata/TestSIFGet/ImagePlatform.golden | 16 + .../testdata/TestSIFGet/IndexDefaults.golden | 1 + .../testdata/TestSIFGet/IndexDigest.golden | 1 + .../testdata/TestSIFGet/IndexPlatform.golden | 16 + .../TestSIFWrite/ImageDefaults.golden | Bin 0 -> 12489 bytes .../TestSIFWrite/ImageWithReference.golden | Bin 0 -> 12552 bytes .../TestSIFWrite/IndexDefaults.golden | Bin 0 -> 73116 bytes .../TestSIFWrite/IndexWithReference.golden | Bin 0 -> 73179 bytes ...7680938f8dcbe55e51fbf08032cf37326a677f92ed | 1 + ...1a36d9e6db7d66a9c1d1bf134053d5c4c978b3376d | 1 + ...a36cdf9dd99b8b0c338075000f555d5adf8e9c0547 | Bin 0 -> 2993 bytes ...77fa12d08de36239e713c704fa0151abffb1bb0126 | 1 + ...bdadd9ee552e8c9b35d60e8f1247bd9ee0260313e1 | 1 + ...0435194b1ae66c861c2aca8a7692e752e9acfaa696 | 1 + ...ad50659133315b485ac68647119775b37578eaf629 | 1 + ...0aa0cbe380ccf2b16a23a00543dd69bd8fb1dc4fae | 1 + ...571494bb844e424bb48c2eceefed73434eb9a84dc3 | 1 + ...7bcbf64eb980e26fffd716e3f3205ed4a7e17e6493 | 1 + ...efde1b59cacc61d3e491c8473c2b0a4f15b4d2fdcb | 1 + ...694094b9b4338aa9ee5c40b930cb8063a1be392c54 | Bin 0 -> 2479 bytes ...279255455bf3f61f2a95fcd17427eb858953422620 | 1 + ...af7757d078bf92e55a3ea29c5fdef5c785bcef09c4 | 16 + ...9cfb0e9322acb1a48c318620b89c9ae5e233d416b7 | 1 + ...8cabc0aae667d47d8f25ed51cbe66e148e3a77e19c | 1 + ...a75356395f2695a7abad34f010656740e90ddce399 | Bin 0 -> 3000 bytes ...747ab3f97844eeca509df705db44a736df863b76af | 16 + ...e99c144d94d1afe3fd201368777ef2ce29750f5738 | 1 + ...8ab28f5c16e96fdb504e8c134fc58dff4bae8bf338 | 16 + ...244c4d5d160f6708b4ee8731cda05ccd52b0fdac7b | 1 + ...14d75725f6de3bb5c63e266e236e04389820a234c4 | 1 + ...cd6e561597e7b358abfdbf58167d6a8f2fcd035c0a | 1 + ...deca4d5764fa4db05592a7a9a641e4ac37cc619ba1 | 1 + ...d92eab0451cf7ceece9cfe3650e4d4844243b2b24d | Bin 0 -> 3929 bytes ...8acb44ab0ec116b28edd090a54db3e9d3071749b6a | 1 + ...9483e9310f087c8f93d8d85d82be6883321b72f60b | 1 + ...1c686e7c69ee612961db34c8b90da079e5473be83b | 16 + ...39a0a7ab8152cc0c93a415d0746cd8aa9ba9bd9510 | Bin 0 -> 3682 bytes ...3f138b327cf641e4d537fc9bc453f52b46f19ec3ff | 1 + ...5eff915842962cb813f32062d3bbdd35c750dd7d01 | Bin 0 -> 3208 bytes ...2da105b1dac81a75b47a869602096c27b6a75a525c | 1 + ...c658be0b98e790b14527d831414cc5d13bd68c0259 | 1 + ...54d8fb0c6bd6e104d6e01b98adfebc1235173b94ec | 1 + ...2b5914b5ec642133c0fb884539045de33fbcd2eadb | Bin 0 -> 2736 bytes ...f4e1c60605cfe75000be6e7c2e1455490414829767 | 1 + ...f5dae3b03673cfea2d83b4c4582af8e47904d717fa | 1 + ...8302f36c0a9f8133d36325d859a3023a97eff16879 | 1 + ...5e8fea684ea95e4de11b6893ea50201bd6c8dfc3c3 | 1 + ...2a8dfab33089ccb778686ed6ce0c4e666d348402a9 | 1 + ...d3fbe594fce7996234b259f27eac9428b84050c849 | 16 + ...aa77a59298a62a9e9fbb4b77f36c189774ec9b1089 | 16 + ...6d274ebf2925db16611d707465beb0fb4032f73048 | 1 + ...e176a92b4dc339add792996d06c83a53bea6898bbb | 1 + ...cc5c259dd9babb40a9df152e88b286fada1d3248bd | Bin 0 -> 3276 bytes ...29bee36603c0df0bc34798eed5067f6e1335a9d391 | 1 + ...829b1cb96b55a1ce7060e4bdc57ac196d93b2dee63 | 1 + ...0b3f65189ffbe354cf8ae97e7a55d588e855097174 | Bin 0 -> 4092 bytes ...99ae53cf38992f33e084dd97b132957c5101e643ec | 1 + ...660d95fb54d69bbd531de724c7ce6fc9f743c0b861 | 16 + ...09a66c9673d6e4aea18e2d387d9c5fda634415dfc9 | 1 + ...e2d1c9bbacb506091f42a3b0fe77a209006f409fd8 | 1 + ...22c4502dd8674c6fe0f904ca02509c2fdf24e137e4 | 1 + ...f392c4e1296a53b0fb4780d8b0382f7996a15d5392 | 16 + ...81fc8ce7a3e8b28f9580a4cf1ea738c5525f0977f1 | 1 + ...6ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4 | 16 + ...d851dcf98581f35d46c64aa049558a04dc5e4401fe | 1 + ...5d78c358ae2816b527092acb225c31d08c88fba58b | 1 + ...6087565b3433a7447f3eff39b96cdbbcbb568db94b | 1 + ...52af8e1f701795c3862e3760d4421f468b2f0e082a | 1 + ...e879d862b825965ba48de054caab5ef356dc6b3412 | 1 + .../index.json | 1 + .../oci-layout | 3 + ...8ab28f5c16e96fdb504e8c134fc58dff4bae8bf338 | 16 + ...14d75725f6de3bb5c63e266e236e04389820a234c4 | 1 + ...65c2398591df2288eacbe411bc97a9e39ef104b99a | 1 + ...5eff915842962cb813f32062d3bbdd35c750dd7d01 | Bin 0 -> 3208 bytes ...a06c67d69d1efb2ce06bd3a76ef2d06aeefd861d58 | 1 + ...0ee52f1a11c07fcc9f70796b2bc7cc939e9b9c65ea | 1 + ...d763e00380ea89957b527694c98327fc1a96bf9464 | 1 + ...d1c5a0bb784568249aa9c64b57c75055c548e58281 | 1 + ...c34e82be58a63da388204d93f948710c74a9730682 | 1 + .../hello-world-cosign-manifest/index.json | 1 + .../hello-world-cosign-manifest/oci-layout | 3 + 96 files changed, 2017 insertions(+), 35 deletions(-) create mode 100644 pkg/sourcesink/cosign.go create mode 100644 pkg/sourcesink/cosign_sif.go create mode 100644 pkg/sourcesink/cosign_sif_test.go create mode 100644 pkg/sourcesink/sif.go create mode 100644 pkg/sourcesink/sif_test.go create mode 100644 pkg/sourcesink/sink.go create mode 100644 pkg/sourcesink/source.go create mode 100644 pkg/sourcesink/sourcesink.go create mode 100644 pkg/sourcesink/testdata/TestSIFBlob/ImageConfig.golden create mode 100644 pkg/sourcesink/testdata/TestSIFBlob/ImageLayer.golden create mode 100644 pkg/sourcesink/testdata/TestSIFGet/ImageDefaults.golden create mode 100644 pkg/sourcesink/testdata/TestSIFGet/ImageDigest.golden create mode 100644 pkg/sourcesink/testdata/TestSIFGet/ImagePlatform.golden create mode 100644 pkg/sourcesink/testdata/TestSIFGet/IndexDefaults.golden create mode 100644 pkg/sourcesink/testdata/TestSIFGet/IndexDigest.golden create mode 100644 pkg/sourcesink/testdata/TestSIFGet/IndexPlatform.golden create mode 100644 pkg/sourcesink/testdata/TestSIFWrite/ImageDefaults.golden create mode 100644 pkg/sourcesink/testdata/TestSIFWrite/ImageWithReference.golden create mode 100644 pkg/sourcesink/testdata/TestSIFWrite/IndexDefaults.golden create mode 100644 pkg/sourcesink/testdata/TestSIFWrite/IndexWithReference.golden create mode 100755 test/images/hello-world-cosign-manifest-list/blobs/sha256/00e1ee7c898a2c393ea2fe7680938f8dcbe55e51fbf08032cf37326a677f92ed create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/02623e64de6f2252401a401a36d9e6db7d66a9c1d1bf134053d5c4c978b3376d create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/04341b189be695acecd201a36cdf9dd99b8b0c338075000f555d5adf8e9c0547 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/0473adddc4b4a6b8456d5077fa12d08de36239e713c704fa0151abffb1bb0126 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/04d584bf278d95c3bdf6aebdadd9ee552e8c9b35d60e8f1247bd9ee0260313e1 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/155c39610faa3bae95d5bd0435194b1ae66c861c2aca8a7692e752e9acfaa696 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/165760e771f0d295a89c06ad50659133315b485ac68647119775b37578eaf629 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/16692a792468762200c57d0aa0cbe380ccf2b16a23a00543dd69bd8fb1dc4fae create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/1e4c6e59fe9ed668252140571494bb844e424bb48c2eceefed73434eb9a84dc3 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/29a03bf1904f1d59ec50227bcbf64eb980e26fffd716e3f3205ed4a7e17e6493 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/2a16e122fe466459770f0defde1b59cacc61d3e491c8473c2b0a4f15b4d2fdcb create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/2db29710123e3e53a794f2694094b9b4338aa9ee5c40b930cb8063a1be392c54 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/3154f2b2183d33ec662331279255455bf3f61f2a95fcd17427eb858953422620 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/3209b9aec056b296ea55b2af7757d078bf92e55a3ea29c5fdef5c785bcef09c4 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/3374ed2b382445f1a06cf49cfb0e9322acb1a48c318620b89c9ae5e233d416b7 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/36d89aa75357c8f99e359f8cabc0aae667d47d8f25ed51cbe66e148e3a77e19c create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/3caa6dc69d0b73f21d29bfa75356395f2695a7abad34f010656740e90ddce399 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/40d0cfd0861719208ff9f7747ab3f97844eeca509df705db44a736df863b76af create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/40ddc5646e05a17eeb7caae99c144d94d1afe3fd201368777ef2ce29750f5738 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/432f982638b3aefab73cc58ab28f5c16e96fdb504e8c134fc58dff4bae8bf338 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/45ea150db157113f1e2946244c4d5d160f6708b4ee8731cda05ccd52b0fdac7b create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/46331d942d6350436f64e614d75725f6de3bb5c63e266e236e04389820a234c4 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/4f923680062bbea891b21ccd6e561597e7b358abfdbf58167d6a8f2fcd035c0a create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/5004e9d559e7a75f42249ddeca4d5764fa4db05592a7a9a641e4ac37cc619ba1 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/54971af28fe60a8c72e395d92eab0451cf7ceece9cfe3650e4d4844243b2b24d create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/60ff2fae9751401b312ee38acb44ab0ec116b28edd090a54db3e9d3071749b6a create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/61941acdb959d25d7ad28f9483e9310f087c8f93d8d85d82be6883321b72f60b create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/6253ef1af25aabd67777a01c686e7c69ee612961db34c8b90da079e5473be83b create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/64e3c106413894c80284b439a0a7ab8152cc0c93a415d0746cd8aa9ba9bd9510 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/6569af6e782a5c31546c763f138b327cf641e4d537fc9bc453f52b46f19ec3ff create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/7050e35b49f5e348c4809f5eff915842962cb813f32062d3bbdd35c750dd7d01 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/7066d68bd2f224dbb7c3332da105b1dac81a75b47a869602096c27b6a75a525c create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/72d7b2a56244ff17b6ce61c658be0b98e790b14527d831414cc5d13bd68c0259 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/781ea9e9358a3d6307205054d8fb0c6bd6e104d6e01b98adfebc1235173b94ec create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/7f0d4fad461d1ac69488092b5914b5ec642133c0fb884539045de33fbcd2eadb create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/897d8fbdf18b7e2eec4a53f4e1c60605cfe75000be6e7c2e1455490414829767 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/89815ad2fbca952d269f07f5dae3b03673cfea2d83b4c4582af8e47904d717fa create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/8ff188302c77050dcb64e08302f36c0a9f8133d36325d859a3023a97eff16879 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/958d0aa20c81ae813ef2ab5e8fea684ea95e4de11b6893ea50201bd6c8dfc3c3 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/97576b63fdca9f120886ae2a8dfab33089ccb778686ed6ce0c4e666d348402a9 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/98c9722322be649df94780d3fbe594fce7996234b259f27eac9428b84050c849 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/995efde2e81b21d1ea7066aa77a59298a62a9e9fbb4b77f36c189774ec9b1089 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/9a8c4a3156d3d8662e57276d274ebf2925db16611d707465beb0fb4032f73048 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/a2d16425ea631d6254d948e176a92b4dc339add792996d06c83a53bea6898bbb create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/abc70fcc95b2f52b325d69cc5c259dd9babb40a9df152e88b286fada1d3248bd create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/b3593dab05491cdf5ee88c29bee36603c0df0bc34798eed5067f6e1335a9d391 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/b61d5036614f79e5610341829b1cb96b55a1ce7060e4bdc57ac196d93b2dee63 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/bbc6052697e5fdcd1b311e0b3f65189ffbe354cf8ae97e7a55d588e855097174 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/bf4cb7b5c44789f31a104b99ae53cf38992f33e084dd97b132957c5101e643ec create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/c7b6944911848ce39b44ed660d95fb54d69bbd531de724c7ce6fc9f743c0b861 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/dc285da8291208f50dced509a66c9673d6e4aea18e2d387d9c5fda634415dfc9 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/df5477cea5582b0ae6a31de2d1c9bbacb506091f42a3b0fe77a209006f409fd8 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/e58c180ca4d73dc4b0a65122c4502dd8674c6fe0f904ca02509c2fdf24e137e4 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/eb11b1a194ff8e236a01eff392c4e1296a53b0fb4780d8b0382f7996a15d5392 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/f30a18a9413fc29432347c81fc8ce7a3e8b28f9580a4cf1ea738c5525f0977f1 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4 create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/f85bca573013bd8d0ecb52d851dcf98581f35d46c64aa049558a04dc5e4401fe create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/fa552c1bfe5aa7859652795d78c358ae2816b527092acb225c31d08c88fba58b create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/fa9dfc3e3e2a35077691b46087565b3433a7447f3eff39b96cdbbcbb568db94b create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/fe0a7ee955986c6c86f05e52af8e1f701795c3862e3760d4421f468b2f0e082a create mode 100644 test/images/hello-world-cosign-manifest-list/blobs/sha256/feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412 create mode 100755 test/images/hello-world-cosign-manifest-list/index.json create mode 100755 test/images/hello-world-cosign-manifest-list/oci-layout create mode 100644 test/images/hello-world-cosign-manifest/blobs/sha256/432f982638b3aefab73cc58ab28f5c16e96fdb504e8c134fc58dff4bae8bf338 create mode 100644 test/images/hello-world-cosign-manifest/blobs/sha256/46331d942d6350436f64e614d75725f6de3bb5c63e266e236e04389820a234c4 create mode 100644 test/images/hello-world-cosign-manifest/blobs/sha256/51a5ebe9c08828b74e4c6b65c2398591df2288eacbe411bc97a9e39ef104b99a create mode 100644 test/images/hello-world-cosign-manifest/blobs/sha256/7050e35b49f5e348c4809f5eff915842962cb813f32062d3bbdd35c750dd7d01 create mode 100644 test/images/hello-world-cosign-manifest/blobs/sha256/8fa40880617d755574fbb0a06c67d69d1efb2ce06bd3a76ef2d06aeefd861d58 create mode 100644 test/images/hello-world-cosign-manifest/blobs/sha256/a6ad4f8c0122fd2eb192cb0ee52f1a11c07fcc9f70796b2bc7cc939e9b9c65ea create mode 100644 test/images/hello-world-cosign-manifest/blobs/sha256/bbfb5811b9c372086df099d763e00380ea89957b527694c98327fc1a96bf9464 create mode 100644 test/images/hello-world-cosign-manifest/blobs/sha256/e2138afe1d1bb80dd0348ed1c5a0bb784568249aa9c64b57c75055c548e58281 create mode 100644 test/images/hello-world-cosign-manifest/blobs/sha256/f764ee0fbe0e49555602e3c34e82be58a63da388204d93f948710c74a9730682 create mode 100755 test/images/hello-world-cosign-manifest/index.json create mode 100755 test/images/hello-world-cosign-manifest/oci-layout diff --git a/go.mod b/go.mod index aa333dc..6e16557 100644 --- a/go.mod +++ b/go.mod @@ -1,31 +1,74 @@ module github.com/sylabs/oci-tools -go 1.22.0 +go 1.22.7 require ( github.com/containerd/platforms v0.2.1 github.com/google/go-containerregistry v0.20.2 github.com/opencontainers/image-spec v1.1.0 github.com/sebdah/goldie/v2 v2.5.5 + github.com/sigstore/cosign/v2 v2.4.1 github.com/sylabs/sif/v2 v2.20.2 ) require ( + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/blang/semver v3.5.1+incompatible // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect + github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 // indirect github.com/docker/cli v27.1.1+incompatible // indirect - github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/docker-credential-helpers v0.7.0 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/docker/distribution v2.8.3+incompatible // indirect + github.com/docker/docker-credential-helpers v0.8.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/go-chi/chi v4.1.2+incompatible // indirect + github.com/go-jose/go-jose/v4 v4.0.4 // indirect + github.com/go-openapi/analysis v0.23.0 // indirect + github.com/go-openapi/errors v0.22.0 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/loads v0.22.0 // indirect + github.com/go-openapi/runtime v0.28.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/strfmt v0.23.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/validate v0.24.0 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.16.5 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/sassoftware/relic v7.2.1+incompatible // indirect + github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect github.com/sergi/go-diff v1.2.0 // indirect + github.com/sigstore/protobuf-specs v0.3.2 // indirect + github.com/sigstore/rekor v1.3.6 // indirect + github.com/sigstore/sigstore v1.8.11 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/vbatts/tar-split v0.11.3 // indirect - golang.org/x/sync v0.2.0 // indirect + github.com/spf13/cobra v1.8.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/theupdateframework/go-tuf v0.7.0 // indirect + github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect + github.com/vbatts/tar-split v0.11.5 // indirect + go.mongodb.org/mongo-driver v1.14.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect + golang.org/x/mod v0.20.0 // indirect + golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.28.0 // indirect + golang.org/x/term v0.27.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 3185894..de5a18d 100644 --- a/go.sum +++ b/go.sum @@ -1,33 +1,95 @@ -github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 h1:2Dx4IHfC1yHWI12AxQDJM1QbRCDfk6M+blLzlZCXdrc= +github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2oNn0GkeZE= github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= -github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= -github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= +github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8= +github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= +github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= +github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= +github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= +github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= +github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= +github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= +github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= +github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= +github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ= +github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= +github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= +github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= +github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= +github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.20.2 h1:B1wPJ1SN/S7pB+ZAimcciVD+r+yV/l/DSArMxlbwseo= github.com/google/go-containerregistry v0.20.2/go.mod h1:z38EKdKh4h7IP2gSfUUqEvalZBqs6AoLeWfUy34nQC8= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= -github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY= +github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E= +github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs= +github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec h1:2tTW6cDth2TSgRbAhD7yjZzTQmcN25sDRPEeinR51yQ= +github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec/go.mod h1:TmwEoGCwIti7BCeJ9hescZgRtatxRE+A72pCoPfmcfk= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -35,44 +97,97 @@ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2sz github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg= +github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGqpgjJU3DYAZeI05A= +github.com/sassoftware/relic v7.2.1+incompatible/go.mod h1:CWfAxv73/iLZ17rbyhIEq3K9hs5w6FpNMdUT//qR+zk= github.com/sebdah/goldie/v2 v2.5.5 h1:rx1mwF95RxZ3/83sdS4Yp7t2C5TCokvWP4TBRbAyEWY= github.com/sebdah/goldie/v2 v2.5.5/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= +github.com/secure-systems-lab/go-securesystemslib v0.8.0 h1:mr5An6X45Kb2nddcFlbmfHkLguCE9laoZCUzEEpIZXA= +github.com/secure-systems-lab/go-securesystemslib v0.8.0/go.mod h1:UH2VZVuJfCYR8WgMlCU1uFsOUU+KeyrTWcSS73NBOzU= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sigstore/cosign/v2 v2.4.1 h1:b8UXEfJFks3hmTwyxrRNrn6racpmccUycBHxDMkEPvU= +github.com/sigstore/cosign/v2 v2.4.1/go.mod h1:GvzjBeUKigI+XYnsoVQDmMAsMMc6engxztRSuxE+x9I= +github.com/sigstore/protobuf-specs v0.3.2 h1:nCVARCN+fHjlNCk3ThNXwrZRqIommIeNKWwQvORuRQo= +github.com/sigstore/protobuf-specs v0.3.2/go.mod h1:RZ0uOdJR4OB3tLQeAyWoJFbNCBFrPQdcokntde4zRBA= +github.com/sigstore/rekor v1.3.6 h1:QvpMMJVWAp69a3CHzdrLelqEqpTM3ByQRt5B5Kspbi8= +github.com/sigstore/rekor v1.3.6/go.mod h1:JDTSNNMdQ/PxdsS49DJkJ+pRJCO/83nbR5p3aZQteXc= +github.com/sigstore/sigstore v1.8.11 h1:tEqeQqbT+awtM87ec9KEeSUxT/AFvJNawneYJyAkFrQ= +github.com/sigstore/sigstore v1.8.11/go.mod h1:fdrFQosxCQ4wTL5H1NrZcQkqQ72AQbPjtpcL2QOGKV0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/sylabs/sif/v2 v2.20.2 h1:HGEPzauCHhIosw5o6xmT3jczuKEuaFzSfdjAsH33vYw= github.com/sylabs/sif/v2 v2.20.2/go.mod h1:WyYryGRaR4Wp21SAymm5pK0p45qzZCSRiZMFvUZiuhc= -github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= -github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck= -github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI= +github.com/theupdateframework/go-tuf v0.7.0/go.mod h1:uEB7WSY+7ZIugK6R1hiBMBjQftaFzn7ZCDJcp1tCUug= +github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= +github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= +github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= +github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk= +go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= +go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= +golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 h1:BulPr26Jqjnd4eYDVe+YvyR7Yc2vJGkO5/0UxD0/jZU= +google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1:3RgNmBoI9MZhsj3QxC+AP/qQhNwpCLOvYDYYsFrhFt0= +google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= +google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/sourcesink/cosign.go b/pkg/sourcesink/cosign.go new file mode 100644 index 0000000..daef654 --- /dev/null +++ b/pkg/sourcesink/cosign.go @@ -0,0 +1,77 @@ +// Copyright 2024-2025 Sylabs Inc. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 + +package sourcesink + +import ( + "context" + "fmt" + + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + cosignoci "github.com/sigstore/cosign/v2/pkg/oci" + cosignremote "github.com/sigstore/cosign/v2/pkg/oci/remote" +) + +// SignedDescriptor provides access to cosign signatures stored against it. +type SignedDescriptor interface { + // CosignImages checks for image manifests providing cosign signatures & + // attestations that are associated with the image or index with the descriptor + // If image manifests providing cosign signatures and / or attestations + // exist, then these images are returned in a name.Reference -> v1.Image map. + // + // If recursive is true, then if the descriptor is an index, we also check for + // signatures and attestations for each of its associated manifests. + // + // In the returned map, the images are referenced as '_cosign:', where + // matches the tag at src. The '_cosign' repository placeholder string + // is used instead of any original registry & repository names. + CosignImages(ctx context.Context, recursive bool) ([]ReferencedImage, error) + // SignedImage wraps an image Descriptor as a cosign oci.SignedImage, + // allowing access to signatures and attestations stored alongside the image. + SignedImage(context.Context) (cosignoci.SignedImage, error) + // SignedImageIndex wraps an image index Descriptor as a cosign oci.SignedImageIndex, + // allowing access to signatures and attestations stored alongside the image. + SignedImageIndex(context.Context) (cosignoci.SignedImageIndex, error) +} + +// CosignPlaceholderRepo is a placeholder repository name for cosign images. +const CosignPlaceholderRepo = "_cosign" + +type ReferencedImage struct { + Ref name.Reference + Img v1.Image +} + +func NumDescriptorsForCosign(imgs []ReferencedImage) (int64, error) { + descCount := int64(0) + for _, ri := range imgs { + ls, err := ri.Img.Layers() + if err != nil { + return 0, err + } + descCount += int64(len(ls) + 2) + } + return descCount, nil +} + +//nolint:gochecknoglobals +var cosignSuffixes = []string{ + cosignremote.SignatureTagSuffix, + cosignremote.AttestationTagSuffix, +} + +func CosignTag(h v1.Hash, suffix string) string { + return fmt.Sprint(h.Algorithm, "-", h.Hex, ".", suffix) +} + +func CosignRef(imgDigest v1.Hash, imgRef name.Reference, suffix string, opts ...name.Option) (name.Reference, error) { + t := CosignTag(imgDigest, suffix) + repo := CosignPlaceholderRepo + if imgRef != nil { + repo = imgRef.Context().Name() + } + opts = append(opts, name.WithDefaultRegistry("")) + return name.ParseReference(repo+":"+t, opts...) +} diff --git a/pkg/sourcesink/cosign_sif.go b/pkg/sourcesink/cosign_sif.go new file mode 100644 index 0000000..0ba39a0 --- /dev/null +++ b/pkg/sourcesink/cosign_sif.go @@ -0,0 +1,278 @@ +// Copyright 2024-2025 Sylabs Inc. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 + +package sourcesink + +import ( + "bytes" + "context" + "errors" + "log/slog" + + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/match" + "github.com/google/go-containerregistry/pkg/v1/partial" + cosignoci "github.com/sigstore/cosign/v2/pkg/oci" + cosignempty "github.com/sigstore/cosign/v2/pkg/oci/empty" + cosignremote "github.com/sigstore/cosign/v2/pkg/oci/remote" + cosignsignature "github.com/sigstore/cosign/v2/pkg/oci/signature" + "github.com/sylabs/oci-tools/pkg/sif" +) + +var _ SignedDescriptor = &sifDescriptor{} + +// CosignImages checks for image manifests providing cosign signatures & +// attestations that are associated with the image or index with the descriptor +// If image manifests providing cosign signatures and / or attestations +// exist, then these images are returned in a name.Reference -> v1.Image map. +// +// If recursive is true, then if the descriptor is an index, we also check for +// signatures and attestations for each of its associated manifests. +// +// In the returned map, the images are referenced as '_cosign:', where +// matches the tag at src. The '_cosign' repository placeholder string +// is used instead of any original registry & repository names. +func (d *sifDescriptor) CosignImages(_ context.Context, recursive bool) ([]ReferencedImage, error) { + csImgs := []ReferencedImage{} + + // Targets lists digests to check for the existence of associated signatures / images. + targets := []v1.Hash{d.descriptor.Digest} + + if d.MediaType().IsIndex() && recursive { + rmf, err := d.RawManifest() + if err != nil { + return nil, err + } + mf, err := v1.ParseIndexManifest(bytes.NewBuffer(rmf)) + if err != nil { + return nil, err + } + for _, m := range mf.Manifests { + targets = append(targets, m.Digest) + } + } + + for _, target := range targets { + for _, suffix := range cosignSuffixes { + csRef, err := CosignRef(target, nil, suffix) + if err != nil { + return nil, err + } + slog.Debug("checking for cosign image", slog.String("ref", csRef.Name())) + csImg, err := d.ofi.Image(match.Name(csRef.Name())) + if err == nil { + slog.Debug("found cosign image", slog.String("ref", csRef.Name())) + csImgs = append(csImgs, ReferencedImage{Ref: csRef, Img: csImg}) + continue + } + if errors.Is(err, sif.ErrNoMatch) { + continue + } + return nil, err + } + } + return csImgs, nil +} + +// SignedImage returns an image Descriptor as a cosign oci.SignedImage, allowing +// access to signatures and attestations stored alongside the image in the SIF. +func (d *sifDescriptor) SignedImage(ctx context.Context) (cosignoci.SignedImage, error) { + img, err := d.Image() + if err != nil { + return nil, err + } + + cosignImages, err := d.CosignImages(ctx, false) + if err != nil { + return nil, err + } + + return &sifSignedimage{ + Image: img, + cosignImages: cosignImages, + }, nil +} + +type sifSigs struct { + v1.Image +} + +var _ cosignoci.Signatures = (*sifSigs)(nil) + +func (s *sifSigs) Get() ([]cosignoci.Signature, error) { + m, err := s.Manifest() + if err != nil { + return nil, err + } + signatures := make([]cosignoci.Signature, 0, len(m.Layers)) + for _, desc := range m.Layers { + layer, err := s.Image.LayerByDigest(desc.Digest) + if err != nil { + return nil, err + } + signatures = append(signatures, cosignsignature.New(layer, desc)) + } + return signatures, nil +} + +type sifSignedimage struct { + v1.Image + cosignImages []ReferencedImage +} + +var _ cosignoci.SignedImage = (*sifSignedimage)(nil) + +func (i *sifSignedimage) Signatures() (cosignoci.Signatures, error) { + h, err := i.Digest() + if err != nil { + return nil, err + } + return i.signatures(h, cosignremote.SignatureTagSuffix) +} + +func (i *sifSignedimage) Attestations() (cosignoci.Signatures, error) { + h, err := i.Digest() + if err != nil { + return nil, err + } + return i.signatures(h, cosignremote.AttestationTagSuffix) +} + +func (i *sifSignedimage) signatures(digest v1.Hash, suffix string) (cosignoci.Signatures, error) { + ref, err := CosignRef(digest, nil, suffix) + if err != nil { + return nil, err + } + for _, csi := range i.cosignImages { + if csi.Ref == ref { + return &sifSigs{Image: csi.Img}, nil + } + } + return cosignempty.Signatures(), nil +} + +var errUnsupportedAttachment = errors.New("cosign attachments are not supported") + +func (i *sifSignedimage) Attachment(_ string) (cosignoci.File, error) { + return nil, errUnsupportedAttachment +} + +// SignedImageIndex returns an image index Descriptor as a cosign +// oci.SignedImageIndex, allowing access to signatures and attestations stored +// alongside the image in the SIF. +func (d *sifDescriptor) SignedImageIndex(ctx context.Context) (cosignoci.SignedImageIndex, error) { + if !d.MediaType().IsIndex() { + return nil, ErrUnsupportedMediaType + } + idx, err := d.ImageIndex() + if err != nil { + return nil, err + } + + cosignImages, err := d.CosignImages(ctx, false) + if err != nil { + return nil, err + } + + return &sifSignedImageIndex{ + v1Index: idx, + ofi: d.ofi, + cosignImages: cosignImages, + }, nil +} + +type v1Index v1.ImageIndex + +type sifSignedImageIndex struct { + v1Index + ofi *sif.OCIFileImage + cosignImages []ReferencedImage +} + +var _ cosignoci.SignedImageIndex = (*sifSignedImageIndex)(nil) + +func (i *sifSignedImageIndex) Signatures() (cosignoci.Signatures, error) { + h, err := i.Digest() + if err != nil { + return nil, err + } + return i.signatures(h, cosignremote.SignatureTagSuffix) +} + +func (i *sifSignedImageIndex) Attestations() (cosignoci.Signatures, error) { + h, err := i.Digest() + if err != nil { + return nil, err + } + return i.signatures(h, cosignremote.AttestationTagSuffix) +} + +func (i *sifSignedImageIndex) SignedImage(h v1.Hash) (cosignoci.SignedImage, error) { + img, err := i.ofi.Image(match.Digests(h)) + if err != nil { + return nil, err + } + d, err := partial.Descriptor(img) + if err != nil { + return nil, err + } + mf, err := img.RawManifest() + if err != nil { + return nil, err + } + parent, err := i.Digest() + if err != nil { + return nil, err + } + sd := &sifDescriptor{ + descriptor: *d, + Manifest: mf, + ofi: i.ofi, + parent: &parent, // must be able to traverse index.json -> parent index -> image in OCIDescriptor.Image() + } + return sd.SignedImage(context.Background()) +} + +func (i *sifSignedImageIndex) SignedImageIndex(h v1.Hash) (cosignoci.SignedImageIndex, error) { + img, err := i.ofi.Index(match.Digests(h)) + if err != nil { + return nil, err + } + d, err := partial.Descriptor(img) + if err != nil { + return nil, err + } + mf, err := img.RawManifest() + if err != nil { + return nil, err + } + parent, err := i.Digest() + if err != nil { + return nil, err + } + sd := &sifDescriptor{ + descriptor: *d, + Manifest: mf, + ofi: i.ofi, + parent: &parent, // must be able to traverse index.json -> parent index -> image in OCIDescriptor.Image() + } + return sd.SignedImageIndex(context.Background()) +} + +func (i *sifSignedImageIndex) signatures(digest v1.Hash, suffix string) (cosignoci.Signatures, error) { + ref, err := CosignRef(digest, nil, suffix) + if err != nil { + return nil, err + } + for _, csi := range i.cosignImages { + if csi.Ref == ref { + return &sifSigs{Image: csi.Img}, nil + } + } + return cosignempty.Signatures(), nil +} + +func (i *sifSignedImageIndex) Attachment(_ string) (cosignoci.File, error) { + return nil, errUnsupportedAttachment +} diff --git a/pkg/sourcesink/cosign_sif_test.go b/pkg/sourcesink/cosign_sif_test.go new file mode 100644 index 0000000..731889a --- /dev/null +++ b/pkg/sourcesink/cosign_sif_test.go @@ -0,0 +1,214 @@ +// Copyright 2024-2025 Sylabs Inc. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 + +package sourcesink + +import ( + "context" + "testing" + + cosignoci "github.com/sigstore/cosign/v2/pkg/oci" +) + +func Test_sifDescriptor_CosignImages(t *testing.T) { + tests := []struct { + name string + src string + recursive bool + wantCount int + }{ + { + name: "Image", + src: corpus.SIF(t, "hello-world-cosign-manifest"), + recursive: false, + wantCount: 2, // 1 signature, 1 attestation against image + }, + { + name: "IndexOnly", + src: corpus.SIF(t, "hello-world-cosign-manifest-list"), + recursive: false, + wantCount: 2, // 1 signature, 1 attestation against index + }, + { + name: "IndexRecursive", + src: corpus.SIF(t, "hello-world-cosign-manifest-list"), + recursive: true, + wantCount: 11, // 1 signature, 1 attestation against index + 1 signature against each referenced image (9 total) + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s, err := SIFFromPath(tt.src) + if err != nil { + t.Fatal(err) + } + d, err := s.Get(context.Background()) + if err != nil { + t.Fatal(err) + } + + sd, ok := d.(SignedDescriptor) + if !ok { + t.Fatal("could not upgrade Descriptor to SignedDescriptor") + } + + got, err := sd.CosignImages(context.Background(), tt.recursive) + if err != nil { + t.Fatal(err) + } + + if len(got) != tt.wantCount { + t.Errorf("Got %d cosign images, expected %d", len(got), tt.wantCount) + } + }) + } +} + +//nolint:dupl +func Test_sifDescriptor_SignedImage(t *testing.T) { + tests := []struct { + name string + src string + wantSignatures int + wantAttestations int + }{ + { + name: "UnsignedImage", + src: corpus.SIF(t, "hello-world-docker-v2-manifest"), + wantSignatures: 0, + wantAttestations: 0, + }, + { + name: "SignedImage", + src: corpus.SIF(t, "hello-world-cosign-manifest"), + wantSignatures: 1, + wantAttestations: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s, err := SIFFromPath(tt.src) + if err != nil { + t.Fatal(err) + } + d, err := s.Get(context.Background()) + if err != nil { + t.Fatal(err) + } + + sd, ok := d.(SignedDescriptor) + if !ok { + t.Fatal("could not upgrade Descriptor to SignedDescriptor") + } + + si, err := sd.SignedImage(context.Background()) + if err != nil { + t.Fatal(err) + } + checkSignedImage(t, si, tt.wantSignatures, tt.wantAttestations) + }) + } +} + +func checkSignedImage(t *testing.T, si cosignoci.SignedImage, wantSigs, wantAtts int) { + t.Helper() + sig, err := si.Signatures() + if err != nil { + t.Fatal(err) + } + sigs, err := sig.Get() + if err != nil { + t.Fatal(err) + } + if len(sigs) != wantSigs { + t.Errorf("Got %d cosign signatures, expected %d", len(sigs), wantSigs) + } + + att, err := si.Attestations() + if err != nil { + t.Fatal(err) + } + atts, err := att.Get() + if err != nil { + t.Fatal(err) + } + if len(atts) != wantAtts { + t.Errorf("Got %d cosign attestations, expected %d", len(atts), wantAtts) + } +} + +//nolint:dupl +func Test_sifDescriptor_SignedImageIndex(t *testing.T) { + tests := []struct { + name string + src string + wantSignatures int + wantAttestations int + }{ + { + name: "UnsignedIndex", + src: corpus.SIF(t, "hello-world-docker-v2-manifest-list"), + wantSignatures: 0, + wantAttestations: 0, + }, + { + name: "SignedIndex", + src: corpus.SIF(t, "hello-world-cosign-manifest-list"), + wantSignatures: 1, + wantAttestations: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s, err := SIFFromPath(tt.src) + if err != nil { + t.Fatal(err) + } + d, err := s.Get(context.Background()) + if err != nil { + t.Fatal(err) + } + + sd, ok := d.(SignedDescriptor) + if !ok { + t.Fatal("could not upgrade Descriptor to SignedDescriptor") + } + + sii, err := sd.SignedImageIndex(context.Background()) + if err != nil { + t.Fatal(err) + } + checkSignedImageIndex(t, sii, tt.wantSignatures, tt.wantAttestations) + }) + } +} + +func checkSignedImageIndex(t *testing.T, sii cosignoci.SignedImageIndex, wantSigs, wantAtts int) { + t.Helper() + sig, err := sii.Signatures() + if err != nil { + t.Fatal(err) + } + sigs, err := sig.Get() + if err != nil { + t.Fatal(err) + } + if len(sigs) != wantSigs { + t.Errorf("Got %d cosign signatures, expected %d", len(sigs), wantSigs) + } + + att, err := sii.Attestations() + if err != nil { + t.Fatal(err) + } + atts, err := att.Get() + if err != nil { + t.Fatal(err) + } + if len(atts) != wantAtts { + t.Errorf("Got %d cosign attestations, expected %d", len(atts), wantAtts) + } +} diff --git a/pkg/sourcesink/sif.go b/pkg/sourcesink/sif.go new file mode 100644 index 0000000..51a0517 --- /dev/null +++ b/pkg/sourcesink/sif.go @@ -0,0 +1,425 @@ +// Copyright 2024-2025 Sylabs Inc. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 + +package sourcesink + +import ( + "context" + "errors" + "fmt" + "io" + "log/slog" + + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/empty" + "github.com/google/go-containerregistry/pkg/v1/match" + "github.com/google/go-containerregistry/pkg/v1/partial" + "github.com/google/go-containerregistry/pkg/v1/types" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/sylabs/oci-tools/pkg/instrumented" + "github.com/sylabs/oci-tools/pkg/ociplatform" + ocisif "github.com/sylabs/oci-tools/pkg/sif" + "github.com/sylabs/sif/v2/pkg/sif" +) + +// sifSourceSink is used to retrieve/write images and indexes from/to a SIF file. +type sifSourceSink struct { + ofi *ocisif.OCIFileImage + opts options +} + +var _ SourceSink = &sifSourceSink{} + +func handleOptionsSIF(opts ...Option) (*sifSourceSink, error) { + ss := sifSourceSink{ + opts: options{}, + } + for _, opt := range opts { + if err := opt(&ss.opts); err != nil { + return nil, err + } + } + + return &ss, nil +} + +// SIFFromPath returns a sifSourceSink backed by an existing SIF file at src. +func SIFFromPath(src string, opts ...Option) (SourceSink, error) { + s, err := handleOptionsSIF(opts...) + if err != nil { + return nil, err + } + + fi, err := sif.LoadContainerFromPath(src) + if err != nil { + return nil, err + } + + s.ofi, err = ocisif.FromFileImage(fi) + if err != nil { + return nil, err + } + + return s, err +} + +// SIFEmpty will create a new, empty SIF file at dst, with a specified capacity +// of descriptors, and return a sifSourceSink that can be used to write/read +// to/from it. +func SIFEmpty(dst string, descriptors int64, opts ...Option) (SourceSink, error) { + s, err := handleOptionsSIF(opts...) + if err != nil { + return nil, err + } + if err := ocisif.Write(dst, empty.Index, ocisif.OptWriteWithSpareDescriptorCapacity(descriptors)); err != nil { + return nil, err + } + + fi, err := sif.LoadContainerFromPath(dst) + if err != nil { + return nil, err + } + s.ofi, err = ocisif.FromFileImage(fi) + if err != nil { + return nil, err + } + return s, nil +} + +var _ Descriptor = &sifDescriptor{} + +// sifDescriptor wraps a v1.Descriptor, providing methods to access the image or +// index to which it pertains, and the associated manifest, from an underlying +// SIF file. +type sifDescriptor struct { + descriptor v1.Descriptor + Manifest []byte + + ofi *ocisif.OCIFileImage + parent *v1.Hash // digest of parent index if descriptor is not referenced in the RootIndex directly. + + instrumentationLogger *slog.Logger +} + +// RawManifest returns the manifest of the image or index described by this +// descriptor. +func (d *sifDescriptor) RawManifest() ([]byte, error) { + return d.Manifest, nil +} + +// MediaType returns the types.MediaType of this descriptor. +func (d *sifDescriptor) MediaType() types.MediaType { + return d.descriptor.MediaType +} + +// Image returns a v1.Image directly if the descriptor is associated with an +// OCI image, or an image for the local platform if the descriptor is +// associated with an OCI ImageIndex. +func (d *sifDescriptor) Image() (v1.Image, error) { + switch { + case d.descriptor.MediaType.IsImage(): + var ( + img v1.Image + err error + ) + if d.parent == nil { + img, err = d.ofi.Image(match.Digests(d.descriptor.Digest)) + if err != nil { + return nil, err + } + } else { + ii, err := d.ofi.Index(match.Digests(*d.parent)) + if err != nil { + return nil, err + } + img, err = ii.Image(d.descriptor.Digest) + if err != nil { + return nil, err + } + } + if d.instrumentationLogger != nil { + return instrumented.Image(img, d.instrumentationLogger) + } + return img, nil + + case d.descriptor.MediaType.IsIndex(): + ii, err := d.ofi.Index(match.Digests(d.descriptor.Digest)) + if err != nil { + return nil, err + } + p := ociplatform.DefaultPlatform() + ims, err := partial.FindImages(ii, ociplatform.Matcher(p)) + if err != nil { + return nil, err + } + if n := len(ims); n == 0 { + return nil, ErrNoManifest + } else if n > 1 { + return nil, ErrMultipleManifests + } + if d.instrumentationLogger != nil { + return instrumented.Image(ims[0], d.instrumentationLogger) + } + return ims[0], nil + + default: + return nil, ErrUnsupportedMediaType + } +} + +// ImageIndex returns a v1.ImageIndex if the descriptor is associated with +// an OCI ImageIndex. +func (d *sifDescriptor) ImageIndex() (v1.ImageIndex, error) { + if !d.descriptor.MediaType.IsIndex() { + return nil, ErrUnsupportedMediaType + } + ii, err := d.ofi.Index(match.Digests(d.descriptor.Digest)) + if err != nil { + return nil, err + } + if d.instrumentationLogger != nil { + return instrumented.Index(ii, d.instrumentationLogger) + } + return ii, err +} + +// getMatcher returns a Matcher that selects descriptors from an OCI layout +// index.json according to the getOpts provided. +func getMatcher(o getOpts) match.Matcher { + return func(desc v1.Descriptor) bool { + // Specified digest must match if provided. + if o.digest != nil && desc.Digest != *o.digest { + return false + } + + if o.reference != nil { + // Specified reference must match if provided. + if desc.Annotations != nil || desc.Annotations[imagespec.AnnotationRefName] != o.reference.Name() { + return false + } + } else { + // Otherwise, no ref.name annotation is set. + if desc.Annotations != nil && desc.Annotations[imagespec.AnnotationRefName] != "" { + return false + } + } + + // If desc is an image, then must satisfy platform if specified. + if o.platform != nil && desc.MediaType.IsImage() { + return desc.Platform != nil && ociplatform.DescriptorSatisfies(desc, *o.platform) + } + return true + } +} + +// Get will find an image or index in the SIF file that matches the requirements +// specified by opts. If GetWithPlatform is specified then the Descriptor +// returned will always be an image that satisfies the platform. Otherwise, the +// Descriptor returned can be an image or an index. +func (o *sifSourceSink) Get(_ context.Context, opts ...GetOpt) (Descriptor, error) { + gOpts := getOpts{} + for _, opt := range opts { + if err := opt(&gOpts); err != nil { + return nil, err + } + } + + ds, err := o.ofi.FindManifests(getMatcher(gOpts)) + if err != nil { + return nil, err + } + if len(ds) == 0 { + return nil, ErrNoManifest + } + if len(ds) > 1 { + return nil, ErrMultipleManifests + } + + mt := ds[0].MediaType + switch { + case mt.IsImage(): + img, err := o.ofi.Image(match.Digests(ds[0].Digest)) + if err != nil { + return nil, err + } + if gOpts.platform != nil { + if err := ociplatform.EnsureImageSatisfies(img, *gOpts.platform); err != nil { + return nil, err + } + } + mf, err := img.RawManifest() + if err != nil { + return nil, err + } + return &sifDescriptor{ + descriptor: ds[0], + Manifest: mf, + ofi: o.ofi, + instrumentationLogger: o.opts.instrumentationLogger, + }, nil + case mt.IsIndex(): + ii, err := o.ofi.Index(match.Digests(ds[0].Digest)) + if err != nil { + return nil, err + } + // Platform wasn't requested - return the index itself. + if gOpts.platform == nil { + mf, err := ii.RawManifest() + if err != nil { + return nil, err + } + return &sifDescriptor{ + descriptor: ds[0], + Manifest: mf, + ofi: o.ofi, + instrumentationLogger: o.opts.instrumentationLogger, + }, nil + } + // Platform was requested - find an image in the index. + return o.imageFromIndex(ii, gOpts.platform) + default: + return nil, fmt.Errorf("%w: %v", ErrUnsupportedMediaType, mt) + } +} + +func (o *sifSourceSink) imageFromIndex(ii v1.ImageIndex, p *v1.Platform) (Descriptor, error) { + iiDigest, err := ii.Digest() + if err != nil { + return nil, err + } + ims, err := partial.FindImages(ii, ociplatform.Matcher(p)) + if err != nil { + return nil, err + } + if n := len(ims); n == 0 { + return nil, ErrNoManifest + } else if n > 1 { + return nil, ErrMultipleManifests + } + d, err := partial.Descriptor(ims[0]) + if err != nil { + return nil, err + } + mf, err := ims[0].RawManifest() + if err != nil { + return nil, err + } + return &sifDescriptor{ + descriptor: *d, + Manifest: mf, + ofi: o.ofi, + parent: &iiDigest, // must be able to traverse index.json -> parent index -> image in OCIDescriptor.Image() + }, nil +} + +// Write will append an image or index w to the SIF file associated with the +// sifSourceSink. +func (o *sifSourceSink) Write(_ context.Context, w Writable, opts ...WriteOpt) error { + wOpts := writeOpts{} + for _, opt := range opts { + if err := opt(&wOpts); err != nil { + return err + } + } + + appendOpts := []ocisif.AppendOpt{} + if wOpts.reference != nil { + appendOpts = append(appendOpts, ocisif.OptAppendReference(wOpts.reference)) + } + + if img, ok := w.(v1.Image); ok { + return o.ofi.AppendImage(img, appendOpts...) + } + + if ii, ok := w.(v1.ImageIndex); ok { + return o.ofi.AppendIndex(ii, appendOpts...) + } + + return ErrUnsupportedMediaType +} + +// NumDescriptorsForImage returns the number of descriptors required to store img. +func NumDescriptorsForImage(img v1.Image) (int64, error) { + ls, err := img.Layers() + if err != nil { + return 0, err + } + + return int64(len(ls) + 2), nil +} + +// NumDescriptorsForIndex returns the number of descriptors required to store ii. +func NumDescriptorsForIndex(ii v1.ImageIndex) (int64, error) { + index, err := ii.IndexManifest() + if err != nil { + return 0, err + } + + var count int64 + + for _, desc := range index.Manifests { + //nolint:exhaustive // Exhaustive cases not appropriate. + switch desc.MediaType { + case types.DockerManifestList, types.OCIImageIndex: + ii, err := ii.ImageIndex(desc.Digest) + if err != nil { + return 0, err + } + + n, err := NumDescriptorsForIndex(ii) + if err != nil { + return 0, err + } + + count += n + + case types.DockerManifestSchema2, types.OCIManifestSchema1: + img, err := ii.Image(desc.Digest) + if err != nil { + return 0, err + } + + n, err := NumDescriptorsForImage(img) + if err != nil { + return 0, err + } + + count += n + + default: + count++ + } + } + + return count + 1, nil +} + +var ( + errSIFBlobNoDigest = errors.New("a digest must be provided to get a blob") + errSIFBlobReference = errors.New("a reference cannot be provided when getting a blob") + errSIFBlobPlatform = errors.New("a platform cannot be provided when getting a blob") +) + +// Blob returns an io.Readcloser for the content of the blob with a digest +// specified using the GetWithDigest option. +func (o *sifSourceSink) Blob(_ context.Context, opts ...GetOpt) (io.ReadCloser, error) { + gOpts := getOpts{} + for _, opt := range opts { + if err := opt(&gOpts); err != nil { + return nil, err + } + } + + if gOpts.reference != nil { + return nil, errSIFBlobReference + } + if gOpts.platform != nil { + return nil, errSIFBlobPlatform + } + if gOpts.digest == nil { + return nil, errSIFBlobNoDigest + } + + return o.ofi.Blob(*gOpts.digest) +} diff --git a/pkg/sourcesink/sif_test.go b/pkg/sourcesink/sif_test.go new file mode 100644 index 0000000..5ab7e2b --- /dev/null +++ b/pkg/sourcesink/sif_test.go @@ -0,0 +1,377 @@ +// Copyright 2024-2025 Sylabs Inc. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 + +package sourcesink + +import ( + "context" + "errors" + "io" + "log/slog" + "os" + "path/filepath" + "testing" + + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/sebdah/goldie/v2" + "github.com/sylabs/oci-tools/pkg/ociplatform" + "github.com/sylabs/oci-tools/test" +) + +//nolint:gochecknoglobals +var corpus = test.NewCorpus(filepath.Join("..", "..", "test")) + +func TestSIFFromPath(t *testing.T) { + tests := []struct { + name string + src string + opts []Option + wantErr error + }{ + { + name: "Defaults", + src: corpus.SIF(t, "hello-world-docker-v2-manifest"), + }, + { + name: "WithInstrumentationLogs", + src: corpus.SIF(t, "hello-world-docker-v2-manifest"), + opts: []Option{OptWithInstrumentationLogs(slog.Default())}, + wantErr: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := SIFFromPath(tt.src, tt.opts...) + if !errors.Is(err, tt.wantErr) { + t.Fatalf("SIFFromPath() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestSIFGet(t *testing.T) { + imgDigest := v1.Hash{Algorithm: "sha256", Hex: "432f982638b3aefab73cc58ab28f5c16e96fdb504e8c134fc58dff4bae8bf338"} + idxDigest := v1.Hash{Algorithm: "sha256", Hex: "00e1ee7c898a2c393ea2fe7680938f8dcbe55e51fbf08032cf37326a677f92ed"} + + tests := []struct { + name string + src string + opts []GetOpt + wantErr error + }{ + { + name: "ImageDefaults", + src: corpus.SIF(t, "hello-world-docker-v2-manifest"), + opts: []GetOpt{}, + wantErr: nil, + }, + { + name: "ImagePlatform", + src: corpus.SIF(t, "hello-world-docker-v2-manifest"), + opts: []GetOpt{GetWithPlatform(v1.Platform{OS: "Linux", Architecture: "arm64"})}, + wantErr: nil, + }, + { + name: "ImageBadPlatform", + src: corpus.SIF(t, "hello-world-docker-v2-manifest"), + opts: []GetOpt{GetWithPlatform(v1.Platform{OS: "Linux", Architecture: "m68k"})}, + wantErr: ErrNoManifest, + }, + { + name: "ImageDigest", + src: corpus.SIF(t, "hello-world-docker-v2-manifest"), + opts: []GetOpt{GetWithDigest(imgDigest)}, + wantErr: nil, + }, + { + name: "ImageBadDigest", + src: corpus.SIF(t, "hello-world-docker-v2-manifest"), + opts: []GetOpt{GetWithDigest(v1.Hash{})}, + wantErr: ErrNoManifest, + }, + { + name: "IndexDefaults", + src: corpus.SIF(t, "hello-world-docker-v2-manifest-list"), + opts: []GetOpt{}, + wantErr: nil, + }, + { + name: "IndexPlatform", + src: corpus.SIF(t, "hello-world-docker-v2-manifest-list"), + opts: []GetOpt{GetWithPlatform(v1.Platform{OS: "Linux", Architecture: "arm64", Variant: "v8"})}, + wantErr: nil, + }, + { + name: "IndexBadPlatform", + src: corpus.SIF(t, "hello-world-docker-v2-manifest-list"), + opts: []GetOpt{GetWithPlatform(v1.Platform{OS: "Linux", Architecture: "m68k"})}, + wantErr: ErrNoManifest, + }, + { + name: "IndexDigest", + src: corpus.SIF(t, "hello-world-docker-v2-manifest-list"), + opts: []GetOpt{GetWithDigest(idxDigest)}, + wantErr: nil, + }, + { + name: "IndexBadDigest", + src: corpus.SIF(t, "hello-world-docker-v2-manifest-list"), + opts: []GetOpt{GetWithDigest(v1.Hash{})}, + wantErr: ErrNoManifest, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s, err := SIFFromPath(tt.src) + if err != nil { + t.Fatalf("SIFFromPath() error = %v", err) + } + d, err := s.Get(context.Background(), tt.opts...) + if !errors.Is(err, tt.wantErr) { + t.Fatalf("Get() error = %v, wantErr %v", err, tt.wantErr) + } + + if err != nil { + return + } + + mf, err := d.RawManifest() + if err != nil { + t.Fatalf("RawManifest() error = %v", err) + } + g := goldie.New(t, goldie.WithTestNameForDir(true)) + g.Assert(t, tt.name, mf) + }) + } +} + +func TestSIFDescriptorImage(t *testing.T) { + tests := []struct { + name string + src string + wantPlatform v1.Platform + }{ + { + name: "FromImage", + src: corpus.SIF(t, "hello-world-docker-v2-manifest"), + wantPlatform: v1.Platform{OS: "Linux", Architecture: "arm64", Variant: "v8"}, + }, + { + name: "FromIndex", + src: corpus.SIF(t, "hello-world-docker-v2-manifest-list"), + wantPlatform: *ociplatform.DefaultPlatform(), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s, err := SIFFromPath(tt.src) + if err != nil { + t.Fatalf("SIFFromPath() error = %v", err) + } + d, err := s.Get(context.Background()) + if err != nil { + t.Fatalf(".Get() error = %v", err) + } + + img, err := d.Image() + if err != nil { + t.Fatalf(".Image() error = %v", err) + } + + if err := ociplatform.EnsureImageSatisfies(img, tt.wantPlatform); err != nil { + t.Fatalf("Image does not satisfy expected platform %v", tt.wantPlatform) + } + }) + } +} + +func TestSIFDescriptorImageIndex(t *testing.T) { + tests := []struct { + name string + src string + wantErr error + }{ + { + name: "FromImage", + src: corpus.SIF(t, "hello-world-docker-v2-manifest"), + wantErr: ErrUnsupportedMediaType, + }, + { + name: "FromIndex", + src: corpus.SIF(t, "hello-world-docker-v2-manifest-list"), + wantErr: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s, err := SIFFromPath(tt.src) + if err != nil { + t.Fatalf("SIFFromPath() error = %v", err) + } + d, err := s.Get(context.Background()) + if err != nil { + t.Fatalf(".Get() error = %v", err) + } + + _, err = d.ImageIndex() + if !errors.Is(err, tt.wantErr) { + t.Fatalf(".ImageIndex() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestSIFEmpty(t *testing.T) { + tests := []struct { + name string + opts []Option + wantErr error + }{ + { + name: "Defaults", + }, + { + name: "WithInstrumentationLogs", + opts: []Option{OptWithInstrumentationLogs(slog.Default())}, + wantErr: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + path := filepath.Join(t.TempDir(), "test.sif") + _, err := SIFEmpty(path, 16, tt.opts...) + if !errors.Is(err, tt.wantErr) { + t.Fatalf("SIFEmpty() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestSIFWrite(t *testing.T) { + tests := []struct { + name string + write Writable + descriptors int64 + opts []WriteOpt + }{ + { + name: "ImageDefaults", + write: corpus.Image(t, "hello-world-docker-v2-manifest"), + descriptors: 4, + opts: []WriteOpt{}, + }, + { + name: "ImageWithReference", + write: corpus.Image(t, "hello-world-docker-v2-manifest"), + descriptors: 4, + opts: []WriteOpt{WriteWithReference(name.MustParseReference("my:image", name.WithDefaultRegistry("")))}, + }, + { + name: "IndexDefaults", + write: corpus.ImageIndex(t, "hello-world-docker-v2-manifest-list"), + descriptors: 32, + opts: []WriteOpt{}, + }, + { + name: "IndexWithReference", + write: corpus.ImageIndex(t, "hello-world-docker-v2-manifest-list"), + descriptors: 32, + opts: []WriteOpt{WriteWithReference(name.MustParseReference("my:image", name.WithDefaultRegistry("")))}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + path := filepath.Join(t.TempDir(), "test.sif") + + s, err := SIFEmpty(path, tt.descriptors) + if err != nil { + t.Fatalf("SIFEmpty() error = %v", err) + } + err = s.Write(context.Background(), tt.write, tt.opts...) + if err != nil { + t.Fatalf(".Write() error = %v", err) + } + + index, err := os.ReadFile(path) + if err != nil { + t.Fatalf("while reading test.sif: %v", err) + } + g := goldie.New(t, goldie.WithTestNameForDir(true)) + g.Assert(t, tt.name, index) + }) + } +} + +func TestSIFBlob(t *testing.T) { + tests := []struct { + name string + src string + opts []GetOpt + wantErr error + }{ + { + name: "ImageConfig", + src: corpus.SIF(t, "hello-world-docker-v2-manifest"), + opts: []GetOpt{GetWithDigest( + v1.Hash{Algorithm: "sha256", Hex: "46331d942d6350436f64e614d75725f6de3bb5c63e266e236e04389820a234c4"})}, + wantErr: nil, + }, + { + name: "ImageLayer", + src: corpus.SIF(t, "hello-world-docker-v2-manifest"), + opts: []GetOpt{GetWithDigest( + v1.Hash{Algorithm: "sha256", Hex: "7050e35b49f5e348c4809f5eff915842962cb813f32062d3bbdd35c750dd7d01"})}, + wantErr: nil, + }, + { + name: "ErrNoDigest", + src: corpus.SIF(t, "hello-world-docker-v2-manifest"), + opts: []GetOpt{}, + wantErr: errSIFBlobNoDigest, + }, + { + name: "ErrPlatform", + src: corpus.SIF(t, "hello-world-docker-v2-manifest"), + opts: []GetOpt{ + GetWithDigest(v1.Hash{Algorithm: "sha256", Hex: "7050e35b49f5e348c4809f5eff95842962cb813f32062d3bbdd35c750dd7d01"}), + GetWithPlatform(*ociplatform.DefaultPlatform()), + }, + wantErr: errSIFBlobPlatform, + }, + { + name: "ErrReference", + src: corpus.SIF(t, "hello-world-docker-v2-manifest"), + opts: []GetOpt{ + GetWithDigest(v1.Hash{Algorithm: "sha256", Hex: "7050e35b49f5e348c4809f5eff95842962cb813f32062d3bbdd35c750dd7d01"}), + GetWithReference(name.MustParseReference("test")), + }, + wantErr: errSIFBlobReference, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s, err := SIFFromPath(tt.src) + if err != nil { + t.Fatalf("OCIFromPath() error = %v", err) + } + rc, err := s.Blob(context.Background(), tt.opts...) + if !errors.Is(err, tt.wantErr) { + t.Fatalf("Get() error = %v, wantErr %v", err, tt.wantErr) + } + + if err != nil { + return + } + + b, err := io.ReadAll(rc) + if err != nil { + t.Fatalf("ReadAll error: %v", err) + } + + g := goldie.New(t, goldie.WithTestNameForDir(true)) + g.Assert(t, tt.name, b) + }) + } +} diff --git a/pkg/sourcesink/sink.go b/pkg/sourcesink/sink.go new file mode 100644 index 0000000..58a0061 --- /dev/null +++ b/pkg/sourcesink/sink.go @@ -0,0 +1,42 @@ +// Copyright 2024-2025 Sylabs Inc. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 + +package sourcesink + +import ( + "context" + + "github.com/google/go-containerregistry/pkg/name" +) + +// Writable can represent a v1.Image or v1.ImageIndex. Consumers of a Writable +// will cast to one of these types. +type Writable interface { + RawManifest() ([]byte, error) +} + +// Sink implements methods to write images and indexes to a specific type of +// storage, and location. +type Sink interface { + Write(ctx context.Context, w Writable, opts ...WriteOpt) error +} + +// writeOpts holds options that should apply across to a single Write operation +// against a sink. +type writeOpts struct { + reference name.Reference +} + +// WriteOpt sets an option that applies to a single Write operation against a +// sink. +type WriteOpt func(*writeOpts) error + +// WriteWithReference will set a reference for the image or index written, at +// the destination. +func WriteWithReference(r name.Reference) WriteOpt { + return func(o *writeOpts) error { + o.reference = r + return nil + } +} diff --git a/pkg/sourcesink/source.go b/pkg/sourcesink/source.go new file mode 100644 index 0000000..0e5d789 --- /dev/null +++ b/pkg/sourcesink/source.go @@ -0,0 +1,92 @@ +// Copyright 2024-2025 Sylabs Inc. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 + +package sourcesink + +import ( + "context" + "errors" + "io" + + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/types" +) + +// Descriptor wraps a v1.Descriptor, providing methods to access the image or +// index to which it pertains, and the associated manifest. +type Descriptor interface { + // RawManifest returns the manifest of the image or index described by this + // descriptor. + RawManifest() ([]byte, error) + // MediaType returns the types.MediaType of this descriptor. + MediaType() types.MediaType + // Image returns a v1.Image directly if the descriptor is associated with an + // OCI image, or an image for the local platform if the descriptor is + // associated with an OCI ImageIndex. + Image() (v1.Image, error) + // ImageIndex returns a v1.ImageIndex if the descriptor is associated with + // an OCI ImageIndex. + ImageIndex() (v1.ImageIndex, error) +} + +// Source implements methods to read images and indexes from a specific type of +// storage, and location. +type Source interface { + // Get will find an image or index at the source that matches the + // requirements specified by opts. The image or index is returned as a + // Descriptor. + Get(ctx context.Context, opts ...GetOpt) (Descriptor, error) + // Blob will return an io.ReadCloser that provides the content of the blob + // specified via opts. + Blob(ctx context.Context, opts ...GetOpt) (io.ReadCloser, error) +} + +// getOpts holds options that should apply across to a single Get operation +// against a source. +type getOpts struct { + platform *v1.Platform + digest *v1.Hash + reference name.Reference +} + +// GetOpt sets an option that applies to a single Get operation against a +// source. +type GetOpt func(*getOpts) error + +// GetPlatform overrides the platform when choosing an image. +func GetWithPlatform(p v1.Platform) GetOpt { + return func(o *getOpts) error { + o.platform = &p + return nil + } +} + +// GetDigest sets the digest of the image or index to retrieve. +func GetWithDigest(d v1.Hash) GetOpt { + return func(o *getOpts) error { + o.digest = &d + return nil + } +} + +// GetReference sets the name.ref of the image or index to retrieve. +func GetWithReference(r name.Reference) GetOpt { + return func(o *getOpts) error { + o.reference = r + return nil + } +} + +var ( + // ErrNoManifest is returned when no manifests that satisfy provided + // criteria are found in a source. + ErrNoManifest = errors.New("no matching image / index found") + // ErrMultipleManifests is returned when more than one manifest that + // satisfies provided criteria is found in a source. + ErrMultipleManifests = errors.New("multiple matching images / indices found") + // ErrUnsupportedMediaType is returned when an operation is attempted + // against an OCI media type that does not support it. + ErrUnsupportedMediaType = errors.New("unsupported media type") +) diff --git a/pkg/sourcesink/sourcesink.go b/pkg/sourcesink/sourcesink.go new file mode 100644 index 0000000..1d93f5b --- /dev/null +++ b/pkg/sourcesink/sourcesink.go @@ -0,0 +1,34 @@ +// Copyright 2024-2025 Sylabs Inc. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 + +package sourcesink + +import ( + "log/slog" +) + +// SourceSink implements methods to read / write images and indexes from / to a +// specific type of storage, and location. +type SourceSink interface { + Source + Sink +} + +// options holds options that should apply across multiple Get / Write +// operations against a source or sink. +type options struct { + instrumentationLogger *slog.Logger +} + +// Option sets an option that applies across multiple Get / Write operations against +// a source or sink. +type Option func(*options) error + +// OptWithInstrumentationLogs adds instrumentation of operations against the underlying image. +func OptWithInstrumentationLogs(l *slog.Logger) Option { + return func(o *options) error { + o.instrumentationLogger = l + return nil + } +} diff --git a/pkg/sourcesink/testdata/TestSIFBlob/ImageConfig.golden b/pkg/sourcesink/testdata/TestSIFBlob/ImageConfig.golden new file mode 100644 index 0000000..902a739 --- /dev/null +++ b/pkg/sourcesink/testdata/TestSIFBlob/ImageConfig.golden @@ -0,0 +1 @@ +{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:cc0fff24c4ece63ade5d9f549e42c926cf569112c4f5c439a4a57f3f33f5588b","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"b2af51419cbf516f3c99b877a64906b21afedc175bd3cd082eb5798e2f277bb4","container_config":{"Hostname":"b2af51419cbf","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:cc0fff24c4ece63ade5d9f549e42c926cf569112c4f5c439a4a57f3f33f5588b","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2022-03-19T16:12:58.923371954Z","docker_version":"20.10.12","history":[{"created":"2022-03-19T16:12:58.834095198Z","created_by":"/bin/sh -c #(nop) COPY file:a79dd5bda1e77203401956a93401d3aef45221fc750295a4291896f3386f4f54 in / "},{"created":"2022-03-19T16:12:58.923371954Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:efb53921da3394806160641b72a2cbd34ca1a9a8345ac670a85a04ad3d0e3507"]},"variant":"v8"} \ No newline at end of file diff --git a/pkg/sourcesink/testdata/TestSIFBlob/ImageLayer.golden b/pkg/sourcesink/testdata/TestSIFBlob/ImageLayer.golden new file mode 100644 index 0000000000000000000000000000000000000000..c93dccfd3e0eb48bb9933945112e1143c805bfe7 GIT binary patch literal 3208 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 P@fQ#OlUHO&v8(vcH72!~ literal 0 HcmV?d00001 diff --git a/pkg/sourcesink/testdata/TestSIFWrite/ImageWithReference.golden b/pkg/sourcesink/testdata/TestSIFWrite/ImageWithReference.golden new file mode 100644 index 0000000000000000000000000000000000000000..c7f060a2b32dd78d386b09cb42b872612a1d1136 GIT binary patch literal 12552 zcmeHM2~<-_)&@jqMHF#i6Nyow5ypD z6%-W}lucU!Q8p3mMnpsfv1O5#ML;$MS(?lXi{110e`e;NIdlG*IlKd}s%}-?s{7rq zD#^VvGJpNCx7guky=A9`xeNv?gTef9@FGs+phO~(nJr~!M=YEhsWMaXR+=rfX3Ddx z<_64{^9al%Fpt1I0`myWBQTG^JOc9w%p)+5z℞2+Sk!uSP)0Oh!gl`lB8GACNBQ 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 Ddj87| literal 0 HcmV?d00001 diff --git a/pkg/sourcesink/testdata/TestSIFWrite/IndexDefaults.golden b/pkg/sourcesink/testdata/TestSIFWrite/IndexDefaults.golden new file mode 100644 index 0000000000000000000000000000000000000000..6319acd1339819f95a3346289f52ee76cfb725e3 GIT binary patch literal 73116 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 literal 0 HcmV?d00001 diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/00e1ee7c898a2c393ea2fe7680938f8dcbe55e51fbf08032cf37326a677f92ed b/test/images/hello-world-cosign-manifest-list/blobs/sha256/00e1ee7c898a2c393ea2fe7680938f8dcbe55e51fbf08032cf37326a677f92ed new file mode 100755 index 0000000..b691c34 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/00e1ee7c898a2c393ea2fe7680938f8dcbe55e51fbf08032cf37326a677f92ed @@ -0,0 +1 @@ +{"manifests":[{"digest":"sha256:f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"amd64","os":"linux"},"size":525},{"digest":"sha256:6253ef1af25aabd67777a01c686e7c69ee612961db34c8b90da079e5473be83b","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"arm","os":"linux","variant":"v5"},"size":525},{"digest":"sha256:40d0cfd0861719208ff9f7747ab3f97844eeca509df705db44a736df863b76af","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"arm","os":"linux","variant":"v7"},"size":525},{"digest":"sha256:432f982638b3aefab73cc58ab28f5c16e96fdb504e8c134fc58dff4bae8bf338","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"arm64","os":"linux","variant":"v8"},"size":525},{"digest":"sha256:995efde2e81b21d1ea7066aa77a59298a62a9e9fbb4b77f36c189774ec9b1089","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"386","os":"linux"},"size":525},{"digest":"sha256:eb11b1a194ff8e236a01eff392c4e1296a53b0fb4780d8b0382f7996a15d5392","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"mips64le","os":"linux"},"size":525},{"digest":"sha256:3209b9aec056b296ea55b2af7757d078bf92e55a3ea29c5fdef5c785bcef09c4","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"ppc64le","os":"linux"},"size":525},{"digest":"sha256:98c9722322be649df94780d3fbe594fce7996234b259f27eac9428b84050c849","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"riscv64","os":"linux"},"size":525},{"digest":"sha256:c7b6944911848ce39b44ed660d95fb54d69bbd531de724c7ce6fc9f743c0b861","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"s390x","os":"linux"},"size":525}],"mediaType":"application\/vnd.docker.distribution.manifest.list.v2+json","schemaVersion":2} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/02623e64de6f2252401a401a36d9e6db7d66a9c1d1bf134053d5c4c978b3376d b/test/images/hello-world-cosign-manifest-list/blobs/sha256/02623e64de6f2252401a401a36d9e6db7d66a9c1d1bf134053d5c4c978b3376d new file mode 100644 index 0000000..1929267 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/02623e64de6f2252401a401a36d9e6db7d66a9c1d1bf134053d5c4c978b3376d @@ -0,0 +1 @@ +{"critical":{"identity":{"docker-reference":"127.0.0.1:44949/hello-world-docker-v2-manifest-list"},"image":{"docker-manifest-digest":"sha256:432f982638b3aefab73cc58ab28f5c16e96fdb504e8c134fc58dff4bae8bf338"},"type":"cosign container image signature"},"optional":null} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/04341b189be695acecd201a36cdf9dd99b8b0c338075000f555d5adf8e9c0547 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/04341b189be695acecd201a36cdf9dd99b8b0c338075000f555d5adf8e9c0547 new file mode 100644 index 0000000000000000000000000000000000000000..5d62fb61e111195e076a2638b4955f66d2af6c5a GIT binary patch literal 2993 zcmV;i3r_SOiwFP!00000|LjUNG4_Ye5Iwe zrRDJ9gV0ix-&k8)+YYrrYkS+l_Ctpc9Xilv;@b|i0&e-7$$r6&MD zMF95F^W$%;iLGKWpPTL;eOpazws!(pN^N+Yom)no>9AuKJp+1ry{O4`GzI$GcK~cr zRO_6j@Ho@?tNJ$3$JPNm=OFiv6M)mf#p&Q7`^FfN#k$x1HVZmo5QV#iJ+rQuD>}iP z>nG0A(R2OeSqP%DWzlE*iCyqr;#nk;Q=so#w@rW5pneTG&4ZxEY&`%RG2@RoVvgu2 zGr^2A-|8k8Y_aS88>x@FSywN3$>u%H6D(BogrDkFZWjs zJZ4~wTA<<1Vn@`rG700%GXpm9)r&`>+rBr>_y_JkS21&_Z;YV_4o2PI8)p{znv46- zyDzpKJHxa^U+%9QI1rubcMp``-roePPWVBt@kL_gk8EEusK#Dns_~7b=7#@Ts5H=n z(6GK3U_qDG_e>SmrVDT8{d>=K+ZNx<-?#T%H(K2F?CBq!W&=T}HBlD~6eL;VELlqg zsk0D#h~@OZbHJ?!*k`)oXN9-6MaLO(iEAdO3ms0E9dUcAGUT=>-~~69D!BK#&ILFGp}>*6~PT?ZD$fJrId9r<2 zy2Ku4;nolf`d8P9Y10QaoesCm{>zWP6?pAsq5-8z1JxY3*_F08Je4L5qJ}icnueP{ zNjn=zgR0qolj-Jkbdb_Xs$wU(L+T0YB!P~f4>%hbgQ}^zc{z{#fd(c|`n@+V=SlzN zyv@(#9eyTn^OHJ71==fi?qzV>o(6cMWe#`rVh{0_y2-GS=#uJX%1hZ58 z&jH^Yrx#j&y#%=zT?l^RLh$D<1gZROoqJdQ&7;o_5H(OrVD< zsw+ET#o?rwpR&|yx~%u2D~8z#=2_{z<5!I2DAX zZ1OOm5eTh1iMIx(a#ZbC_^I3uzA@GqnP5hl9a0xR(duVfnOdDhh<~O2cWweEgTcL= zUTC+mzsqv^yaR3>W(#X-p|I9jD1J}omi4E0i1vE>;(76<6^cReS9XF^8od$Km^n^Pc*JqY>FYb75S@*7ABUUj{q3`kTUO1@{ zTXLM#zImq3bB&Vex#ip5xn+N6I&9|n^T|@2Hk(e` zIPF#U>#Nvfay-9E5$`$}E5Ds|ZD}ojnwI}K>C-_cE|HRqmk79JMQ;7 z4Jt-8{PNno{=y{gnAiVw^3rO+`}o48Rj0Snw78mJXO?e!afcP})gF!N;j~JI(QFK- zRrU62_Fhig#0;g@epVb_vIBoj_Va++jX@R1tA*#8a zC^7H7aqYpanfG#9WrERc`#7yi=+*4|Ic?i1R&(6XY1@awn)3lp3y2Y|td7%mNPQYz z&uP_9L^W4Ki8+4b+P|%0x7k^$q5S%1S90~*NzIep=tXc-FTTHg+k4GnP342uR380~ z0rS>WK4?wl(Mbd59n-~*0}!zeb`NWQ1JYp|cwyHs)85CAq{AEkhv&>3?3FT8GcB>8Brd|U{&N*JSJxqETu9kpG@+qB&RT+P7Az}!K#c01w0}v zr=`>oj?0Q7#MR_jh^9}-ct}VI3a<)S-Nf5i@`hDeK8;mTz^CM7QXVnwGpdlzbkMjp zginaV1~8tKgp`Woa!Tdns*tdZO3xC!Ff6A+G(PYNlj1f`XOqbiK4_g?nnq+LnFwNO z*v!z%eG^$EI~bxd#<-4GhT9H2dAOd&ZCmli6@fPc;c-eBDF!B`1Z9JeS4$2?L@6#} zC7UwqC|K0Os1VPp{9sZj0@I3|$i@W=faR>3&RXThydvOuR#AkMnjFK5z$c{CP>9Cu zTg8)66@eeNGUe3`7FFJyTd|0ZrI0daK_%6SNR^BIRRv{OO7Y2J?^IJoG5xXaZQqnvqj(_pAl*L z%c7a2RjEuP=Ci6iYz~V#OsA6ah`E%Gd{vvKlBoC1CX`8T86B%`Cs@5 zV65i^bR7TyUf>5MK;{|OcDShv?6jlHiOL9?s-W&em8c4BCj+ROs6o4_Ac9av%&3aW z4?;*vNh*X?VN`|CDJdmENRbn~%0oyHPo7fvVWEgQ$twy!R>W*v56LQoir~Ra20~qr zJ`&s*w3#)WubL$6yD5R{+5)rFRb-LX=kjCfp@JaLL4#eT<_@>-J5!D`g0- zlx@wotAsP}UoS)OdKo}F`7v&zQ~NjJpd0~|f9z|s-(~>t000Ra?@>ODGxex>RxIJn zzJB-_xNylYS(*><0We$Oj%~s*)@*z--wp0ZOLaAI$9x1F^8sM=Y25D>G3kwc6W0cx nuFFTUmE;>ffT1mL_vD`3lY4Scit;}J00960Wpz`K02%-Q;tA>* literal 0 HcmV?d00001 diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/0473adddc4b4a6b8456d5077fa12d08de36239e713c704fa0151abffb1bb0126 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/0473adddc4b4a6b8456d5077fa12d08de36239e713c704fa0151abffb1bb0126 new file mode 100644 index 0000000..9ff4340 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/0473adddc4b4a6b8456d5077fa12d08de36239e713c704fa0151abffb1bb0126 @@ -0,0 +1 @@ +{"critical":{"identity":{"docker-reference":"127.0.0.1:44949/hello-world-docker-v2-manifest-list"},"image":{"docker-manifest-digest":"sha256:00e1ee7c898a2c393ea2fe7680938f8dcbe55e51fbf08032cf37326a677f92ed"},"type":"cosign container image signature"},"optional":null} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/04d584bf278d95c3bdf6aebdadd9ee552e8c9b35d60e8f1247bd9ee0260313e1 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/04d584bf278d95c3bdf6aebdadd9ee552e8c9b35d60e8f1247bd9ee0260313e1 new file mode 100644 index 0000000..1232226 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/04d584bf278d95c3bdf6aebdadd9ee552e8c9b35d60e8f1247bd9ee0260313e1 @@ -0,0 +1 @@ +{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:f85bca573013bd8d0ecb52d851dcf98581f35d46c64aa049558a04dc5e4401fe"]},"config":{}} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/155c39610faa3bae95d5bd0435194b1ae66c861c2aca8a7692e752e9acfaa696 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/155c39610faa3bae95d5bd0435194b1ae66c861c2aca8a7692e752e9acfaa696 new file mode 100644 index 0000000..b6fc903 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/155c39610faa3bae95d5bd0435194b1ae66c861c2aca8a7692e752e9acfaa696 @@ -0,0 +1 @@ +{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:6569af6e782a5c31546c763f138b327cf641e4d537fc9bc453f52b46f19ec3ff"]},"config":{}} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/165760e771f0d295a89c06ad50659133315b485ac68647119775b37578eaf629 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/165760e771f0d295a89c06ad50659133315b485ac68647119775b37578eaf629 new file mode 100644 index 0000000..01447b6 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/165760e771f0d295a89c06ad50659133315b485ac68647119775b37578eaf629 @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":233,"digest":"sha256:b61d5036614f79e5610341829b1cb96b55a1ce7060e4bdc57ac196d93b2dee63"},"layers":[{"mediaType":"application/vnd.dsse.envelope.v1+json","size":680,"digest":"sha256:bf4cb7b5c44789f31a104b99ae53cf38992f33e084dd97b132957c5101e643ec","annotations":{"dev.cosignproject.cosign/signature":"","predicateType":"https://cosign.sigstore.dev/attestation/v1"}}]} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/16692a792468762200c57d0aa0cbe380ccf2b16a23a00543dd69bd8fb1dc4fae b/test/images/hello-world-cosign-manifest-list/blobs/sha256/16692a792468762200c57d0aa0cbe380ccf2b16a23a00543dd69bd8fb1dc4fae new file mode 100644 index 0000000..b53fceb --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/16692a792468762200c57d0aa0cbe380ccf2b16a23a00543dd69bd8fb1dc4fae @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":233,"digest":"sha256:4f923680062bbea891b21ccd6e561597e7b358abfdbf58167d6a8f2fcd035c0a"},"layers":[{"mediaType":"application/vnd.dev.cosign.simplesigning.v1+json","size":267,"digest":"sha256:e58c180ca4d73dc4b0a65122c4502dd8674c6fe0f904ca02509c2fdf24e137e4","annotations":{"dev.cosignproject.cosign/signature":"MEQCIBvQ9MCugZYfLkEljUAgheYC4eu9jsOgijXAIlAjv84SAiBmpKRcgzn55Ewf0YjKIuemX4CXPWW5uiYfftX3qMLMrg=="}}]} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/1e4c6e59fe9ed668252140571494bb844e424bb48c2eceefed73434eb9a84dc3 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/1e4c6e59fe9ed668252140571494bb844e424bb48c2eceefed73434eb9a84dc3 new file mode 100644 index 0000000..eebfd02 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/1e4c6e59fe9ed668252140571494bb844e424bb48c2eceefed73434eb9a84dc3 @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":233,"digest":"sha256:fa9dfc3e3e2a35077691b46087565b3433a7447f3eff39b96cdbbcbb568db94b"},"layers":[{"mediaType":"application/vnd.dev.cosign.simplesigning.v1+json","size":267,"digest":"sha256:0473adddc4b4a6b8456d5077fa12d08de36239e713c704fa0151abffb1bb0126","annotations":{"dev.cosignproject.cosign/signature":"MEQCIHgsbQoaSvCrNHFwYqhxSfgBW7nQi3qdFNeZyphMgpK5AiByT9v+DFnZWyS+OSpXmM3psuSC1+in7yhLWr16dWXWzw=="}}]} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/29a03bf1904f1d59ec50227bcbf64eb980e26fffd716e3f3205ed4a7e17e6493 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/29a03bf1904f1d59ec50227bcbf64eb980e26fffd716e3f3205ed4a7e17e6493 new file mode 100644 index 0000000..eb90dbf --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/29a03bf1904f1d59ec50227bcbf64eb980e26fffd716e3f3205ed4a7e17e6493 @@ -0,0 +1 @@ +{"architecture":"ppc64le","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:5517a5f16b947fafec2002881809a5798f6dea15680d3fcca1fb459f31f11aaf","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"6d3e77fdf98e3d063da72fbf9c00aa70eb24f8e34e702b9c7bcd20fb40c7bbab","container_config":{"Hostname":"6d3e77fdf98e","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:5517a5f16b947fafec2002881809a5798f6dea15680d3fcca1fb459f31f11aaf","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2023-03-13T16:29:40.50644322Z","docker_version":"20.10.23","history":[{"created":"2023-03-13T16:29:40.32077059Z","created_by":"/bin/sh -c #(nop) COPY file:3f80414426e41becdbb214f7a6d2e211f255be120a2409e43668203eafd069af in / "},{"created":"2023-03-13T16:29:40.50644322Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:fc37b056115d612a4d58475e5dc5532e12e8a179d9a5d548ef54ca79d8392471"]}} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/2a16e122fe466459770f0defde1b59cacc61d3e491c8473c2b0a4f15b4d2fdcb b/test/images/hello-world-cosign-manifest-list/blobs/sha256/2a16e122fe466459770f0defde1b59cacc61d3e491c8473c2b0a4f15b4d2fdcb new file mode 100644 index 0000000..fb4d3d3 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/2a16e122fe466459770f0defde1b59cacc61d3e491c8473c2b0a4f15b4d2fdcb @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":233,"digest":"sha256:a2d16425ea631d6254d948e176a92b4dc339add792996d06c83a53bea6898bbb"},"layers":[{"mediaType":"application/vnd.dev.cosign.simplesigning.v1+json","size":267,"digest":"sha256:60ff2fae9751401b312ee38acb44ab0ec116b28edd090a54db3e9d3071749b6a","annotations":{"dev.cosignproject.cosign/signature":"MEYCIQDbvQCllrlIVbSSfhV0G0orK1SU0oLcfbN5LdqdiDVuwAIhAIPB96X56Y9duSgxksDKLUje0/naDneCH5u6lxiOfP4g"}}]} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/2db29710123e3e53a794f2694094b9b4338aa9ee5c40b930cb8063a1be392c54 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/2db29710123e3e53a794f2694094b9b4338aa9ee5c40b930cb8063a1be392c54 new file mode 100644 index 0000000000000000000000000000000000000000..d3283db35c373e269c07bf4857751f6e28eb72a9 GIT binary patch literal 2479 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 literal 0 HcmV?d00001 diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/40d0cfd0861719208ff9f7747ab3f97844eeca509df705db44a736df863b76af b/test/images/hello-world-cosign-manifest-list/blobs/sha256/40d0cfd0861719208ff9f7747ab3f97844eeca509df705db44a736df863b76af new file mode 100644 index 0000000..c1258cb --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/40d0cfd0861719208ff9f7747ab3f97844eeca509df705db44a736df863b76af @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1483, + "digest": "sha256:7066d68bd2f224dbb7c3332da105b1dac81a75b47a869602096c27b6a75a525c" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 2993, + "digest": "sha256:04341b189be695acecd201a36cdf9dd99b8b0c338075000f555d5adf8e9c0547" + } + ] +} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/40ddc5646e05a17eeb7caae99c144d94d1afe3fd201368777ef2ce29750f5738 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/40ddc5646e05a17eeb7caae99c144d94d1afe3fd201368777ef2ce29750f5738 new file mode 100644 index 0000000..3405bf6 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/40ddc5646e05a17eeb7caae99c144d94d1afe3fd201368777ef2ce29750f5738 @@ -0,0 +1 @@ +{"critical":{"identity":{"docker-reference":"127.0.0.1:44949/hello-world-docker-v2-manifest-list"},"image":{"docker-manifest-digest":"sha256:c7b6944911848ce39b44ed660d95fb54d69bbd531de724c7ce6fc9f743c0b861"},"type":"cosign container image signature"},"optional":null} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/432f982638b3aefab73cc58ab28f5c16e96fdb504e8c134fc58dff4bae8bf338 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/432f982638b3aefab73cc58ab28f5c16e96fdb504e8c134fc58dff4bae8bf338 new file mode 100644 index 0000000..01e8098 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/432f982638b3aefab73cc58ab28f5c16e96fdb504e8c134fc58dff4bae8bf338 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1485, + "digest": "sha256:46331d942d6350436f64e614d75725f6de3bb5c63e266e236e04389820a234c4" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 3208, + "digest": "sha256:7050e35b49f5e348c4809f5eff915842962cb813f32062d3bbdd35c750dd7d01" + } + ] +} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/45ea150db157113f1e2946244c4d5d160f6708b4ee8731cda05ccd52b0fdac7b b/test/images/hello-world-cosign-manifest-list/blobs/sha256/45ea150db157113f1e2946244c4d5d160f6708b4ee8731cda05ccd52b0fdac7b new file mode 100644 index 0000000..36d3f75 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/45ea150db157113f1e2946244c4d5d160f6708b4ee8731cda05ccd52b0fdac7b @@ -0,0 +1 @@ +{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:02623e64de6f2252401a401a36d9e6db7d66a9c1d1bf134053d5c4c978b3376d"]},"config":{}} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/46331d942d6350436f64e614d75725f6de3bb5c63e266e236e04389820a234c4 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/46331d942d6350436f64e614d75725f6de3bb5c63e266e236e04389820a234c4 new file mode 100644 index 0000000..902a739 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/46331d942d6350436f64e614d75725f6de3bb5c63e266e236e04389820a234c4 @@ -0,0 +1 @@ +{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:cc0fff24c4ece63ade5d9f549e42c926cf569112c4f5c439a4a57f3f33f5588b","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"b2af51419cbf516f3c99b877a64906b21afedc175bd3cd082eb5798e2f277bb4","container_config":{"Hostname":"b2af51419cbf","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:cc0fff24c4ece63ade5d9f549e42c926cf569112c4f5c439a4a57f3f33f5588b","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2022-03-19T16:12:58.923371954Z","docker_version":"20.10.12","history":[{"created":"2022-03-19T16:12:58.834095198Z","created_by":"/bin/sh -c #(nop) COPY file:a79dd5bda1e77203401956a93401d3aef45221fc750295a4291896f3386f4f54 in / "},{"created":"2022-03-19T16:12:58.923371954Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:efb53921da3394806160641b72a2cbd34ca1a9a8345ac670a85a04ad3d0e3507"]},"variant":"v8"} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/4f923680062bbea891b21ccd6e561597e7b358abfdbf58167d6a8f2fcd035c0a b/test/images/hello-world-cosign-manifest-list/blobs/sha256/4f923680062bbea891b21ccd6e561597e7b358abfdbf58167d6a8f2fcd035c0a new file mode 100644 index 0000000..c84bfb7 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/4f923680062bbea891b21ccd6e561597e7b358abfdbf58167d6a8f2fcd035c0a @@ -0,0 +1 @@ +{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:e58c180ca4d73dc4b0a65122c4502dd8674c6fe0f904ca02509c2fdf24e137e4"]},"config":{}} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/5004e9d559e7a75f42249ddeca4d5764fa4db05592a7a9a641e4ac37cc619ba1 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/5004e9d559e7a75f42249ddeca4d5764fa4db05592a7a9a641e4ac37cc619ba1 new file mode 100644 index 0000000..1987fa5 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/5004e9d559e7a75f42249ddeca4d5764fa4db05592a7a9a641e4ac37cc619ba1 @@ -0,0 +1 @@ +{"architecture":"mips64le","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:3ac6f4925cd994f08d51e346a272c63b8de3d099bc9a3a315e6cd2aff40ac96a","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"013e92274db6f063cd47953240ec4997ad495d6ddb52cee9e2ad778895e2fdb7","container_config":{"Hostname":"013e92274db6","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:3ac6f4925cd994f08d51e346a272c63b8de3d099bc9a3a315e6cd2aff40ac96a","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2022-03-19T06:38:10.482068091Z","docker_version":"20.10.12","history":[{"created":"2022-03-19T06:38:09.022057705Z","created_by":"/bin/sh -c #(nop) COPY file:9acd5b5706455a6fe3d36fc638bf68bead9cf9f0ac938fc68ec9e669f0d2f8c7 in / "},{"created":"2022-03-19T06:38:10.482068091Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:1de14bf941d802d2269f86583945dd7fc38005dcf92b4f2a69737d1e325c0e3d"]}} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/54971af28fe60a8c72e395d92eab0451cf7ceece9cfe3650e4d4844243b2b24d b/test/images/hello-world-cosign-manifest-list/blobs/sha256/54971af28fe60a8c72e395d92eab0451cf7ceece9cfe3650e4d4844243b2b24d new file mode 100644 index 0000000000000000000000000000000000000000..a661124727cd08cd295c764bc93a22158926ce7e GIT binary patch literal 3929 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 A+yDRo literal 0 HcmV?d00001 diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/6569af6e782a5c31546c763f138b327cf641e4d537fc9bc453f52b46f19ec3ff b/test/images/hello-world-cosign-manifest-list/blobs/sha256/6569af6e782a5c31546c763f138b327cf641e4d537fc9bc453f52b46f19ec3ff new file mode 100644 index 0000000..7e2056e --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/6569af6e782a5c31546c763f138b327cf641e4d537fc9bc453f52b46f19ec3ff @@ -0,0 +1 @@ +{"critical":{"identity":{"docker-reference":"127.0.0.1:44949/hello-world-docker-v2-manifest-list"},"image":{"docker-manifest-digest":"sha256:98c9722322be649df94780d3fbe594fce7996234b259f27eac9428b84050c849"},"type":"cosign container image signature"},"optional":null} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/7050e35b49f5e348c4809f5eff915842962cb813f32062d3bbdd35c750dd7d01 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/7050e35b49f5e348c4809f5eff915842962cb813f32062d3bbdd35c750dd7d01 new file mode 100644 index 0000000000000000000000000000000000000000..c93dccfd3e0eb48bb9933945112e1143c805bfe7 GIT binary patch literal 3208 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 literal 0 HcmV?d00001 diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/897d8fbdf18b7e2eec4a53f4e1c60605cfe75000be6e7c2e1455490414829767 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/897d8fbdf18b7e2eec4a53f4e1c60605cfe75000be6e7c2e1455490414829767 new file mode 100644 index 0000000..6fd8586 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/897d8fbdf18b7e2eec4a53f4e1c60605cfe75000be6e7c2e1455490414829767 @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":233,"digest":"sha256:155c39610faa3bae95d5bd0435194b1ae66c861c2aca8a7692e752e9acfaa696"},"layers":[{"mediaType":"application/vnd.dev.cosign.simplesigning.v1+json","size":267,"digest":"sha256:6569af6e782a5c31546c763f138b327cf641e4d537fc9bc453f52b46f19ec3ff","annotations":{"dev.cosignproject.cosign/signature":"MEQCIBb2bbJKoGuUJ/hQM0URJWwP63hnqJSG4JMyXZ/CbDelAiAdPaCXZRwqFAQIdCd3EMPIBg/gMJbIw8/lOOZrpA9cxA=="}}]} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/89815ad2fbca952d269f07f5dae3b03673cfea2d83b4c4582af8e47904d717fa b/test/images/hello-world-cosign-manifest-list/blobs/sha256/89815ad2fbca952d269f07f5dae3b03673cfea2d83b4c4582af8e47904d717fa new file mode 100644 index 0000000..1c67209 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/89815ad2fbca952d269f07f5dae3b03673cfea2d83b4c4582af8e47904d717fa @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":233,"digest":"sha256:61941acdb959d25d7ad28f9483e9310f087c8f93d8d85d82be6883321b72f60b"},"layers":[{"mediaType":"application/vnd.dev.cosign.simplesigning.v1+json","size":267,"digest":"sha256:40ddc5646e05a17eeb7caae99c144d94d1afe3fd201368777ef2ce29750f5738","annotations":{"dev.cosignproject.cosign/signature":"MEYCIQC7H0GxMqGJQTB3wzJH5fAlmjeg6v+a8SHRqKSLn2SrfgIhAOse16BZezpj9r//XVqp5D1Ua4t5RhAfIKke14oUngX5"}}]} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/8ff188302c77050dcb64e08302f36c0a9f8133d36325d859a3023a97eff16879 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/8ff188302c77050dcb64e08302f36c0a9f8133d36325d859a3023a97eff16879 new file mode 100644 index 0000000..47c36ba --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/8ff188302c77050dcb64e08302f36c0a9f8133d36325d859a3023a97eff16879 @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":233,"digest":"sha256:781ea9e9358a3d6307205054d8fb0c6bd6e104d6e01b98adfebc1235173b94ec"},"layers":[{"mediaType":"application/vnd.dev.cosign.simplesigning.v1+json","size":267,"digest":"sha256:f30a18a9413fc29432347c81fc8ce7a3e8b28f9580a4cf1ea738c5525f0977f1","annotations":{"dev.cosignproject.cosign/signature":"MEUCIQDEIOsnKrIAUAUB29hOGgOuQNzqsL2nMuJNJ4QcM3QbFQIgConva6Hn1fW8bnkeLVMQDFsDvwmHTnOpRHPt612S7Y0="}}]} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/958d0aa20c81ae813ef2ab5e8fea684ea95e4de11b6893ea50201bd6c8dfc3c3 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/958d0aa20c81ae813ef2ab5e8fea684ea95e4de11b6893ea50201bd6c8dfc3c3 new file mode 100644 index 0000000..bf93c7f --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/958d0aa20c81ae813ef2ab5e8fea684ea95e4de11b6893ea50201bd6c8dfc3c3 @@ -0,0 +1 @@ +{"critical":{"identity":{"docker-reference":"127.0.0.1:44949/hello-world-docker-v2-manifest-list"},"image":{"docker-manifest-digest":"sha256:40d0cfd0861719208ff9f7747ab3f97844eeca509df705db44a736df863b76af"},"type":"cosign container image signature"},"optional":null} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/97576b63fdca9f120886ae2a8dfab33089ccb778686ed6ce0c4e666d348402a9 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/97576b63fdca9f120886ae2a8dfab33089ccb778686ed6ce0c4e666d348402a9 new file mode 100644 index 0000000..e0eb648 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/97576b63fdca9f120886ae2a8dfab33089ccb778686ed6ce0c4e666d348402a9 @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":233,"digest":"sha256:fa552c1bfe5aa7859652795d78c358ae2816b527092acb225c31d08c88fba58b"},"layers":[{"mediaType":"application/vnd.dev.cosign.simplesigning.v1+json","size":267,"digest":"sha256:fe0a7ee955986c6c86f05e52af8e1f701795c3862e3760d4421f468b2f0e082a","annotations":{"dev.cosignproject.cosign/signature":"MEUCIQDfBt/oR+IMoGTpzzh+bQ/fhU1RwQoRxVRUtVaCYJnT7AIgQ2PUqhDEtdoEArLociduB3p98zGKjepL3h8bgc/i6Mg="}}]} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/98c9722322be649df94780d3fbe594fce7996234b259f27eac9428b84050c849 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/98c9722322be649df94780d3fbe594fce7996234b259f27eac9428b84050c849 new file mode 100644 index 0000000..c1151d4 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/98c9722322be649df94780d3fbe594fce7996234b259f27eac9428b84050c849 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1471, + "digest": "sha256:b3593dab05491cdf5ee88c29bee36603c0df0bc34798eed5067f6e1335a9d391" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 3000, + "digest": "sha256:3caa6dc69d0b73f21d29bfa75356395f2695a7abad34f010656740e90ddce399" + } + ] +} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/995efde2e81b21d1ea7066aa77a59298a62a9e9fbb4b77f36c189774ec9b1089 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/995efde2e81b21d1ea7066aa77a59298a62a9e9fbb4b77f36c189774ec9b1089 new file mode 100644 index 0000000..015ffd5 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/995efde2e81b21d1ea7066aa77a59298a62a9e9fbb4b77f36c189774ec9b1089 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1468, + "digest": "sha256:36d89aa75357c8f99e359f8cabc0aae667d47d8f25ed51cbe66e148e3a77e19c" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 2736, + "digest": "sha256:7f0d4fad461d1ac69488092b5914b5ec642133c0fb884539045de33fbcd2eadb" + } + ] +} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/9a8c4a3156d3d8662e57276d274ebf2925db16611d707465beb0fb4032f73048 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/9a8c4a3156d3d8662e57276d274ebf2925db16611d707465beb0fb4032f73048 new file mode 100644 index 0000000..6839b51 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/9a8c4a3156d3d8662e57276d274ebf2925db16611d707465beb0fb4032f73048 @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":233,"digest":"sha256:3374ed2b382445f1a06cf49cfb0e9322acb1a48c318620b89c9ae5e233d416b7"},"layers":[{"mediaType":"application/vnd.dev.cosign.simplesigning.v1+json","size":267,"digest":"sha256:958d0aa20c81ae813ef2ab5e8fea684ea95e4de11b6893ea50201bd6c8dfc3c3","annotations":{"dev.cosignproject.cosign/signature":"MEQCIErQTn+B1nAZTNI21UvQruf8qNrChJ2KNXXMN9U/xYrLAiAwK/t/nDg+H3Lo5py5PrnNJrxtAsj63bhqgyypOLclyw=="}}]} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/a2d16425ea631d6254d948e176a92b4dc339add792996d06c83a53bea6898bbb b/test/images/hello-world-cosign-manifest-list/blobs/sha256/a2d16425ea631d6254d948e176a92b4dc339add792996d06c83a53bea6898bbb new file mode 100644 index 0000000..e452239 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/a2d16425ea631d6254d948e176a92b4dc339add792996d06c83a53bea6898bbb @@ -0,0 +1 @@ +{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:60ff2fae9751401b312ee38acb44ab0ec116b28edd090a54db3e9d3071749b6a"]},"config":{}} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/abc70fcc95b2f52b325d69cc5c259dd9babb40a9df152e88b286fada1d3248bd b/test/images/hello-world-cosign-manifest-list/blobs/sha256/abc70fcc95b2f52b325d69cc5c259dd9babb40a9df152e88b286fada1d3248bd new file mode 100644 index 0000000000000000000000000000000000000000..4401b5648d6bdace3fbf78c96e835d6360a07190 GIT binary patch literal 3276 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 literal 0 HcmV?d00001 diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/b3593dab05491cdf5ee88c29bee36603c0df0bc34798eed5067f6e1335a9d391 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/b3593dab05491cdf5ee88c29bee36603c0df0bc34798eed5067f6e1335a9d391 new file mode 100644 index 0000000..6c4d8ca --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/b3593dab05491cdf5ee88c29bee36603c0df0bc34798eed5067f6e1335a9d391 @@ -0,0 +1 @@ +{"architecture":"riscv64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:1068f8c97468e4ea831a16a1b77bf6bb02523b9014d66292195dda5002f3b49f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"44669466789c281844b427902cdf085bfb58bbb46fdbfe99a825db2a309364e4","container_config":{"Hostname":"44669466789c","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:1068f8c97468e4ea831a16a1b77bf6bb02523b9014d66292195dda5002f3b49f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2021-09-23T21:24:50.101692955Z","docker_version":"20.10.7","history":[{"created":"2021-09-23T21:24:49.655520257Z","created_by":"/bin/sh -c #(nop) COPY file:84444ad88bd7fb1ac993a256408f10ce0befd4338385371c4b1943d8b219e0b4 in / "},{"created":"2021-09-23T21:24:50.101692955Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:86d357c4e1f53247f3338e8ec2d66987ff8fcd3e37f2d52fde187a15fa0671e7"]}} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/b61d5036614f79e5610341829b1cb96b55a1ce7060e4bdc57ac196d93b2dee63 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/b61d5036614f79e5610341829b1cb96b55a1ce7060e4bdc57ac196d93b2dee63 new file mode 100644 index 0000000..4f4bbd7 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/b61d5036614f79e5610341829b1cb96b55a1ce7060e4bdc57ac196d93b2dee63 @@ -0,0 +1 @@ +{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:bf4cb7b5c44789f31a104b99ae53cf38992f33e084dd97b132957c5101e643ec"]},"config":{}} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/bbc6052697e5fdcd1b311e0b3f65189ffbe354cf8ae97e7a55d588e855097174 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/bbc6052697e5fdcd1b311e0b3f65189ffbe354cf8ae97e7a55d588e855097174 new file mode 100644 index 0000000000000000000000000000000000000000..d75a9768807c4a0464b7a2df2ecb09cdeb3240b7 GIT binary patch literal 4092 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 literal 0 HcmV?d00001 diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/bf4cb7b5c44789f31a104b99ae53cf38992f33e084dd97b132957c5101e643ec b/test/images/hello-world-cosign-manifest-list/blobs/sha256/bf4cb7b5c44789f31a104b99ae53cf38992f33e084dd97b132957c5101e643ec new file mode 100644 index 0000000..2640aae --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/bf4cb7b5c44789f31a104b99ae53cf38992f33e084dd97b132957c5101e643ec @@ -0,0 +1 @@ +{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL2Nvc2lnbi5zaWdzdG9yZS5kZXYvYXR0ZXN0YXRpb24vdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoiMTI3LjAuMC4xOjQ0OTQ5L2hlbGxvLXdvcmxkLWRvY2tlci12Mi1tYW5pZmVzdC1saXN0IiwiZGlnZXN0Ijp7InNoYTI1NiI6IjAwZTFlZTdjODk4YTJjMzkzZWEyZmU3NjgwOTM4ZjhkY2JlNTVlNTFmYmYwODAzMmNmMzczMjZhNjc3ZjkyZWQifX1dLCJwcmVkaWNhdGUiOnsiRGF0YSI6IntcbiAgICBcIm5hbWVcIjogXCJwYW5vcGxpYS10ZXN0XCJcbn1cbiIsIlRpbWVzdGFtcCI6IjIwMjQtMTAtMDlUMTM6Mjc6MTNaIn19","signatures":[{"keyid":"","sig":"MEUCIQCow5xHixfbQVMyBxl12/JJ5WBSxEsE6I+YZT/Q9CyOWQIgJYKSX7TX+LiWuD/xj9PPnaBP/TrZyC3f25p+XwlkYqU="}]} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/c7b6944911848ce39b44ed660d95fb54d69bbd531de724c7ce6fc9f743c0b861 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/c7b6944911848ce39b44ed660d95fb54d69bbd531de724c7ce6fc9f743c0b861 new file mode 100644 index 0000000..b7cc82d --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/c7b6944911848ce39b44ed660d95fb54d69bbd531de724c7ce6fc9f743c0b861 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1469, + "digest": "sha256:df5477cea5582b0ae6a31de2d1c9bbacb506091f42a3b0fe77a209006f409fd8" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 3276, + "digest": "sha256:abc70fcc95b2f52b325d69cc5c259dd9babb40a9df152e88b286fada1d3248bd" + } + ] +} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/dc285da8291208f50dced509a66c9673d6e4aea18e2d387d9c5fda634415dfc9 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/dc285da8291208f50dced509a66c9673d6e4aea18e2d387d9c5fda634415dfc9 new file mode 100644 index 0000000..e8e44c8 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/dc285da8291208f50dced509a66c9673d6e4aea18e2d387d9c5fda634415dfc9 @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":233,"digest":"sha256:04d584bf278d95c3bdf6aebdadd9ee552e8c9b35d60e8f1247bd9ee0260313e1"},"layers":[{"mediaType":"application/vnd.dev.cosign.simplesigning.v1+json","size":267,"digest":"sha256:f85bca573013bd8d0ecb52d851dcf98581f35d46c64aa049558a04dc5e4401fe","annotations":{"dev.cosignproject.cosign/signature":"MEQCIGwHmZEWB1MBs9BJqDa6douGq4ZVT5lGJBmGYgI8CH7IAiBLKq7MZk49XlZWczz0qN0zuDuETbCxSMTolASePTOjNA=="}}]} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/df5477cea5582b0ae6a31de2d1c9bbacb506091f42a3b0fe77a209006f409fd8 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/df5477cea5582b0ae6a31de2d1c9bbacb506091f42a3b0fe77a209006f409fd8 new file mode 100644 index 0000000..227d37b --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/df5477cea5582b0ae6a31de2d1c9bbacb506091f42a3b0fe77a209006f409fd8 @@ -0,0 +1 @@ +{"architecture":"s390x","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:214c20be6ceaa7b24f8fa966550831a7f608c00cbb3408ac8f6171a222cacb14","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"f7ac7ed191763ba1d368b5b35d668adf6aad7ffabdea048634935eb900450c2e","container_config":{"Hostname":"f7ac7ed19176","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:214c20be6ceaa7b24f8fa966550831a7f608c00cbb3408ac8f6171a222cacb14","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2021-09-23T22:39:54.089350115Z","docker_version":"20.10.7","history":[{"created":"2021-09-23T22:39:53.962038173Z","created_by":"/bin/sh -c #(nop) COPY file:600d8ab1c71de7b59c96ed558afbed478d81ebf3ef7517c4c4f3757cc136475f in / "},{"created":"2021-09-23T22:39:54.089350115Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:9731f28beed099abd643f17ffb5aceea4cd916affaacc79261a98b9ddddd4a36"]}} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/e58c180ca4d73dc4b0a65122c4502dd8674c6fe0f904ca02509c2fdf24e137e4 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/e58c180ca4d73dc4b0a65122c4502dd8674c6fe0f904ca02509c2fdf24e137e4 new file mode 100644 index 0000000..bdee112 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/e58c180ca4d73dc4b0a65122c4502dd8674c6fe0f904ca02509c2fdf24e137e4 @@ -0,0 +1 @@ +{"critical":{"identity":{"docker-reference":"127.0.0.1:44949/hello-world-docker-v2-manifest-list"},"image":{"docker-manifest-digest":"sha256:f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4"},"type":"cosign container image signature"},"optional":null} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/eb11b1a194ff8e236a01eff392c4e1296a53b0fb4780d8b0382f7996a15d5392 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/eb11b1a194ff8e236a01eff392c4e1296a53b0fb4780d8b0382f7996a15d5392 new file mode 100644 index 0000000..fb59d4b --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/eb11b1a194ff8e236a01eff392c4e1296a53b0fb4780d8b0382f7996a15d5392 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1473, + "digest": "sha256:5004e9d559e7a75f42249ddeca4d5764fa4db05592a7a9a641e4ac37cc619ba1" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 4092, + "digest": "sha256:bbc6052697e5fdcd1b311e0b3f65189ffbe354cf8ae97e7a55d588e855097174" + } + ] +} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/f30a18a9413fc29432347c81fc8ce7a3e8b28f9580a4cf1ea738c5525f0977f1 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/f30a18a9413fc29432347c81fc8ce7a3e8b28f9580a4cf1ea738c5525f0977f1 new file mode 100644 index 0000000..03ae8c7 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/f30a18a9413fc29432347c81fc8ce7a3e8b28f9580a4cf1ea738c5525f0977f1 @@ -0,0 +1 @@ +{"critical":{"identity":{"docker-reference":"127.0.0.1:44949/hello-world-docker-v2-manifest-list"},"image":{"docker-manifest-digest":"sha256:6253ef1af25aabd67777a01c686e7c69ee612961db34c8b90da079e5473be83b"},"type":"cosign container image signature"},"optional":null} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4 new file mode 100644 index 0000000..10e6c84 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1469, + "digest": "sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 2479, + "digest": "sha256:2db29710123e3e53a794f2694094b9b4338aa9ee5c40b930cb8063a1be392c54" + } + ] +} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/f85bca573013bd8d0ecb52d851dcf98581f35d46c64aa049558a04dc5e4401fe b/test/images/hello-world-cosign-manifest-list/blobs/sha256/f85bca573013bd8d0ecb52d851dcf98581f35d46c64aa049558a04dc5e4401fe new file mode 100644 index 0000000..2659073 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/f85bca573013bd8d0ecb52d851dcf98581f35d46c64aa049558a04dc5e4401fe @@ -0,0 +1 @@ +{"critical":{"identity":{"docker-reference":"127.0.0.1:44949/hello-world-docker-v2-manifest-list"},"image":{"docker-manifest-digest":"sha256:995efde2e81b21d1ea7066aa77a59298a62a9e9fbb4b77f36c189774ec9b1089"},"type":"cosign container image signature"},"optional":null} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/fa552c1bfe5aa7859652795d78c358ae2816b527092acb225c31d08c88fba58b b/test/images/hello-world-cosign-manifest-list/blobs/sha256/fa552c1bfe5aa7859652795d78c358ae2816b527092acb225c31d08c88fba58b new file mode 100644 index 0000000..621a869 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/fa552c1bfe5aa7859652795d78c358ae2816b527092acb225c31d08c88fba58b @@ -0,0 +1 @@ +{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:fe0a7ee955986c6c86f05e52af8e1f701795c3862e3760d4421f468b2f0e082a"]},"config":{}} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/fa9dfc3e3e2a35077691b46087565b3433a7447f3eff39b96cdbbcbb568db94b b/test/images/hello-world-cosign-manifest-list/blobs/sha256/fa9dfc3e3e2a35077691b46087565b3433a7447f3eff39b96cdbbcbb568db94b new file mode 100644 index 0000000..72fffce --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/fa9dfc3e3e2a35077691b46087565b3433a7447f3eff39b96cdbbcbb568db94b @@ -0,0 +1 @@ +{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:0473adddc4b4a6b8456d5077fa12d08de36239e713c704fa0151abffb1bb0126"]},"config":{}} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/fe0a7ee955986c6c86f05e52af8e1f701795c3862e3760d4421f468b2f0e082a b/test/images/hello-world-cosign-manifest-list/blobs/sha256/fe0a7ee955986c6c86f05e52af8e1f701795c3862e3760d4421f468b2f0e082a new file mode 100644 index 0000000..ab9a8a1 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/fe0a7ee955986c6c86f05e52af8e1f701795c3862e3760d4421f468b2f0e082a @@ -0,0 +1 @@ +{"critical":{"identity":{"docker-reference":"127.0.0.1:44949/hello-world-docker-v2-manifest-list"},"image":{"docker-manifest-digest":"sha256:eb11b1a194ff8e236a01eff392c4e1296a53b0fb4780d8b0382f7996a15d5392"},"type":"cosign container image signature"},"optional":null} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/blobs/sha256/feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412 b/test/images/hello-world-cosign-manifest-list/blobs/sha256/feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412 new file mode 100644 index 0000000..b85269e --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/blobs/sha256/feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412 @@ -0,0 +1 @@ +{"architecture":"amd64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:b9935d4e8431fb1a7f0989304ec86b3329a99a25f5efdc7f09f3f8c41434ca6d","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"8746661ca3c2f215da94e6d3f7dfdcafaff5ec0b21c9aff6af3dc379a82fbc72","container_config":{"Hostname":"8746661ca3c2","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:b9935d4e8431fb1a7f0989304ec86b3329a99a25f5efdc7f09f3f8c41434ca6d","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2021-09-23T23:47:57.442225064Z","docker_version":"20.10.7","history":[{"created":"2021-09-23T23:47:57.098990892Z","created_by":"/bin/sh -c #(nop) COPY file:50563a97010fd7ce1ceebd1fa4f4891ac3decdf428333fb2683696f4358af6c2 in / "},{"created":"2021-09-23T23:47:57.442225064Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:e07ee1baac5fae6a26f30cabfe54a36d3402f96afda318fe0a96cec4ca393359"]}} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/index.json b/test/images/hello-world-cosign-manifest-list/index.json new file mode 100755 index 0000000..a0597ac --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/index.json @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.index.v1+json","manifests":[{"mediaType":"application/vnd.docker.distribution.manifest.list.v2+json","size":2069,"digest":"sha256:00e1ee7c898a2c393ea2fe7680938f8dcbe55e51fbf08032cf37326a677f92ed"},{"mediaType":"application/vnd.oci.image.manifest.v1+json","size":512,"digest":"sha256:165760e771f0d295a89c06ad50659133315b485ac68647119775b37578eaf629","annotations":{"org.opencontainers.image.ref.name":"_cosign:sha256-00e1ee7c898a2c393ea2fe7680938f8dcbe55e51fbf08032cf37326a677f92ed.att"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","size":558,"digest":"sha256:1e4c6e59fe9ed668252140571494bb844e424bb48c2eceefed73434eb9a84dc3","annotations":{"org.opencontainers.image.ref.name":"_cosign:sha256-00e1ee7c898a2c393ea2fe7680938f8dcbe55e51fbf08032cf37326a677f92ed.sig"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","size":558,"digest":"sha256:2a16e122fe466459770f0defde1b59cacc61d3e491c8473c2b0a4f15b4d2fdcb","annotations":{"org.opencontainers.image.ref.name":"_cosign:sha256-3209b9aec056b296ea55b2af7757d078bf92e55a3ea29c5fdef5c785bcef09c4.sig"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","size":558,"digest":"sha256:9a8c4a3156d3d8662e57276d274ebf2925db16611d707465beb0fb4032f73048","annotations":{"org.opencontainers.image.ref.name":"_cosign:sha256-40d0cfd0861719208ff9f7747ab3f97844eeca509df705db44a736df863b76af.sig"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","size":558,"digest":"sha256:3154f2b2183d33ec662331279255455bf3f61f2a95fcd17427eb858953422620","annotations":{"org.opencontainers.image.ref.name":"_cosign:sha256-432f982638b3aefab73cc58ab28f5c16e96fdb504e8c134fc58dff4bae8bf338.sig"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","size":558,"digest":"sha256:8ff188302c77050dcb64e08302f36c0a9f8133d36325d859a3023a97eff16879","annotations":{"org.opencontainers.image.ref.name":"_cosign:sha256-6253ef1af25aabd67777a01c686e7c69ee612961db34c8b90da079e5473be83b.sig"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","size":558,"digest":"sha256:897d8fbdf18b7e2eec4a53f4e1c60605cfe75000be6e7c2e1455490414829767","annotations":{"org.opencontainers.image.ref.name":"_cosign:sha256-98c9722322be649df94780d3fbe594fce7996234b259f27eac9428b84050c849.sig"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","size":558,"digest":"sha256:dc285da8291208f50dced509a66c9673d6e4aea18e2d387d9c5fda634415dfc9","annotations":{"org.opencontainers.image.ref.name":"_cosign:sha256-995efde2e81b21d1ea7066aa77a59298a62a9e9fbb4b77f36c189774ec9b1089.sig"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","size":558,"digest":"sha256:89815ad2fbca952d269f07f5dae3b03673cfea2d83b4c4582af8e47904d717fa","annotations":{"org.opencontainers.image.ref.name":"_cosign:sha256-c7b6944911848ce39b44ed660d95fb54d69bbd531de724c7ce6fc9f743c0b861.sig"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","size":558,"digest":"sha256:97576b63fdca9f120886ae2a8dfab33089ccb778686ed6ce0c4e666d348402a9","annotations":{"org.opencontainers.image.ref.name":"_cosign:sha256-eb11b1a194ff8e236a01eff392c4e1296a53b0fb4780d8b0382f7996a15d5392.sig"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","size":558,"digest":"sha256:16692a792468762200c57d0aa0cbe380ccf2b16a23a00543dd69bd8fb1dc4fae","annotations":{"org.opencontainers.image.ref.name":"_cosign:sha256-f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4.sig"}}]} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest-list/oci-layout b/test/images/hello-world-cosign-manifest-list/oci-layout new file mode 100755 index 0000000..224a869 --- /dev/null +++ b/test/images/hello-world-cosign-manifest-list/oci-layout @@ -0,0 +1,3 @@ +{ + "imageLayoutVersion": "1.0.0" +} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest/blobs/sha256/432f982638b3aefab73cc58ab28f5c16e96fdb504e8c134fc58dff4bae8bf338 b/test/images/hello-world-cosign-manifest/blobs/sha256/432f982638b3aefab73cc58ab28f5c16e96fdb504e8c134fc58dff4bae8bf338 new file mode 100644 index 0000000..01e8098 --- /dev/null +++ b/test/images/hello-world-cosign-manifest/blobs/sha256/432f982638b3aefab73cc58ab28f5c16e96fdb504e8c134fc58dff4bae8bf338 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1485, + "digest": "sha256:46331d942d6350436f64e614d75725f6de3bb5c63e266e236e04389820a234c4" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 3208, + "digest": "sha256:7050e35b49f5e348c4809f5eff915842962cb813f32062d3bbdd35c750dd7d01" + } + ] +} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest/blobs/sha256/46331d942d6350436f64e614d75725f6de3bb5c63e266e236e04389820a234c4 b/test/images/hello-world-cosign-manifest/blobs/sha256/46331d942d6350436f64e614d75725f6de3bb5c63e266e236e04389820a234c4 new file mode 100644 index 0000000..902a739 --- /dev/null +++ b/test/images/hello-world-cosign-manifest/blobs/sha256/46331d942d6350436f64e614d75725f6de3bb5c63e266e236e04389820a234c4 @@ -0,0 +1 @@ +{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:cc0fff24c4ece63ade5d9f549e42c926cf569112c4f5c439a4a57f3f33f5588b","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"b2af51419cbf516f3c99b877a64906b21afedc175bd3cd082eb5798e2f277bb4","container_config":{"Hostname":"b2af51419cbf","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:cc0fff24c4ece63ade5d9f549e42c926cf569112c4f5c439a4a57f3f33f5588b","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2022-03-19T16:12:58.923371954Z","docker_version":"20.10.12","history":[{"created":"2022-03-19T16:12:58.834095198Z","created_by":"/bin/sh -c #(nop) COPY file:a79dd5bda1e77203401956a93401d3aef45221fc750295a4291896f3386f4f54 in / "},{"created":"2022-03-19T16:12:58.923371954Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:efb53921da3394806160641b72a2cbd34ca1a9a8345ac670a85a04ad3d0e3507"]},"variant":"v8"} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest/blobs/sha256/51a5ebe9c08828b74e4c6b65c2398591df2288eacbe411bc97a9e39ef104b99a b/test/images/hello-world-cosign-manifest/blobs/sha256/51a5ebe9c08828b74e4c6b65c2398591df2288eacbe411bc97a9e39ef104b99a new file mode 100644 index 0000000..900958a --- /dev/null +++ b/test/images/hello-world-cosign-manifest/blobs/sha256/51a5ebe9c08828b74e4c6b65c2398591df2288eacbe411bc97a9e39ef104b99a @@ -0,0 +1 @@ +{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL2Nvc2lnbi5zaWdzdG9yZS5kZXYvYXR0ZXN0YXRpb24vdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoiMTI3LjAuMC4xOjM5NzAzL2hlbGxvLXdvcmxkLWRvY2tlci12Mi1tYW5pZmVzdCIsImRpZ2VzdCI6eyJzaGEyNTYiOiI0MzJmOTgyNjM4YjNhZWZhYjczY2M1OGFiMjhmNWMxNmU5NmZkYjUwNGU4YzEzNGZjNThkZmY0YmFlOGJmMzM4In19XSwicHJlZGljYXRlIjp7IkRhdGEiOiJ7XG4gICAgXCJuYW1lXCI6IFwicGFub3BsaWEtdGVzdFwiXG59XG4iLCJUaW1lc3RhbXAiOiIyMDI0LTEwLTA5VDEzOjI3OjEyWiJ9fQ==","signatures":[{"keyid":"","sig":"MEUCIE/hcHIYmayaoQreqa83ZazMWm1fj0o4G0g+Au7pJXUUAiEAhpsDoQg9MQeD6tifuEGoJGernxBLmXdwgFIllTXheiw="}]} \ No newline at end of file diff --git a/test/images/hello-world-cosign-manifest/blobs/sha256/7050e35b49f5e348c4809f5eff915842962cb813f32062d3bbdd35c750dd7d01 b/test/images/hello-world-cosign-manifest/blobs/sha256/7050e35b49f5e348c4809f5eff915842962cb813f32062d3bbdd35c750dd7d01 new file mode 100644 index 0000000000000000000000000000000000000000..c93dccfd3e0eb48bb9933945112e1143c805bfe7 GIT binary patch literal 3208 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