Skip to content

ci: keep the Docker Hub listing in a fixed order - #822

Draft
LeeroyHannigan wants to merge 1 commit into
mainfrom
ci/dockerhub-listing-order
Draft

LeeroyHannigan wants to merge 1 commit into
mainfrom
ci/dockerhub-listing-order

Conversation

@LeeroyHannigan

@LeeroyHannigan LeeroyHannigan commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

What

This PR adds ci/dockerhub-order.py and runs it at the end of each job that pushes to Docker Hub:

  • release-dev-image.yml, job publish
  • release-image.yml, job publish-candidate
  • sign-image.yml, job sign
  • promote-image.yml, job promote

The script keeps the extenddb repositories on Docker Hub in this order: postgres, dev, cassandra, mongodb. It finds the lowest repository that is not newer than the one below it. Then, from the bottom up, it pushes the current latest manifest again, byte for byte, for that repository and each one above it.

The digest does not change, so the image, its signature and pinned pulls stay the same. Before a push, the script checks that the bytes hash to the digest that Docker Hub reports. After the push, it checks that latest still resolves to that digest.

The new step has continue-on-error: true and runs the script with --warn-only. A failure in the step gives a warning, and the release continues. Without --apply, the script needs no credentials. It prints the plan and checks the manifests.

Why

Docker Hub has no setting for the order of the repositories in a namespace. It lists them by last push, newest first. Each publish moves its image to the top. After the 2026-10-23 release, the listing was mongodb, postgres, dev.

The step runs inside the dockerhub environment jobs, because only those jobs hold the Docker Hub credential. A separate workflow would need a second approval for each run. A scheduled job would need the credential outside the protected environment.

Points for reviewers:

  • A job that publishes one image can now push the latest manifest of other images again. For example, a mongodb promotion pushes the latest manifests of cassandra, dev and postgres. No digest changes, but Docker Hub shows a new "last pushed" time for those tags.
  • The script cannot move a repository that has no latest tag. Cassandra has none until its first promotion. If a release publishes mongodb before then, the step warns and mongodb stays above cassandra.
  • feat(container): publish a Cassandra-backed ExtendDB image #725 merged after I created this branch. It adds cassandra to these workflows. This commit applies to main at 7c8a776 without conflicts, so cassandra releases also run the step.

Testing done

  • A dry run on 2026-11-04, before the manual run below, gave the plan dev, then postgres. The manifest bytes matched the latest digests (dev sha256:f7fa71e39d2c, postgres sha256:9f54c9f4b7a4).
  • A manual --apply run on 2026-11-04 used an earlier copy of this script with the same push logic. It pushed the latest tag of dev at 14:03:51 UTC and of postgres at 14:03:57 UTC. The listing then showed postgres, dev, cassandra, mongodb, and both latest tags kept their digests.
  • A dry run from this branch after that run printed Already in order. Nothing to push.
  • Plan checks used stubbed Docker Hub reads. They covered six cases: already in order, the state before the manual run, and a publish of each of the four images. Each case gave the expected push list.
  • With --warn-only, a missing latest tag, a missing token and a network error each printed a ::warning line and exited 0. Without --warn-only, the missing tag exited 1 and the network error raised an exception.
  • actionlint on the four workflows, on this branch and with this commit applied to main at 7c8a776: no findings.
  • The publish workflows run only on dispatch, so the CI of this PR does not run the new step. The first publish after the merge is the first run in CI.

Checklist

  • I have read CONTRIBUTING.md
  • All tests pass (cargo test --workspace)
  • Code is formatted (cargo fmt --check)
  • Clippy is clean (cargo clippy -- -W clippy::pedantic)
  • I have added or updated tests for new functionality
  • I have updated documentation if behavior changed
  • Breaking changes are noted below (if any)
  • If this changes the wire protocol, Storage trait, auth model, on-disk
    format, or public CLI surface, an RFC has been accepted or is linked
    below. Otherwise, an ADR captures the decision (link below).

ADR / RFC: n/a


By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache License 2.0 and I agree to the Developer Certificate of
Origin (DCO). See CONTRIBUTING.md for details.

Docker Hub lists a namespace's repositories by last push, newest first.
It has no setting for the order, so each publish moves its image to the
top of the list.

ci/dockerhub-order.py keeps the order postgres, dev, cassandra,
mongodb. It finds the lowest repository that is not newer than the one
below it. Then, from the bottom up, it pushes the manifest that the
latest tag already points to, byte for byte, for that repository and
each one above it. No tag changes digest, so signatures and pinned
pulls stay the same.

The Docker Hub jobs of release-dev-image, release-image, sign-image and
promote-image run it after their last Docker Hub push. The script reads
the credential that those jobs already hold. The step has
continue-on-error and the script runs with --warn-only, so a failure in
it never fails a release.

This branch has not been deployed

No deployments
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.

1 participant