Skip to content

Use staging token directly for production image copy source#757

Merged
justin808 merged 1 commit into
masterfrom
jg-codex/use-staging-token-for-native-copy
Jun 2, 2026
Merged

Use staging token directly for production image copy source#757
justin808 merged 1 commit into
masterfrom
jg-codex/use-staging-token-for-native-copy

Conversation

@justin808

@justin808 justin808 commented Jun 2, 2026

Copy link
Copy Markdown
Member

Summary

  • remove the temporary cpln profile create path from the production copy step
  • run staging docker-login, manifest inspect, and source-side cpln image copy with CPLN_TOKEN_STAGING scoped to those commands
  • keep --to-profile default so the destination copy still uses the production profile created by setup

Why

The fresh post-#756 production run failed with:

/org/shakacode-open-source-examples-production/serviceaccount/github-actions-production is not granted [view] on /org/shakacode-open-source-examples-staging

That shows CPLN_TOKEN=... cpln profile create did not store the staging token in the temporary profile. The copy source needs the staging token directly, while the destination should keep using the default production profile.

Failed run: https://github.com/shakacode/react-webpack-rails-tutorial/actions/runs/26849170364

Verification

  • git diff --check -- .github/workflows/cpflow-promote-staging-to-production.yml
  • bin/conductor-exec bin/test-cpflow-github-flow

Note

Medium Risk
Changes production promotion credentials and cross-org image copy; failure would block releases but does not alter runtime app code.

Overview
Fixes staging→production image promotion in cpflow-promote-staging-to-production when a temporary Control Plane profile did not actually hold the staging token (production runs failed with missing view on the staging org).

The Copy image from staging step drops cpln profile create / --profile upstream and instead runs staging docker-login, docker manifest inspect, and the source side of cpln image copy with CPLN_TOKEN_STAGING on each command. Credentials go in an isolated DOCKER_CONFIG temp dir with cleanup on exit. Destination copy still uses --to-profile default (production profile from setup).

Reviewed by Cursor Bugbot for commit 937cbfc. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • Bug Fixes
    • Enhanced staging-to-production promotion workflow with improved error handling and validation during Docker image copying.
    • Streamlined authentication process and added manifest verification before each copy attempt.
    • Improved temporary file cleanup procedures.

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

🚀 Quick Review App Commands

Welcome! Here are the commands you can use in this PR:
They require the repository to have cpflow review apps configured, including the CPLN_TOKEN_STAGING secret.

+review-app-deploy

Deploy your PR branch for testing.

+review-app-delete

Remove the review app when done.

+review-app-help

Show detailed instructions, environment setup, and configuration options.

Comment +review-app-help for full setup details.

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0a2ce014-f7f5-4e40-8e79-4a2afb18911a

📥 Commits

Reviewing files that changed from the base of the PR and between 7e04fed and 937cbfc.

📒 Files selected for processing (1)
  • .github/workflows/cpflow-promote-staging-to-production.yml

Walkthrough

The deployment workflow's image staging-to-production copy step is refactored to use temporary Docker configuration directory management with cleanup, authenticate via cpln image docker-login, and validate the source image with docker manifest inspect before initiating the copy operation, replacing the prior profile-based Docker login approach.

Changes

Image Copy Authentication and Validation

Layer / File(s) Summary
Image copy authentication and preflight validation
.github/workflows/cpflow-promote-staging-to-production.yml
The "Copy image from staging" step now creates a temporary DOCKER_CONFIG directory with EXIT trap cleanup, authenticates using cpln image docker-login, validates the source image with docker manifest inspect, then runs cpln image copy in the retry loop.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • shakacode/react-webpack-rails-tutorial#756: Both PRs modify the same "Copy image from staging" step, updating the cpln image copy authentication flow to use docker-login and docker manifest inspect with temporary config cleanup.
  • shakacode/react-webpack-rails-tutorial#755: Both PRs refactor the "Copy image from staging" logic in the same workflow to gate image copy retries with Docker preflight validation and updated authentication.

Poem

