Skip to content

ci: publish docker image on push to main#435

Open
mvanhorn wants to merge 1 commit into
lambdaclass:mainfrom
mvanhorn:ci/94-publish-docker-on-main
Open

ci: publish docker image on push to main#435
mvanhorn wants to merge 1 commit into
lambdaclass:mainfrom
mvanhorn:ci/94-publish-docker-on-main

Conversation

@mvanhorn

Copy link
Copy Markdown
Contributor

🗒️ Description / Motivation

The docker_publish workflow was workflow_dispatch-only, so the published latest GHCR image only refreshed when someone manually dispatched the workflow and otherwise drifted behind main. The issue asks that every commit to main update the latest Docker tag automatically, which is what this change does.

What Changed

The single file touched is .github/workflows/docker_publish.yaml. A push trigger on main now runs alongside the existing workflow_dispatch. Because inputs.tags is empty on a push event, a workflow-level TAGS_INPUT: ${{ inputs.tags || 'latest' }} env now provides the effective tag list, and the two ${{ inputs.tags }} reads (the Prepare tags step and the Create multi-arch manifests step) consume $TAGS_INPUT instead.

Correctness / Behavior Guarantees

Manual dispatch behaves exactly as before, since TAGS_INPUT falls through to whatever the user passed in inputs.tags, so custom comma-separated tags still expand unchanged. On a push to main the list resolves to latest, producing the same latest + sha-<short> manifest that a dispatch with tags=latest already produced. The one behavior change worth flagging for reviewers is that latest now moves on every main commit; nothing inside the repo consumes the image tag, so this only affects external consumers who pin latest.

Tests Added / Run

No automated tests apply to a workflow trigger change. I confirmed the file still parses with python3 -c "import yaml; yaml.safe_load(open('.github/workflows/docker_publish.yaml'))" and hand-traced the tag derivation: a dispatch with tags=latest,v0.1.0 still expands both tags, while a push with empty inputs.tags resolves to latest.

Related Issues / PRs

Closes #94

✅ Verification Checklist

  • Ran make fmt — N/A, this PR changes only workflow YAML and no Rust source
  • Ran make lint (clippy with -D warnings) — N/A, no Rust source changed
  • Ran cargo test --workspace --release — N/A, no Rust source changed; YAML validated via yaml.safe_load instead

@greptile-apps

greptile-apps Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds an automatic push trigger on main to the docker_publish workflow so the latest GHCR tag is updated on every commit instead of only on manual dispatch. The tag-resolution logic is centralised in a workflow-level TAGS_INPUT env var that falls back to \"latest\" when inputs.tags is absent (push events), while preserving existing manual-dispatch behaviour for custom tag lists.

  • The TAGS_INPUT: ${{ inputs.tags || 'latest' }} expression correctly evaluates to 'latest' on push events and to the user-supplied value on manual dispatches.
  • No concurrency group is defined, so rapid successive pushes to main can run two workflow instances simultaneously; because the arch-specific intermediate tags (latest-amd64, latest-arm64) are shared and overwritten by each run, the publish-manifest job may assemble a manifest list mixing layers from different commits.

Confidence Score: 3/5

Safe to merge for the trigger and tag logic itself, but the missing concurrency group means two rapid pushes to main can produce a latest manifest that silently mixes amd64 and arm64 layers from different commits.

The TAGS_INPUT fallback and the two shell-variable substitutions are correct, and manual dispatch behaviour is preserved. The gap is that adding a push trigger without a concurrency constraint lets parallel runs corrupt the shared arch-specific intermediate tags and the final manifest list — a real problem for any consumer relying on latest being a coherent image.

.github/workflows/docker_publish.yaml — needs a concurrency group before the jobs block.

Important Files Changed

Filename Overview
.github/workflows/docker_publish.yaml Adds push-to-main trigger and TAGS_INPUT env var to keep latest in sync; missing concurrency group creates a race condition that can produce mixed-arch manifest lists under consecutive pushes.

Sequence Diagram

sequenceDiagram
    participant G as GitHub (push to main)
    participant W as Workflow Trigger
    participant BA as build-image (amd64)
    participant BAR as build-image (arm64)
    participant M as publish-manifest
    participant R as GHCR Registry

    G->>W: push event on main
    W->>BA: "start (TAGS_INPUT=latest)"
    W->>BAR: "start (TAGS_INPUT=latest)"
    BA->>R: push latest-amd64
    BAR->>R: push latest-arm64
    BA-->>M: done
    BAR-->>M: done
    M->>R: imagetools create latest
    M->>R: imagetools create sha-short

    Note over W,R: Without concurrency group two runs can interleave producing a latest manifest that mixes arch layers from different commits
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
.github/workflows/docker_publish.yaml:1-22
**Missing concurrency group risks mixed-arch `latest` manifests**

The new push trigger means two workflow runs can be in flight simultaneously for consecutive commits to `main`. Because the arch-specific tags (`latest-amd64`, `latest-arm64`) are shared across runs, run A could push `latest-amd64` from commit 1 while run B has already pushed `latest-arm64` from commit 2. The `publish-manifest` job of either run then assembles a manifest list pointing to images from *different* commits — a silently corrupted `latest` image.

Adding a `concurrency` block before `jobs:` serialises (or cancels-and-restarts) builds so the arch-specific layers and manifest always come from the same commit.

Reviews (1): Last reviewed commit: "ci: publish docker image on push to main" | Re-trigger Greptile

Comment on lines 1 to +22
@@ -15,6 +17,9 @@ permissions:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
# On push to main, inputs.tags is empty, so fall back to "latest" so the
# latest tag tracks main. Manual dispatch still honors custom tags.
TAGS_INPUT: ${{ inputs.tags || 'latest' }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Missing concurrency group risks mixed-arch latest manifests

The new push trigger means two workflow runs can be in flight simultaneously for consecutive commits to main. Because the arch-specific tags (latest-amd64, latest-arm64) are shared across runs, run A could push latest-amd64 from commit 1 while run B has already pushed latest-arm64 from commit 2. The publish-manifest job of either run then assembles a manifest list pointing to images from different commits — a silently corrupted latest image.

Adding a concurrency block before jobs: serialises (or cancels-and-restarts) builds so the arch-specific layers and manifest always come from the same commit.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/docker_publish.yaml
Line: 1-22

Comment:
**Missing concurrency group risks mixed-arch `latest` manifests**

The new push trigger means two workflow runs can be in flight simultaneously for consecutive commits to `main`. Because the arch-specific tags (`latest-amd64`, `latest-arm64`) are shared across runs, run A could push `latest-amd64` from commit 1 while run B has already pushed `latest-arm64` from commit 2. The `publish-manifest` job of either run then assembles a manifest list pointing to images from *different* commits — a silently corrupted `latest` image.

Adding a `concurrency` block before `jobs:` serialises (or cancels-and-restarts) builds so the arch-specific layers and manifest always come from the same commit.

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish docker image on each commit

1 participant