diff --git a/.github/workflows/build-container.yml b/.github/workflows/build-container.yml index 078a3e84a5ec..fe2724361d70 100644 --- a/.github/workflows/build-container.yml +++ b/.github/workflows/build-container.yml @@ -25,8 +25,8 @@ on: type: string outputs: path: - description: "Path to built container" - value: ghcr.io/${{ jobs.build-amd64.outputs.repo }}/${{ inputs.name }}:${{ jobs.build-amd64.outputs.tag }} + description: "Digest reference to the container built by this run" + value: ${{ jobs.create-manifest.outputs.path }} jobs: build-amd64: @@ -70,11 +70,11 @@ jobs: file: ${{ inputs.file }} push: true platforms: linux/amd64 + # Only trusted events may write tags that other runs read tags: | - ghcr.io/${{ steps.prepare.outputs.repo }}/${{ inputs.name }}:${{ hashFiles(inputs.file) }}-amd64 + ghcr.io/${{ steps.prepare.outputs.repo }}/${{ inputs.name }}:${{ github.event_name == 'push' && format('trusted-{0}', hashFiles(inputs.file)) || 'untrusted' }}-amd64 cache-from: | - type=registry,ref=ghcr.io/${{ steps.prepare.outputs.repo }}/${{ inputs.name }}:${{ hashFiles(inputs.file) }}-amd64 - type=registry,ref=ghcr.io/${{ steps.prepare.outputs.repo }}/${{ inputs.name }}:${{ steps.prepare.outputs.tag }} + type=registry,ref=ghcr.io/${{ steps.prepare.outputs.repo }}/${{ inputs.name }}:trusted-${{ hashFiles(inputs.file) }}-amd64 cache-to: type=inline build-arm64: @@ -116,17 +116,19 @@ jobs: file: ${{ inputs.file }} push: true platforms: linux/arm64 + # Only trusted events may write tags that other runs read tags: | - ghcr.io/${{ steps.prepare.outputs.repo }}/${{ inputs.name }}:${{ hashFiles(inputs.file) }}-arm64 + ghcr.io/${{ steps.prepare.outputs.repo }}/${{ inputs.name }}:${{ github.event_name == 'push' && format('trusted-{0}', hashFiles(inputs.file)) || 'untrusted' }}-arm64 cache-from: | - type=registry,ref=ghcr.io/${{ steps.prepare.outputs.repo }}/${{ inputs.name }}:${{ hashFiles(inputs.file) }}-arm64 - type=registry,ref=ghcr.io/${{ steps.prepare.outputs.repo }}/${{ inputs.name }}:${{ steps.prepare.outputs.tag }} + type=registry,ref=ghcr.io/${{ steps.prepare.outputs.repo }}/${{ inputs.name }}:trusted-${{ hashFiles(inputs.file) }}-arm64 cache-to: type=inline create-manifest: name: Create multi-arch manifest runs-on: ${{ inputs.runs-on-arm64 }} needs: [build-amd64, build-arm64] + outputs: + path: ${{ steps.manifest.outputs.path }} steps: - name: Checkout code uses: actions/checkout@v6 @@ -146,20 +148,24 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Create and push multi-arch manifest + id: manifest + env: + TRUSTED: ${{ github.event_name == 'push' }} run: | REPO="ghcr.io/${{ needs.build-amd64.outputs.repo }}/${{ inputs.name }}" TAG="${{ needs.build-amd64.outputs.tag }}" HASH_TAG="${{ hashFiles(inputs.file) }}" - # Create manifest from arch-specific images - docker buildx imagetools create -t "${REPO}:${HASH_TAG}" \ - "${REPO}:${HASH_TAG}-amd64" \ - "${REPO}:${HASH_TAG}-arm64" + if [[ "$TRUSTED" == "true" ]]; then + TAGS=(-t "${REPO}:${HASH_TAG}" -t "${REPO}:${TAG}" -t "${REPO}:latest") + else + TAGS=(-t "${REPO}:untrusted") + fi - docker buildx imagetools create -t "${REPO}:${TAG}" \ - "${REPO}:${HASH_TAG}-amd64" \ - "${REPO}:${HASH_TAG}-arm64" + # Use this run's digests: tags can be moved by concurrent runs + docker buildx imagetools create --metadata-file "${RUNNER_TEMP}/manifest.json" "${TAGS[@]}" \ + "${REPO}@${{ needs.build-amd64.outputs.digest }}" \ + "${REPO}@${{ needs.build-arm64.outputs.digest }}" - docker buildx imagetools create -t "${REPO}:latest" \ - "${REPO}:${HASH_TAG}-amd64" \ - "${REPO}:${HASH_TAG}-arm64" + DIGEST=$(jq -er '."containerimage.descriptor".digest' "${RUNNER_TEMP}/manifest.json") + echo "path=${REPO}@${DIGEST}" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a8332aa110e9..616d127834ea 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,7 +7,7 @@ on: permissions: actions: read contents: read - packages: write + packages: read concurrency: group: | @@ -97,6 +97,9 @@ jobs: runs-on: ${{ needs.check-skip.outputs['runner-arm64'] }} container: + permissions: + contents: read + packages: write name: Build container needs: [check-skip] if: ${{ needs.check-skip.outputs.skip == 'false' }} @@ -109,6 +112,9 @@ jobs: runs-on-arm64: ${{ needs.check-skip.outputs['runner-arm64'] }} container-slim: + permissions: + contents: read + packages: write name: Build slim container needs: [check-skip] if: ${{ needs.check-skip.outputs.skip == 'false' }} diff --git a/.github/workflows/guix-build.yml b/.github/workflows/guix-build.yml index 98ecc74afe9e..f79b85a6a8eb 100644 --- a/.github/workflows/guix-build.yml +++ b/.github/workflows/guix-build.yml @@ -1,7 +1,7 @@ name: Guix Build permissions: - packages: write + packages: read id-token: write attestations: write @@ -15,14 +15,15 @@ on: jobs: build-image: + permissions: + packages: write runs-on: ubuntu-24.04-arm if: | (github.event_name == 'push' && (startsWith(github.ref, 'refs/tags/') || vars.RUN_GUIX_ON_ALL_PUSH == 'true')) || contains(github.event.pull_request.labels.*.name, 'guix-build') || github.event_name == 'schedule' outputs: - image-tag: ${{ steps.prepare.outputs.image-tag }} - repo-name: ${{ steps.prepare.outputs.repo-name }} + image: ghcr.io/${{ steps.prepare.outputs.repo-name }}/dashcore-guix-builder@${{ steps.build.outputs.digest }} steps: - name: Checkout uses: actions/checkout@v6 @@ -38,13 +39,21 @@ jobs: - name: Commit variables id: prepare + env: + TRUSTED: ${{ github.event_name == 'push' || github.event_name == 'schedule' }} run: | echo "hash=$(sha256sum ./dash/contrib/containers/guix/Dockerfile | cut -d ' ' -f1)" >> $GITHUB_OUTPUT echo "host_user_id=$(id -u)" >> $GITHUB_OUTPUT echo "host_group_id=$(id -g)" >> $GITHUB_OUTPUT BRANCH_NAME=$(echo "${GITHUB_REF##*/}" | tr '[:upper:]' '[:lower:]') REPO_NAME=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]') - echo "image-tag=${BRANCH_NAME}" >> $GITHUB_OUTPUT + IMAGE="ghcr.io/${REPO_NAME}/dashcore-guix-builder" + # Only trusted events may write tags that other runs read + if [[ "$TRUSTED" == "true" ]]; then + echo "tags=${IMAGE}:${BRANCH_NAME},${IMAGE}:latest,${IMAGE}:trusted-latest" >> "$GITHUB_OUTPUT" + else + echo "tags=${IMAGE}:untrusted" >> "$GITHUB_OUTPUT" + fi echo "repo-name=${REPO_NAME}" >> $GITHUB_OUTPUT - name: Login to GitHub Container Registry @@ -55,6 +64,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build Docker image + id: build uses: docker/build-push-action@v7 with: context: ${{ github.workspace }}/dash @@ -65,10 +75,8 @@ jobs: docker_root=${{ github.workspace }}/dash/contrib/containers/guix file: ./dash/contrib/containers/guix/Dockerfile push: true - tags: | - ghcr.io/${{ steps.prepare.outputs.repo-name }}/dashcore-guix-builder:${{ steps.prepare.outputs.image-tag }} - ghcr.io/${{ steps.prepare.outputs.repo-name }}/dashcore-guix-builder:latest - cache-from: type=registry,ref=ghcr.io/${{ steps.prepare.outputs.repo-name }}/dashcore-guix-builder:latest + tags: ${{ steps.prepare.outputs.tags }} + cache-from: type=registry,ref=ghcr.io/${{ steps.prepare.outputs.repo-name }}/dashcore-guix-builder:trusted-latest cache-to: type=inline,mode=max build: @@ -128,7 +136,7 @@ jobs: -v ${{ github.workspace }}/dash:/src/dash \ -v ${{ github.workspace }}/.cache:/home/ubuntu/.cache \ -w /src/dash \ - ghcr.io/${{ needs.build-image.outputs.repo-name }}/dashcore-guix-builder:${{ needs.build-image.outputs.image-tag }} && \ + ${{ needs.build-image.outputs.image }} && \ docker exec guix-daemon bash -c 'HOSTS=${{ matrix.build_target }} /usr/local/bin/guix-start /src/dash' - name: Ensure build passes