Repository navigation
fix: source release-config.sh from main in build-docker.yaml #139
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build Docker | |
| on: | |
| pull_request: | |
| types: [labeled, synchronize] | |
| branches: | |
| - main | |
| - release/* | |
| workflow_call: | |
| inputs: | |
| tag: | |
| description: 'Tag to build and publish Docker images for (e.g. v0.6.0)' | |
| required: true | |
| type: string | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Tag to build and publish Docker images for (e.g. v0.6.0)' | |
| required: true | |
| type: string | |
| concurrency: | |
| group: docker-${{ (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch') && inputs.tag || github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| env: | |
| REGISTRY: docker.cloudsmith.io | |
| REGISTRY_NAMESPACE: circle/arc-network | |
| jobs: | |
| build: | |
| if: >- | |
| github.event_name == 'workflow_call' || | |
| github.event_name == 'workflow_dispatch' || | |
| contains(github.event.pull_request.labels.*.name, 'build-docker') | |
| name: Build ${{ matrix.image }} (${{ matrix.platform }}) | |
| permissions: | |
| contents: read | |
| id-token: write | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| image: | |
| - arc-execution | |
| - arc-consensus | |
| platform: | |
| - linux/amd64 | |
| - linux/arm64 | |
| include: | |
| - platform: linux/amd64 | |
| arch: amd64 | |
| runner: ubuntu-latest | |
| - platform: linux/arm64 | |
| arch: arm64 | |
| runner: ubuntu-24.04-arm | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| with: | |
| ref: ${{ (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch') && format('refs/tags/{0}', inputs.tag) || github.ref }} | |
| submodules: recursive | |
| fetch-depth: 0 | |
| - name: Resolve image metadata | |
| id: vars | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| INPUT_TAG: ${{ inputs.tag }} | |
| run: | | |
| SHA="$(git rev-parse HEAD)" | |
| if [[ "$EVENT_NAME" == "workflow_call" || "$EVENT_NAME" == "workflow_dispatch" ]]; then | |
| # A release branch's release-config.sh can predate functions this workflow | |
| # (always run from main) expects, so pull main's copy rather than whatever | |
| # is checked out at the tagged commit above. | |
| git show origin/main:scripts/release-config.sh > "${RUNNER_TEMP}/release-config.sh" | |
| # shellcheck source=/dev/null | |
| source "${RUNNER_TEMP}/release-config.sh" | |
| if ! release_docker_image_version_from_tag "$INPUT_TAG" >/dev/null; then | |
| echo "::error::Invalid tag format: '$INPUT_TAG' (expected e.g. v1.2.3 or v1.2.3-rc.1)" | |
| exit 1 | |
| fi | |
| fi | |
| { | |
| echo "full_hash=${SHA}" | |
| echo "short_hash=${SHA::8}" | |
| echo "git_version=$(git describe --tags --always --dirty 2>/dev/null || echo 'v0.0.0-unknown')" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 | |
| - name: Build image | |
| id: build | |
| uses: docker/bake-action@6614cfa25eff9a0b2b2697efb0b6159e7680d584 # v7.2.0 | |
| with: | |
| source: . | |
| files: docker-bake.hcl | |
| targets: ${{ matrix.image }} | |
| set: | | |
| ${{ matrix.image }}.platform=${{ matrix.platform }} | |
| ${{ matrix.image }}.tags= | |
| ${{ matrix.image }}.output=type=oci,tar=false,dest=/tmp/image | |
| env: | |
| BUILDX_NO_DEFAULT_ATTESTATIONS: 1 | |
| GITHUB_TOKEN: ${{ github.token }} | |
| GIT_COMMIT_HASH: ${{ steps.vars.outputs.full_hash }} | |
| GIT_VERSION: ${{ steps.vars.outputs.git_version }} | |
| GIT_SHORT_HASH: ${{ steps.vars.outputs.short_hash }} | |
| - name: Trivy vulnerability scan | |
| uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 | |
| with: | |
| input: /tmp/image | |
| format: sarif | |
| output: trivy-results.sarif | |
| severity: CRITICAL | |
| limit-severities-for-sarif: true | |
| exit-code: '1' | |
| - name: Upload Trivy scan results | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: trivy-${{ matrix.image }}-${{ matrix.arch }} | |
| path: trivy-results.sarif | |
| - name: Login to Cloudsmith | |
| if: ${{ github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' }} | |
| uses: ./.github/actions/cloudsmith-login | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| - name: Push image by digest | |
| if: ${{ github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' }} | |
| env: | |
| IMAGE: ${{ env.REGISTRY }}/${{ env.REGISTRY_NAMESPACE }}/${{ matrix.image }} | |
| BAKE_METADATA: ${{ steps.build.outputs.metadata }} | |
| MATRIX_IMAGE: ${{ matrix.image }} | |
| MATRIX_PLATFORM: ${{ matrix.platform }} | |
| run: | | |
| DIGEST=$(echo "${BAKE_METADATA}" | jq -r --arg img "${MATRIX_IMAGE}" '.[$img]."containerimage.digest"') | |
| if [ -z "${DIGEST}" ] || [ "${DIGEST}" = "null" ]; then | |
| echo "::error::Failed to extract digest from build metadata" | |
| exit 1 | |
| fi | |
| skopeo copy "oci:/tmp/image" "docker://${IMAGE}@${DIGEST}" --digestfile /tmp/push-digest | |
| rm -rf /tmp/image | |
| REGISTRY_DIGEST=$(cat /tmp/push-digest) | |
| if [ "${DIGEST}" != "${REGISTRY_DIGEST}" ]; then | |
| echo "::warning::Bake metadata digest ${DIGEST} differs from registry digest ${REGISTRY_DIGEST}" | |
| fi | |
| PLATFORM_SLUG=$(echo "${MATRIX_PLATFORM}" | tr '/' '-') | |
| mkdir -p "/tmp/digests/${MATRIX_IMAGE}" | |
| echo "${REGISTRY_DIGEST}" > "/tmp/digests/${MATRIX_IMAGE}/${PLATFORM_SLUG}" | |
| - name: Upload digest | |
| if: ${{ github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' }} | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: digest-${{ matrix.image }}-${{ matrix.arch }} | |
| path: /tmp/digests/${{ matrix.image }}/* | |
| if-no-files-found: error | |
| manifest: | |
| if: ${{ github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' }} | |
| name: Manifest ${{ matrix.image }} | |
| permissions: | |
| contents: read | |
| id-token: write | |
| attestations: write | |
| needs: [build] | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| image: | |
| - arc-execution | |
| - arc-consensus | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| with: | |
| ref: ${{ format('refs/tags/{0}', inputs.tag) }} | |
| sparse-checkout: | | |
| .github/actions | |
| scripts | |
| fetch-depth: 0 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 | |
| - name: Login to Cloudsmith | |
| uses: ./.github/actions/cloudsmith-login | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| - name: Download digests | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| pattern: digest-${{ matrix.image }}-* | |
| merge-multiple: true | |
| path: /tmp/digests | |
| - name: Resolve image version | |
| id: vars | |
| env: | |
| RELEASE_TAG: ${{ inputs.tag }} | |
| run: | | |
| # A release branch's release-config.sh can predate functions this workflow | |
| # (always run from main) expects, so pull main's copy rather than whatever | |
| # is checked out at the tagged commit above. | |
| git show origin/main:scripts/release-config.sh > "${RUNNER_TEMP}/release-config.sh" | |
| # shellcheck source=/dev/null | |
| source "${RUNNER_TEMP}/release-config.sh" | |
| if ! IMAGE_VERSION="$(release_docker_image_version_from_tag "$RELEASE_TAG")"; then | |
| echo "::error::Invalid tag format: '$RELEASE_TAG' (expected e.g. v1.2.3 or v1.2.3-rc.1)" | |
| exit 1 | |
| fi | |
| SHA="$(git rev-parse HEAD)" | |
| { | |
| echo "image_version=${IMAGE_VERSION}" | |
| echo "short_hash=${SHA::8}" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.REGISTRY_NAMESPACE }}/${{ matrix.image }} | |
| flavor: latest=false | |
| tags: | | |
| type=semver,pattern={{version}},value=${{ steps.vars.outputs.image_version }} | |
| type=semver,pattern={{version}},value=${{ steps.vars.outputs.image_version }},suffix=-${{ steps.vars.outputs.short_hash }} | |
| - name: Create and inspect multi-arch manifest | |
| id: manifest | |
| env: | |
| IMAGE: ${{ env.REGISTRY }}/${{ env.REGISTRY_NAMESPACE }}/${{ matrix.image }} | |
| IMAGE_VERSION: ${{ steps.vars.outputs.image_version }} | |
| TAGS: ${{ steps.meta.outputs.tags }} | |
| run: | | |
| # Build digest args from all platform artifacts | |
| DIGEST_ARGS=() | |
| for f in /tmp/digests/*; do | |
| DIGEST_ARGS+=("${IMAGE}@$(cat "$f")") | |
| done | |
| if [ ${#DIGEST_ARGS[@]} -eq 0 ]; then | |
| echo "::error::No digest files found" | |
| exit 1 | |
| fi | |
| # docker/metadata-action silently drops a tag it can't parse as semver | |
| # rather than failing the step, so an empty `tags` output here means | |
| # image_version wasn't valid semver and must be treated as fatal. | |
| TAG_ARGS=() | |
| while IFS= read -r t; do | |
| [ -n "${t}" ] && TAG_ARGS+=(-t "${t}") | |
| done <<< "${TAGS}" | |
| if [ ${#TAG_ARGS[@]} -eq 0 ]; then | |
| echo "::error::docker/metadata-action produced no tags for image_version='${IMAGE_VERSION}'" | |
| exit 1 | |
| fi | |
| # Create and push the manifest list, tagged per docker/metadata-action's output | |
| docker buildx imagetools create "${TAG_ARGS[@]}" "${DIGEST_ARGS[@]}" | |
| FIRST_TAG="$(head -n1 <<< "${TAGS}")" | |
| MANIFEST_DIGEST=$(docker buildx imagetools inspect "${FIRST_TAG}" --raw | sha256sum | awk '{print "sha256:"$1}') | |
| echo "digest=${MANIFEST_DIGEST}" >> "$GITHUB_OUTPUT" | |
| echo "image-with-digest=${IMAGE}@${MANIFEST_DIGEST}" >> "$GITHUB_OUTPUT" | |
| - name: Generate SBOM | |
| continue-on-error: true | |
| uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0 | |
| with: | |
| image: ${{ steps.manifest.outputs.image-with-digest }} | |
| artifact-name: sbom-${{ matrix.image }}.spdx.json | |
| output-file: sbom-${{ matrix.image }}.spdx.json | |
| upload-release-assets: false | |
| - name: Attest build provenance | |
| uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0 | |
| with: | |
| subject-name: ${{ env.REGISTRY }}/${{ env.REGISTRY_NAMESPACE }}/${{ matrix.image }} | |
| subject-digest: ${{ steps.manifest.outputs.digest }} | |
| push-to-registry: true | |
| - name: Attest SBOM | |
| uses: actions/attest-sbom@07e74fc4e78d1aad915e867f9a094073a9f71527 # v4.0.0 | |
| with: | |
| subject-name: ${{ env.REGISTRY }}/${{ env.REGISTRY_NAMESPACE }}/${{ matrix.image }} | |
| subject-digest: ${{ steps.manifest.outputs.digest }} | |
| sbom-path: sbom-${{ matrix.image }}.spdx.json | |
| push-to-registry: true |