diff --git a/.github/actions/build-image/action.yml b/.github/actions/build-image/action.yml new file mode 100644 index 00000000..2e249018 --- /dev/null +++ b/.github/actions/build-image/action.yml @@ -0,0 +1,188 @@ +name: Docker build and optionally push image on Windows +description: Build a Windows Docker image, optionally push it, and output its digest + +inputs: + context: + required: true + description: Docker build context path + + dockerfile: + required: true + description: Dockerfile path + + tags: + required: true + description: Newline-separated image tags + + label_revision: + required: true + description: org.opencontainers.image.revision label value + + label_created: + required: true + description: org.opencontainers.image.created label value + + pull_images: + required: false + default: "" + description: Newline-separated image references to pull before build + + build_args: + required: false + default: "" + description: Newline-separated build arguments in NAME=value format + + push: + required: false + default: "true" + description: Whether to push built image tags + + remove_readme: + required: false + default: "true" + description: Whether to remove README.md from the build context + +outputs: + digest: + description: Built image digest or image ID + value: ${{ steps.build_push.outputs.digest }} + +runs: + using: composite + steps: + - name: Build and optionally push image + id: build_push + shell: pwsh + env: + CONTEXT: ${{ inputs.context }} + DOCKERFILE: ${{ inputs.dockerfile }} + TAGS: ${{ inputs.tags }} + LABEL_REVISION: ${{ inputs.label_revision }} + LABEL_CREATED: ${{ inputs.label_created }} + PULL_IMAGES: ${{ inputs.pull_images }} + BUILD_ARGS_INPUT: ${{ inputs.build_args }} + PUSH_IMAGES: ${{ inputs.push }} + REMOVE_README: ${{ inputs.remove_readme }} + run: | + $ErrorActionPreference = 'Stop' + Set-StrictMode -Version Latest + + Write-Output '::group::Docker version' + docker version + Write-Output '::endgroup::' + + Write-Output '::group::Docker info' + docker info + Write-Output '::endgroup::' + + if ($Env:REMOVE_README -eq 'true') { + Remove-Item -ErrorAction Ignore -Force -Path (Join-Path $Env:CONTEXT 'README.md') + } + + $tagsArray = $Env:TAGS -split "\r?\n" | Where-Object { $_.Trim() } + if ($tagsArray.Count -eq 0) { + throw 'No image tags provided' + } + + $tagArgs = @() + foreach ($tag in $tagsArray) { + $tagArgs += "--tag=$tag" + } + + Write-Output '::group::Image tags' + $tagsArray | ForEach-Object { Write-Output $_ } + Write-Output '::endgroup::' + + $pullImagesArray = $Env:PULL_IMAGES -split "\r?\n" | Where-Object { $_.Trim() } + if ($pullImagesArray.Count -gt 0) { + Write-Output '::group::Pull base images' + foreach ($image in $pullImagesArray) { + Write-Output "docker pull $image" + docker pull $image + if (-not $?) { + throw "Failed to pull $image" + } + } + Write-Output '::endgroup::' + } + + $buildArgsInputArray = $Env:BUILD_ARGS_INPUT -split "\r?\n" | Where-Object { $_.Trim() } + $buildArgCliArgs = @() + + foreach ($buildArg in $buildArgsInputArray) { + $buildArgCliArgs += "--build-arg=$buildArg" + } + + Write-Output '::group::Build arguments' + if ($buildArgsInputArray.Count -gt 0) { + $buildArgsInputArray | ForEach-Object { Write-Output $_ } + } + else { + Write-Output 'No build arguments provided' + } + Write-Output '::endgroup::' + + Write-Output '::group::Build image' + Write-Output @" + docker build --label org.opencontainers.image.revision=$Env:LABEL_REVISION ` + --label org.opencontainers.image.created=$Env:LABEL_CREATED ` + $($buildArgCliArgs -join " ") ` + --file=$Env:DOCKERFILE ` + $($tagArgs -join " ") ` + $Env:CONTEXT + "@ + + docker build ` + --label "org.opencontainers.image.revision=$Env:LABEL_REVISION" ` + --label "org.opencontainers.image.created=$Env:LABEL_CREATED" ` + $buildArgCliArgs ` + --file "$Env:DOCKERFILE" ` + $tagArgs ` + "$Env:CONTEXT" + + if (-not $?) { + throw 'Failed to build image' + } + Write-Output '::endgroup::' + + Write-Output '::group::Publish image' + if ($Env:PUSH_IMAGES -eq 'true') { + foreach ($tag in $tagsArray) { + Write-Output "docker image push $tag" + docker image push $tag + if (-not $?) { + throw "Failed to push $tag" + } + } + + $repoDigest = docker inspect $tagsArray[0] --format "{{ index .RepoDigests 0}}" + if (-not $?) { + throw "Failed to inspect RepoDigests for $($tagsArray[0])" + } + + $digest = $repoDigest.Split('@')[-1] + if ([string]::IsNullOrWhiteSpace($digest)) { + throw 'Image digest is empty' + } + + Write-Output 'Image digest got from RepoDigests' + } + else { + $digest = docker inspect $tagsArray[0] --format "{{ .Id }}" + if (-not $?) { + throw "Failed to inspect image Id for $($tagsArray[0])" + } + + if ([string]::IsNullOrWhiteSpace($digest)) { + throw 'Image ID digest is empty' + } + + Write-Output 'Image digest got from Id' + } + Write-Output '::endgroup::' + + Write-Output '::group::Digest' + Write-Output $digest + Write-Output '::endgroup::' + + "digest=$digest" >> $Env:GITHUB_OUTPUT diff --git a/.github/actions/cosign-sign/action.yml b/.github/actions/cosign-sign/action.yml index b799b060..5eb02c37 100644 --- a/.github/actions/cosign-sign/action.yml +++ b/.github/actions/cosign-sign/action.yml @@ -7,12 +7,13 @@ inputs: description: Built image digest tags: required: true - description: Space-separated image tags + description: Newline-separated image tags runs: using: composite steps: - - name: Sign images + - name: Sign images on Linux + if: runner.os != 'Windows' shell: bash env: DIGEST: ${{ inputs.digest }} @@ -21,9 +22,16 @@ runs: set -euo pipefail images=() - for tag in ${TAGS}; do + + while IFS= read -r tag; do + [[ -n "$tag" ]] || continue images+=("${tag}@${DIGEST}") - done + done <<< "$TAGS" + + if [[ ${#images[@]} -eq 0 ]]; then + echo "No image tags provided" + exit 1 + fi echo "::group::Images to sign" printf '%s\n' "${images[@]}" @@ -32,3 +40,32 @@ runs: echo "::group::Signing" cosign sign --yes "${images[@]}" echo "::endgroup::" + + - name: Sign images on Windows + if: runner.os == 'Windows' + shell: pwsh + env: + DIGEST: ${{ inputs.digest }} + TAGS: ${{ inputs.tags }} + run: | + $ErrorActionPreference = 'Stop' + Set-StrictMode -Version Latest + + $images = @() + $tagsArray = $Env:TAGS -split "\r?\n" | Where-Object { $_.Trim() } + + foreach ($tag in $tagsArray) { + $images += "$tag@$Env:DIGEST" + } + + if ($images.Count -eq 0) { + throw 'No image tags provided' + } + + Write-Output '::group::Images to sign' + $images | ForEach-Object { Write-Output $_ } + Write-Output '::endgroup::' + + Write-Output '::group::Signing' + cosign sign --yes $images + Write-Output '::endgroup::' diff --git a/.github/actions/cosign-verify/action.yml b/.github/actions/cosign-verify/action.yml index d6bea4dc..6714fbb7 100644 --- a/.github/actions/cosign-verify/action.yml +++ b/.github/actions/cosign-verify/action.yml @@ -15,7 +15,8 @@ inputs: runs: using: composite steps: - - name: Verify image signature + - name: Verify image signature on Linux + if: runner.os != 'Windows' shell: bash env: IMAGE: ${{ inputs.image }} @@ -36,3 +37,27 @@ runs: --certificate-identity-regexp "$IDENTITY_REGEX" \ "$IMAGE" | jq echo "::endgroup::" + + - name: Verify image signature on Windows + if: runner.os != 'Windows' + shell: pwsh + env: + IMAGE: ${{ inputs.image }} + OIDC_ISSUER: ${{ inputs.oidc_issuer }} + IDENTITY_REGEX: ${{ inputs.identity_regexp }} + run: | + $ErrorActionPreference = 'Stop' + Set-StrictMode -Version Latest + + Write-Output '::group::Image sign data' + Write-Output "OIDC issuer=$env:OIDC_ISSUER" + Write-Output "Identity=$env:IDENTITY_REGEX" + Write-Output "Image to verify=$env:IMAGE" + Write-Output '::endgroup::' + + Write-Output '::group::Verify signature' + cosign verify ` + --certificate-oidc-issuer-regexp "$env:OIDC_ISSUER" ` + --certificate-identity-regexp "$env:IDENTITY_REGEX" ` + "$env:IMAGE" | ConvertFrom-Json | ConvertTo-Json -Depth 100 + Write-Output '::endgroup::' diff --git a/.github/workflows/images_build_windows.yml b/.github/workflows/images_build_windows.yml index c5dc8d9e..8c92da70 100644 --- a/.github/workflows/images_build_windows.yml +++ b/.github/workflows/images_build_windows.yml @@ -221,112 +221,30 @@ jobs: - name: Build and push image id: docker_build - env: - DOCKERFILES_DIRECTORY: ${{ env.DOCKERFILES_DIRECTORY }} - BASE_BUILD_IMAGE: ${{ env.MSFT_BASE_BUILD_IMAGE }} - BASE_IMAGE_NAME: ${{ env.BASE_IMAGE_NAME }} - MATRIX_COMPONENT: ${{ matrix.component }} - TAGS: ${{ steps.meta.outputs.tags }} - BASE_OS_TAG: ${{ steps.base_os_tag.outputs.os_tag }} - LABEL_REVISION: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} - LABEL_CREATED: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} - run: | - echo "::group::Docker version" - docker version - echo "::endgroup::" - - echo "::group::Docker info" - docker info - echo "::endgroup::" - - $context = "$Env:DOCKERFILES_DIRECTORY\$Env:BASE_IMAGE_NAME\windows\" - $dockerfile = "$context" + "Dockerfile." + "$Env:MATRIX_COMPONENT" - $baseOsImage = "$Env:BASE_BUILD_IMAGE" + ":" + "$Env:BASE_OS_TAG" - - Remove-Item -ErrorAction Ignore -Force -Path "$context\README.md" - - $tagsArray = $Env:TAGS.Split("`n", [System.StringSplitOptions]::RemoveEmptyEntries) - $tagArgs = $tagsArray | ForEach-Object { "--tag=$_" } - - echo "::group::Image tags" - echo "$Env:TAGS" - echo "::endgroup::" - - echo "::group::Pull base image" - docker pull $baseOsImage - if (-not $?) { throw "Failed to pull $baseOsImage" } - echo "::endgroup::" - - echo "::group::Build Image" - Write-Host @" - docker build --label org.opencontainers.image.revision=$Env:LABEL_REVISION - --label org.opencontainers.image.created=$Env:LABEL_CREATED - --build-arg=OS_BASE_IMAGE=$baseOsImage - --file=$dockerfile - $tagArgs - $context - "@ - - docker build --label org.opencontainers.image.revision=$Env:LABEL_REVISION ` - --label org.opencontainers.image.created=$Env:LABEL_CREATED ` - --build-arg=OS_BASE_IMAGE=$baseOsImage ` - --file=$dockerfile ` - $tagArgs ` - $context - if (-not $?) { throw "Failed to build image" } - echo "::endgroup::" - - echo "::group::Publish Image" - foreach ($tag in $tagsArray) { - echo "docker image push $tag" - docker image push $tag - if (-not $?) { throw "Failed to push $tag" } - } - - $repoDigest = docker inspect $tagsArray[0] --format "{{ index .RepoDigests 0}}" - if (-not $?) { throw "Failed to inspect RepoDigests for $($tagsArray[0])" } - - $digest = $repoDigest.Split('@')[-1] - if ([string]::IsNullOrWhiteSpace($digest)) { - throw "Image digest is empty" - } - echo "Image digest got from RepoDigests" - echo "::endgroup::" - - echo "::group::Digest" - echo "$digest" - echo "::endgroup::" - - echo "digest=$digest" >> $Env:GITHUB_OUTPUT + uses: ./.github/actions/docker-build-push-windows + with: + context: ${{ env.DOCKERFILES_DIRECTORY }}\${{ env.BASE_IMAGE_NAME }}\windows + dockerfile: ${{ env.DOCKERFILES_DIRECTORY }}\${{ env.BASE_IMAGE_NAME }}\windows\Dockerfile.${{ matrix.component }} + tags: ${{ steps.meta.outputs.tags }} + label_revision: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} + label_created: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} + pull_images: | + ${{ env.MSFT_BASE_BUILD_IMAGE }}:${{ steps.base_os_tag.outputs.os_tag }} + build_args: | + OS_BASE_IMAGE=${{ env.MSFT_BASE_BUILD_IMAGE }}:${{ steps.base_os_tag.outputs.os_tag }} + push: true - name: Sign the images with GitHub OIDC Token - env: - DIGEST: ${{ steps.docker_build.outputs.digest }} - TAGS: ${{ steps.meta.outputs.tags }} - run: | - $tagsArray = $Env:TAGS.Split("`n", [System.StringSplitOptions]::RemoveEmptyEntries) - $tagList = @() - - foreach ($tag in $tagsArray) { - $tagName = $tag.Split(":")[0] - $tagList += "$tagName@$Env:DIGEST" - } - - echo "::group::Images to sign" - echo "$tagList" - echo "::endgroup::" - - echo "::group::Signing" - echo "cosign sign --yes $tagList" - cosign sign --yes $tagList - echo "::endgroup::" + uses: ./.github/actions/cosign-sign + with: + digest: ${{ steps.docker_build.outputs.digest }} + tags: ${{ steps.meta.outputs.tags }} - name: Attest images - uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 + uses: ./.github/actions/attest-image with: - subject-name: ${{ format('{0}/{1}/{2}{3}', env.DOCKER_REGISTRY, env.DOCKER_REPOSITORY, env.IMAGES_PREFIX, env.BASE_IMAGE_NAME ) }} - subject-digest: ${{ steps.docker_build.outputs.digest }} - push-to-registry: true + subject_name: ${{ format('{0}/{1}/{2}{3}', env.DOCKER_REGISTRY, env.DOCKER_REPOSITORY, env.IMAGES_PREFIX, env.BASE_IMAGE_NAME ) }} + subject_digest: ${{ steps.docker_build.outputs.digest }} - name: Image digest env: @@ -458,125 +376,38 @@ jobs: echo "base_build_image=$buildBaseImage" >> $Env:GITHUB_OUTPUT - name: Verify ${{ env.BASE_IMAGE_NAME }}:${{ matrix.os }} cosign - env: - BASE_IMAGE: ${{ steps.base_build.outputs.base_build_image }} - OIDC_ISSUER: ${{ env.OIDC_ISSUER }} - IDENTITY_REGEX: ${{ env.IDENTITY_REGEX }} - run: | - cosign verify ` - --certificate-oidc-issuer-regexp "$Env:OIDC_ISSUER" ` - --certificate-identity-regexp "$Env:IDENTITY_REGEX" ` - "$Env:BASE_IMAGE" | jq + uses: ./.github/actions/cosign-verify + with: + image: ${{ steps.base_build.outputs.base_build_image }} + oidc_issuer: ${{ env.OIDC_ISSUER }} + identity_regexp: ${{ env.IDENTITY_REGEX }} - name: Build and push image id: docker_build - env: - DOCKERFILES_DIRECTORY: ${{ env.DOCKERFILES_DIRECTORY }} - BASE_BUILD_IMAGE: ${{ steps.base_build.outputs.base_build_image }} - BASE_BUILD_IMAGE_NAME: ${{ env.BASE_BUILD_IMAGE_NAME }} - BASE_BUILD_OS_TAG: ${{ steps.base_os_tag.outputs.os_tag }} - MATRIX_COMPONENT: ${{ matrix.component }} - TAGS: ${{ steps.meta.outputs.tags }} - LABEL_REVISION: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} - LABEL_CREATED: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} - run: | - echo "::group::Docker version" - docker version - echo "::endgroup::" - - echo "::group::Docker info" - docker info - echo "::endgroup::" - - $context = "$Env:DOCKERFILES_DIRECTORY\$Env:BASE_BUILD_IMAGE_NAME\windows\" - $dockerfile = "$context" + "Dockerfile." + "$Env:MATRIX_COMPONENT" - $baseBuildImage = $Env:BASE_BUILD_IMAGE - - Remove-Item -ErrorAction Ignore -Force -Path "$context\README.md" - - $tagsArray = $Env:TAGS.Split("`n", [System.StringSplitOptions]::RemoveEmptyEntries) - $tagArgs = $tagsArray | ForEach-Object { "--tag=$_" } - - echo "::group::Image tags" - echo "$Env:TAGS" - echo "::endgroup::" - - echo "::group::Pull base image" - docker pull $baseBuildImage - if (-not $?) { throw "Failed to pull $baseBuildImage" } - echo "::endgroup::" - - echo "::group::Build Image" - Write-Host @" - docker build --label org.opencontainers.image.revision=$Env:LABEL_REVISION - --label org.opencontainers.image.created=$Env:LABEL_CREATED - --build-arg=BUILD_BASE_IMAGE=$baseBuildImage - --file=$dockerfile - $tagArgs - $context - "@ - - docker build --label org.opencontainers.image.revision=$Env:LABEL_REVISION ` - --label org.opencontainers.image.created=$Env:LABEL_CREATED ` - --build-arg=BUILD_BASE_IMAGE=$baseBuildImage ` - --file=$dockerfile ` - $tagArgs ` - $context - if (-not $?) { throw "Failed to build image" } - echo "::endgroup::" - - echo "::group::Publish Image" - foreach ($tag in $tagsArray) { - echo "docker image push $tag" - docker image push $tag - if (-not $?) { throw "Failed to push $tag" } - } - - $repoDigest = docker inspect $tagsArray[0] --format "{{ index .RepoDigests 0}}" - if (-not $?) { throw "Failed to inspect RepoDigests for $($tagsArray[0])" } - - $digest = $repoDigest.Split('@')[-1] - if ([string]::IsNullOrWhiteSpace($digest)) { - throw "Image digest is empty" - } - - echo "Image digest got from RepoDigests" - echo "::endgroup::" - - echo "::group::Digest" - echo "$digest" - echo "::endgroup::" - - echo "digest=$digest" >> $Env:GITHUB_OUTPUT + uses: ./.github/actions/docker-build-push-windows + with: + context: ${{ env.DOCKERFILES_DIRECTORY }}\${{ env.BASE_BUILD_IMAGE_NAME }}\windows + dockerfile: ${{ env.DOCKERFILES_DIRECTORY }}\${{ env.BASE_BUILD_IMAGE_NAME }}\windows\Dockerfile.${{ matrix.component }} + tags: ${{ steps.meta.outputs.tags }} + label_revision: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} + label_created: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} + pull_images: | + ${{ steps.base_build.outputs.base_build_image }} + build_args: | + BUILD_BASE_IMAGE=${{ steps.base_build.outputs.base_build_image }} + push: true - name: Attest images - uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 + uses: ./.github/actions/attest-image with: - subject-name: ${{ format('{0}/{1}/{2}{3}', env.DOCKER_REGISTRY, env.DOCKER_REPOSITORY, env.IMAGES_PREFIX, env.BASE_BUILD_IMAGE_NAME ) }} - subject-digest: ${{ steps.docker_build.outputs.digest }} - push-to-registry: true + subject_name: ${{ format('{0}/{1}/{2}{3}', env.DOCKER_REGISTRY, env.DOCKER_REPOSITORY, env.IMAGES_PREFIX, env.BASE_BUILD_IMAGE_NAME ) }} + subject_digest: ${{ steps.docker_build.outputs.digest }} - name: Sign the images with GitHub OIDC Token - env: - DIGEST: ${{ steps.docker_build.outputs.digest }} - TAGS: ${{ steps.meta.outputs.tags }} - run: | - $tagsArray = $Env:TAGS.Split("`n", [System.StringSplitOptions]::RemoveEmptyEntries) - $tagList = @() - - foreach ($tag in $tagsArray) { - $tagName = $tag.Split(":")[0] - $tagList += "$tagName@$Env:DIGEST" - } - - echo "::group::Images to sign" - echo "$tagList" - echo "::endgroup::" - - echo "::group::Signing" - echo "cosign sign --yes $tagList" - cosign sign --yes $tagList - echo "::endgroup::" + uses: ./.github/actions/cosign-sign + with: + digest: ${{ steps.docker_build.outputs.digest }} + tags: ${{ steps.meta.outputs.tags }} - name: Image digest env: @@ -710,150 +541,41 @@ jobs: echo "base_build_image=$buildBaseImage" >> $Env:GITHUB_OUTPUT - name: Verify ${{ env.BASE_BUILD_IMAGE_NAME }}:${{ matrix.os }} cosign - env: - BASE_IMAGE: ${{ steps.base_build.outputs.base_build_image }} - OIDC_ISSUER: ${{ env.OIDC_ISSUER }} - IDENTITY_REGEX: ${{ env.IDENTITY_REGEX }} - run: | - cosign verify ` - --certificate-oidc-issuer-regexp "$Env:OIDC_ISSUER" ` - --certificate-identity-regexp "$Env:IDENTITY_REGEX" ` - "$Env:BASE_IMAGE" | jq + uses: ./.github/actions/cosign-verify + with: + image: ${{ steps.base_build.outputs.base_build_image }} + oidc_issuer: ${{ env.OIDC_ISSUER }} + identity_regexp: ${{ env.IDENTITY_REGEX }} - - name: Build and optionally push image + - name: Build and push image id: docker_build - env: - DOCKERFILES_DIRECTORY: ${{ env.DOCKERFILES_DIRECTORY }} - BASE_BUILD_IMAGE: ${{ steps.base_build.outputs.base_build_image }} - BASE_BUILD_IMAGE_NAME: ${{ env.BASE_BUILD_IMAGE_NAME }} - MATRIX_COMPONENT: ${{ matrix.component }} - TAGS: ${{ steps.meta.outputs.tags }} - BASE_BUILD_OS_TAG: ${{ steps.base_os_tag.outputs.os_tag }} - LABEL_REVISION: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} - LABEL_CREATED: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} - OS_BASE_IMAGE_NAME: ${{ env.OS_BASE_IMAGE_NAME }} - AUTO_PUSH_IMAGES: ${{ env.AUTO_PUSH_IMAGES }} - run: | - echo "::group::Docker version" - docker version - echo "::endgroup::" - - echo "::group::Docker info" - docker info - echo "::endgroup::" - - $context = "$Env:DOCKERFILES_DIRECTORY\$Env:MATRIX_COMPONENT\windows\" - $dockerfile = "$context" + "Dockerfile" - $baseBuildImage = $Env:BASE_BUILD_IMAGE - - Remove-Item -ErrorAction Ignore -Force -Path "$context\README.md" - - $tagsArray = $Env:TAGS.Split("`n", [System.StringSplitOptions]::RemoveEmptyEntries) - $tagArgs = $tagsArray | ForEach-Object { "--tag=$_" } - - $osTagSuffix = $Env:BASE_BUILD_OS_TAG - $baseImage = "$Env:OS_BASE_IMAGE_NAME" + ":" + $osTagSuffix - - echo "::group::Image tags" - echo "$Env:TAGS" - echo "::endgroup::" - - echo "::group::Pull build base image" - docker pull $baseBuildImage - if (-not $?) { throw "Failed to pull $baseBuildImage" } - echo "::endgroup::" - - echo "::group::Pull PowerShell base image" - docker pull $baseImage - if (-not $?) { throw "Failed to pull $baseImage" } - echo "::endgroup::" - - echo "::group::Build Image" - Write-Host @" - docker build --label org.opencontainers.image.revision=$Env:LABEL_REVISION - --label org.opencontainers.image.created=$Env:LABEL_CREATED - --build-arg=BUILD_BASE_IMAGE=$baseBuildImage - --build-arg=OS_BASE_IMAGE=$baseImage - --file=$dockerfile - $tagArgs - $context - "@ - - docker build --label org.opencontainers.image.revision=$Env:LABEL_REVISION ` - --label org.opencontainers.image.created=$Env:LABEL_CREATED ` - --build-arg=BUILD_BASE_IMAGE=$baseBuildImage ` - --build-arg=OS_BASE_IMAGE=$baseImage ` - --file=$dockerfile ` - $tagArgs ` - $context - if (-not $?) { throw "Failed to build image" } - echo "::endgroup::" - - echo "::group::Publish Image" - if ($Env:AUTO_PUSH_IMAGES -eq 'true') { - foreach ($tag in $tagsArray) { - echo "docker image push $tag" - docker image push $tag - if (-not $?) { throw "Failed to push $tag" } - } - - $repoDigest = docker inspect $tagsArray[0] --format "{{ index .RepoDigests 0}}" - if (-not $?) { throw "Failed to inspect RepoDigests for $($tagsArray[0])" } - - $digest = $repoDigest.Split('@')[-1] - if ([string]::IsNullOrWhiteSpace($digest)) { - throw "Image digest is empty" - } - - echo "Image digest got from RepoDigests" - } - else { - $digest = docker inspect $tagsArray[0] --format "{{ index .Id}}" - if (-not $?) { throw "Failed to inspect image Id for $($tagsArray[0])" } - - if ([string]::IsNullOrWhiteSpace($digest)) { - throw "Image ID digest is empty" - } - - echo "Image digest got from Id" - } - echo "::endgroup::" - - echo "::group::Digest" - echo "$digest" - echo "::endgroup::" - - echo "digest=$digest" >> $Env:GITHUB_OUTPUT + uses: ./.github/actions/docker-build-push-windows + with: + context: ${{ env.DOCKERFILES_DIRECTORY }}\${{ matrix.component }}\windows + dockerfile: ${{ env.DOCKERFILES_DIRECTORY }}\${{ matrix.component }}\windows\Dockerfile + tags: ${{ steps.meta.outputs.tags }} + label_revision: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} + label_created: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} + pull_images: | + ${{ steps.base_build.outputs.base_build_image }} + ${{ env.OS_BASE_IMAGE_NAME }}:${{ steps.base_os_tag.outputs.os_tag }} + build_args: | + BUILD_BASE_IMAGE=${{ steps.base_build.outputs.base_build_image }} + OS_BASE_IMAGE=${{ env.OS_BASE_IMAGE_NAME }}:${{ steps.base_os_tag.outputs.os_tag }} + push: ${{ env.AUTO_PUSH_IMAGES }} - name: Sign the images with GitHub OIDC Token if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} - env: - DIGEST: ${{ steps.docker_build.outputs.digest }} - TAGS: ${{ steps.meta.outputs.tags }} - run: | - $tagsArray = $Env:TAGS.Split("`n", [System.StringSplitOptions]::RemoveEmptyEntries) - $tagList = @() - - foreach ($tag in $tagsArray) { - $tagName = $tag.Split(":")[0] - $tagList += "$tagName@$Env:DIGEST" - } - - echo "::group::Images to sign" - echo "$tagList" - echo "::endgroup::" - - echo "::group::Signing" - echo "cosign sign --yes $tagList" - cosign sign --yes $tagList - echo "::endgroup::" + uses: ./.github/actions/cosign-sign + with: + digest: ${{ steps.docker_build.outputs.digest }} + tags: ${{ steps.meta.outputs.tags }} - name: Attest images - uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 + uses: ./.github/actions/attest-image with: - subject-name: ${{ format('{0}/{1}/{2}{3}', env.DOCKER_REGISTRY, env.DOCKER_REPOSITORY, env.IMAGES_PREFIX, matrix.component ) }} - subject-digest: ${{ steps.docker_build.outputs.digest }} - push-to-registry: true + subject_name: ${{ format('{0}/{1}/{2}{3}', env.DOCKER_REGISTRY, env.DOCKER_REPOSITORY, env.IMAGES_PREFIX, matrix.component ) }} + subject_digest: ${{ steps.docker_build.outputs.digest }} - name: Print final image digest if: ${{ env.AUTO_PUSH_IMAGES == 'true' }}