docker / build-push-action

GitHub Action to build and push Docker images with Buildx
https://github.com/marketplace/actions/build-and-push-docker-images
Apache License 2.0
4.11k stars 527 forks source link

bug parsing build args #1026

Closed Goldziher closed 6 months ago

Goldziher commented 6 months ago

Contributing guidelines

I've found a bug, and:

Description

There is an indeterminate behaviour parsing multiple build args. Sometimes it works as intended, sometimes the parsing results in a bug.

Given the following configuration:

jobs:
    build:
        runs-on: ubuntu-latest
        timeout-minutes: 15
        permissions:
            contents: read
            id-token: write
        steps:
            - name: Checkout
              id: checkout
              uses: actions/checkout@v4
            - name: Set up QEMU
              uses: docker/setup-qemu-action@v3
            - name: Set up Docker BuildX
              uses: docker/setup-buildx-action@v3
            - name: Build and Push
              uses: docker/build-push-action@v5
              with:
                  push: true
                  context: .
                  file: ${{env.FILE_PATH}}
                  build-args: |
                      BACKEND_URL=${{vars.BACKEND_URL}}
                      BUILD_TARGET=${{env.SERVICE_NAME}}
                      DISCORD_INVITE_URL=${{env.DISCORD_INVITE_URL}}
                      FIREBASE_API_KEY=${{secrets.FIREBASE_API_KEY}}
                      FIREBASE_APP_ID=${{vars.FIREBASE_APP_ID}}
                      FIREBASE_AUTH_DOMAIN=${{vars.FIREBASE_AUTH_DOMAIN}}
                      FIREBASE_MEASUREMENT_ID=${{vars.FIREBASE_MEASUREMENT_ID}}
                      FIREBASE_MESSAGE_SENDER_ID=${{vars.FIREBASE_MESSAGING_SENDER_ID}}
                      FIREBASE_MICROSOFT_TENANT_ID=${{vars.FIREBASE_MICROSOFT_TENANT_ID}}
                      FIREBASE_PROJECT_ID=${{vars.GCP_PROJECT_ID}}
                      FIREBASE_STORAGE_BUCKET=${{vars.FIREBASE_STORAGE_BUCKET}}
                      FRONTEND_HOST=${{vars.FRONTEND_HOST}}
                      SEGMENT_WRITE_KEY=${{secrets.SEGMENT_WRITE_KEY}}
                      SERVICE_NAME=${{env.SERVICE_NAME}}

I am seeing a bug where the commands are sometimes parsed correctly and sometimes not.

Expected behaviour

All build arguments are parsed correctly and have --build-arg set before them:

/usr/bin/docker buildx build --build-arg BACKEND_URL=value --build-arg BUILD_TARGET=value --build-arg DISCORD_INVITE_URL=value --build-arg FIREBASE_API_KEY=value --build-arg FIREBASE_APP_ID=value --build-arg FIREBASE_AUTH_DOMAIN=value --build-arg FIREBASE_MEASUREMENT_ID=value --build-arg FIREBASE_MESSAGE_SENDER_ID=value --build-arg FIREBASE_MICROSOFT_TENANT_ID=value --build-arg FIREBASE_PROJECT_ID=value --build-arg FIREBASE_STORAGE_BUCKET=value --build-arg FRONTEND_HOST=value --build-arg SEGMENT_WRITE_KEY=value --build-arg SERVICE_NAME=value --file ./docker/Dockerfile.frontend --iidfile /home/runner/work/_temp/docker-actions-toolkit-bGcbJX/iidfile <...redacted>

Actual behaviour

Only the first two build arguments are parsed and the rest of them remain as a single string:

/usr/bin/docker buildx build --build-arg BACKEND_URL=value --build-arg BUILD_TARGET=value
DISCORD_INVITE_URL=value
FIREBASE_API_KEY=value
FIREBASE_APP_ID=value
FIREBASE_AUTH_DOMAIN=value
FIREBASE_MEASUREMENT_ID=value
FIREBASE_MESSAGE_SENDER_ID=value
FIREBASE_MICROSOFT_TENANT_ID=value
FIREBASE_PROJECT_ID=value
FIREBASE_STORAGE_BUCKET=value
FRONTEND_HOST=value
SEGMENT_WRITE_KEY=value
SERVICE_NAME=value --file ./docker/Dockerfile.frontend --iidfile /home/runner/work/_temp/docker-actions-toolkit-bGcbJX/iidfile <...redacted>

Repository URL

No response

Workflow run URL

No response

YAML workflow

name: 'Build (Frontend)'
on:
    push:
        branches:
            - main
env:
    SERVICE_NAME: my-service
    FILE_PATH: ./docker/Dockerfile.frontend
    DISCORD_INVITE_URL: https://discord.gg
