diff --git a/docs/reference/buildx_imagetools_inspect.md b/docs/reference/buildx_imagetools_inspect.md index 82555b49..df51cbda 100644 --- a/docs/reference/buildx_imagetools_inspect.md +++ b/docs/reference/buildx_imagetools_inspect.md @@ -72,7 +72,6 @@ unset. Following fields are available: * `.Name`: provides the reference of the image * `.Manifest`: provides the manifest or manifest list * `.Image`: provides the image config -* `.BuildInfo`: provides [build info from image config](https://github.com/moby/buildkit/blob/master/docs/build-repro.md#image-config) #### `.Name` @@ -122,39 +121,6 @@ Manifests: Platform: linux/riscv64 ``` -#### `.BuildInfo` - -```console -$ docker buildx imagetools inspect crazymax/buildx:buildinfo --format "{{.BuildInfo}}" -Name: docker.io/crazymax/buildx:buildinfo -Frontend: dockerfile.v0 -Attrs: - filename: Dockerfile - source: docker/dockerfile-upstream:master-labs - build-arg:bar: foo - build-arg:foo: bar -Sources: - Type: docker-image - Ref: docker.io/docker/buildx-bin:0.6.1@sha256:a652ced4a4141977c7daaed0a074dcd9844a78d7d2615465b12f433ae6dd29f0 - Pin: sha256:a652ced4a4141977c7daaed0a074dcd9844a78d7d2615465b12f433ae6dd29f0 - - Type: docker-image - Ref: docker.io/library/alpine:3.13 - Pin: sha256:026f721af4cf2843e07bba648e158fb35ecc876d822130633cc49f707f0fc88c - - Type: docker-image - Ref: docker.io/moby/buildkit:v0.9.0 - Pin: sha256:8dc668e7f66db1c044aadbed306020743516a94848793e0f81f94a087ee78cab - - Type: docker-image - Ref: docker.io/tonistiigi/xx@sha256:21a61be4744f6531cb5f33b0e6f40ede41fa3a1b8c82d5946178f80cc84bfc04 - Pin: sha256:21a61be4744f6531cb5f33b0e6f40ede41fa3a1b8c82d5946178f80cc84bfc04 - - Type: http - Ref: https://raw.githubusercontent.com/moby/moby/master/README.md - Pin: sha256:419455202b0ef97e480d7f8199b26a721a417818bc0e2d106975f74323f25e6c -``` - #### JSON output A `json` go template func is also available if you want to render fields as @@ -166,7 +132,7 @@ $ docker buildx imagetools inspect crazymax/loop --format "{{json .Manifest}}" ```json { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:08602e7340970e92bde5e0a2e887c1fde4d9ae753d1e05efb4c8ef3b609f97f1", + "digest": "sha256:a9ca35b798e0b198f9be7f3b8b53982e9a6cf96814cb10d78083f40ad8c127f1", "size": 949 } ``` @@ -177,23 +143,23 @@ $ docker buildx imagetools inspect moby/buildkit:master --format "{{json .Manife ```json { "schemaVersion": 2, - "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", - "digest": "sha256:79d97f205e2799d99a3a8ae2a1ef17acb331e11784262c3faada847dc6972c52", - "size": 2010, + "mediaType": "application/vnd.oci.image.index.v1+json", + "digest": "sha256:d895e8fdcf5e2bb39acb5966f97fc4cd87a2d13d27c939c320025eb4aca5440c", + "size": 4654, "manifests": [ { - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:bd1e78f06de26610fadf4eb9d04b1a45a545799d6342701726e952cc0c11c912", - "size": 1158, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:ac9dd4fbec9e36b562f910618975a2936533f8e411a3fea2858aacc0ac972e1c", + "size": 1054, "platform": { "architecture": "amd64", "os": "linux" } }, { - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:d37dcced63ec0965824fca644f0ac9efad8569434ec15b4c83adfcb3dcfc743b", - "size": 1158, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:0f4dc6797db467372cbf52c7236816203654a839f64a6542c9135d1973c9d744", + "size": 1054, "platform": { "architecture": "arm", "os": "linux", @@ -201,260 +167,404 @@ $ docker buildx imagetools inspect moby/buildkit:master --format "{{json .Manife } }, { - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:ce142eb2255e6af46f2809e159fd03081697c7605a3de03b9cbe9a52ddb244bf", - "size": 1158, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:d62bb533d95afe17c4a9caf1e7c57a3b0a7a67409ccfa7af947aeb0f670ffb87", + "size": 1054, "platform": { "architecture": "arm64", "os": "linux" } }, { - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:f59bfb5062fff76ce464bfa4e25ebaaaac887d6818238e119d68613c456d360c", - "size": 1158, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:b4944057e0c68203cdcc3dceff3b2df3c7d9e3dd801724fa977b01081da7771e", + "size": 1054, "platform": { "architecture": "s390x", "os": "linux" } }, { - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:cc96426e0c50a78105d5637d31356db5dd6ec594f21b24276e534a32da09645c", - "size": 1159, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:825702a51eb4234904fc9253d8b0bf0a584787ffd8fc3fd6fa374188233ce399", + "size": 1054, "platform": { "architecture": "ppc64le", "os": "linux" } }, { - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:39f9c1e2878e6c333acb23187d6b205ce82ed934c60da326cb2c698192631478", - "size": 1158, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:dfb27c6acc9b9f3a7c9d47366d137089565062f43c8063c9f5e408d34c87ee4a", + "size": 1054, "platform": { "architecture": "riscv64", "os": "linux" } - } - ] -} -``` - -```console -$ docker buildx imagetools inspect crazymax/buildx:buildinfo --format "{{json .BuildInfo}}" -``` -```json -{ - "frontend": "dockerfile.v0", - "attrs": { - "build-arg:bar": "foo", - "build-arg:foo": "bar", - "filename": "Dockerfile", - "source": "crazymax/dockerfile:buildattrs" - }, - "sources": [ + }, { - "type": "docker-image", - "ref": "docker.io/docker/buildx-bin:0.6.1@sha256:a652ced4a4141977c7daaed0a074dcd9844a78d7d2615465b12f433ae6dd29f0", - "pin": "sha256:a652ced4a4141977c7daaed0a074dcd9844a78d7d2615465b12f433ae6dd29f0" + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:f2fe69bccc878e658caf21dfc99eaf726fb20d28f17398c1d66a90e62cc019f9", + "size": 1113, + "annotations": { + "vnd.docker.reference.digest": "sha256:ac9dd4fbec9e36b562f910618975a2936533f8e411a3fea2858aacc0ac972e1c", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } }, { - "type": "docker-image", - "ref": "docker.io/library/alpine:3.13@sha256:026f721af4cf2843e07bba648e158fb35ecc876d822130633cc49f707f0fc88c", - "pin": "sha256:026f721af4cf2843e07bba648e158fb35ecc876d822130633cc49f707f0fc88c" + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:9e112f8d4e383186f36369fba7b454e246d2e9ca5def797f1b84ede265e9f3ca", + "size": 1113, + "annotations": { + "vnd.docker.reference.digest": "sha256:0f4dc6797db467372cbf52c7236816203654a839f64a6542c9135d1973c9d744", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } }, { - "type": "docker-image", - "ref": "docker.io/moby/buildkit:v0.9.0@sha256:8dc668e7f66db1c044aadbed306020743516a94848793e0f81f94a087ee78cab", - "pin": "sha256:8dc668e7f66db1c044aadbed306020743516a94848793e0f81f94a087ee78cab" + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:09d593587f8665269ec6753eaed7fbdb09968f71587dd53e06519502cbc16775", + "size": 1113, + "annotations": { + "vnd.docker.reference.digest": "sha256:d62bb533d95afe17c4a9caf1e7c57a3b0a7a67409ccfa7af947aeb0f670ffb87", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } }, { - "type": "docker-image", - "ref": "docker.io/tonistiigi/xx@sha256:21a61be4744f6531cb5f33b0e6f40ede41fa3a1b8c82d5946178f80cc84bfc04", - "pin": "sha256:21a61be4744f6531cb5f33b0e6f40ede41fa3a1b8c82d5946178f80cc84bfc04" + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:985a3f4544dfb042db6a8703f5f76438667dd7958aba14cb04bebe3b4cbd9307", + "size": 1113, + "annotations": { + "vnd.docker.reference.digest": "sha256:b4944057e0c68203cdcc3dceff3b2df3c7d9e3dd801724fa977b01081da7771e", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:cfccb6afeede7dc29bf8abef4815d56f2723fa482ea63c9cd519cd991c379294", + "size": 1113, + "annotations": { + "vnd.docker.reference.digest": "sha256:825702a51eb4234904fc9253d8b0bf0a584787ffd8fc3fd6fa374188233ce399", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } }, { - "type": "http", - "ref": "https://raw.githubusercontent.com/moby/moby/master/README.md", - "pin": "sha256:419455202b0ef97e480d7f8199b26a721a417818bc0e2d106975f74323f25e6c" + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:2e93733432c6a14cb57db33928b3a17d7ca298b3babe24d9f56dca2754dbde3b", + "size": 1113, + "annotations": { + "vnd.docker.reference.digest": "sha256:dfb27c6acc9b9f3a7c9d47366d137089565062f43c8063c9f5e408d34c87ee4a", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } } ] } ``` +Following command provides [SLSA](https://github.com/moby/buildkit/blob/master/docs/attestations/slsa-provenance.md) JSON output: + ```console -$ docker buildx imagetools inspect crazymax/buildx:buildinfo --format "{{json .}}" +$ docker buildx imagetools inspect crazymax/buildkit:attest --format "{{json .SLSA}}" ``` ```json { - "name": "crazymax/buildx:buildinfo", + "Provenance": { + "_type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://slsa.dev/provenance/v0.2", + "subject": [ + { + "name": "pkg:docker/crazymax/buildkit@attest?platform=linux%2Famd64", + "digest": { + "sha256": "fbd10fe50b4b174bb9ea273e2eb9827fa8bf5c88edd8635a93dc83e0d1aecb55" + } + } + ], + "predicate": { + "builder": { + "id": "" + }, + "buildType": "https://mobyproject.org/buildkit@v1", + "materials": [ + { + "uri": "pkg:docker/docker/buildkit-syft-scanner@stable-1", + "digest": { + "sha256": "b45f1d207e16c3a3a5a10b254ad8ad358d01f7ea090d382b95c6b2ee2b3ef765" + } + }, + { + "uri": "pkg:docker/alpine@latest?platform=linux%2Famd64", + "digest": { + "sha256": "8914eb54f968791faf6a8638949e480fef81e697984fba772b3976835194c6d4" + } + } + ], + "invocation": { + "configSource": {}, + "parameters": { + "frontend": "dockerfile.v0", + "locals": [ + { + "name": "context" + }, + { + "name": "dockerfile" + } + ] + }, + "environment": { + "platform": "linux/amd64" + } + }, + "metadata": { + "buildInvocationID": "02tdha2xkbxvin87mz9drhag4", + "buildStartedOn": "2022-12-01T11:50:07.264704131Z", + "buildFinishedOn": "2022-12-01T11:50:08.243788739Z", + "reproducible": false, + "completeness": { + "parameters": true, + "environment": true, + "materials": false + }, + "https://mobyproject.org/buildkit@v1#metadata": {} + } + } + } +} +``` + +Following command provides [SBOM](https://github.com/moby/buildkit/blob/master/docs/attestations/sbom.md) JSON output: + +```console +$ docker buildx imagetools inspect crazymax/buildkit:attest --format "{{json .SBOM}}" +``` +```json +{ + "SPDX": { + "_type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://spdx.dev/Document", + "subject": [ + { + "name": "pkg:docker/crazymax/buildkit@attest?platform=linux%2Famd64", + "digest": { + "sha256": "fbd10fe50b4b174bb9ea273e2eb9827fa8bf5c88edd8635a93dc83e0d1aecb55" + } + } + ], + "predicate": { + "SPDXID": "SPDXRef-DOCUMENT", + "creationInfo": { + "created": "2022-12-01T11:46:48.063400162Z", + "creators": [ + "Tool: syft-v0.60.3", + "Tool: buildkit-1ace2bb", + "Organization: Anchore, Inc" + ], + "licenseListVersion": "3.18" + }, + "dataLicense": "CC0-1.0", + "documentNamespace": "https://anchore.com/syft/dir/run/src/core-0a4ccc6d-1a72-4c3a-a40e-3df1a2ffca94", + "files": [...], + "spdxVersion": "SPDX-2.2" + } + } +} +``` + +```console +$ docker buildx imagetools inspect crazymax/buildkit:attest --format "{{json .}}" +``` +```json +{ + "name": "crazymax/buildkit:attest", "manifest": { - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:899d2c7acbc124d406820857bb51d9089717bbe4e22b97eb4bc5789e99f09f83", - "size": 2628 + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.index.v1+json", + "digest": "sha256:7007b387ccd52bd42a050f2e8020e56e64622c9269bf7bbe257b326fe99daf19", + "size": 855, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:fbd10fe50b4b174bb9ea273e2eb9827fa8bf5c88edd8635a93dc83e0d1aecb55", + "size": 673, + "platform": { + "architecture": "amd64", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:a9de632c16998489fd63fbca42a03431df00639cfb2ecb8982bf9984b83c5b2b", + "size": 839, + "annotations": { + "vnd.docker.reference.digest": "sha256:fbd10fe50b4b174bb9ea273e2eb9827fa8bf5c88edd8635a93dc83e0d1aecb55", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } + } + ] }, "image": { - "created": "2022-02-24T12:27:43.627154558Z", + "created": "2022-12-01T11:46:47.713777178Z", "architecture": "amd64", "os": "linux", "config": { "Env": [ - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "DOCKER_TLS_CERTDIR=/certs", - "DOCKER_CLI_EXPERIMENTAL=enabled" - ], - "Entrypoint": [ - "docker-entrypoint.sh" + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ - "sh" + "/bin/sh" ] }, "rootfs": { "type": "layers", "diff_ids": [ - "sha256:7fcb75871b2101082203959c83514ac8a9f4ecfee77a0fe9aa73bbe56afdf1b4", - "sha256:d3c0b963ff5684160641f936d6a4aa14efc8ff27b6edac255c07f2d03ff92e82", - "sha256:3f8d78f13fa9b1f35d3bc3f1351d03a027c38018c37baca73f93eecdea17f244", - "sha256:8e6eb1137b182ae0c3f5d40ca46341fda2eaeeeb5fa516a9a2bf96171238e2e0", - "sha256:fde4c869a56b54dd76d7352ddaa813fd96202bda30b9dceb2c2f2ad22fa2e6ce", - "sha256:52025823edb284321af7846419899234b3c66219bf06061692b709875ed0760f", - "sha256:50adb5982dbf6126c7cf279ac3181d1e39fc9116b610b947a3dadae6f7e7c5bc", - "sha256:9801c319e1c66c5d295e78b2d3e80547e73c7e3c63a4b71e97c8ca357224af24", - "sha256:dfbfac44d5d228c49b42194c8a2f470abd6916d072f612a6fb14318e94fde8ae", - "sha256:3dfb74e19dedf61568b917c19b0fd3ee4580870027ca0b6054baf239855d1322", - "sha256:b182e707c23e4f19be73f9022a99d2d1ca7bf1ca8f280d40e4d1c10a6f51550e" + "sha256:ded7a220bb058e28ee3254fbba04ca90b679070424424761a53a043b93b612bf", + "sha256:d85d09ab4b4e921666ccc2db8532e857bf3476b7588e52c9c17741d7af14204f" ] }, "history": [ { - "created": "2021-11-12T17:19:58.698676655Z", - "created_by": "/bin/sh -c #(nop) ADD file:5a707b9d6cb5fff532e4c2141bc35707593f21da5528c9e71ae2ddb6ba4a4eb6 in / " + "created": "2022-11-22T22:19:28.870801855Z", + "created_by": "/bin/sh -c #(nop) ADD file:587cae71969871d3c6456d844a8795df9b64b12c710c275295a1182b46f630e7 in / " }, { - "created": "2021-11-12T17:19:58.948920855Z", + "created": "2022-11-22T22:19:29.008562326Z", "created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]", "empty_layer": true }, { - "created": "2022-02-24T12:27:38.285594601Z", - "created_by": "RUN /bin/sh -c apk --update --no-cache add bash ca-certificates openssh-client \u0026\u0026 rm -rf /tmp/* /var/cache/apk/* # buildkit", - "comment": "buildkit.dockerfile.v0" - }, - { - "created": "2022-02-24T12:27:41.061874167Z", - "created_by": "COPY /opt/docker/ /usr/local/bin/ # buildkit", - "comment": "buildkit.dockerfile.v0" - }, - { - "created": "2022-02-24T12:27:41.174098947Z", - "created_by": "COPY /usr/bin/buildctl /usr/local/bin/buildctl # buildkit", - "comment": "buildkit.dockerfile.v0" - }, - { - "created": "2022-02-24T12:27:41.320343683Z", - "created_by": "COPY /usr/bin/buildkit* /usr/local/bin/ # buildkit", - "comment": "buildkit.dockerfile.v0" - }, - { - "created": "2022-02-24T12:27:41.447149933Z", - "created_by": "COPY /buildx /usr/libexec/docker/cli-plugins/docker-buildx # buildkit", - "comment": "buildkit.dockerfile.v0" - }, - { - "created": "2022-02-24T12:27:43.057722191Z", - "created_by": "COPY /opt/docker-compose /usr/libexec/docker/cli-plugins/docker-compose # buildkit", - "comment": "buildkit.dockerfile.v0" - }, - { - "created": "2022-02-24T12:27:43.145224134Z", - "created_by": "ADD https://raw.githubusercontent.com/moby/moby/master/README.md / # buildkit", - "comment": "buildkit.dockerfile.v0" - }, - { - "created": "2022-02-24T12:27:43.422212427Z", - "created_by": "ENV DOCKER_TLS_CERTDIR=/certs", - "comment": "buildkit.dockerfile.v0", - "empty_layer": true - }, - { - "created": "2022-02-24T12:27:43.422212427Z", - "created_by": "ENV DOCKER_CLI_EXPERIMENTAL=enabled", - "comment": "buildkit.dockerfile.v0", - "empty_layer": true - }, - { - "created": "2022-02-24T12:27:43.422212427Z", - "created_by": "RUN /bin/sh -c docker --version \u0026\u0026 buildkitd --version \u0026\u0026 buildctl --version \u0026\u0026 docker buildx version \u0026\u0026 docker compose version \u0026\u0026 mkdir /certs /certs/client \u0026\u0026 chmod 1777 /certs /certs/client # buildkit", - "comment": "buildkit.dockerfile.v0" - }, - { - "created": "2022-02-24T12:27:43.514320155Z", - "created_by": "COPY rootfs/modprobe.sh /usr/local/bin/modprobe # buildkit", + "created": "2022-12-01T11:46:47.713777178Z", + "created_by": "RUN /bin/sh -c apk add curl # buildkit", "comment": "buildkit.dockerfile.v0" - }, - { - "created": "2022-02-24T12:27:43.627154558Z", - "created_by": "COPY rootfs/docker-entrypoint.sh /usr/local/bin/ # buildkit", - "comment": "buildkit.dockerfile.v0" - }, - { - "created": "2022-02-24T12:27:43.627154558Z", - "created_by": "ENTRYPOINT [\"docker-entrypoint.sh\"]", - "comment": "buildkit.dockerfile.v0", - "empty_layer": true - }, - { - "created": "2022-02-24T12:27:43.627154558Z", - "created_by": "CMD [\"sh\"]", - "comment": "buildkit.dockerfile.v0", - "empty_layer": true } ] }, - "buildinfo": { - "frontend": "dockerfile.v0", - "attrs": { - "build-arg:bar": "foo", - "build-arg:foo": "bar", - "filename": "Dockerfile", - "source": "docker/dockerfile-upstream:master-labs" - }, - "sources": [ - { - "type": "docker-image", - "ref": "docker.io/docker/buildx-bin:0.6.1@sha256:a652ced4a4141977c7daaed0a074dcd9844a78d7d2615465b12f433ae6dd29f0", - "pin": "sha256:a652ced4a4141977c7daaed0a074dcd9844a78d7d2615465b12f433ae6dd29f0" - }, - { - "type": "docker-image", - "ref": "docker.io/library/alpine:3.13", - "pin": "sha256:026f721af4cf2843e07bba648e158fb35ecc876d822130633cc49f707f0fc88c" - }, - { - "type": "docker-image", - "ref": "docker.io/moby/buildkit:v0.9.0", - "pin": "sha256:8dc668e7f66db1c044aadbed306020743516a94848793e0f81f94a087ee78cab" - }, - { - "type": "docker-image", - "ref": "docker.io/tonistiigi/xx@sha256:21a61be4744f6531cb5f33b0e6f40ede41fa3a1b8c82d5946178f80cc84bfc04", - "pin": "sha256:21a61be4744f6531cb5f33b0e6f40ede41fa3a1b8c82d5946178f80cc84bfc04" - }, - { - "type": "http", - "ref": "https://raw.githubusercontent.com/moby/moby/master/README.md", - "pin": "sha256:419455202b0ef97e480d7f8199b26a721a417818bc0e2d106975f74323f25e6c" + "SLSA": { + "Provenance": { + "_type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://slsa.dev/provenance/v0.2", + "subject": [ + { + "name": "pkg:docker/crazymax/buildkit@attest?platform=linux%2Famd64", + "digest": { + "sha256": "fbd10fe50b4b174bb9ea273e2eb9827fa8bf5c88edd8635a93dc83e0d1aecb55" + } + } + ], + "predicate": { + "builder": { + "id": "" + }, + "buildType": "https://mobyproject.org/buildkit@v1", + "materials": [ + { + "uri": "pkg:docker/docker/buildkit-syft-scanner@stable-1", + "digest": { + "sha256": "b45f1d207e16c3a3a5a10b254ad8ad358d01f7ea090d382b95c6b2ee2b3ef765" + } + }, + { + "uri": "pkg:docker/alpine@latest?platform=linux%2Famd64", + "digest": { + "sha256": "8914eb54f968791faf6a8638949e480fef81e697984fba772b3976835194c6d4" + } + } + ], + "invocation": { + "configSource": {}, + "parameters": { + "frontend": "dockerfile.v0", + "locals": [ + { + "name": "context" + }, + { + "name": "dockerfile" + } + ] + }, + "environment": { + "platform": "linux/amd64" + } + }, + "metadata": { + "buildInvocationID": "02tdha2xkbxvin87mz9drhag4", + "buildStartedOn": "2022-12-01T11:50:07.264704131Z", + "buildFinishedOn": "2022-12-01T11:50:08.243788739Z", + "reproducible": false, + "completeness": { + "parameters": true, + "environment": true, + "materials": false + }, + "https://mobyproject.org/buildkit@v1#metadata": {} + } } - ] + } + }, + "SBOM": { + "SPDX": { + "_type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://spdx.dev/Document", + "subject": [ + { + "name": "pkg:docker/crazymax/buildkit@attest?platform=linux%2Famd64", + "digest": { + "sha256": "fbd10fe50b4b174bb9ea273e2eb9827fa8bf5c88edd8635a93dc83e0d1aecb55" + } + } + ], + "predicate": { + "SPDXID": "SPDXRef-DOCUMENT", + "creationInfo": { + "created": "2022-12-01T11:46:48.063400162Z", + "creators": [ + "Tool: syft-v0.60.3", + "Tool: buildkit-1ace2bb", + "Organization: Anchore, Inc" + ], + "licenseListVersion": "3.18" + }, + "dataLicense": "CC0-1.0", + "documentNamespace": "https://anchore.com/syft/dir/run/src/core-0a4ccc6d-1a72-4c3a-a40e-3df1a2ffca94", + "files": [...], + "spdxVersion": "SPDX-2.2" + } + } } } ``` #### Multi-platform -Multi-platform images are supported for `.Image` and `.BuildInfo` fields. If -you want to pick up a specific platform, you can specify it using the `index` +Multi-platform images are supported for `.Image`, `.SLSA` and `.SBOM` fields. +If you want to pick up a specific platform, you can specify it using the `index` go template function: ```console @@ -462,7 +572,7 @@ $ docker buildx imagetools inspect --format '{{json (index .Image "linux/s390x") ``` ```json { - "created": "2022-02-25T17:13:27.89891722Z", + "created": "2022-11-30T17:42:26.414957336Z", "architecture": "s390x", "os": "linux", "config": { @@ -481,8 +591,8 @@ $ docker buildx imagetools inspect --format '{{json (index .Image "linux/s390x") "diff_ids": [ "sha256:41048e32d0684349141cf05f629c5fc3c5915d1f3426b66dbb8953a540e01e1e", "sha256:2651209b9208fff6c053bc3c17353cb07874e50f1a9bc96d6afd03aef63de76a", - "sha256:6741ed7e73039d853fa8902246a4c7e8bf9dd09652fd1b08251bc5f9e8876a7f", - "sha256:92ac046adeeb65c86ae3f0b458dee04ad4a462e417661c04d77642c66494f69b" + "sha256:88577322e65f094ce8ac27435880f1a8a9baadb569258026bb141770451bafcb", + "sha256:de8f9a790e4ed10ff1f1f8ea923c9da4f97246a7e200add2dc6650eba3f10a20" ] }, "history": [ @@ -501,23 +611,23 @@ $ docker buildx imagetools inspect --format '{{json (index .Image "linux/s390x") "comment": "buildkit.dockerfile.v0" }, { - "created": "2022-02-24T00:34:00.924540012Z", + "created": "2022-08-25T00:39:25.652811078Z", "created_by": "COPY examples/buildctl-daemonless/buildctl-daemonless.sh /usr/bin/ # buildkit", "comment": "buildkit.dockerfile.v0" }, { - "created": "2022-02-25T17:13:27.89891722Z", + "created": "2022-11-30T17:42:26.414957336Z", "created_by": "VOLUME [/var/lib/buildkit]", "comment": "buildkit.dockerfile.v0", "empty_layer": true }, { - "created": "2022-02-25T17:13:27.89891722Z", + "created": "2022-11-30T17:42:26.414957336Z", "created_by": "COPY / /usr/bin/ # buildkit", "comment": "buildkit.dockerfile.v0" }, { - "created": "2022-02-25T17:13:27.89891722Z", + "created": "2022-11-30T17:42:26.414957336Z", "created_by": "ENTRYPOINT [\"buildkitd\"]", "comment": "buildkit.dockerfile.v0", "empty_layer": true @@ -541,24 +651,24 @@ $ docker buildx imagetools inspect --raw crazymax/loop | jq "schemaVersion": 2, "config": { "mediaType": "application/vnd.docker.container.image.v1+json", - "digest": "sha256:7ace7d324e79b360b2db8b820d83081863d96d22e734cdf297a8e7fd83f6ceb3", - "size": 2298 + "digest": "sha256:a98999183d2c7a8845f6d56496e51099ce6e4359ee7255504174b05430c4b78b", + "size": 2762 }, "layers": [ { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "digest": "sha256:5843afab387455b37944e709ee8c78d7520df80f8d01cf7f861aae63beeddb6b", - "size": 2811478 + "digest": "sha256:8663204ce13b2961da55026a2034abb9e5afaaccf6a9cfb44ad71406dcd07c7b", + "size": 2818370 }, { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "digest": "sha256:726d3732a87e1c430d67e8969de6b222a889d45e045ebae1a008a37ba38f3b1f", - "size": 1776812 + "digest": "sha256:f0868a92f8e1e5018ed4e60eb845ed4ff0e2229897f4105e5a4735c1d6fd874f", + "size": 1821402 }, { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "digest": "sha256:5d7cf9b33148a8f220c84f27dd2cfae46aca019a3ea3fbf7274f6d6dbfae8f3b", - "size": 382855 + "digest": "sha256:d010066dbdfcf7c12fca30cd4b567aa7218eb6762ab53169d043655b7a8d7f2e", + "size": 404457 } ] } @@ -574,7 +684,7 @@ $ docker buildx imagetools inspect --raw moby/buildkit:master | jq "manifests": [ { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:667d28c9fb33820ce686887a717a148e89fa77f9097f9352996bbcce99d352b1", + "digest": "sha256:f9f41c85124686c2afe330a985066748a91d7a5d505777fe274df804ab5e077e", "size": 1158, "platform": { "architecture": "amd64", @@ -583,7 +693,7 @@ $ docker buildx imagetools inspect --raw moby/buildkit:master | jq }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:71789527b64ab3d7b3de01d364b449cd7f7a3da758218fbf73b9c9aae05a6775", + "digest": "sha256:82097c2be19c617aafb3c3e43c88548738d4b2bf3db5c36666283a918b390266", "size": 1158, "platform": { "architecture": "arm", @@ -593,7 +703,7 @@ $ docker buildx imagetools inspect --raw moby/buildkit:master | jq }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:fb64667e1ce6ab0d05478f3a8402af07b27737598dcf9a510fb1d792b13a66be", + "digest": "sha256:b6b91e6c823d7220ded7d3b688e571ba800b13d91bbc904c1d8053593e3ee42c", "size": 1158, "platform": { "architecture": "arm64", @@ -602,7 +712,7 @@ $ docker buildx imagetools inspect --raw moby/buildkit:master | jq }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:1c3ddf95a0788e23f72f25800c05abc4458946685e2b66788c3d978cde6da92b", + "digest": "sha256:797061bcc16778de048b96f769c018ec24da221088050bbe926ea3b8d51d77e8", "size": 1158, "platform": { "architecture": "s390x", @@ -611,7 +721,7 @@ $ docker buildx imagetools inspect --raw moby/buildkit:master | jq }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:05bcde6d460a284e5bc88026cd070277e8380355de3126cbc8fe8a452708c6b1", + "digest": "sha256:b93d3a84d18c4d0b8c279e77343d854d9b5177df7ea55cf468d461aa2523364e", "size": 1159, "platform": { "architecture": "ppc64le", @@ -620,7 +730,7 @@ $ docker buildx imagetools inspect --raw moby/buildkit:master | jq }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:c04c57765304ab84f4f9807fff3e11605c3a60e16435c734b02c723680f6bd6e", + "digest": "sha256:d5c950dd1b270d437c838187112a0cb44c9258248d7a3a8bcb42fae8f717dc01", "size": 1158, "platform": { "architecture": "riscv64", diff --git a/util/imagetools/loader.go b/util/imagetools/loader.go new file mode 100644 index 00000000..8dbc32a6 --- /dev/null +++ b/util/imagetools/loader.go @@ -0,0 +1,357 @@ +package imagetools + +// TODO: replace with go-imageinspect library when public + +import ( + "context" + "encoding/json" + "sort" + "strings" + "sync" + + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/remotes" + "github.com/docker/distribution/reference" + "github.com/moby/buildkit/util/contentutil" + "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + "golang.org/x/sync/errgroup" +) + +const ( + annotationReference = "vnd.docker.reference.digest" +) + +type contentCache interface { + content.Provider + content.Ingester +} + +type loader struct { + resolver remotes.Resolver + cache contentCache +} + +type manifest struct { + desc ocispec.Descriptor + manifest ocispec.Manifest +} + +type index struct { + desc ocispec.Descriptor + index ocispec.Index +} + +type asset struct { + config *ocispec.Image + sbom *sbomStub + slsa *slsaStub +} + +type result struct { + mu sync.Mutex + indexes map[digest.Digest]index + manifests map[digest.Digest]manifest + images map[string]digest.Digest + refs map[digest.Digest][]digest.Digest + + platforms []string + assets map[string]asset +} + +func newLoader(resolver remotes.Resolver) *loader { + return &loader{ + resolver: resolver, + cache: contentutil.NewBuffer(), + } +} + +func (l *loader) Load(ctx context.Context, ref string) (*result, error) { + named, err := parseRef(ref) + if err != nil { + return nil, err + } + + _, desc, err := l.resolver.Resolve(ctx, named.String()) + if err != nil { + return nil, err + } + + canonical, err := reference.WithDigest(named, desc.Digest) + if err != nil { + return nil, err + } + + fetcher, err := l.resolver.Fetcher(ctx, canonical.String()) + if err != nil { + return nil, err + } + + r := &result{ + indexes: make(map[digest.Digest]index), + manifests: make(map[digest.Digest]manifest), + images: make(map[string]digest.Digest), + refs: make(map[digest.Digest][]digest.Digest), + assets: make(map[string]asset), + } + + if err := l.fetch(ctx, fetcher, desc, r); err != nil { + return nil, err + } + + for platform, dgst := range r.images { + r.platforms = append(r.platforms, platform) + + mfst, ok := r.manifests[dgst] + if !ok { + return nil, errors.Errorf("image %s not found", platform) + } + + var a asset + annotations := make(map[string]string, len(mfst.manifest.Annotations)+len(mfst.desc.Annotations)) + for k, v := range mfst.desc.Annotations { + annotations[k] = v + } + for k, v := range mfst.manifest.Annotations { + annotations[k] = v + } + + if err := l.scanConfig(ctx, fetcher, mfst.manifest.Config, &a); err != nil { + return nil, err + } + + refs, ok := r.refs[dgst] + if ok { + if err := l.scanSBOM(ctx, fetcher, r, refs, &a); err != nil { + return nil, err + } + } + + if err := l.scanProvenance(ctx, fetcher, r, refs, &a); err != nil { + return nil, err + } + + r.assets[platform] = a + } + + sort.Strings(r.platforms) + return r, nil +} + +func (l *loader) fetch(ctx context.Context, fetcher remotes.Fetcher, desc ocispec.Descriptor, r *result) error { + _, err := remotes.FetchHandler(l.cache, fetcher)(ctx, desc) + if err != nil { + return err + } + + switch desc.MediaType { + case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: + var mfst ocispec.Manifest + dt, err := content.ReadBlob(ctx, l.cache, desc) + if err != nil { + return err + } + if err := json.Unmarshal(dt, &mfst); err != nil { + return err + } + r.mu.Lock() + r.manifests[desc.Digest] = manifest{ + desc: desc, + manifest: mfst, + } + r.mu.Unlock() + + ref, ok := desc.Annotations[annotationReference] + if ok { + refdgst, err := digest.Parse(ref) + if err != nil { + return err + } + r.mu.Lock() + r.refs[refdgst] = append(r.refs[refdgst], desc.Digest) + r.mu.Unlock() + } else { + p := desc.Platform + if p == nil { + p, err = l.readPlatformFromConfig(ctx, fetcher, mfst.Config) + if err != nil { + return err + } + } + r.mu.Lock() + r.images[platforms.Format(platforms.Normalize(*p))] = desc.Digest + r.mu.Unlock() + } + case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex: + var idx ocispec.Index + dt, err := content.ReadBlob(ctx, l.cache, desc) + if err != nil { + return err + } + + if err := json.Unmarshal(dt, &idx); err != nil { + return err + } + + r.mu.Lock() + r.indexes[desc.Digest] = index{ + desc: desc, + index: idx, + } + r.mu.Unlock() + + eg, ctx := errgroup.WithContext(ctx) + for _, d := range idx.Manifests { + d := d + eg.Go(func() error { + return l.fetch(ctx, fetcher, d, r) + }) + } + + if err := eg.Wait(); err != nil { + return err + } + default: + } + return nil +} + +func (l *loader) readPlatformFromConfig(ctx context.Context, fetcher remotes.Fetcher, desc ocispec.Descriptor) (*ocispec.Platform, error) { + _, err := remotes.FetchHandler(l.cache, fetcher)(ctx, desc) + if err != nil { + return nil, err + } + + dt, err := content.ReadBlob(ctx, l.cache, desc) + if err != nil { + return nil, err + } + + var config ocispec.Image + if err := json.Unmarshal(dt, &config); err != nil { + return nil, err + } + + return &ocispec.Platform{ + OS: config.OS, + Architecture: config.Architecture, + Variant: config.Variant, + }, nil +} + +func (l *loader) scanConfig(ctx context.Context, fetcher remotes.Fetcher, desc ocispec.Descriptor, as *asset) error { + _, err := remotes.FetchHandler(l.cache, fetcher)(ctx, desc) + if err != nil { + return err + } + dt, err := content.ReadBlob(ctx, l.cache, desc) + if err != nil { + return err + } + return json.Unmarshal(dt, &as.config) +} + +type sbomStub struct { + SPDX json.RawMessage `json:",omitempty"` +} + +func (l *loader) scanSBOM(ctx context.Context, fetcher remotes.Fetcher, r *result, refs []digest.Digest, as *asset) error { + ctx = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.in-toto+json", "intoto") + for _, dgst := range refs { + mfst, ok := r.manifests[dgst] + if !ok { + return errors.Errorf("referenced image %s not found", dgst) + } + for _, layer := range mfst.manifest.Layers { + if layer.MediaType == "application/vnd.in-toto+json" && layer.Annotations["in-toto.io/predicate-type"] == "https://spdx.dev/Document" { + _, err := remotes.FetchHandler(l.cache, fetcher)(ctx, layer) + if err != nil { + return err + } + dt, err := content.ReadBlob(ctx, l.cache, layer) + if err != nil { + return err + } + as.sbom = &sbomStub{ + SPDX: dt, + } + } + } + } + return nil +} + +type slsaStub struct { + Provenance json.RawMessage `json:",omitempty"` +} + +func (l *loader) scanProvenance(ctx context.Context, fetcher remotes.Fetcher, r *result, refs []digest.Digest, as *asset) error { + ctx = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.in-toto+json", "intoto") + for _, dgst := range refs { + mfst, ok := r.manifests[dgst] + if !ok { + return errors.Errorf("referenced image %s not found", dgst) + } + for _, layer := range mfst.manifest.Layers { + if layer.MediaType == "application/vnd.in-toto+json" && strings.HasPrefix(layer.Annotations["in-toto.io/predicate-type"], "https://slsa.dev/provenance/") { + _, err := remotes.FetchHandler(l.cache, fetcher)(ctx, layer) + if err != nil { + return err + } + dt, err := content.ReadBlob(ctx, l.cache, layer) + if err != nil { + return err + } + as.slsa = &slsaStub{ + Provenance: dt, + } + } + } + } + return nil +} + +func (r *result) Configs() map[string]*ocispec.Image { + if len(r.assets) == 0 { + return nil + } + res := make(map[string]*ocispec.Image) + for p, a := range r.assets { + if a.config == nil { + continue + } + res[p] = a.config + } + return res +} + +func (r *result) SLSA() map[string]slsaStub { + if len(r.assets) == 0 { + return nil + } + res := make(map[string]slsaStub) + for p, a := range r.assets { + if a.slsa == nil { + continue + } + res[p] = *a.slsa + } + return res +} + +func (r *result) SBOM() map[string]sbomStub { + if len(r.assets) == 0 { + return nil + } + res := make(map[string]sbomStub) + for p, a := range r.assets { + if a.sbom == nil { + continue + } + res[p] = *a.sbom + } + return res +} diff --git a/util/imagetools/printers.go b/util/imagetools/printers.go index 37160701..a0b1560e 100644 --- a/util/imagetools/printers.go +++ b/util/imagetools/printers.go @@ -6,20 +6,15 @@ import ( "fmt" "io" "os" - "sort" "strings" - "sync" "text/tabwriter" "text/template" "github.com/containerd/containerd/images" "github.com/containerd/containerd/platforms" "github.com/docker/distribution/reference" - binfotypes "github.com/moby/buildkit/util/buildinfo/types" - "github.com/moby/buildkit/util/imageutil" "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" - "golang.org/x/sync/errgroup" ) const defaultPfx = " " @@ -31,11 +26,10 @@ type Printer struct { name string format string - raw []byte - ref reference.Named - manifest ocispecs.Descriptor - index ocispecs.Index - platforms []ocispecs.Platform + raw []byte + ref reference.Named + manifest ocispecs.Descriptor + index ocispecs.Index } func NewPrinter(ctx context.Context, opt Opt, name string, format string) (*Printer, error) { @@ -46,38 +40,25 @@ func NewPrinter(ctx context.Context, opt Opt, name string, format string) (*Prin return nil, err } - dt, manifest, err := resolver.Get(ctx, name) + dt, mfst, err := resolver.Get(ctx, ref.String()) if err != nil { return nil, err } - var index ocispecs.Index - if err = json.Unmarshal(dt, &index); err != nil { + var idx ocispecs.Index + if err = json.Unmarshal(dt, &idx); err != nil { return nil, err } - var pforms []ocispecs.Platform - switch manifest.MediaType { - case images.MediaTypeDockerSchema2ManifestList, ocispecs.MediaTypeImageIndex: - for _, m := range index.Manifests { - if m.Platform != nil { - pforms = append(pforms, *m.Platform) - } - } - default: - pforms = append(pforms, platforms.DefaultSpec()) - } - return &Printer{ - ctx: ctx, - resolver: resolver, - name: name, - format: format, - raw: dt, - ref: ref, - manifest: manifest, - index: index, - platforms: pforms, + ctx: ctx, + resolver: resolver, + name: name, + format: format, + raw: dt, + ref: ref, + manifest: mfst, + index: idx, }, nil } @@ -102,6 +83,11 @@ func (p *Printer) Print(raw bool, out io.Writer) error { return nil } + res, err := newLoader(p.resolver.resolver()).Load(p.ctx, p.name) + if err != nil { + return err + } + tpl, err := template.New("").Funcs(template.FuncMap{ "json": func(v interface{}) string { b, _ := json.MarshalIndent(v, "", " ") @@ -112,46 +98,17 @@ func (p *Printer) Print(raw bool, out io.Writer) error { return err } - imageconfigs := make(map[string]*ocispecs.Image) - imageconfigsMutex := sync.Mutex{} - buildinfos := make(map[string]*binfotypes.BuildInfo) - buildinfosMutex := sync.Mutex{} - - eg, _ := errgroup.WithContext(p.ctx) - for _, platform := range p.platforms { - func(platform ocispecs.Platform) { - eg.Go(func() error { - img, dtic, err := p.getImageConfig(&platform) - if err != nil { - return err - } else if img != nil { - imageconfigsMutex.Lock() - imageconfigs[platforms.Format(platform)] = img - imageconfigsMutex.Unlock() - } - if bi, err := imageutil.BuildInfo(dtic); err != nil { - return err - } else if bi != nil { - buildinfosMutex.Lock() - buildinfos[platforms.Format(platform)] = bi - buildinfosMutex.Unlock() - } - return nil - }) - }(platform) - } - if err := eg.Wait(); err != nil { - return err - } - + imageconfigs := res.Configs() + slsas := res.SLSA() + sboms := res.SBOM() format := tpl.Root.String() - var manifest interface{} + var mfst interface{} switch p.manifest.MediaType { case images.MediaTypeDockerSchema2Manifest, ocispecs.MediaTypeImageManifest: - manifest = p.manifest + mfst = p.manifest case images.MediaTypeDockerSchema2ManifestList, ocispecs.MediaTypeImageIndex: - manifest = struct { + mfst = struct { SchemaVersion int `json:"schemaVersion"` MediaType string `json:"mediaType,omitempty"` Digest digest.Digest `json:"digest"` @@ -170,10 +127,11 @@ func (p *Printer) Print(raw bool, out io.Writer) error { switch { // TODO: print formatted config - case strings.HasPrefix(format, "{{.Manifest"), strings.HasPrefix(format, "{{.BuildInfo"): + case strings.HasPrefix(format, "{{.Manifest"): w := tabwriter.NewWriter(out, 0, 0, 1, ' ', 0) _, _ = fmt.Fprintf(w, "Name:\t%s\n", p.ref.String()) - if strings.HasPrefix(format, "{{.Manifest") { + switch { + case strings.HasPrefix(format, "{{.Manifest"): _, _ = fmt.Fprintf(w, "MediaType:\t%s\n", p.manifest.MediaType) _, _ = fmt.Fprintf(w, "Digest:\t%s\n", p.manifest.Digest) _ = w.Flush() @@ -181,42 +139,47 @@ func (p *Printer) Print(raw bool, out io.Writer) error { case images.MediaTypeDockerSchema2ManifestList, ocispecs.MediaTypeImageIndex: _ = p.printManifestList(out) } - } else if strings.HasPrefix(format, "{{.BuildInfo") { - _ = w.Flush() - _ = p.printBuildInfos(buildinfos, out) } default: - if len(p.platforms) > 1 { + if len(res.platforms) > 1 { return tpl.Execute(out, struct { - Name string `json:"name,omitempty"` - Manifest interface{} `json:"manifest,omitempty"` - Image map[string]*ocispecs.Image `json:"image,omitempty"` - BuildInfo map[string]*binfotypes.BuildInfo `json:"buildinfo,omitempty"` + Name string `json:"name,omitempty"` + Manifest interface{} `json:"manifest,omitempty"` + Image map[string]*ocispecs.Image `json:"image,omitempty"` + SLSA map[string]slsaStub `json:"SLSA,omitempty"` + SBOM map[string]sbomStub `json:"SBOM,omitempty"` }{ - Name: p.name, - Manifest: manifest, - Image: imageconfigs, - BuildInfo: buildinfos, + Name: p.name, + Manifest: mfst, + Image: imageconfigs, + SLSA: slsas, + SBOM: sboms, }) } var ic *ocispecs.Image for _, v := range imageconfigs { ic = v } - var bi *binfotypes.BuildInfo - for _, v := range buildinfos { - bi = v + var slsa slsaStub + for _, v := range slsas { + slsa = v + } + var sbom sbomStub + for _, v := range sboms { + sbom = v } return tpl.Execute(out, struct { - Name string `json:"name,omitempty"` - Manifest interface{} `json:"manifest,omitempty"` - Image *ocispecs.Image `json:"image,omitempty"` - BuildInfo *binfotypes.BuildInfo `json:"buildinfo,omitempty"` + Name string `json:"name,omitempty"` + Manifest interface{} `json:"manifest,omitempty"` + Image *ocispecs.Image `json:"image,omitempty"` + SLSA slsaStub `json:"SLSA,omitempty"` + SBOM sbomStub `json:"SBOM,omitempty"` }{ - Name: p.name, - Manifest: manifest, - Image: ic, - BuildInfo: bi, + Name: p.name, + Manifest: mfst, + Image: ic, + SLSA: slsa, + SBOM: sbom, }) } @@ -264,83 +227,3 @@ func (p *Printer) printManifestList(out io.Writer) error { } return w.Flush() } - -func (p *Printer) printBuildInfos(bis map[string]*binfotypes.BuildInfo, out io.Writer) error { - if len(bis) == 0 { - return nil - } else if len(bis) == 1 { - for _, bi := range bis { - return p.printBuildInfo(bi, "", out) - } - } - var pkeys []string - for _, pform := range p.platforms { - pkeys = append(pkeys, platforms.Format(pform)) - } - sort.Strings(pkeys) - for _, platform := range pkeys { - bi := bis[platform] - w := tabwriter.NewWriter(out, 0, 0, 1, ' ', 0) - _, _ = fmt.Fprintf(w, "\t\nPlatform:\t%s\t\n", platform) - _ = w.Flush() - if err := p.printBuildInfo(bi, "", out); err != nil { - return err - } - } - return nil -} - -func (p *Printer) printBuildInfo(bi *binfotypes.BuildInfo, pfx string, out io.Writer) error { - w := tabwriter.NewWriter(out, 0, 0, 1, ' ', 0) - _, _ = fmt.Fprintf(w, "%sFrontend:\t%s\n", pfx, bi.Frontend) - - if len(bi.Attrs) > 0 { - _, _ = fmt.Fprintf(w, "%sAttrs:\t\n", pfx) - _ = w.Flush() - for k, v := range bi.Attrs { - _, _ = fmt.Fprintf(w, "%s%s:\t%s\n", pfx+defaultPfx, k, *v) - } - } - - if len(bi.Sources) > 0 { - _, _ = fmt.Fprintf(w, "%sSources:\t\n", pfx) - _ = w.Flush() - for i, v := range bi.Sources { - if i != 0 { - _, _ = fmt.Fprintf(w, "\t\n") - } - _, _ = fmt.Fprintf(w, "%sType:\t%s\n", pfx+defaultPfx, v.Type) - _, _ = fmt.Fprintf(w, "%sRef:\t%s\n", pfx+defaultPfx, v.Ref) - _, _ = fmt.Fprintf(w, "%sPin:\t%s\n", pfx+defaultPfx, v.Pin) - } - } - - if len(bi.Deps) > 0 { - _, _ = fmt.Fprintf(w, "%sDeps:\t\n", pfx) - _ = w.Flush() - firstPass := true - for k, v := range bi.Deps { - if !firstPass { - _, _ = fmt.Fprintf(w, "\t\n") - } - _, _ = fmt.Fprintf(w, "%sName:\t%s\n", pfx+defaultPfx, k) - _ = w.Flush() - _ = p.printBuildInfo(&v, pfx+defaultPfx, out) - firstPass = false - } - } - - return w.Flush() -} - -func (p *Printer) getImageConfig(platform *ocispecs.Platform) (*ocispecs.Image, []byte, error) { - _, dtic, err := p.resolver.ImageConfig(p.ctx, p.name, platform) - if err != nil { - return nil, nil, err - } - var img *ocispecs.Image - if err = json.Unmarshal(dtic, &img); err != nil { - return nil, nil, err - } - return img, dtic, nil -}