ci: publish privately, then promote to Docker Hub - #47
Merged
Conversation
Docker Hub is public and its tags are permanent in practice, so a release reaching it as a side effect of a tag push leaves no room to check the image first. Publishing now lands in the private GHCR package by default, and getting to Docker Hub is a separate dispatch. - `registries` input on Publish Testnode selects where a run pushes; a tag push falls through to `ghcr`. One resolved selection feeds both the build and the alias job, so they cannot disagree about where a release went. - Verify Published Image boots a published version's l2 and l3-eth images through the action against GHCR, with a credential, and checks each image's bundle labels match the tag it was pulled as. - Mirror Images to Docker Hub now sources from arbitrum-litro, and carries `latest-<variant>` across when the source alias still names a version being mirrored. Without this the public repository has version tags but no `latest-*`, which is what the action and bake resolve by default. - Ref resolution, the taken-tag guard and the credential check move into scripts/ci/resolve-publish-refs.mjs, built on buildTestnodeImageRef so a published tag is always one a consumer resolves. It now runs before the snapshot rather than after, so a taken tag fails in a minute. - The image carries org.opencontainers.image.source, which is what grants this repository's workflows access to the private package. - snapshot bake defaulted to ghcr.io/offchainlabs/arbitrum-testnode-ci, a package that has no `latest-*` tags; it now resolves the shared default.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Docker Hub is public and its tags are permanent in practice, so a release reaching it as a side effect of a tag push leaves no room to check the image first. This splits publishing from going public: build into the private GHCR package, verify, then promote.
Two holes turned up while wiring it:
v0.2.10version tags and nolatest-*tags. Bothaction.yml(version: latest) andbake/action.yml(bundle-version: latest) resolveoffchainlabs/arbitrum-litro:latest-<variant>by default, so the default path currently names a tag that does not exist. Aliases only started with feat(bake): customize composed contract bundles without rebuilding #39 and nothing has published them yet.packages/coresnapshot bakedefaulted its base image toghcr.io/offchainlabs/arbitrum-testnode-ci:latest-<variant>— the old package name, which has nolatest-*tags either.What changed
Publish Testnode
registriesinput:ghcr(default) orghcr,dockerhub. Dispatch inputs do not exist on a tag push, so a tag falls through toghcr.resolve-publish-matrixand consumed by both the build and the alias job, so they cannot disagree about where a release went.Resolve image refs, the taken-tag guard and the credential check collapse intoscripts/ci/resolve-publish-refs.mjs, built onbuildTestnodeImageRefrather than re-deriving the tag suffix in bash. It runs before the snapshot now, so a taken tag or missing credential fails in a minute instead of after ~30 minutes ofinit.org.opencontainers.image.source. That label is what links a GHCR package to a repository and grants the repository's own workflows access to it while private, so the new package does not start orphaned.Verify Published Image (new, dispatch only)
Boots a published version's
l2andl3-ethimages through the action, authenticating against GHCR, and asserts each image's bundle labels match the tag it was pulled as. Promotion copies digests, so a mislabelled image would stay mislabelled all the way to the public registry. This is deliberately the opposite oftest-action.yml'stest-published-image-action, which proves the public default needs no credential.Mirror Images to Docker Hub
source-repositorydefault moves toghcr.io/offchainlabs/arbitrum-litro, where releases now go.latest-<variant>across, but only when the source alias still names a version this run mirrored. An alias whose digest is not in the mirrored set is reported asheldand left alone, so the public alias can never claim a version Docker Hub does not have.Verification
pnpm validate: 280/280.resolve-publish-refs.mjsexercised on all four paths: GHCR-only, Docker Hub without credentials (fails), Docker Hub against the existingv0.2.10-nc3.2-l2(refuses), Docker Hub against a freev0.3.0tag (proceeds).latest-l2copies because the source alias points at a mirrored version,latest-l3-ethis held because the source alias points elsewhere. Re-running reportsalready currentrather than copying again.yaml-lintclean on all three workflows.After merge
pnpm release 0.3.0and push the tag. That run creates thearbitrum-litroGHCR package (private, linked via the new label), thenVerify Published Imageforv0.3.0, thenMirror Images to Docker Hubto make it public along with itslatest-*aliases.