🐰 A Docker config born, then vanishes with grace,
Auth flows now cleaner in this staging space,
Manifest inspected ere the image takes flight,
Temporary directories—then cleanup so tight! 🎯

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: using staging token directly for the production image copy source, which is the core objective of the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jg-codex/use-staging-token-for-native-copy

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

copy_status=1
for attempt in $(seq 1 "${copy_image_attempts}"); do
if CPLN_PROFILE="${upstream_profile}" docker manifest inspect "${source_image_ref}" >/dev/null &&
if CPLN_TOKEN="${CPLN_TOKEN_STAGING}" cpln image docker-login --org "${CPLN_ORG_STAGING}" >/dev/null &&

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Re-running docker-login on every retry is safe (and refreshes credentials for long retry sequences), but it means copy_status=$? can capture a docker-login exit code rather than a copy exit code when login itself fails. The warning message will still say "Image copy attempt … failed" even if the real problem was authentication. Consider logging which step failed for easier diagnosis:

Suggested change
if CPLN_TOKEN="${CPLN_TOKEN_STAGING}" cpln image docker-login --org "${CPLN_ORG_STAGING}" >/dev/null &&
if CPLN_TOKEN="${CPLN_TOKEN_STAGING}" cpln image docker-login --org "${CPLN_ORG_STAGING}" >/dev/null 2>&1 \
|| { echo "::warning::docker-login to staging failed on attempt ${attempt}"; false; }; then
if docker manifest inspect "${source_image_ref}" >/dev/null &&

Or at minimum, keep the current structure but drop the >/dev/null on docker-login stderr so auth errors surface directly in the log.

cleanup_upstream_profile
CPLN_TOKEN="${CPLN_TOKEN_STAGING}" cpln profile create "${upstream_profile}" >/dev/null
CPLN_PROFILE="${upstream_profile}" cpln image docker-login --org "${CPLN_ORG_STAGING}" >/dev/null
export DOCKER_CONFIG="${docker_config_dir}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

DOCKER_CONFIG is exported for the whole step, so any Docker commands that run after the loop (e.g. in the same run: block if code is added later) will also use the temp dir — which will be cleaned up on EXIT. This is intentional and correct for isolation; just worth a comment so future editors don't wonder why the env var is set here instead of inline on each docker call.

@claude

claude Bot commented Jun 2, 2026

Copy link
Copy Markdown

Code Review

Overview

This PR correctly fixes the root cause of the staging→production promotion failure. The previous approach of calling cpln profile create with a staging token and then using CPLN_PROFILE= to scope commands was silently unreliable — the token wasn't being stored in the temporary profile, leading to cross-org permission errors. Passing CPLN_TOKEN_STAGING directly on each command is simpler and more trustworthy.

What's Good

  • Root cause fix is sound. Inline CPLN_TOKEN= env-var scoping is the standard cpln pattern; it doesn't depend on profile storage working correctly.
  • Credential isolation via DOCKER_CONFIG. Using mktemp -d + export DOCKER_CONFIG is the right way to prevent staging Docker credentials from leaking into the default Docker config dir.
  • Cleanup via trap … EXIT. The temp dir is reliably removed on any exit path (success, error, or signal), matching the pattern from the old profile cleanup.
  • Token ownership is clear. Source side uses CPLN_TOKEN_STAGING; destination side uses --to-profile default (production). The split is explicit and correct.

Concerns

1. Observability: docker-login is now inside the retry condition (line 394)
Moving docker-login into the if chain means a login failure short-circuits the chain and copy_status=$? captures the login exit code, not the copy exit code. The warning message will read "Image copy attempt N failed" even when the real problem was authentication. Two options:

  • Remove >/dev/null from docker-login so stderr surfaces in the log (low-effort).
  • Add an explicit log line when login fails before continuing to the next retry.

2. Minor: docker-login stderr is suppressed (line 394)
>/dev/null only redirects stdout; if cpln image docker-login fails, its error message is silently dropped. The old code had the same pattern, but since login is now inside the retry condition this is more likely to hide the real failure. Consider redirecting both: >/dev/null 2>&1 for a clean log on success, but at least drop the stdout-only suppression so errors are visible.

