From f0845ac8867a03a4762cfb940e13928036247f23 Mon Sep 17 00:00:00 2001 From: CrazyMax <1951866+crazy-max@users.noreply.github.com> Date: Sat, 14 Mar 2026 15:24:14 +0100 Subject: [PATCH] set index annotations on imagetools create Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com> --- .github/workflows/.test-bake.yml | 26 ++++++++++++++++++++++++++ .github/workflows/.test-build.yml | 26 ++++++++++++++++++++++++++ .github/workflows/bake.yml | 25 +++++++++++++++++++++++++ .github/workflows/build.yml | 27 +++++++++++++++++++++++++++ 4 files changed, 104 insertions(+) diff --git a/.github/workflows/.test-bake.yml b/.github/workflows/.test-bake.yml index 2ae83e0a..dbbdb488 100644 --- a/.github/workflows/.test-bake.yml +++ b/.github/workflows/.test-bake.yml @@ -596,3 +596,29 @@ jobs: sbom: true sign: ${{ github.event_name != 'pull_request' }} target: go-cross-with-contexts + + bake-ghcr-index-annotations: + uses: ./.github/workflows/bake.yml + permissions: + contents: read + id-token: write + packages: write + with: + context: test + output: image + push: ${{ github.event_name != 'pull_request' }} + sbom: true + set: | + *.args.VERSION={{meta.version}} + target: hello-cross + set-meta-annotations: true + meta-images: ghcr.io/docker/github-builder-test + meta-tags: | + type=raw,value=bake-index-annotations-${{ github.run_id }} + meta-annotations: | + io.github.docker.github-builder.test-index-annotation=bake-${{ github.run_id }} + secrets: + registry-auths: | + - registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/.test-build.yml b/.github/workflows/.test-build.yml index c8c81e59..9f889bbe 100644 --- a/.github/workflows/.test-build.yml +++ b/.github/workflows/.test-build.yml @@ -615,3 +615,29 @@ jobs: - registry: registry-1-stage.docker.io username: ${{ vars.DOCKERHUB_STAGE_USERNAME }} password: ${{ secrets.DOCKERHUB_STAGE_TOKEN }} + + build-ghcr-index-annotations: + uses: ./.github/workflows/build.yml + permissions: + contents: read + id-token: write + packages: write + with: + annotations: | + io.github.docker.github-builder.test-index-annotation=build-${{ github.run_id }} + build-args: | + VERSION={{meta.version}} + file: test/hello.Dockerfile + output: image + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + sbom: true + set-meta-annotations: true + meta-images: ghcr.io/docker/github-builder-test + meta-tags: | + type=raw,value=build-index-annotations-${{ github.run_id }} + secrets: + registry-auths: | + - registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/bake.yml b/.github/workflows/bake.yml index 1bd630b1..6655e300 100644 --- a/.github/workflows/bake.yml +++ b/.github/workflows/bake.yml @@ -976,6 +976,8 @@ jobs: INPUT_IMAGE-NAMES: ${{ inputs.meta-images }} INPUT_TAG-NAMES: ${{ steps.meta.outputs.tag-names }} INPUT_BUILD-OUTPUTS: ${{ toJSON(needs.build.outputs) }} + INPUT_SET-META-ANNOTATIONS: ${{ inputs.set-meta-annotations }} + INPUT_META-ANNOTATIONS: ${{ steps.meta.outputs.annotations }} with: script: | const { ImageTools } = require('@docker/actions-toolkit/lib/buildx/imagetools'); @@ -984,6 +986,28 @@ jobs: const inpImageNames = core.getMultilineInput('image-names'); const inpTagNames = core.getMultilineInput('tag-names'); const inpBuildOutputs = JSON.parse(core.getInput('build-outputs')); + const inpSetMetaAnnotations = core.getBooleanInput('set-meta-annotations'); + const inpMetaAnnotations = core.getMultilineInput('meta-annotations'); + + const toIndexAnnotation = annotation => { + const keyEnd = annotation.indexOf('='); + const rawKey = keyEnd === -1 ? annotation : annotation.substring(0, keyEnd); + const rawValue = keyEnd === -1 ? '' : annotation.substring(keyEnd); + const typeSeparator = rawKey.indexOf(':'); + if (typeSeparator !== -1) { + const typeExpr = rawKey.substring(0, typeSeparator); + const key = rawKey.substring(typeSeparator + 1); + const hasKnownType = typeExpr.split(',').map(type => type.replace(/\[.*\]$/, '')).some(type => ['manifest', 'index', 'manifest-descriptor', 'index-descriptor'].includes(type)); + if (hasKnownType) { + return `index:${key}${rawValue}`; + } + } + return `index:${annotation}`; + }; + const indexAnnotations = []; + if (inpSetMetaAnnotations && inpMetaAnnotations.length > 0) { + indexAnnotations.push(...inpMetaAnnotations.filter(annotation => annotation.length > 0).map(toIndexAnnotation)); + } const digests = []; for (const key of Object.keys(inpBuildOutputs)) { @@ -1006,6 +1030,7 @@ jobs: const result = await new ImageTools().create({ sources: digests, tags: tags, + annotations: indexAnnotations, skipExec: !inpPush }); if (inpPush) { diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 12a1d544..bdde9af8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -839,6 +839,9 @@ jobs: INPUT_IMAGE-NAMES: ${{ inputs.meta-images }} INPUT_TAG-NAMES: ${{ steps.meta.outputs.tag-names }} INPUT_BUILD-OUTPUTS: ${{ toJSON(needs.build.outputs) }} + INPUT_ANNOTATIONS: ${{ inputs.annotations }} + INPUT_SET-META-ANNOTATIONS: ${{ inputs.set-meta-annotations }} + INPUT_META-ANNOTATIONS: ${{ steps.meta.outputs.annotations }} with: script: | const { ImageTools } = require('@docker/actions-toolkit/lib/buildx/imagetools'); @@ -847,6 +850,29 @@ jobs: const inpImageNames = core.getMultilineInput('image-names'); const inpTagNames = core.getMultilineInput('tag-names'); const inpBuildOutputs = JSON.parse(core.getInput('build-outputs')); + const inpAnnotations = core.getMultilineInput('annotations'); + const inpSetMetaAnnotations = core.getBooleanInput('set-meta-annotations'); + const inpMetaAnnotations = core.getMultilineInput('meta-annotations'); + + const toIndexAnnotation = annotation => { + const keyEnd = annotation.indexOf('='); + const rawKey = keyEnd === -1 ? annotation : annotation.substring(0, keyEnd); + const rawValue = keyEnd === -1 ? '' : annotation.substring(keyEnd); + const typeSeparator = rawKey.indexOf(':'); + if (typeSeparator !== -1) { + const typeExpr = rawKey.substring(0, typeSeparator); + const key = rawKey.substring(typeSeparator + 1); + const hasKnownType = typeExpr.split(',').map(type => type.replace(/\[.*\]$/, '')).some(type => ['manifest', 'index', 'manifest-descriptor', 'index-descriptor'].includes(type)); + if (hasKnownType) { + return `index:${key}${rawValue}`; + } + } + return `index:${annotation}`; + }; + if (inpSetMetaAnnotations && inpMetaAnnotations.length > 0) { + inpAnnotations.push(...inpMetaAnnotations); + } + const indexAnnotations = inpAnnotations.filter(annotation => annotation.length > 0).map(toIndexAnnotation); const digests = []; for (const key of Object.keys(inpBuildOutputs)) { @@ -869,6 +895,7 @@ jobs: const result = await new ImageTools().create({ sources: digests, tags: tags, + annotations: indexAnnotations, skipExec: !inpPush }); if (inpPush) {