Skip to content

Unexpected push attempt when push=false #1340

Closed
@offbyone

Description

@offbyone

Contributing guidelines

I've found a bug, and:

  • The documentation does not mention anything about my problem
  • There are no open or closed issues that are related to my problem

Description

I have a workflow that runs on PRs that can perform a push if the PR is from the same repository, but will otherwise just build.

I've observed that, even when push: is false in this workflow, my run is attempting to push.

A test PR: WorldconVotingSystems/seattle-2025#35

The build: https://github.com/WorldconVotingSystems/seattle-2025/actions/runs/14010277251/job/39229206566?pr=35#step:7:4

Expected behaviour

I expect no push attempt to occur when CAN_PUSH_IMAGES is not true

(note: I actually expect this workflow to fail after the build step for related reasons, but my problem is that I'm trying to get to those and debug them, but it's failing early at a point that doesn't make sense to me)

Actual behaviour

Specifically, you can see that push: false is set at the top, however the build is failing:

#27 ERROR: failed to push ghcr.io/worldconvotingsystems/seattle-2025: failed to authorize: failed to fetch anonymous token: unexpected status from GET request to https://ghcr.io/token?scope=repository%3Aworldconvotingsystems%2Fseattle-2025%3Apull%2Cpush&service=ghcr.io: 403 Forbidden

Repository URL

https://github.com/WorldconVotingSystems/seattle-2025/

Workflow run URL

https://github.com/WorldconVotingSystems/seattle-2025/actions/runs/14010277251/job/39229206566?pr=35

YAML workflow

name: Docker

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

on:
  schedule:
    - cron: "41 14 * * *"
  push:
    branches: ["main"]
    # Publish semver tags as releases.
    tags: ["v*.*.*"]
  pull_request:
    branches: ["main"]

env:
  REGISTRY: ghcr.io

jobs:
  prepare:
    permissions: {}
    runs-on: ubuntu-latest
    steps:
      - name: set the build step environment
        run: |
          # what even the fuck is this.
          # here purely because of https://github.com/orgs/community/discussions/25768
          registry_image=$REGISTRY/${{ github.repository }}
          echo REGISTRY_IMAGE_LC="${registry_image,,}" >> "$GITHUB_ENV"
          # Default to allowing push
          echo "CAN_PUSH_IMAGES=true" >> "$GITHUB_ENV"
      - name: Check for push image permissions
        # if this is a pull request from another repository, then disable pushing
        if: github.event.pull_request.head.repo.full_name != github.repository && github.event_name == 'pull_request'
        run: |
          echo "This is a pull request from an external repository. Disabling image push."
          echo "CAN_PUSH_IMAGES=false" >> "$GITHUB_ENV"
      - name: persist the push instruction
        id: persist
        run: |
          echo "can_push_images=$CAN_PUSH_IMAGES" >> "$GITHUB_OUTPUT"
          echo "registry_image=$REGISTRY_IMAGE_LC" >> "$GITHUB_OUTPUT"
    outputs:
      can_push_images: ${{ steps.persist.outputs.can_push_images }}
      registry_image: ${{ steps.persist.outputs.registry_image }}

  build:
    runs-on: ubuntu-latest
    needs: prepare
    strategy:
      fail-fast: false
      matrix:
        platform:
          - linux/amd64
          # we don't run this on ARM, no sense in building for it
          # - linux/arm64
    permissions:
      contents: read
      packages: write
      # This is used to complete the identity challenge
      # with sigstore/fulcio when running outside of PRs.
      id-token: write

    env:
      CAN_PUSH_IMAGES: ${{ needs.prepare.outputs.can_push_images }}
      REGISTRY_IMAGE: ${{ needs.prepare.outputs.registry_image }}

    steps:
      - name: Set up the platform
        run: |
          # set the platform pair for later
          platform=${{ matrix.platform }}
          echo "PLATFORM_PAIR=${platform//\//-}" >> "$GITHUB_ENV"
      - name: Checkout repository
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          persist-credentials: false

      # Set up BuildKit Docker container builder to be able to build
      # multi-platform images and export cache
      # https://github.com/docker/setup-buildx-action
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0

      # Login against a Docker registry except on PR
      # https://github.com/docker/login-action
      - name: Log into registry ${{ env.REGISTRY }}
        if: env.CAN_PUSH_IMAGES == 'true'
        uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      # Extract metadata (tags, labels) for Docker
      # https://github.com/docker/metadata-action
      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
        with:
          images: ${{ env.REGISTRY_IMAGE }}

          tags: |
            type=ref,event=branch
            type=ref,event=tag
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=sha
      - name: Build and push by digest
        id: build
        uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
        with:
          context: .
          push: ${{ env.CAN_PUSH_IMAGES == 'true' }}
          platforms: ${{ matrix.platform }}
          labels: ${{ steps.meta.outputs.labels }}
          outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Export digest
        run: |
          mkdir -p /tmp/digests
          digest="${{ steps.build.outputs.digest }}"
          touch "/tmp/digests/${digest#sha256:}"
      - name: Upload digest
        uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
        with:
          name: digests-${{ env.PLATFORM_PAIR }}
          path: /tmp/digests/*
          if-no-files-found: error
          retention-days: 1

  merge:
    runs-on: ubuntu-latest
    permissions:
      packages: write
      # This is used to complete the identity challenge
      # with sigstore/fulcio when running outside of PRs.
      id-token: write
    needs:
      - prepare
      - build
    env:
      CAN_PUSH_IMAGES: ${{ needs.prepare.outputs.can_push_images }}
      REGISTRY_IMAGE: ${{ needs.prepare.outputs.registry_image }}

    steps:
      - name: Download digests
        uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9
        with:
          path: /tmp/digests
          pattern: digests-*
          merge-multiple: true

      - name: Login to Docker Hub
        uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0

      - name: Docker meta
        id: meta
        uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
        with:
          images: ${{ env.REGISTRY_IMAGE }}

      - name: Create manifest list and push
        working-directory: /tmp/digests
        if: ${{ env.CAN_PUSH_IMAGES }}
        run: |
          docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
            $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
      - name: Inspect image
        run: |
          docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }}
    outputs:
      version: ${{ steps.meta.outputs.version }}

  validate:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: read

    env:
      NOMNOM_VERSION: ${{ needs.merge.outputs.version }}

    needs:
      - merge

    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          persist-credentials: false

      - name: copy the environment
        run: |
          cp deploy/staging/.env.template deploy/staging/.env
      - name: pull the staging images
        run: |
          docker compose -f deploy/staging/compose.yml -p staging pull
      - name: start the staging environment
        run: |
          docker compose -f deploy/staging/compose.yml -p staging up --wait
      - name: attempt to read the home page from the website
        run: |
          curl -s -o /dev/null \
            -H Host:nomnom-staging.seattlein2025.org \
            -w "%{http_code}" \
            http://localhost:8000/ >> /tmp/status_code
      - name: check the status code
        run: |
          status_code=$(cat /tmp/status_code)
          if [ "$status_code" != "200" ]; then
            echo "The status code was not 200. It was $status_code."
            exit 1
          fi
  notify:
    runs-on: ubuntu-latest
    needs:
      - validate
      - merge
    steps:
      - uses: umahmood/pushover-actions@5da31193f672e7418804bdb51836bdf20f393c8f # v1.1.0
        env:
          PUSHOVER_TOKEN: ${{ secrets.PUSHOVER_API_KEY }}
          PUSHOVER_USER: ${{ secrets.PUSHOVER_USER_KEY }}
        with:
          status: ${{ job.status }}
          title: Seattle Image Updates
          message: |-
            The Seattle docker image has been updated: ${{ needs.merge.outputs.version }}

Workflow logs

logs_36069566078.zip

BuildKit logs


Additional info

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions