Skip to content

Publish images to Docker Hub on release#3

Draft
fnando wants to merge 5 commits into
matrixfrom
publish
Draft

Publish images to Docker Hub on release#3
fnando wants to merge 5 commits into
matrixfrom
publish

Conversation

@fnando
Copy link
Copy Markdown
Member

@fnando fnando commented May 21, 2026

What

Adds the release publish workflow that pushes per-arch images to docker.io/stellar/stellar-cli, assembles per-pair multi-arch manifest lists, and moves the :<cli> and :latest aliases. Driven entirely by GitHub Actions native steps (docker/build-push-action, docker buildx imagetools create) — no bespoke shell wrappers, since publishing is a CI-only operation that can never run usefully on a developer's laptop.

Also extends scripts/resolve-matrix.sh so each matrix row carries the inputs the publish job needs (stellar_cli_ref, rust_image_digest) instead of re-querying builds.json inside the workflow.

Why

Without this, the repo has scripts and a smoke build but no path from "merge to main" or "tag a release" to "image lives on Docker Hub". This is the actual production-publish flow.

Notable choices

  • docker/build-push-action over bespoke shell. The script-based layer that's load-bearing elsewhere in this repo (locally-runnable, testable on a laptop) earns nothing here — pushing to docker.io/stellar/stellar-cli needs DOCKERHUB_TOKEN and the runner's OIDC environment. The native action also sets up cleanly for the next PR's SLSA + SBOM (provenance: and sbom: flags). All uses: are SHA-pinned to the latest releases.
  • Per-arch native runners. amd64 on ubuntu-24.04, arm64 on ubuntu-24.04-arm. No QEMU, no cross-compilation; each platform builds on its actual hardware.
  • Tag immutability is unconditional, no force flag. Per-arch tags (:26.0.0-rust1.94.0-amd64) and per-pair multi-arch lists (:26.0.0-rust1.94.0) are content-stable in this repo's model. A pre-push docker buildx imagetools inspect aborts the job if the target tag already exists. There is no workflow input to override. If a publish needs to be genuinely redone (corrupt push, etc.), the manual remedy is to delete the offending tag in Docker Hub by hand and re-run — that's a deliberate human choice, not a workflow toggle.
  • Strict multi-arch parity. GH's default success() semantics on needs: build means a single per-arch failure skips manifest assembly and aliases entirely. Verifiers can still cite the succeeded per-arch digest; the manifest list and :latest simply don't move for that release.
  • Restart story. Re-run failed jobs is the path. It re-runs only failed jobs, so the existence check never fires on a job that already succeeded. A whole-workflow rerun is intentionally noisy — it fails loudly on tags it already pushed.
  • Aliases are moving by design (:<cli>, :latest) and are exempt from the existence check — each release re-points them at the new manifest list.
  • Triggers: workflow_dispatch (for manual reruns and ad-hoc publishes) + push of v* tags. Push to main is NOT a publish trigger.

Out of scope

SLSA provenance attestation and SBOM generation — those are the next PR and slot in naturally as provenance: + sbom: flags on the existing docker/build-push-action step plus a release page that attaches the artifacts.

Depends on

#2 (matrix) — this branch is based on it. Base will auto-update to main once #2 merges.

Verification

  • ./scripts/resolve-matrix.sh --pretty now includes stellar_cli_ref and rust_image_digest per row; ./scripts/validate-json.sh still passes.
  • Workflow YAML is valid (no parse errors locally; GH Actions will verify on first run).
  • End-to-end behavior verifiable by running workflow_dispatch from the Actions UI against a tag once this PR merges.

@fnando fnando self-assigned this May 21, 2026
@fnando fnando added this to DevX May 21, 2026
@github-project-automation github-project-automation Bot moved this to Backlog (Not Ready) in DevX May 21, 2026
@fnando fnando moved this from Backlog (Not Ready) to Needs Review in DevX May 21, 2026
@fnando fnando requested a review from Copilot May 21, 2026 16:19
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a release-time publish pipeline to build and push per-arch images to Docker Hub, assemble per-(cli,rust) multi-arch manifest lists, and then publish moving aliases (:<cli>, :latest). It also extends the build matrix generator so the workflow doesn’t need to re-derive base-image digests or upstream refs during CI.

Changes:

  • Extend scripts/resolve-matrix.sh matrix rows to include stellar_cli_ref and rust_image_digest.
  • Add .github/workflows/publish.yml to build/push per-arch images on tag release, then create manifest lists and update aliases.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
scripts/resolve-matrix.sh Adds stellar_cli_ref and rust_image_digest fields to each matrix include row for publish-time consumption.
.github/workflows/publish.yml New workflow to publish per-arch images, assemble multi-arch manifests, and move :<cli> / :latest tags on releases.
Comments suppressed due to low confidence (2)

.github/workflows/publish.yml:103

  • The manifest job uses docker buildx imagetools inspect/create but never sets up Buildx (unlike the build job). Add docker/setup-buildx-action (and, if needed, a builder selection) in this job to avoid reliance on whatever Buildx happens to be preinstalled on the runner.
  manifest:
    name: assemble manifest lists
    needs: build
    runs-on: ubuntu-24.04
    steps:
      - name: checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - name: login to Docker Hub
        uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      - name: create manifest list per (cli, rust) pair
        run: |

.github/workflows/publish.yml:146

  • The aliases job also uses docker buildx imagetools create without setting up Buildx. Add docker/setup-buildx-action in this job as well so alias publishing doesn’t depend on implicit runner state.
  aliases:
    name: publish moving aliases
    needs: manifest
    runs-on: ubuntu-24.04
    steps:
      - name: checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - name: login to Docker Hub
        uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      - name: publish :<cli> and :latest aliases
        run: |
          newest_cli="$(./scripts/newest-pair.sh --stellar-cli-version)"

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/resolve-matrix.sh Outdated
Comment thread .github/workflows/publish.yml
Comment thread .github/workflows/publish.yml
@fnando fnando moved this from Needs Review to In Progress in DevX May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants