char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
4d19b2876
char/aliceai-t5-moe
1# This workflow uses actions that are not certified by GitHub. 2# They are provided by a third-party and are governed by 3# separate terms of service, privacy policy, and support 4# 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 image 11 12on : 13workflow_dispatch : # allows manual triggering 14inputs : 15skip_s390x : 16description : "Skip the s390x build target (useful for fast test runs that do not need the IBM Z runner)" 17type : boolean 18default : false 19schedule : 20# Rebuild daily rather than on every push because it is expensive 21- cron : '12 4 * * *' 22 23concurrency : 24group : ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }} 25cancel-in-progress : true 26 27# Fine-grant permission 28# https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token 29permissions : 30packages : write 31 32jobs : 33create_tag : 34name : Create and push git tag 35runs-on : ubuntu-slim 36permissions : 37contents : write 38outputs : 39source_tag : ${{ steps.srctag.outputs.name }} 40 41steps : 42- name : Clone 43id : checkout 44uses : actions/checkout@v6 45with : 46fetch-depth : 0 47ssh-key : ${{ secrets.DEPLOY_KEY_RELEASE }} 48 49- name : Determine source tag name 50id : srctag 51uses : ./.github/actions/get-tag-name 52env : 53BRANCH_NAME : ${{ github.head_ref || github.ref_name }} 54 55- name : Create and push git tag 56env : 57GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} 58run : | 59git tag ${{ steps.srctag.outputs.name }} || exit 0 60git push origin ${{ steps.srctag.outputs.name }} || exit 0 61 62build_ui : 63name : Build UI 64needs : create_tag 65uses : ./.github/workflows/ui-build.yml 66with : 67ui_version : ${{ needs.create_tag.outputs.source_tag }} 68 69prepare_matrices : 70name : Prepare Docker matrices 71runs-on : ubuntu-24.04 72outputs : 73build_matrix : ${{ steps.matrices.outputs.build_matrix }} 74merge_matrix : ${{ steps.matrices.outputs.merge_matrix }} 75 76steps : 77- name : Generate build and merge matrices 78id : matrices 79shell : bash 80env : 81SKIP_S390X : ${{ inputs.skip_s390x || 'false' }} 82run : | 83set -euo pipefail 84 85# Keep all build targets in one place and derive merge targets from it. 86cat > 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] 102JSON 103 104if [ "${SKIP_S390X}" = "true" ]; then 105jq 'map(select(.platforms != "linux/s390x"))' build-matrix.json > build-matrix.json.tmp 106mv build-matrix.json.tmp build-matrix.json 107fi 108 109BUILD_MATRIX="$(jq -c . build-matrix.json)" 110MERGE_MATRIX="$(jq -c ' 111reduce .[] as $entry ({}; .[$entry.tag] |= ( 112. // { 113tag: $entry.tag, 114arches: [], 115full: false, 116light: false, 117server: false 118} 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)) then 126. + { 127s390x: { 128tag: "s390x", 129arches: ["s390x"], 130full: .cpu.full, 131light: .cpu.light, 132server: .cpu.server 133} 134} 135else 136. 137end 138| [.[] | .arches = (.arches | unique | sort | join(" "))] 139' build-matrix.json)" 140 141echo "build_matrix=$BUILD_MATRIX" >> "$GITHUB_OUTPUT" 142echo "merge_matrix=$MERGE_MATRIX" >> "$GITHUB_OUTPUT" 143 144push_to_registry : 145name : Push Docker image to Docker Registry 146needs : [ prepare_matrices , create_tag , build_ui ] 147 148runs-on : ${{ matrix.config.runs_on }} 149strategy : 150fail-fast : false 151matrix : 152config : ${{ fromJSON(needs.prepare_matrices.outputs.build_matrix) }} 153steps : 154- name : Check out the repo 155id : checkout 156uses : actions/checkout@v6 157with : 158fetch-depth : 0 159ref : ${{ needs.create_tag.outputs.source_tag }} 160 161- name : Download prebuilt UI 162if : ${{ matrix.config.prebuilt_ui == true }} 163uses : actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 164with : 165name : llama-ui.zip 166path : tools/ui/dist 167 168- name : Set up QEMU 169if : ${{ contains(matrix.config.platforms, 'linux/amd64') }} 170uses : docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4 171with : 172image : tonistiigi/binfmt:qemu-v10.2.1 173 174- name : Set up Docker Buildx 175uses : docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 176 177- name : Log in to Docker Registry 178uses : docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4 179with : 180registry : ghcr.io 181username : ${{ github.repository_owner }} 182password : ${{ secrets.GITHUB_TOKEN }} 183 184- name : Determine image metadata 185id : meta 186shell : bash 187run : | 188set -euo pipefail 189 190REPO_OWNER="${GITHUB_REPOSITORY_OWNER@L}" # to lower case 191REPO_NAME="${{ github.event.repository.name }}" 192IMAGE_REPO="ghcr.io/${REPO_OWNER}/${REPO_NAME}" 193PREFIX="${IMAGE_REPO}:" 194PLATFORM="${{ matrix.config.platforms }}" 195ARCH_SUFFIX="${PLATFORM#linux/}" 196 197# list all tags possible 198tags="${{ matrix.config.tag }}" 199for tag in $tags; do 200if [[ "$tag" == "cpu" ]]; then 201TYPE="" 202else 203TYPE="-$tag" 204fi 205CACHETAG="${PREFIX}buildcache${TYPE}-${ARCH_SUFFIX}" 206done 207 208SAFE_TAGS="$(echo "$tags" | tr ' ' '_')" 209 210echo "image_repo=$IMAGE_REPO" >> $GITHUB_OUTPUT 211echo "arch_suffix=$ARCH_SUFFIX" >> $GITHUB_OUTPUT 212echo "cache_output_tag=$CACHETAG" >> $GITHUB_OUTPUT 213echo "digest_artifact_suffix=${SAFE_TAGS}-${ARCH_SUFFIX}" >> $GITHUB_OUTPUT 214echo "cache_output_tag=$CACHETAG" # print out for debugging 215env : 216GITHUB_REPOSITORY_OWNER : '${{ github.repository_owner }}' 217 218- name : Get build date 219id : build_date 220run : echo "date=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT 221 222- name : Free Disk Space (Ubuntu) 223if : ${{ matrix.config.free_disk_space == true }} 224uses : ggml-org/free-disk-space@v1.3.1 225with : 226# this might remove tools that are actually needed, 227# if set to "true" but frees about 6 GB 228tool-cache : false 229 230# all of these default to true, but feel free to set to 231# "false" if necessary for your workflow 232android : true 233dotnet : true 234haskell : true 235large-packages : true 236docker-images : true 237swap-storage : true 238 239- name : Build and push Full Docker image by digest 240id : build_full 241if : ${{ (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && matrix.config.full == true }} 242uses : docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7 243with : 244context : . 245platforms : ${{ matrix.config.platforms }} 246outputs : type=image,name=${{ steps.meta.outputs.image_repo }},push-by-digest=true,name-canonical=true,push=true,oci-mediatypes=true 247file : ${{ matrix.config.dockerfile }} 248target : full 249provenance : false 250build-args : | 251BUILD_DATE=${{ steps.build_date.outputs.date }} 252APP_VERSION=${{ needs.create_tag.outputs.source_tag }} 253APP_REVISION=${{ steps.checkout.outputs.commit }} 254IMAGE_URL=${{ github.server_url }}/${{ github.repository }} 255IMAGE_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) || '' }} 258annotations : | 259manifest:org.opencontainers.image.created=${{ steps.build_date.outputs.date }} 260manifest:org.opencontainers.image.version=${{ needs.create_tag.outputs.source_tag }} 261manifest:org.opencontainers.image.revision=${{ steps.checkout.outputs.commit }} 262manifest:org.opencontainers.image.title=llama.cpp 263manifest:org.opencontainers.image.description=LLM inference in C/C++ 264manifest:org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }} 265manifest:org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} 266# using github experimental cache 267#cache-from: type=gha 268#cache-to: type=gha,mode=max 269# return to this if the experimental github cache is having issues 270#cache-to: type=local,dest=/tmp/.buildx-cache 271#cache-from: type=local,src=/tmp/.buildx-cache 272# using registry cache (no storage limit) 273cache-from : type=registry,ref=${{ steps.meta.outputs.cache_output_tag }} 274cache-to : type=registry,ref=${{ steps.meta.outputs.cache_output_tag }},mode=max 275 276- name : Build and push Light Docker image by digest 277id : build_light 278if : ${{ (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && matrix.config.light == true }} 279uses : docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7 280with : 281context : . 282platforms : ${{ matrix.config.platforms }} 283outputs : type=image,name=${{ steps.meta.outputs.image_repo }},push-by-digest=true,name-canonical=true,push=true,oci-mediatypes=true 284file : ${{ matrix.config.dockerfile }} 285target : light 286provenance : false 287build-args : | 288BUILD_DATE=${{ steps.build_date.outputs.date }} 289APP_VERSION=${{ needs.create_tag.outputs.source_tag }} 290APP_REVISION=${{ steps.checkout.outputs.commit }} 291IMAGE_URL=${{ github.server_url }}/${{ github.repository }} 292IMAGE_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) || '' }} 295annotations : | 296manifest:org.opencontainers.image.created=${{ steps.build_date.outputs.date }} 297manifest:org.opencontainers.image.version=${{ needs.create_tag.outputs.source_tag }} 298manifest:org.opencontainers.image.revision=${{ steps.checkout.outputs.commit }} 299manifest:org.opencontainers.image.title=llama.cpp 300manifest:org.opencontainers.image.description=LLM inference in C/C++ 301manifest:org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }} 302manifest:org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} 303# using github experimental cache 304#cache-from: type=gha 305#cache-to: type=gha,mode=max 306# return to this if the experimental github cache is having issues 307#cache-to: type=local,dest=/tmp/.buildx-cache 308#cache-from: type=local,src=/tmp/.buildx-cache 309# using registry cache (no storage limit) 310cache-from : type=registry,ref=${{ steps.meta.outputs.cache_output_tag }} 311cache-to : type=registry,ref=${{ steps.meta.outputs.cache_output_tag }},mode=max 312 313- name : Build and push Server Docker image by digest 314id : build_server 315if : ${{ (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && matrix.config.server == true }} 316uses : docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7 317with : 318context : . 319platforms : ${{ matrix.config.platforms }} 320outputs : type=image,name=${{ steps.meta.outputs.image_repo }},push-by-digest=true,name-canonical=true,push=true,oci-mediatypes=true 321file : ${{ matrix.config.dockerfile }} 322target : server 323provenance : false 324build-args : | 325BUILD_DATE=${{ steps.build_date.outputs.date }} 326APP_VERSION=${{ needs.create_tag.outputs.source_tag }} 327APP_REVISION=${{ steps.checkout.outputs.commit }} 328IMAGE_URL=${{ github.server_url }}/${{ github.repository }} 329IMAGE_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) || '' }} 332annotations : | 333manifest:org.opencontainers.image.created=${{ steps.build_date.outputs.date }} 334manifest:org.opencontainers.image.version=${{ needs.create_tag.outputs.source_tag }} 335manifest:org.opencontainers.image.revision=${{ steps.checkout.outputs.commit }} 336manifest:org.opencontainers.image.title=llama.cpp 337manifest:org.opencontainers.image.description=LLM inference in C/C++ 338manifest:org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }} 339manifest:org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} 340# using github experimental cache 341#cache-from: type=gha 342#cache-to: type=gha,mode=max 343# return to this if the experimental github cache is having issues 344#cache-to: type=local,dest=/tmp/.buildx-cache 345#cache-from: type=local,src=/tmp/.buildx-cache 346# using registry cache (no storage limit) 347cache-from : type=registry,ref=${{ steps.meta.outputs.cache_output_tag }} 348cache-to : type=registry,ref=${{ steps.meta.outputs.cache_output_tag }},mode=max 349 350- name : Export digest metadata 351shell : bash 352run : | 353set -euo pipefail 354 355TAGS="${{ matrix.config.tag }}" 356ARCH_SUFFIX="${{ steps.meta.outputs.arch_suffix }}" 357DIGEST_FILE="/tmp/digests/${{ steps.meta.outputs.digest_artifact_suffix }}.tsv" 358mkdir -p /tmp/digests 359 360add_digest_rows() { 361local image_type="$1" 362local digest="$2" 363 364if [[ -z "$digest" ]]; then 365echo "Missing digest for image_type=${image_type}" >&2 366exit 1 367fi 368 369for tag in $TAGS; do 370printf '%s\t%s\t%s\t%s\n' "$tag" "$ARCH_SUFFIX" "$image_type" "$digest" >> "$DIGEST_FILE" 371done 372} 373 374if [[ "${{ matrix.config.full }}" == "true" ]]; then 375add_digest_rows "full" "${{ steps.build_full.outputs.digest }}" 376fi 377 378if [[ "${{ matrix.config.light }}" == "true" ]]; then 379add_digest_rows "light" "${{ steps.build_light.outputs.digest }}" 380fi 381 382if [[ "${{ matrix.config.server }}" == "true" ]]; then 383add_digest_rows "server" "${{ steps.build_server.outputs.digest }}" 384fi 385 386- name : Upload digest metadata 387uses : actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 388with : 389name : digests-${{ steps.meta.outputs.digest_artifact_suffix }} 390path : /tmp/digests/${{ steps.meta.outputs.digest_artifact_suffix }}.tsv 391if-no-files-found : error 392 393merge_arch_tags : 394name : Create shared tags from digests 395needs : [ prepare_matrices , push_to_registry , create_tag ] 396runs-on : ubuntu-24.04 397permissions : 398contents : read 399packages : write 400id-token : write 401attestations : write 402strategy : 403fail-fast : false 404matrix : 405config : ${{ fromJSON(needs.prepare_matrices.outputs.merge_matrix) }} 406 407steps : 408- name : Check out the repo 409id : checkout 410uses : actions/checkout@v6 411with : 412fetch-depth : 0 413 414- name : Get build date 415id : build_date 416run : echo "date=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT 417 418- name : Download digest metadata 419uses : actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 420with : 421pattern : digests-* 422path : /tmp/digests 423merge-multiple : true 424 425- name : Set up Docker Buildx 426uses : docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 427 428- name : Log in to Docker Registry 429uses : docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4 430with : 431registry : ghcr.io 432username : ${{ github.repository_owner }} 433password : ${{ secrets.GITHUB_TOKEN }} 434 435- name : Create tags from digests 436id : create_tags 437shell : bash 438run : | 439set -euo pipefail 440 441REPO_OWNER="${GITHUB_REPOSITORY_OWNER@L}" # to lower case 442REPO_NAME="${{ github.event.repository.name }}" 443IMAGE_REPO="ghcr.io/${REPO_OWNER}/${REPO_NAME}" 444PREFIX="${IMAGE_REPO}:" 445SRC_TAG="${{ needs.create_tag.outputs.source_tag }}" 446BUILD_DATE="${{ steps.build_date.outputs.date }}" 447COMMIT_SHA="${{ steps.checkout.outputs.commit }}" 448echo "image_repo=${IMAGE_REPO}" >> "$GITHUB_OUTPUT" 449TAGS="${{ matrix.config.tag }}" 450ARCHES="${{ matrix.config.arches }}" 451DIGEST_GLOB="/tmp/digests/*.tsv" 452 453if ! ls ${DIGEST_GLOB} >/dev/null 2>&1; then 454echo "No digest metadata found in /tmp/digests" >&2 455exit 1 456fi 457 458if [[ -z "$SRC_TAG" ]]; then 459echo "Missing source tag from create_tag" >&2 460exit 1 461fi 462 463find_digest() { 464local tag_name="$1" 465local arch="$2" 466local image_type="$3" 467local digest 468 469digest="$(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. 472if [[ -z "$digest" && "$tag_name" == "s390x" && "$arch" == "s390x" ]]; then 473digest="$(awk -F '\t' -v t="cpu" -v a="$arch" -v i="$image_type" '$1 == t && $2 == a && $3 == i { print $4; exit }' ${DIGEST_GLOB})" 474fi 475 476if [[ -z "$digest" ]]; then 477echo "Missing digest for tag=${tag_name} arch=${arch} image_type=${image_type}" >&2 478exit 1 479fi 480 481echo "$digest" 482} 483 484create_manifest_tags() { 485local image_type="$1" 486local tag_name="$2" 487local suffix="$3" 488 489local merged_tag="${PREFIX}${image_type}${suffix}" 490local merged_versioned_tag="${merged_tag}-${SRC_TAG}" 491 492local refs=() 493 494for arch in $ARCHES; do 495local digest 496digest="$(find_digest "$tag_name" "$arch" "$image_type")" 497refs+=("${IMAGE_REPO}@${digest}") 498done 499 500local 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 510echo "Creating ${merged_tag} from ${refs[*]}" 511docker buildx imagetools create "${annotations[@]}" --tag "${merged_tag}" "${refs[@]}" 512 513echo "Creating ${merged_versioned_tag} from ${refs[*]}" 514docker buildx imagetools create "${annotations[@]}" --tag "${merged_versioned_tag}" "${refs[@]}" 515 516if [[ "$tag_name" == "${TAGS%% *}" ]]; then 517local digest 518digest="$(docker buildx imagetools inspect "${merged_versioned_tag}" --format '{{.Manifest.Digest}}')" 519if [[ ! "$digest" =~ ^sha256:[0-9a-f]{64}$ ]]; then 520echo "Invalid digest for ${merged_versioned_tag}: ${digest}" >&2 521exit 1 522fi 523echo "${image_type}_digest=${digest}" >> "$GITHUB_OUTPUT" 524fi 525} 526 527for tag in $TAGS; do 528if [[ "$tag" == "cpu" ]]; then 529TYPE="" 530else 531TYPE="-$tag" 532fi 533 534if [[ "${{ matrix.config.full }}" == "true" ]]; then 535create_manifest_tags "full" "$tag" "$TYPE" 536fi 537 538if [[ "${{ matrix.config.light }}" == "true" ]]; then 539create_manifest_tags "light" "$tag" "$TYPE" 540fi 541 542if [[ "${{ matrix.config.server }}" == "true" ]]; then 543create_manifest_tags "server" "$tag" "$TYPE" 544fi 545done 546env : 547GITHUB_REPOSITORY_OWNER : '${{ github.repository_owner }}' 548 549- name : Attest full image 550if : ${{ matrix.config.full }} 551uses : actions/attest@v4 552with : 553subject-name : ${{ steps.create_tags.outputs.image_repo }} 554subject-digest : ${{ steps.create_tags.outputs.full_digest }} 555 556- name : Attest light image 557if : ${{ matrix.config.light }} 558uses : actions/attest@v4 559with : 560subject-name : ${{ steps.create_tags.outputs.image_repo }} 561subject-digest : ${{ steps.create_tags.outputs.light_digest }} 562 563- name : Attest server image 564if : ${{ matrix.config.server }} 565uses : actions/attest@v4 566with : 567subject-name : ${{ steps.create_tags.outputs.image_repo }} 568subject-digest : ${{ steps.create_tags.outputs.server_digest }}