debug action #14
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-test-sign-image | |
| on: | |
| push: | |
| branches: [main, master] | |
| release: | |
| types: [published] | |
| workflow_dispatch: | |
| # Needed for pushing to GHCR + keyless cosign signing (OIDC) | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| env: | |
| REGISTRY: ghcr.io | |
| jobs: | |
| build_test_and_release: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| # Docker repository names must be lowercase | |
| - name: Set image name (lowercase) | |
| id: image | |
| run: echo "name=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT | |
| - name: Set up QEMU (optional) | |
| uses: docker/setup-qemu-action@v3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # Log in to Azure CR with token that can pull the base image (ARACHNE_DOCKER_REGISTRY_TOKEN). | |
| - name: Log in to Azure CR (pull base image) | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: executionengine.azurecr.io | |
| username: github-actions-push | |
| password: ${{ secrets.ARACHNE_DOCKER_REGISTRY_TOKEN }} | |
| # Try to pull base image; only build if pull fails (e.g. first run or base not yet published). | |
| - name: Try pull base image | |
| id: pull_base | |
| run: | | |
| BASE_IMAGE="executionengine.azurecr.io/${{ steps.image.outputs.name }}-base:latest" | |
| if docker pull "$BASE_IMAGE"; then | |
| docker tag "$BASE_IMAGE" examplestudy-base:latest | |
| echo "need_build=false" >> $GITHUB_OUTPUT | |
| else | |
| echo "need_build=true" >> $GITHUB_OUTPUT | |
| fi | |
| # Build base image only when it could not be pulled. | |
| - name: Build base image (CI / local load) | |
| if: steps.pull_base.outputs.need_build == 'true' | |
| run: | | |
| docker buildx build \ | |
| --load \ | |
| --file ./Dockerfile.base \ | |
| --tag examplestudy-base:latest \ | |
| --cache-from type=gha \ | |
| --cache-to type=gha,mode=max \ | |
| --platform linux/amd64 \ | |
| . | |
| # Re-login to Azure CR with token that can push (for release step). | |
| - name: Log in to Azure Container Registry (push) | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: executionengine.azurecr.io | |
| username: github-actions-push | |
| password: ${{ secrets.CONTAINER_REGISTRY_TOKEN }} | |
| # When we built the base locally, push it so future runs can pull it. | |
| - name: Push base image to Azure CR | |
| if: steps.pull_base.outputs.need_build == 'true' | |
| run: | | |
| BASE_REPO="executionengine.azurecr.io/${{ steps.image.outputs.name }}-base:latest" | |
| docker tag examplestudy-base:latest "$BASE_REPO" | |
| docker push "$BASE_REPO" | |
| # Produces tags + labels (commit SHA, semver if you use tags, etc.) | |
| - name: Docker metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ steps.image.outputs.name }} | |
| tags: | | |
| type=sha,format=long | |
| type=ref,event=branch | |
| type=ref,event=tag | |
| labels: | | |
| org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} | |
| org.opencontainers.image.revision=${{ github.sha }} | |
| # 1b) Build study image (LOAD) so we can run tests inside it. | |
| # Attestations (sbom/provenance) require pushing, so we do that only after tests pass. | |
| - name: Build study image (CI / local load) | |
| id: build_ci | |
| run: | | |
| set -o pipefail | |
| docker buildx build \ | |
| --progress=plain \ | |
| --load \ | |
| --file ./Dockerfile \ | |
| --build-arg BASE_IMAGE=examplestudy-base:latest \ | |
| --tag ${{ env.REGISTRY }}/${{ steps.image.outputs.name }}:ci-${{ github.sha }} \ | |
| --label "org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}" \ | |
| --label "org.opencontainers.image.revision=${{ github.sha }}" \ | |
| --cache-from type=gha \ | |
| --cache-to type=gha,mode=max \ | |
| --platform linux/amd64 \ | |
| . 2>&1 | tee build.log | |
| - name: Upload build log | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: docker-build-log | |
| path: build.log | |
| retention-days: 30 | |
| if-no-files-found: ignore | |
| # Run your build/test script INSIDE the built image. | |
| # Assumes your image contains your package source (COPY . ...) and that this script exists. | |
| - name: Run build/test script inside image | |
| run: | | |
| set -euo pipefail | |
| docker run --rm \ | |
| ${{ env.REGISTRY }}/${{ steps.image.outputs.name }}:ci-${{ github.sha }} \ | |
| Rscript -f tests/build_test.R | |
| # Optional (but common): scan the image before release | |
| - name: Trivy scan (fail on HIGH/CRITICAL) | |
| uses: aquasecurity/trivy-action@0.28.0 | |
| with: | |
| image-ref: ${{ env.REGISTRY }}/${{ steps.image.outputs.name }}:ci-${{ github.sha }} | |
| format: table | |
| ignore-unfixed: true | |
| vuln-type: os,library | |
| severity: HIGH,CRITICAL | |
| exit-code: "1" | |
| # 2) Release build (PUSH) to GHCR and Azure CR with SBOM + provenance attestations. | |
| - name: Build & push (release + attestations) | |
| id: build_release | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: ./Dockerfile | |
| build-args: BASE_IMAGE=examplestudy-base:latest | |
| platforms: linux/amd64 | |
| push: true | |
| tags: | | |
| ${{ steps.meta.outputs.tags }} | |
| executionengine.azurecr.io/${{ steps.image.outputs.name }}:sha-${{ github.sha }} | |
| executionengine.azurecr.io/${{ steps.image.outputs.name }}:${{ github.ref_name }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| # Supply-chain metadata | |
| provenance: true | |
| sbom: true | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| # Keyless signing using GitHub OIDC (no long-lived keys). | |
| - name: Install cosign | |
| uses: sigstore/cosign-installer@v3 | |
| with: | |
| cosign-release: v2.4.1 | |
| - name: Sign image digest (keyless) | |
| env: | |
| COSIGN_EXPERIMENTAL: "false" | |
| run: | | |
| set -euo pipefail | |
| IMAGE="${{ env.REGISTRY }}/${{ steps.image.outputs.name }}" | |
| DIGEST="${{ steps.build_release.outputs.digest }}" | |
| cosign sign --yes "${IMAGE}@${DIGEST}" | |
| # Optional: sign the SBOM/provenance attestations too (recommended if you plan to verify them client-side) | |
| - name: Sign attestations (keyless) | |
| run: | | |
| set -euo pipefail | |
| IMAGE="${{ env.REGISTRY }}/${{ steps.image.outputs.name }}" | |
| DIGEST="${{ steps.build_release.outputs.digest }}" | |
| # This signs the attached attestations (provenance/SBOM) for that digest. | |
| cosign sign-attestation --yes "${IMAGE}@${DIGEST}" |