Copy production image with direct Docker registry auth#758
Conversation
🚀 Quick Review App CommandsWelcome! Here are the commands you can use in this PR:
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughThe production promotion workflow's image-copy step is refactored to authenticate and transfer images via direct Docker registry operations. Production credentials are added to the environment, staging and production registry endpoints are computed, and the prior cpln-based copy is replaced with a chained flow of docker login, manifest inspection, pull, tag, and push commands. ChangesProduction Image Promotion
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Code Review: Copy production image with direct Docker registry authOverviewThis PR replaces Positives
Issues / RisksMedium – Multi-arch / manifest-list images
If the app is single-platform only, this is a non-issue in practice — but worth confirming. If multi-arch support is needed, consider Minor – Performance: full image materialisation on runnerThe old Minor –
|
| docker pull "${source_image_ref}" && | ||
| docker tag "${source_image_ref}" "${production_image_ref}" && | ||
| docker push "${production_image_ref}"; then |
There was a problem hiding this comment.
Multi-arch concern: docker pull + docker tag + docker push only copies the single-platform image matching the runner's architecture. If the staging image is a multi-platform manifest list, production will silently receive a single-arch image.
If multi-arch is not needed, this is fine. Otherwise consider using docker buildx imagetools create, which copies the manifest list without pulling layers:
| docker pull "${source_image_ref}" && | |
| docker tag "${source_image_ref}" "${production_image_ref}" && | |
| docker push "${production_image_ref}"; then | |
| docker buildx imagetools create -t "${production_image_ref}" "${source_image_ref}"; then |
(that replaces the three lines — if this one-liner works in your buildx setup, remove the pull/tag lines entirely).
| if printf '%s' "${CPLN_TOKEN_STAGING}" | | ||
| docker login "${staging_registry}" -u '<token>' --password-stdin >/dev/null && | ||
| printf '%s' "${CPLN_TOKEN_PRODUCTION}" | | ||
| docker login "${production_registry}" -u '<token>' --password-stdin >/dev/null && |
There was a problem hiding this comment.
These two docker login calls run on every retry attempt, but credentials never change between retries. Consider hoisting them above the loop so they run once — retries are really only needed for the pull/tag/push operations.
| if printf '%s' "${CPLN_TOKEN_STAGING}" | | |
| docker login "${staging_registry}" -u '<token>' --password-stdin >/dev/null && | |
| printf '%s' "${CPLN_TOKEN_PRODUCTION}" | | |
| docker login "${production_registry}" -u '<token>' --password-stdin >/dev/null && | |
| if docker manifest inspect "${source_image_ref}" >/dev/null && |
(Move the two docker login calls to just after the export DOCKER_CONFIG line, before the retry loop.)
Greptile SummaryReplaces the
Confidence Score: 4/5Safe to merge for single-arch deployments; the new direct docker login approach correctly isolates staging and production credentials and avoids the cpln profile mismatch that broke the previous run. The credential handling is sound — tokens flow through stdin, the Docker config is isolated to a temp directory that is cleaned up on exit, and both registries are authenticated independently before any transfer begins. The one gap is that docker pull+tag+push does not preserve multi-arch manifest lists, but for this Rails application that is almost certainly not an issue today. .github/workflows/cpflow-promote-staging-to-production.yml — specifically the retry loop, which re-authenticates and re-downloads the full image on every attempt. Important Files Changed
Sequence DiagramsequenceDiagram
participant GHA as GitHub Actions Runner
participant SR as Staging Registry
participant PR as Production Registry
loop Retry (up to N attempts)
GHA->>SR: docker login --password-stdin (CPLN_TOKEN_STAGING)
SR-->>GHA: Login Succeeded
GHA->>PR: docker login --password-stdin (CPLN_TOKEN_PRODUCTION)
PR-->>GHA: Login Succeeded
GHA->>SR: docker manifest inspect source_image_ref
SR-->>GHA: Manifest OK
GHA->>SR: docker pull source_image_ref
SR-->>GHA: Image layers downloaded
GHA->>GHA: docker tag source_image_ref production_image_ref
GHA->>PR: docker push production_image_ref
PR-->>GHA: Push complete
end
GHA->>GHA: "echo image=production_image to GITHUB_OUTPUT"
Reviews (1): Last reviewed commit: "Copy production image with direct Docker..." | Re-trigger Greptile |
| docker pull "${source_image_ref}" && | ||
| docker tag "${source_image_ref}" "${production_image_ref}" && | ||
| docker push "${production_image_ref}"; then |
There was a problem hiding this comment.
docker pull + push drops multi-arch manifest lists
docker pull fetches only the manifest entry that matches the runner's native platform (e.g., linux/amd64). If the staging image was built as a multi-arch manifest list, the production copy will silently become a single-architecture image. Tools like docker buildx imagetools create or crane copy preserve the full manifest list. This is low-risk for a single-platform Rails app, but worth keeping in mind if the image build ever switches to multi-arch.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
✅ Review App DeletedReview app for PR #758 is deleted |
Summary
Why
The post-#757 production run got past the previous profile-create issue, but failed because cpln image docker-login still configured Docker with the default production profile for the staging registry.
Then Docker could not pull the staging image. Control Plane image docs document the CI-safe direct registry path using docker login with the token on stdin. This keeps staging and production registry credentials explicit and avoids the cpln profile/credential-helper mismatch.
Failed run: https://github.com/shakacode/react-webpack-rails-tutorial/actions/runs/26849578678
Verification
Note
Medium Risk
Changes how production container images are published during promotion; a misconfiguration could block releases or push to the wrong registry, though tagging and retries are preserved.
Overview
The Copy image from staging step in
cpflow-promote-staging-to-production.ymlno longer usescpln image docker-loginandcpln image copy. It now logs into the staging and production Control Plane registries withdocker login --password-stdin(staging and production tokens via env), then pulls the staging image, tags it with the same incremented production name (<app>:<n+1>_<commit>), and pushes to production.That fixes CI failures where
cpln image docker-loginwired Docker to the wrong org/profile so the staging image could not be pulled. Retry logic, isolatedDOCKER_CONFIG, and the step’simageoutput are unchanged.Reviewed by Cursor Bugbot for commit ab4b524. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit