Refactor meta.jq to prepare for signing and oci-import implementation#17
Conversation
|
An example generated build command: # jq -L .scripts 'include "meta"; first(.[]) | build_command' -r ../builds.json
SOURCE_DATE_EPOCH=1705382289 \
docker buildx build --progress=plain \
--provenance=mode=max \
--output '"type=oci","dest=temp.tar"' \
--annotation 'org.opencontainers.image.source=https://github.com/tianon/docker-bash.git#b08b986ade4dab726334b111c89688491534b732:devel' \
--annotation 'org.opencontainers.image.revision=b08b986ade4dab726334b111c89688491534b732' \
--annotation 'org.opencontainers.image.created=2024-01-16T05:18:09Z' \
--annotation 'org.opencontainers.image.version=devel-20240114' \
--annotation 'org.opencontainers.image.url=https://hub.docker.com/_/bash' \
--annotation 'manifest-descriptor:org.opencontainers.image.source=https://github.com/tianon/docker-bash.git#b08b986ade4dab726334b111c89688491534b732:devel' \
--annotation 'manifest-descriptor:org.opencontainers.image.revision=b08b986ade4dab726334b111c89688491534b732' \
--annotation 'manifest-descriptor:org.opencontainers.image.created=2024-01-25T22:46:52Z' \
--annotation 'manifest-descriptor:org.opencontainers.image.version=devel-20240114' \
--annotation 'manifest-descriptor:org.opencontainers.image.url=https://hub.docker.com/_/bash' \
--tag 'bash:devel-20240114' \
--tag 'bash:devel' \
--tag 'bash:devel-20240114-alpine3.19' \
--tag 'bash:devel-alpine3.19' \
--tag 'amd64/bash:devel-20240114' \
--tag 'amd64/bash:devel' \
--tag 'amd64/bash:devel-20240114-alpine3.19' \
--tag 'amd64/bash:devel-alpine3.19' \
--tag 'oisupport/staging-amd64:dbfd320b24fdbcf3e17174640287049bde81906f59592b6d4e3e42f47f9b5517' \
--platform 'linux/amd64' \
--build-context 'alpine:3.19=docker-image://alpine:3.19@sha256:13b7e62e8df80264dbb747995705a986aa530415763a6c58f84a3ca8af9a5bcd' \
--build-arg BUILDKIT_SYNTAX="$BASHBREW_BUILDKIT_SYNTAX" \
--file 'Dockerfile' \
'https://github.com/tianon/docker-bash.git#b08b986ade4dab726334b111c89688491534b732:devel'
mkdir temp
tar -xvf temp.tar -C temp
rm temp.tar
jq '
.manifests |= (
del(.[].annotations)
| unique
| if length != 1 then
error("unexpected number of manifests: " + length)
else . end
)
' temp/index.json > temp/index.json.new
mv temp/index.json.new temp/index.json |
|
Realizing we could (ab)use our So, feel free to review this, but I think I'm going to work on that as a separate thing so I can use this PR as the guinea pig for showing off the result of it. |
|
Rebased on top of #18 so the diff to |
…tion - explicit "containerd image storage in dockerd" placeholder - explicit "annotations" helper/generator (so they can be added in the `oci-import` builder later) - setting the `org.opencontainers.image.created` annoation inside the image index to the actual build date (otherwise `SOURCE_DATE_EPOCH` makes it hard to tell an image is actually freshly built) - more whitespace in generated commands for better readability - extract OCI tar in the build step (so the "output" of the build is an OCI layout directory vs tarball) instead of the pull step (so we can more ergonomically add pre-push signing) - use buildx's `--annotation` flag for making annotations easier to read
|
|
||
| # </pull> | ||
| # <build> | ||
| SOURCE_DATE_EPOCH=1700741054 docker buildx build --progress=plain --provenance=mode=max --sbom=generator="$BASHBREW_BUILDKIT_SBOM_GENERATOR" --output '"type=oci","dest=temp.tar","annotation.org.opencontainers.image.source=https://github.com/docker-library/docker.git#6d541d27b5dd12639e5a33a675ebca04d3837d74:24/cli","annotation-manifest-descriptor.org.opencontainers.image.source=https://github.com/docker-library/docker.git#6d541d27b5dd12639e5a33a675ebca04d3837d74:24/cli","annotation.org.opencontainers.image.revision=6d541d27b5dd12639e5a33a675ebca04d3837d74","annotation-manifest-descriptor.org.opencontainers.image.revision=6d541d27b5dd12639e5a33a675ebca04d3837d74","annotation.org.opencontainers.image.version=24.0.7-cli","annotation-manifest-descriptor.org.opencontainers.image.version=24.0.7-cli","annotation.org.opencontainers.image.url=https://hub.docker.com/_/docker","annotation-manifest-descriptor.org.opencontainers.image.url=https://hub.docker.com/_/docker"' --tag 'docker:24.0.7-cli' --tag 'docker:24.0-cli' --tag 'docker:24-cli' --tag 'docker:cli' --tag 'docker:24.0.7-cli-alpine3.18' --tag 'oisupport/staging-amd64:4b199ac326c74b3058a147e14f553af9e8e1659abc29bd3e82c9c9807b66ee43' --platform 'linux/amd64' --build-context 'alpine:3.18=docker-image://alpine:3.18@sha256:d695c3de6fcd8cfe3a6222b0358425d40adfd129a8a47c3416faff1a8aece389' --build-arg BUILDKIT_SYNTAX="$BASHBREW_BUILDKIT_SYNTAX" --file 'Dockerfile' 'https://github.com/docker-library/docker.git#6d541d27b5dd12639e5a33a675ebca04d3837d74:24/cli' |
There was a problem hiding this comment.
This change is much cuter with --ignore-all-space --word-diff:
Diff:
diff --git a/.test/example-commands.sh b/.test/example-commands.sh
index f165244..4bcbaf8 100644
--- a/.test/example-commands.sh
+++ b/.test/example-commands.sh
@@ -3,15 +3,49 @@
# </pull>
# <build>
SOURCE_DATE_EPOCH=1700741054 {+\+}
docker buildx build --progress=plain {+\+}
--provenance=mode=max {+\+}
--sbom=generator="$BASHBREW_BUILDKIT_SBOM_GENERATOR" {+\+}
--output [-'"type=oci","dest=temp.tar","annotation.org.opencontainers.image.source=https://github.com/docker-library/docker.git#6d541d27b5dd12639e5a33a675ebca04d3837d74:24/cli","annotation-manifest-descriptor.org.opencontainers.image.source=https://github.com/docker-library/docker.git#6d541d27b5dd12639e5a33a675ebca04d3837d74:24/cli","annotation.org.opencontainers.image.revision=6d541d27b5dd12639e5a33a675ebca04d3837d74","annotation-manifest-descriptor.org.opencontainers.image.revision=6d541d27b5dd12639e5a33a675ebca04d3837d74","annotation.org.opencontainers.image.version=24.0.7-cli","annotation-manifest-descriptor.org.opencontainers.image.version=24.0.7-cli","annotation.org.opencontainers.image.url=https://hub.docker.com/_/docker","annotation-manifest-descriptor.org.opencontainers.image.url=https://hub.docker.com/_/docker"'-]{+'"type=oci","dest=temp.tar"' \+}
{+ --annotation 'org.opencontainers.image.source=https://github.com/docker-library/docker.git#6d541d27b5dd12639e5a33a675ebca04d3837d74:24/cli' \+}
{+ --annotation 'org.opencontainers.image.revision=6d541d27b5dd12639e5a33a675ebca04d3837d74' \+}
{+ --annotation 'org.opencontainers.image.created=2023-11-23T12:04:14Z' \+}
{+ --annotation 'org.opencontainers.image.version=24.0.7-cli' \+}
{+ --annotation 'org.opencontainers.image.url=https://hub.docker.com/_/docker' \+}
{+ --annotation 'manifest-descriptor:org.opencontainers.image.source=https://github.com/docker-library/docker.git#6d541d27b5dd12639e5a33a675ebca04d3837d74:24/cli' \+}
{+ --annotation 'manifest-descriptor:org.opencontainers.image.revision=6d541d27b5dd12639e5a33a675ebca04d3837d74' \+}
{+ --annotation 'manifest-descriptor:org.opencontainers.image.created=1970-01-01T00:00:00Z' \+}
{+ --annotation 'manifest-descriptor:org.opencontainers.image.version=24.0.7-cli' \+}
{+ --annotation 'manifest-descriptor:org.opencontainers.image.url=https://hub.docker.com/_/docker' \+}
--tag 'docker:24.0.7-cli' {+\+}
--tag 'docker:24.0-cli' {+\+}
--tag 'docker:24-cli' {+\+}
--tag 'docker:cli' {+\+}
--tag 'docker:24.0.7-cli-alpine3.18' {+\+}
--tag 'oisupport/staging-amd64:4b199ac326c74b3058a147e14f553af9e8e1659abc29bd3e82c9c9807b66ee43' {+\+}
--platform 'linux/amd64' {+\+}
--build-context 'alpine:3.18=docker-image://alpine:3.18@sha256:d695c3de6fcd8cfe3a6222b0358425d40adfd129a8a47c3416faff1a8aece389' {+\+}
--build-arg BUILDKIT_SYNTAX="$BASHBREW_BUILDKIT_SYNTAX" {+\+}
--file 'Dockerfile' {+\+}
'https://github.com/docker-library/docker.git#6d541d27b5dd12639e5a33a675ebca04d3837d74:24/cli'[-# </build>-]
[-# <push>-]
mkdir temp
tar -xvf temp.tar -C temp
{+rm temp.tar+}
jq [-'.manifests-]{+'+}
{+ .manifests+} |= [-(del(.[].annotations)-]{+(+}
{+ del(.[].annotations)+}
| [-unique)'-]{+unique+}
{+ | if length != 1 then+}
{+ error("unexpected number of manifests: " + length)+}
{+ else . end+}
{+ )+}
{+'+} temp/index.json > temp/index.json.new
mv temp/index.json.new temp/index.json
{+# </build>+}
{+# <push>+}
crane push temp 'oisupport/staging-amd64:4b199ac326c74b3058a147e14f553af9e8e1659abc29bd3e82c9c9807b66ee43'
rm -rf temp[-temp.tar-]
# </push>
# docker:24.0.7-windowsservercore-ltsc2022 [windows-amd64]
@@ -20,7 +54,21 @@ docker pull 'mcr.microsoft.com/windows/servercore:ltsc2022@sha256:d4ab2dd7d3d0fc
docker tag 'mcr.microsoft.com/windows/servercore:ltsc2022@sha256:d4ab2dd7d3d0fce6edc5df459565a4c96bbb1d0148065b215ab5ddcab1e42eb4' 'mcr.microsoft.com/windows/servercore:ltsc2022'
# </pull>
# <build>
SOURCE_DATE_EPOCH=1700741054 {+\+}
DOCKER_BUILDKIT=0 {+\+}
docker build {+\+}
--tag 'docker:24.0.7-windowsservercore-ltsc2022' {+\+}
--tag 'docker:24.0-windowsservercore-ltsc2022' {+\+}
--tag 'docker:24-windowsservercore-ltsc2022' {+\+}
--tag 'docker:windowsservercore-ltsc2022' {+\+}
--tag 'docker:24.0.7-windowsservercore' {+\+}
--tag 'docker:24.0-windowsservercore' {+\+}
--tag 'docker:24-windowsservercore' {+\+}
--tag 'docker:windowsservercore' {+\+}
--tag 'oisupport/staging-windows-amd64:9b405cfa5b88ba65121aabdb95ae90fd2e1fee7582174de82ae861613ae3072e' {+\+}
--platform 'windows/amd64' {+\+}
--file 'Dockerfile' {+\+}
'https://github.com/docker-library/docker.git#6d541d27b5dd12639e5a33a675ebca04d3837d74:24/windows/windowsservercore-ltsc2022'
# </build>
# <push>
docker push 'oisupport/staging-windows-amd64:9b405cfa5b88ba65121aabdb95ae90fd2e1fee7582174de82ae861613ae3072e'| rm temp.tar | ||
| jq ' | ||
| .manifests |= ( | ||
| del(.[].annotations) |
There was a problem hiding this comment.
There was a problem hiding this comment.
Then why do we add them in the build? (Sorry for my ignorance)
There was a problem hiding this comment.
So that they show up in the provenance data 😅
| "mkdir temp", | ||
| "tar -xvf temp.tar -C temp", | ||
| "rm temp.tar", | ||
| # munge the index to what crane wants ("Error: layout contains 5 entries, consider --index") |
There was a problem hiding this comment.
Correct -- because of the limitations of an OCI layout as a docker save format, the output from docker buildx build --output type=tar generates an index.json with a new entry for every --tag flag:
$ docker buildx build --builder foo --quiet --output type=oci - <<<$'FROM scratch\nCMD []' --tag foo --tag bar --tag baz | tar --extract --to-stdout index.json | jq
{
"schemaVersion": 2,
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:1be03c71b27e7950b1a52e029ad139847a0771de9d2705ae8ab3742cd7d91ad6",
"size": 288,
"annotations": {
"io.containerd.image.name": "docker.io/library/foo:latest",
"org.opencontainers.image.created": "2024-01-26T18:48:33Z",
"org.opencontainers.image.ref.name": "latest"
},
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:1be03c71b27e7950b1a52e029ad139847a0771de9d2705ae8ab3742cd7d91ad6",
"size": 288,
"annotations": {
"io.containerd.image.name": "docker.io/library/bar:latest",
"org.opencontainers.image.created": "2024-01-26T18:48:33Z",
"org.opencontainers.image.ref.name": "latest"
},
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:1be03c71b27e7950b1a52e029ad139847a0771de9d2705ae8ab3742cd7d91ad6",
"size": 288,
"annotations": {
"io.containerd.image.name": "docker.io/library/baz:latest",
"org.opencontainers.image.created": "2024-01-26T18:48:33Z",
"org.opencontainers.image.ref.name": "latest"
},
"platform": {
"architecture": "amd64",
"os": "linux"
}
}
]
}Because the annotations are where the unique tags are stored, if we delete those, then unique can give us a single entry instead:
$ docker buildx build --builder foo --quiet --output type=oci - <<<$'FROM scratch\nCMD []' --tag foo --tag bar --tag baz | tar --extract --to-stdout index.json | jq '.manifests |= (del(.[].annotations) | unique)'
{
"schemaVersion": 2,
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:1be03c71b27e7950b1a52e029ad139847a0771de9d2705ae8ab3742cd7d91ad6",
"size": 288,
"platform": {
"architecture": "amd64",
"os": "linux"
}
}
]
}And now again, but this time with --provenance turned on (so we get an image index instead of an image manifest -- note the mediaType field in the descriptor):
$ docker buildx build --builder foo --provenance=mode=max --no-cache --quiet --output type=oci - <<<$'FROM hello-world' --tag foo --tag bar --tag baz | tar --extract --to-stdout index.json | jq '.manifests |= (del(.[].annotations) | unique)'
{
"schemaVersion": 2,
"manifests": [
{
"mediaType": "application/vnd.oci.image.index.v1+json",
"digest": "sha256:a3cd4b5d34fcc7fe9ae1f6a9fd5459b7297e6cee7f6a5b200b715932a0fcb246",
"size": 855
}
]
}
oci-importbuilder later)org.opencontainers.image.createdannoation inside the image index to the actual build date (otherwiseSOURCE_DATE_EPOCHmakes it hard to tell an image is actually freshly built)--annotationflag for making annotations easier to read