ci: auto-mirror template image updates to registries#5739
Merged
Conversation
The Start check pinned SUPABASE_INTERNAL_IMAGE_REGISTRY=ghcr.io, so a dependabot image bump failed with "manifest unknown" until the new tag was manually mirrored to ghcr.io — yet the PR still merged (Start is not a required check), breaking Start on develop for every subsequent PR. Two changes: - Drop the ghcr.io override in the Start job so `start` uses the default registry fallback (public.ecr.aws -> ghcr.io -> upstream Docker Hub). A freshly bumped tag exists upstream immediately, so Start stays green while the mirror catches up. - Add mirror-template-images.yml: whenever the templates Dockerfile changes, detect any tag missing from the ghcr.io mirror and backfill it via the existing cli-go-mirror-image reusable workflow. Runs on pull_request_target (guarded to same-repo branches) so it works on dependabot PRs, parses the Dockerfile statically without executing checked-out code, and only mirrors missing tags. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DEeGQ3JAwQD1PGEENE13dc
…_target Avoid pull_request_target (privileged token + cloud creds exposed to PR context). Dependabot pull_request runs can't be granted the AWS role / packages:write needed to mirror anyway, and Start no longer needs the mirror to be done before merge (it falls back to the upstream image), so the backfill runs post-merge on push to develop — a trusted context — and develop self-heals within a minute. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DEeGQ3JAwQD1PGEENE13dc
Revert the cli-go-ci.yml change so the Start job keeps validating against ghcr.io. The post-merge mirror-template-images workflow repopulates ghcr.io/ECR as soon as a bump lands on develop, so develop and PRs rebased on it stop inheriting the manifest-unknown failure. Update the related comments to match. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DEeGQ3JAwQD1PGEENE13dc
Replace the inline bash in mirror-template-images.yml with a Bun script backed by a unit-tested module: - src/shared/services/mirror-images.ts — mirrorImageTarget (mirrors Go's utils.GetRegistryImageUrl) and partitionUnmirroredImages, the idempotent core that splits images by mirror presence. Reuses the existing parseDockerfileServiceImages parser. - scripts/detect-unmirrored-images.ts — thin CI entry that runs the docker inspect check and writes missing=<json> to GITHUB_OUTPUT. Check every image, not just third-party ones: any image already on the mirror is skipped, so a supabase/* image that is somehow absent is still backfilled and a re-run is a no-op. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DEeGQ3JAwQD1PGEENE13dc
An image counts as mirrored only when present on ALL mirror registries (public.ecr.aws and ghcr.io), not just one. The mirror pushes to both at once, so a tag present on one but missing from the other is a partial mirror that must be re-pushed. partitionUnmirroredImages now checks every (image, registry) pair via mirrorImageTargets and flags an image as missing if any registry lacks it. Anonymous imagetools inspect works for public ECR, so the detect job needs no AWS credentials. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DEeGQ3JAwQD1PGEENE13dc
Supabase CLI previewnpx --yes https://pkg.pr.new/supabase/cli/supabase@70aa7ed62ce45347d1fedf16853da8afb95487efPreview package for commit |
The mirror helpers were used only by the detect script and its test, so keep them in scripts/detect-unmirrored-images.ts instead of a separate src module. The executable entry is guarded by import.meta.main so the exported helpers can be imported by the unit test without side effects. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DEeGQ3JAwQD1PGEENE13dc
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cc78a1da42
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
jgoux
approved these changes
Jun 30, 2026
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.
Automatically backfills the image mirror when the CLI template Dockerfile changes, so a dependabot image bump no longer leaves develop (and PRs rebased on it) failing the ghcr.io-pinned
Startcheck withmanifest unknown.Background
The
Startjob incli-go-ci.ymlpinsSUPABASE_INTERNAL_IMAGE_REGISTRY=ghcr.io, so it only goes green once a bumped tag exists on the mirror. Dependabot bumps the Dockerfile before the new tag is mirrored, and the mirror previously only ran via manualworkflow_dispatch— so the bump merged red and every subsequent PR touchingapps/cli-go/**inherited the same failure until someone mirrored by hand. This was the catch-22 already noted incli-go-mirror.yml.Changes
New workflow
mirror-template-images.yml— runs onpushto develop whenapps/cli-go/pkg/config/templates/Dockerfilechanges (plusworkflow_dispatch). It detects any image tag missing from the mirror and backfills it by reusing the existingcli-go-mirror-image.ymlreusable workflow. It runs on push rather than the PR on purpose: mirroring needs the AWS role +packages:write, which a dependabot-triggeredpull_requestrun cannot be granted, and this avoidspull_request_target. The backfill runs as soon as the bump lands on develop, repopulating the mirror so develop and rebased PRs passStart.New script
apps/cli/scripts/detect-unmirrored-images.ts— parses the template Dockerfile, checks each image against the mirror withdocker buildx imagetools inspect, and writes the missing tags as JSON to$GITHUB_OUTPUTfor the workflow matrix. The detection helpers (mirrorImageTarget,mirrorImageTargets,partitionUnmirroredImages) are exported and unit-tested; the executable entry is guarded byimport.meta.main.public.ecr.awsandghcr.io) — a tag on one but missing from the other is re-pushed. Anonymousimagetools inspectworks for public ECR, so the detect job needs no AWS credentials.detect-unmirrored-images.unit.test.ts— covers target derivation, the both-registries rule, de-duplication, and the idempotent re-run.cli-go-mirror.yml— clarified that it is now the manual/bulk entry point; template bumps are mirrored automatically by the new workflow.https://claude.ai/code/session_01DEeGQ3JAwQD1PGEENE13dc