jobs:
    build:
        runs-on: ubuntu-latest
        timeout-minutes: 15
        permissions:
            contents: read
            id-token: write
        steps:
            - name: Checkout
              id: checkout
              uses: actions/checkout@v4
            - name: Set up QEMU
              uses: docker/setup-qemu-action@v3
            - name: Set up Docker BuildX
              uses: docker/setup-buildx-action@v3
            - name: Build and Push
              uses: docker/build-push-action@v5
              with:
                  push: true
                  context: .
                  file: ${{env.FILE_PATH}}
                  build-args: |
                      BACKEND_URL=${{vars.BACKEND_URL}}
                      BUILD_TARGET=${{env.SERVICE_NAME}}
                      DISCORD_INVITE_URL=${{env.DISCORD_INVITE_URL}}
                      FIREBASE_API_KEY=${{secrets.FIREBASE_API_KEY}}
                      FIREBASE_APP_ID=${{vars.FIREBASE_APP_ID}}
                      FIREBASE_AUTH_DOMAIN=${{vars.FIREBASE_AUTH_DOMAIN}}
                      FIREBASE_MEASUREMENT_ID=${{vars.FIREBASE_MEASUREMENT_ID}}
                      FIREBASE_MESSAGE_SENDER_ID=${{vars.FIREBASE_MESSAGING_SENDER_ID}}
                      FIREBASE_MICROSOFT_TENANT_ID=${{vars.FIREBASE_MICROSOFT_TENANT_ID}}
                      FIREBASE_PROJECT_ID=${{vars.GCP_PROJECT_ID}}
                      FIREBASE_STORAGE_BUCKET=${{vars.FIREBASE_STORAGE_BUCKET}}
                      FRONTEND_HOST=${{vars.FRONTEND_HOST}}
                      SEGMENT_WRITE_KEY=${{secrets.SEGMENT_WRITE_KEY}}
                      SERVICE_NAME=${{env.SERVICE_NAME}}
                  tags: |
                      ${{vars.GCP_REGION}}-docker.pkg.dev/${{vars.GCP_PROJECT_ID}}/basemind/${{env.SERVICE_NAME}}:latest
                      ${{vars.GCP_REGION}}-docker.pkg.dev/${{vars.GCP_PROJECT_ID}}/basemind/${{env.SERVICE_NAME}}:${{github.sha}}

``

Workflow logs

No response

BuildKit logs

No response

Additional info

No response

crazy-max commented 6 months ago

Only the first two build arguments are parsed and the rest of them remain as a single string:

This means one of the arg's value is not properly escaped and probably has a " char in its value. This is similar to how secrets parsing work: https://docs.docker.com/build/ci/github-actions/secrets/

Also I see you're passing sensitive information as build-arg (e.g. SEGMENT_WRITE_KEY=${{secrets.SEGMENT_WRITE_KEY}}) which is a bad practice as it would leak credentials in the final image. Please use build time secrets for this: https://docs.docker.com/build/ci/github-actions/secrets/. More info https://docs.docker.com/build/building/secrets/.

@dvdksn I think we should have a similar page like "Secrets" for build arguments in our GHA docs. We could show both cases where user wants to set build arg with the build-push-action and another one with bake-action. WDYT?

Goldziher commented 6 months ago

Only the first two build arguments are parsed and the rest of them remain as a single string:

This means one of the arg's value is not properly escaped and probably has a " char in its value. This is similar to how secrets parsing work: https://docs.docker.com/build/ci/github-actions/secrets/

Also I see you're passing sensitive information as build-arg (e.g. SEGMENT_WRITE_KEY=${{secrets.SEGMENT_WRITE_KEY}}) which is a bad practice as it would leak credentials in the final image. Please use build time secrets for this: https://docs.docker.com/build/ci/github-actions/secrets/. More info https://docs.docker.com/build/building/secrets/.

@dvdksn I think we should have a similar page like "Secrets" for build arguments in our GHA docs. We could show both cases where user wants to set build arg with the build-push-action and another one with bake-action. WDYT?

there was a line break inside one of the values.

Yes. But this just means that the parsing is pretty brittle - its a very hard to identify issue.

Thanks for the tip about using secrets, ill certainly do this.

crazy-max commented 6 months ago

Yes. But this just means that the parsing is pretty brittle - its a very hard to identify issue.

Agree I will take a look if we can detect these cases and warn about it.

crazy-max commented 6 months ago

Current limitation with GitHub Actions inputs makes it hard to detect these cases but will look forward when GitHub implements objects for inputs. We might also consider using a new format such as YAML:

                  build-args: |
                      - BACKEND_URL: |
                          ${{vars.BACKEND_URL}}
                      - BUILD_TARGET: |
                          ${{env.SERVICE_NAME}}
Goldziher commented 6 months ago

Current limitation with GitHub Actions inputs makes it hard to detect these cases but will look forward when GitHub implements objects for inputs. We might also consider using a new format such as YAML:

                  build-args: |
                      - BACKEND_URL: |
                          ${{vars.BACKEND_URL}}
                      - BUILD_TARGET: |
                          ${{env.SERVICE_NAME}}

Thanks for your prompt replies ! Very nice 👍