Team Ai
Modelpublic

Felipe97/llama-cpp-compiled

sourceHugging Faceupdated 18d agoView on Hugging Face
0likes1.2kdownloads
docker.yml569 linesDownload Raw Back to workflows
1# This workflow uses actions that are not certified by GitHub.2# They are provided by a third-party and are governed by3# separate terms of service, privacy policy, and support4# documentation.5 6# GitHub recommends pinning actions to a commit SHA.7# To get a newer version, you will need to update the SHA.8# You can also reference a tag or branch, but the action may change without warning.9 10name: Publish Docker image11 12on:13  workflow_dispatch: # allows manual triggering14    inputs:15      skip_s390x:16        description: "Skip the s390x build target (useful for fast test runs that do not need the IBM Z runner)"17        type: boolean18        default: false19  schedule:20    # Rebuild daily rather than on every push because it is expensive21    - cron: '12 4 * * *'22 23concurrency:24  group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}25  cancel-in-progress: true26 27# Fine-grant permission28# https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token29permissions:30  packages: write31 32jobs:33  create_tag:34    name: Create and push git tag35    runs-on: ubuntu-slim36    permissions:37      contents: write38    outputs:39      source_tag: ${{ steps.srctag.outputs.name }}40 41    steps:42      - name: Clone43        id: checkout44        uses: actions/checkout@v645        with:46          fetch-depth: 047          ssh-key: ${{ secrets.DEPLOY_KEY_RELEASE }}48 49      - name: Determine source tag name50        id: srctag51        uses: ./.github/actions/get-tag-name52        env:53          BRANCH_NAME: ${{ github.head_ref || github.ref_name }}54 55      - name: Create and push git tag56        env:57          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}58        run: |59          git tag ${{ steps.srctag.outputs.name }} || exit 060          git push origin ${{ steps.srctag.outputs.name }} || exit 061 62  build_ui:63    name: Build UI64    needs: create_tag65    uses: ./.github/workflows/ui-build.yml66    with:67      ui_version: ${{ needs.create_tag.outputs.source_tag }}68 69  prepare_matrices:70    name: Prepare Docker matrices71    runs-on: ubuntu-24.0472    outputs:73      build_matrix: ${{ steps.matrices.outputs.build_matrix }}74      merge_matrix: ${{ steps.matrices.outputs.merge_matrix }}75 76    steps:77      - name: Generate build and merge matrices78        id: matrices79        shell: bash80        env:81          SKIP_S390X: ${{ inputs.skip_s390x || 'false' }}82        run: |83          set -euo pipefail84 85          # Keep all build targets in one place and derive merge targets from it.86          cat > build-matrix.json <<'JSON'87          [88            { "tag": "cpu", "dockerfile": ".devops/cpu.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-24.04" },89            { "tag": "cpu", "dockerfile": ".devops/cpu.Dockerfile", "platforms": "linux/arm64", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-24.04-arm" },90            { "tag": "cpu", "dockerfile": ".devops/s390x.Dockerfile", "platforms": "linux/s390x", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-24.04-s390x", "prebuilt_ui": true },91            { "tag": "cuda cuda12", "dockerfile": ".devops/cuda.Dockerfile", "cuda_version": "12.8.1", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-24.04" },92            { "tag": "cuda cuda12", "dockerfile": ".devops/cuda.Dockerfile", "cuda_version": "12.8.1", "platforms": "linux/arm64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-24.04-arm" },93            { "tag": "cuda13", "dockerfile": ".devops/cuda.Dockerfile", "cuda_version": "13.3.0", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-24.04" },94            { "tag": "cuda13", "dockerfile": ".devops/cuda.Dockerfile", "cuda_version": "13.3.0", "platforms": "linux/arm64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-24.04-arm" },95            { "tag": "musa", "dockerfile": ".devops/musa.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-24.04" },96            { "tag": "intel", "dockerfile": ".devops/intel.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-24.04" },97            { "tag": "vulkan", "dockerfile": ".devops/vulkan.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-24.04" },98            { "tag": "vulkan", "dockerfile": ".devops/vulkan.Dockerfile", "platforms": "linux/arm64", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-24.04-arm" },99            { "tag": "rocm", "dockerfile": ".devops/rocm.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-24.04" },100            { "tag": "openvino", "dockerfile": ".devops/openvino.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-24.04" }101          ]102          JSON103 104          if [ "${SKIP_S390X}" = "true" ]; then105            jq 'map(select(.platforms != "linux/s390x"))' build-matrix.json > build-matrix.json.tmp106            mv build-matrix.json.tmp build-matrix.json107          fi108 109          BUILD_MATRIX="$(jq -c . build-matrix.json)"110          MERGE_MATRIX="$(jq -c '111            reduce .[] as $entry ({}; .[$entry.tag] |= (112              . // {113                tag: $entry.tag,114                arches: [],115                full: false,116                light: false,117                server: false118              }119              | .full = (.full or ($entry.full // false))120              | .light = (.light or ($entry.light // false))121              | .server = (.server or ($entry.server // false))122              | .arches += [($entry.platforms | sub("^linux/"; ""))]123            ))124            # Backward compatibility: s390x tags are aliases of cpu for the linux/s390x platform.125            | if (has("cpu") and (((.cpu.arches // []) | index("s390x")) != null)) then126                . + {127                  s390x: {128                    tag: "s390x",129                    arches: ["s390x"],130                    full: .cpu.full,131                    light: .cpu.light,132                    server: .cpu.server133                  }134                }135              else136                .137              end138            | [.[] | .arches = (.arches | unique | sort | join(" "))]139          ' build-matrix.json)"140 141          echo "build_matrix=$BUILD_MATRIX" >> "$GITHUB_OUTPUT"142          echo "merge_matrix=$MERGE_MATRIX" >> "$GITHUB_OUTPUT"143 144  push_to_registry:145    name: Push Docker image to Docker Registry146    needs: [prepare_matrices, create_tag, build_ui]147 148    runs-on: ${{ matrix.config.runs_on }}149    strategy:150      fail-fast: false151      matrix:152        config: ${{ fromJSON(needs.prepare_matrices.outputs.build_matrix) }}153    steps:154      - name: Check out the repo155        id: checkout156        uses: actions/checkout@v6157        with:158          fetch-depth: 0159          ref: ${{ needs.create_tag.outputs.source_tag }}160 161      - name: Download prebuilt UI162        if: ${{ matrix.config.prebuilt_ui == true }}163        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8164        with:165          name: llama-ui.zip166          path: tools/ui/dist167 168      - name: Set up QEMU169        if: ${{ contains(matrix.config.platforms, 'linux/amd64') }}170        uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4171        with:172          image: tonistiigi/binfmt:qemu-v10.2.1173 174      - name: Set up Docker Buildx175        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4176 177      - name: Log in to Docker Registry178        uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4179        with:180          registry: ghcr.io181          username: ${{ github.repository_owner }}182          password: ${{ secrets.GITHUB_TOKEN }}183 184      - name: Determine image metadata185        id: meta186        shell: bash187        run: |188          set -euo pipefail189 190          REPO_OWNER="${GITHUB_REPOSITORY_OWNER@L}"  # to lower case191          REPO_NAME="${{ github.event.repository.name }}"192          IMAGE_REPO="ghcr.io/${REPO_OWNER}/${REPO_NAME}"193          PREFIX="${IMAGE_REPO}:"194          PLATFORM="${{ matrix.config.platforms }}"195          ARCH_SUFFIX="${PLATFORM#linux/}"196 197          # list all tags possible198          tags="${{ matrix.config.tag }}"199          for tag in $tags; do200              if [[ "$tag" == "cpu" ]]; then201                  TYPE=""202              else203                  TYPE="-$tag"204              fi205              CACHETAG="${PREFIX}buildcache${TYPE}-${ARCH_SUFFIX}"206          done207 208          SAFE_TAGS="$(echo "$tags" | tr ' ' '_')"209 210          echo "image_repo=$IMAGE_REPO" >> $GITHUB_OUTPUT211          echo "arch_suffix=$ARCH_SUFFIX" >> $GITHUB_OUTPUT212          echo "cache_output_tag=$CACHETAG" >> $GITHUB_OUTPUT213          echo "digest_artifact_suffix=${SAFE_TAGS}-${ARCH_SUFFIX}" >> $GITHUB_OUTPUT214          echo "cache_output_tag=$CACHETAG"  # print out for debugging215        env:216          GITHUB_REPOSITORY_OWNER: '${{ github.repository_owner }}'217 218      - name: Get build date219        id: build_date220        run: echo "date=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT221 222      - name: Free Disk Space (Ubuntu)223        if: ${{ matrix.config.free_disk_space == true }}224        uses: ggml-org/free-disk-space@v1.3.1225        with:226          # this might remove tools that are actually needed,227          # if set to "true" but frees about 6 GB228          tool-cache: false229 230          # all of these default to true, but feel free to set to231          # "false" if necessary for your workflow232          android: true233          dotnet: true234          haskell: true235          large-packages: true236          docker-images: true237          swap-storage: true238 239      - name: Build and push Full Docker image by digest240        id: build_full241        if: ${{ (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && matrix.config.full == true }}242        uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7243        with:244          context: .245          platforms: ${{ matrix.config.platforms }}246          outputs: type=image,name=${{ steps.meta.outputs.image_repo }},push-by-digest=true,name-canonical=true,push=true,oci-mediatypes=true247          file: ${{ matrix.config.dockerfile }}248          target: full249          provenance: false250          build-args: |251            BUILD_DATE=${{ steps.build_date.outputs.date }}252            APP_VERSION=${{ needs.create_tag.outputs.source_tag }}253            APP_REVISION=${{ steps.checkout.outputs.commit }}254            IMAGE_URL=${{ github.server_url }}/${{ github.repository }}255            IMAGE_SOURCE=${{ github.server_url }}/${{ github.repository }}256            ${{ matrix.config.ubuntu_version && format('UBUNTU_VERSION={0}', matrix.config.ubuntu_version) || '' }}257            ${{ matrix.config.cuda_version && format('CUDA_VERSION={0}', matrix.config.cuda_version) || '' }}258          annotations: |259            manifest:org.opencontainers.image.created=${{ steps.build_date.outputs.date }}260            manifest:org.opencontainers.image.version=${{ needs.create_tag.outputs.source_tag }}261            manifest:org.opencontainers.image.revision=${{ steps.checkout.outputs.commit }}262            manifest:org.opencontainers.image.title=llama.cpp263            manifest:org.opencontainers.image.description=LLM inference in C/C++264            manifest:org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }}265            manifest:org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}266          # using github experimental cache267          #cache-from: type=gha268          #cache-to: type=gha,mode=max269          # return to this if the experimental github cache is having issues270          #cache-to: type=local,dest=/tmp/.buildx-cache271          #cache-from: type=local,src=/tmp/.buildx-cache272          # using registry cache (no storage limit)273          cache-from: type=registry,ref=${{ steps.meta.outputs.cache_output_tag }}274          cache-to: type=registry,ref=${{ steps.meta.outputs.cache_output_tag }},mode=max275 276      - name: Build and push Light Docker image by digest277        id: build_light278        if: ${{ (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && matrix.config.light == true }}279        uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7280        with:281          context: .282          platforms: ${{ matrix.config.platforms }}283          outputs: type=image,name=${{ steps.meta.outputs.image_repo }},push-by-digest=true,name-canonical=true,push=true,oci-mediatypes=true284          file: ${{ matrix.config.dockerfile }}285          target: light286          provenance: false287          build-args: |288            BUILD_DATE=${{ steps.build_date.outputs.date }}289            APP_VERSION=${{ needs.create_tag.outputs.source_tag }}290            APP_REVISION=${{ steps.checkout.outputs.commit }}291            IMAGE_URL=${{ github.server_url }}/${{ github.repository }}292            IMAGE_SOURCE=${{ github.server_url }}/${{ github.repository }}293            ${{ matrix.config.ubuntu_version && format('UBUNTU_VERSION={0}', matrix.config.ubuntu_version) || '' }}294            ${{ matrix.config.cuda_version && format('CUDA_VERSION={0}', matrix.config.cuda_version) || '' }}295          annotations: |296            manifest:org.opencontainers.image.created=${{ steps.build_date.outputs.date }}297            manifest:org.opencontainers.image.version=${{ needs.create_tag.outputs.source_tag }}298            manifest:org.opencontainers.image.revision=${{ steps.checkout.outputs.commit }}299            manifest:org.opencontainers.image.title=llama.cpp300            manifest:org.opencontainers.image.description=LLM inference in C/C++301            manifest:org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }}302            manifest:org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}303          # using github experimental cache304          #cache-from: type=gha305          #cache-to: type=gha,mode=max306          # return to this if the experimental github cache is having issues307          #cache-to: type=local,dest=/tmp/.buildx-cache308          #cache-from: type=local,src=/tmp/.buildx-cache309          # using registry cache (no storage limit)310          cache-from: type=registry,ref=${{ steps.meta.outputs.cache_output_tag }}311          cache-to: type=registry,ref=${{ steps.meta.outputs.cache_output_tag }},mode=max312 313      - name: Build and push Server Docker image by digest314        id: build_server315        if: ${{ (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && matrix.config.server == true }}316        uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7317        with:318          context: .319          platforms: ${{ matrix.config.platforms }}320          outputs: type=image,name=${{ steps.meta.outputs.image_repo }},push-by-digest=true,name-canonical=true,push=true,oci-mediatypes=true321          file: ${{ matrix.config.dockerfile }}322          target: server323          provenance: false324          build-args: |325            BUILD_DATE=${{ steps.build_date.outputs.date }}326            APP_VERSION=${{ needs.create_tag.outputs.source_tag }}327            APP_REVISION=${{ steps.checkout.outputs.commit }}328            IMAGE_URL=${{ github.server_url }}/${{ github.repository }}329            IMAGE_SOURCE=${{ github.server_url }}/${{ github.repository }}330            ${{ matrix.config.ubuntu_version && format('UBUNTU_VERSION={0}', matrix.config.ubuntu_version) || '' }}331            ${{ matrix.config.cuda_version && format('CUDA_VERSION={0}', matrix.config.cuda_version) || '' }}332          annotations: |333            manifest:org.opencontainers.image.created=${{ steps.build_date.outputs.date }}334            manifest:org.opencontainers.image.version=${{ needs.create_tag.outputs.source_tag }}335            manifest:org.opencontainers.image.revision=${{ steps.checkout.outputs.commit }}336            manifest:org.opencontainers.image.title=llama.cpp337            manifest:org.opencontainers.image.description=LLM inference in C/C++338            manifest:org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }}339            manifest:org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}340          # using github experimental cache341          #cache-from: type=gha342          #cache-to: type=gha,mode=max343          # return to this if the experimental github cache is having issues344          #cache-to: type=local,dest=/tmp/.buildx-cache345          #cache-from: type=local,src=/tmp/.buildx-cache346          # using registry cache (no storage limit)347          cache-from: type=registry,ref=${{ steps.meta.outputs.cache_output_tag }}348          cache-to: type=registry,ref=${{ steps.meta.outputs.cache_output_tag }},mode=max349 350      - name: Export digest metadata351        shell: bash352        run: |353            set -euo pipefail354 355            TAGS="${{ matrix.config.tag }}"356            ARCH_SUFFIX="${{ steps.meta.outputs.arch_suffix }}"357            DIGEST_FILE="/tmp/digests/${{ steps.meta.outputs.digest_artifact_suffix }}.tsv"358            mkdir -p /tmp/digests359 360            add_digest_rows() {361                local image_type="$1"362                local digest="$2"363 364                if [[ -z "$digest" ]]; then365                  echo "Missing digest for image_type=${image_type}" >&2366                  exit 1367                fi368 369                for tag in $TAGS; do370                    printf '%s\t%s\t%s\t%s\n' "$tag" "$ARCH_SUFFIX" "$image_type" "$digest" >> "$DIGEST_FILE"371                done372            }373 374            if [[ "${{ matrix.config.full }}" == "true" ]]; then375                add_digest_rows "full" "${{ steps.build_full.outputs.digest }}"376            fi377 378            if [[ "${{ matrix.config.light }}" == "true" ]]; then379                add_digest_rows "light" "${{ steps.build_light.outputs.digest }}"380            fi381 382            if [[ "${{ matrix.config.server }}" == "true" ]]; then383                add_digest_rows "server" "${{ steps.build_server.outputs.digest }}"384            fi385 386      - name: Upload digest metadata387        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7388        with:389          name: digests-${{ steps.meta.outputs.digest_artifact_suffix }}390          path: /tmp/digests/${{ steps.meta.outputs.digest_artifact_suffix }}.tsv391          if-no-files-found: error392 393  merge_arch_tags:394    name: Create shared tags from digests395    needs: [prepare_matrices, push_to_registry, create_tag]396    runs-on: ubuntu-24.04397    permissions:398      contents: read399      packages: write400      id-token: write401      attestations: write402    strategy:403      fail-fast: false404      matrix:405        config: ${{ fromJSON(needs.prepare_matrices.outputs.merge_matrix) }}406 407    steps:408      - name: Check out the repo409        id: checkout410        uses: actions/checkout@v6411        with:412          fetch-depth: 0413 414      - name: Get build date415        id: build_date416        run: echo "date=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT417 418      - name: Download digest metadata419        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8420        with:421          pattern: digests-*422          path: /tmp/digests423          merge-multiple: true424 425      - name: Set up Docker Buildx426        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4427 428      - name: Log in to Docker Registry429        uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4430        with:431          registry: ghcr.io432          username: ${{ github.repository_owner }}433          password: ${{ secrets.GITHUB_TOKEN }}434 435      - name: Create tags from digests436        id: create_tags437        shell: bash438        run: |439          set -euo pipefail440 441          REPO_OWNER="${GITHUB_REPOSITORY_OWNER@L}"  # to lower case442          REPO_NAME="${{ github.event.repository.name }}"443          IMAGE_REPO="ghcr.io/${REPO_OWNER}/${REPO_NAME}"444          PREFIX="${IMAGE_REPO}:"445          SRC_TAG="${{ needs.create_tag.outputs.source_tag }}"446          BUILD_DATE="${{ steps.build_date.outputs.date }}"447          COMMIT_SHA="${{ steps.checkout.outputs.commit }}"448          echo "image_repo=${IMAGE_REPO}" >> "$GITHUB_OUTPUT"449          TAGS="${{ matrix.config.tag }}"450          ARCHES="${{ matrix.config.arches }}"451          DIGEST_GLOB="/tmp/digests/*.tsv"452 453          if ! ls ${DIGEST_GLOB} >/dev/null 2>&1; then454              echo "No digest metadata found in /tmp/digests" >&2455              exit 1456          fi457 458          if [[ -z "$SRC_TAG" ]]; then459              echo "Missing source tag from create_tag" >&2460              exit 1461          fi462 463          find_digest() {464              local tag_name="$1"465              local arch="$2"466              local image_type="$3"467              local digest468 469              digest="$(awk -F '\t' -v t="$tag_name" -v a="$arch" -v i="$image_type" '$1 == t && $2 == a && $3 == i { print $4; exit }' ${DIGEST_GLOB})"470 471              # Backward compatibility: s390x tags are aliases of cpu for the linux/s390x platform.472              if [[ -z "$digest" && "$tag_name" == "s390x" && "$arch" == "s390x" ]]; then473                digest="$(awk -F '\t' -v t="cpu" -v a="$arch" -v i="$image_type" '$1 == t && $2 == a && $3 == i { print $4; exit }' ${DIGEST_GLOB})"474              fi475 476              if [[ -z "$digest" ]]; then477                echo "Missing digest for tag=${tag_name} arch=${arch} image_type=${image_type}" >&2478                exit 1479              fi480 481              echo "$digest"482          }483 484          create_manifest_tags() {485              local image_type="$1"486              local tag_name="$2"487              local suffix="$3"488 489              local merged_tag="${PREFIX}${image_type}${suffix}"490              local merged_versioned_tag="${merged_tag}-${SRC_TAG}"491 492              local refs=()493 494              for arch in $ARCHES; do495                  local digest496                  digest="$(find_digest "$tag_name" "$arch" "$image_type")"497                  refs+=("${IMAGE_REPO}@${digest}")498              done499 500              local annotations=(501                  --annotation "index:org.opencontainers.image.created=${BUILD_DATE}"502                  --annotation "index:org.opencontainers.image.version=${SRC_TAG}"503                  --annotation "index:org.opencontainers.image.revision=${COMMIT_SHA}"504                  --annotation "index:org.opencontainers.image.title=llama.cpp"505                  --annotation "index:org.opencontainers.image.description=LLM inference in C/C++"506                  --annotation "index:org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }}"507                  --annotation "index:org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}"508              )509 510              echo "Creating ${merged_tag} from ${refs[*]}"511              docker buildx imagetools create "${annotations[@]}" --tag "${merged_tag}" "${refs[@]}"512 513              echo "Creating ${merged_versioned_tag} from ${refs[*]}"514              docker buildx imagetools create "${annotations[@]}" --tag "${merged_versioned_tag}" "${refs[@]}"515 516              if [[ "$tag_name" == "${TAGS%% *}" ]]; then517                  local digest518                  digest="$(docker buildx imagetools inspect "${merged_versioned_tag}" --format '{{.Manifest.Digest}}')"519                  if [[ ! "$digest" =~ ^sha256:[0-9a-f]{64}$ ]]; then520                      echo "Invalid digest for ${merged_versioned_tag}: ${digest}" >&2521                      exit 1522                  fi523                  echo "${image_type}_digest=${digest}" >> "$GITHUB_OUTPUT"524              fi525          }526 527          for tag in $TAGS; do528              if [[ "$tag" == "cpu" ]]; then529                  TYPE=""530              else531                  TYPE="-$tag"532              fi533 534              if [[ "${{ matrix.config.full }}" == "true" ]]; then535                  create_manifest_tags "full" "$tag" "$TYPE"536              fi537 538              if [[ "${{ matrix.config.light }}" == "true" ]]; then539                  create_manifest_tags "light" "$tag" "$TYPE"540              fi541 542              if [[ "${{ matrix.config.server }}" == "true" ]]; then543                  create_manifest_tags "server" "$tag" "$TYPE"544              fi545          done546        env:547          GITHUB_REPOSITORY_OWNER: '${{ github.repository_owner }}'548 549      - name: Attest full image550        if: ${{ matrix.config.full }}551        uses: actions/attest@v4552        with:553          subject-name: ${{ steps.create_tags.outputs.image_repo }}554          subject-digest: ${{ steps.create_tags.outputs.full_digest }}555 556      - name: Attest light image557        if: ${{ matrix.config.light }}558        uses: actions/attest@v4559        with:560          subject-name: ${{ steps.create_tags.outputs.image_repo }}561          subject-digest: ${{ steps.create_tags.outputs.light_digest }}562 563      - name: Attest server image564        if: ${{ matrix.config.server }}565        uses: actions/attest@v4566        with:567          subject-name: ${{ steps.create_tags.outputs.image_repo }}568          subject-digest: ${{ steps.create_tags.outputs.server_digest }}569