3. Cosmetic: no comment explaining why DOCKER_CONFIG is exported at step scope (line 390)
Future editors might wonder why the env var is set here rather than inline on each docker call. A one-line comment would make the intent self-documenting.

Security

No regressions. CPLN_TOKEN_STAGING is sourced from a GitHub Actions secret and masked in logs. Passing it as an env-var prefix is standard CI practice and matches existing uses in the same workflow. The mktemp -d directory is created with mode 700, so credentials written by docker-login are not world-readable.

Verdict

Approve with minor suggestions. The fix is correct and the approach is cleaner than the profile-based method it replaces. The main concern worth addressing before merge: remove the >/dev/null on docker-login so auth failures are visible in retry logs — it will make the next debugging session much faster.

@greptile-apps

greptile-apps Bot commented Jun 2, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes a cross-org image copy failure introduced in #756 by dropping the intermediate cpln profile create step and instead passing CPLN_TOKEN_STAGING directly to the commands that need staging access. It also isolates staging Docker credentials in a per-run temp directory via DOCKER_CONFIG.

  • Staging auth: CPLN_TOKEN_STAGING is now passed inline to cpln image docker-login and cpln image copy rather than being stored in a temporary named profile, removing the profile-creation race that caused the "not granted [view]" error.
  • Credential isolation: A mktemp -d directory is exported as DOCKER_CONFIG and removed on EXIT via trap, so staging registry credentials never touch the runner's global Docker config.
  • Retry improvement: Moving docker-login inside the retry loop means transient authentication failures are automatically retried rather than failing the step immediately.

Confidence Score: 4/5

Safe to merge; the change correctly routes staging credentials directly to the commands that need them and cleans up after itself.

The fix is narrowly scoped: three commands that previously relied on a temporary named cpln profile now receive the staging token directly. The cleanup path (trap + rm -rf) is standard and correct. The one design assumption worth verifying is that cpln image copy honours --to-profile default for destination auth even when CPLN_TOKEN is set in the environment — if the env var wins globally, the destination push would use the staging token and likely fail.

.github/workflows/cpflow-promote-staging-to-production.yml — the cpln image copy invocation with both CPLN_TOKEN env var and --to-profile default is the key assumption to watch in the next production run.

Important Files Changed

Filename Overview
.github/workflows/cpflow-promote-staging-to-production.yml Replaces temporary cpln profile creation with direct CPLN_TOKEN_STAGING injection and an isolated DOCKER_CONFIG temp dir; moves docker-login inside the retry loop so transient auth failures are automatically retried.

Sequence Diagram

sequenceDiagram
    participant GH as GitHub Actions
    participant CPLN_S as cpln (staging token)
    participant Docker as docker CLI
    participant CPLN_P as cpln (production profile)

    GH->>GH: mktemp -d → docker_config_dir, export DOCKER_CONFIG
    loop up to copy_image_attempts
        GH->>CPLN_S: "CPLN_TOKEN=STAGING cpln image docker-login --org staging"
        CPLN_S-->>Docker: Write staging credentials to DOCKER_CONFIG
        GH->>Docker: docker manifest inspect staging-registry/image
        Docker-->>GH: manifest found
        GH->>CPLN_S: "CPLN_TOKEN=STAGING cpln image copy --org staging --to-profile default --to-org production"
        CPLN_S-->>CPLN_P: Pull from staging registry, push via production profile
        CPLN_P-->>GH: "copy_status=0, break"
    end
    GH->>GH: trap EXIT → rm -rf docker_config_dir
Loading

Reviews (1): Last reviewed commit: "Use staging token directly for productio..." | Re-trigger Greptile

@justin808 justin808 merged commit 633cf37 into master Jun 2, 2026
14 checks passed
@justin808 justin808 deleted the jg-codex/use-staging-token-for-native-copy branch June 2, 2026 21:38
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

✅ Review App Deleted

Review app for PR #757 is deleted

🎮 Control Plane Console
📋 View Workflow Logs

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