Skip to content

Document cpflow downstream setup#747

Merged
justin808 merged 18 commits into
masterfrom
jg-codex/downstream-cpflow-setup-docs
May 25, 2026
Merged

Document cpflow downstream setup#747
justin808 merged 18 commits into
masterfrom
jg-codex/downstream-cpflow-setup-docs

Conversation

@justin808
Copy link
Copy Markdown
Member

@justin808 justin808 commented May 24, 2026

Summary

  • document the minimal GitHub setup for generated review apps
  • spell out Control Plane-side orgs, app names, secret dictionaries, and sensitive production token handling
  • pin generated cpflow wrappers to the same upstream commit used by the starter test PR and wire production promotion through the protected production environment

Validation

  • git diff --check
  • bin/conductor-exec bin/test-cpflow-github-flow ruby /private/tmp/control-plane-flow-release-check.lWpUu0/repo/bin/cpflow
  • actionlint -ignore SC2129 .github/workflows/cpflow-*.yml

Note

Medium Risk
Changes CI workflow wiring and production token handling (environment-gated promotion), which affects deploy/promote behavior even though application runtime code is untouched.

Overview
This PR documents downstream cpflow setup for this demo repo and aligns generated GitHub Actions with Control Plane Flow v5.0.1.

Documentation now spells out the minimal GitHub path (staging token only for review apps; staging variables for auto-deploy), matching Control Plane orgs/apps/secret dictionaries, and production promotion via a protected production Environment (not repo-level CPLN_TOKEN_PRODUCTION). Generic reusable-workflow mechanics are delegated to the upstream CI guide; local docs are shortened to app-specific values and a canary checklist. Review-app naming drops the -pr segment: leave REVIEW_APP_PREFIX unset so apps are qa-react-webpack-rails-tutorial-<PR>; old …-pr-… apps need manual cleanup.

Workflow wrappers repin from a commit SHA to @v5.0.1, drop obsolete control_plane_flow_ref, replace secrets: inherit with named secrets, and wire promotion with production_environment: production (staging token only from the caller). Staging deploy triggers master only. bin/pin-cpflow-github-ref and bin/test-cpflow-github-flow enforce the new pinning and secret-passing rules.

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

Summary by CodeRabbit

  • Documentation
    • Expanded Review App setup and help: clarified required vs optional secrets/variables, instruct leaving review-app prefix unset (names inferred), require GitHub settings to match app names, separate staging vs production promotion guidance, note production token lives in a protected Environment, and added advanced testing guidance for unreleased control-plane-flow changes.
  • Chores
    • Pinned reusable workflow references and changed CI jobs to explicitly pass required secrets.
  • Tests
    • Validation script enhanced to enforce explicit secret passing for reusable workflows.

Review Change Stack

@github-actions
Copy link
Copy Markdown

🚀 Quick Review App Commands

Welcome! Here are the commands you can use in this PR:

+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
Copy link
Copy Markdown

coderabbitai Bot commented May 24, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a "GitHub Review App Setup" section and clarifies cpflow secrets/variables and advanced testing; repins all cpflow wrapper workflows to a newer immutable upstream commit SHA, and annotates promotion workflow permissions and environment secret usage.

Changes

Control Plane Documentation and Workflow Reference Update

Layer / File(s) Summary
Control Plane setup documentation
.controlplane/readme.md
Adds a "GitHub Review App Setup" section describing required secrets/variables, naming inference from .controlplane/controlplane.yml, optional overrides, and staging/production environment configuration. Updates REVIEW_APP_PREFIX guidance to leave it unset so names are inferred.
CI/CD help documentation and advanced testing reference
.github/cpflow-help.md
Revises secrets and variables guidance, clarifies CPLN_TOKEN_PRODUCTION as a protected production GitHub Environment secret, adjusts required vs optional variables for review apps vs staging/promote, and adds an "Advanced" section detailing how to test unreleased control-plane-flow via pinned refs and CPFLOW_VERSION.
Shakacode team deployment notes
.controlplane/shakacode-team.md
Updates team guidance to prefer leaving REVIEW_APP_PREFIX unset, splits staging vs production required secrets/vars, and documents using a protected production environment for promotion secrets and reviewer protections.
Workflow upstream reference pins to new commit SHA
.github/workflows/cpflow-*.yml
Updates cpflow wrapper workflows to use the new upstream shakacode/control-plane-flow commit SHA (matching control_plane_flow_ref inputs); replaces secrets: inherit with explicit secret mappings and annotates promote workflow permissions and environment usage.
Wrapper validation and local checks
bin/test-cpflow-github-flow, .controlplane/docs/testing-cpflow-github-actions.md, .controlplane/controlplane.yml
Adds validation to prevent secrets: inherit when forwarding reusable-workflow refs, refines abort messaging for secrets/ref mismatches, updates local checks wording to “secret-passing”, and tweaks an example QA app name comment.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I nibbled docs and nudged the SHA,
Review apps learn their names today,
Secrets tucked in envs so neat,
Wrappers pin and checks repeat,
Rabbit hops—CI streams OK!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Document cpflow downstream setup' accurately summarizes the main intent of the PR, which focuses on expanding downstream cpflow documentation and updating GitHub Actions workflows to align with upstream changes.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jg-codex/downstream-cpflow-setup-docs

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 link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issue.

Reviewed by Cursor Bugbot for commit d5e1fd6. Configure here.

Comment thread .github/workflows/cpflow-review-app-help.yml Outdated
@@ -15,4 +15,4 @@ permissions:
jobs:
show-help:
if: vars.REVIEW_APP_PREFIX != ''
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This guard contradicts the new documentation. The README and cpflow-help.md now say REVIEW_APP_PREFIX is optional and inferred from controlplane.yml, but this condition means the help workflow will be silently skipped when REVIEW_APP_PREFIX is unset — which is the new recommended default.

If the upstream reusable workflow now supports inferring the prefix, this guard should be removed (or updated to a condition that always evaluates to true for authorized callers). As-is, teams following the new "leave REVIEW_APP_PREFIX unset" guidance will never see the help command fire.

Suggested change
if: vars.REVIEW_APP_PREFIX != ''
if: true

# upstream workflow. The upstream workflow only reads the named secrets it
# references, but GitHub does not enforce that boundary. Strict consumers can
# set CPFLOW_GITHUB_ACTIONS_REF to an immutable commit SHA.
secrets: inherit
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The comment mentions CPFLOW_GITHUB_ACTIONS_REF as an env var for strict consumers, but the actual input used everywhere else in these workflows is control_plane_flow_ref. This looks like a variable name that doesn't exist — it may confuse readers trying to act on this guidance.

Consider referencing the correct mechanism (the control_plane_flow_ref workflow input or the @<sha> ref in uses:) instead.

@claude
Copy link
Copy Markdown

claude Bot commented May 24, 2026

Code Review: Document cpflow downstream setup

Overview

This PR documents the minimal GitHub/Control Plane setup for review apps, staging, and production, and bumps all generated cpflow workflow wrappers from commit 3e0e7e1 to db013e1. The documentation work is solid and the security guidance around CPLN_TOKEN_PRODUCTION isolation is a meaningful improvement.


Issues

Bug: cpflow-review-app-help.yml guard conflicts with new documentation
The if: vars.REVIEW_APP_PREFIX != '' condition in cpflow-review-app-help.yml will silently skip the help workflow for any team following the new recommended default of leaving REVIEW_APP_PREFIX unset. This is the most actionable issue — see the inline comment.

Minor: Misleading variable name in secrets: inherit comment
The comment in cpflow-promote-staging-to-production.yml references CPFLOW_GITHUB_ACTIONS_REF as a mechanism for strict consumers to limit secret exposure, but this variable doesn't appear elsewhere in the workflows. The correct mechanism is the control_plane_flow_ref input or the pinned @<sha> ref in uses:. See inline comment.


Security

  • Isolating CPLN_TOKEN_PRODUCTION to a protected GitHub Environment with required reviewers is the right call — good improvement over a plain repository secret.
  • The secrets: inherit pattern passes all caller repository secrets to the upstream reusable workflow. GitHub does not filter to only referenced secrets. The added comment acknowledges this honestly. Teams managing strict secret compartmentalization should note that CPLN_TOKEN_PRODUCTION living in the production environment (not the repo) limits its exposure to this specific job, which mitigates most of the risk.
  • Pinning workflow refs to full 40-character commit SHAs (rather than mutable tags or branch names) is a supply-chain best practice and is consistently applied across all workflow files.

Documentation Quality

The new sections in .controlplane/readme.md and .github/cpflow-help.md are clear and well-structured. The table-driven format for secrets/variables is easy to scan. The "Advanced: testing unreleased control-plane-flow changes" section appropriately cautions against pinning to moving branches.

One minor note: the README update changes the review app naming convention from qa-react-webpack-rails-tutorial-pr-<number> (old) to qa-react-webpack-rails-tutorial-<number> (new, without the -pr segment). This is likely intentional but could affect teams who have existing named apps or tooling that pattern-matches on the old format.


Summary

The cpflow-review-app-help.yml guard is the one change that needs attention before merging — everything else is either a straightforward ref bump or documentation improvement.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 24, 2026

Greptile Summary

This PR documents the minimal GitHub and Control Plane setup required for generated cpflow review apps, staging deploys, and production promotion, and bumps all workflow SHA pins from 3e0e7e1 to db013e1 consistently across six workflow files.

  • Documentation: Adds comprehensive setup tables to .controlplane/readme.md and .github/cpflow-help.md covering required/optional secrets, variables, Control Plane org/app/secret-dictionary names, and production environment isolation. REVIEW_APP_PREFIX and CPLN_ORG_STAGING are now marked optional (inferred from controlplane.yml).
  • Promotion workflow: Adds production_environment: production input so the upstream reusable workflow gates production secrets behind the protected GitHub Environment, and adds inline comments explaining the secrets: inherit scope limitation.
  • SHA pins: All six uses: refs and matching control_plane_flow_ref inputs are updated to the same new commit SHA.

Confidence Score: 4/5

Safe to merge with one follow-up: the REVIEW_APP_PREFIX guard in cpflow-review-app-help.yml should be removed or relaxed now that the variable is documented as optional.

The documentation and SHA-pin changes are accurate and consistent. The only functional mismatch is in cpflow-review-app-help.yml, where a pre-existing guard silently suppresses the onboarding help comment for any repo that follows the newly documented standard setup without setting REVIEW_APP_PREFIX. Deploys still work — only the help message is lost — but it directly contradicts the intent of this PR.

.github/workflows/cpflow-review-app-help.yml — the REVIEW_APP_PREFIX guard needs to be removed or updated to match the new optional-variable documentation.

Security Review

  • secrets: inherit scope in promote workflow (.github/workflows/cpflow-promote-staging-to-production.yml): all repository secrets, including CPLN_TOKEN_STAGING and DOCKER_BUILD_SSH_KEY, are forwarded to the upstream reusable workflow. GitHub does not restrict the callee to only the named secrets it references. The PR pins the upstream to an immutable SHA which limits supply-chain risk, but the broad secret exposure during production-promotion runs is worth verifying against org policy.

Important Files Changed

Filename Overview
.github/workflows/cpflow-review-app-help.yml SHA bumped to db013e1; the pre-existing if: vars.REVIEW_APP_PREFIX != '' guard now contradicts the updated docs that say REVIEW_APP_PREFIX is optional, meaning the help job is silently skipped for standard setups.
.github/workflows/cpflow-promote-staging-to-production.yml Added production_environment: production input to gate production secrets behind the protected GitHub Environment; added explanatory comments; SHA bumped. The acknowledged secrets: inherit scope is worth verifying against org policy.
.controlplane/readme.md Large documentation addition covering GitHub secrets/variables, Control Plane org/app/secret-dictionary setup, and production promotion isolation. Content is accurate and consistent with the workflow changes.
.github/cpflow-help.md Updated secrets/variables tables to mark REVIEW_APP_PREFIX optional, clarified CPLN_TOKEN_PRODUCTION placement, and added an advanced section on testing upstream PRs with commit-SHA pins.
.github/workflows/cpflow-cleanup-stale-review-apps.yml SHA bumped from 3e0e7e1 to db013e1 in both uses: and control_plane_flow_ref; no other changes.
.github/workflows/cpflow-delete-review-app.yml SHA bumped consistently; no other changes.
.github/workflows/cpflow-deploy-review-app.yml SHA bumped consistently; no other changes. No REVIEW_APP_PREFIX guard here (intentional asymmetry with cpflow-review-app-help.yml).
.github/workflows/cpflow-deploy-staging.yml SHA bumped consistently; no other changes.
.github/workflows/cpflow-help-command.yml SHA bumped consistently; no other changes.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    PR[Pull Request opened/sync] --> DeployJob[cpflow-deploy-review-app\nno REVIEW_APP_PREFIX guard]
    PR --> HelpJob{cpflow-review-app-help\nif REVIEW_APP_PREFIX != ''}
    HelpJob -- "var set" --> PostHelp[Post help comment on PR]
    HelpJob -- "var unset\n(new standard setup)" --> Skip[Job skipped — no help posted]
    DeployJob --> UpstreamDeploy[Upstream reusable workflow\ninfers prefix from controlplane.yml]
    Master[Push to master] --> StagingDeploy[cpflow-deploy-staging]
    StagingDeploy --> UpstreamStaging[Upstream staging workflow]
    ManualTrigger[workflow_dispatch\nconfirm_promotion=promote] --> PromoteJob[cpflow-promote-staging-to-production]
    PromoteJob --> EnvGate{Protected GitHub Environment\nproduction — requires reviewer approval}
    EnvGate -- approved --> UpstreamPromote[Upstream promote workflow\nreads CPLN_TOKEN_PRODUCTION]
    EnvGate -- rejected --> Blocked[Promotion blocked]
Loading

Reviews (1): Last reviewed commit: "Document cpflow downstream setup" | Re-trigger Greptile

@@ -15,4 +15,4 @@ permissions:
jobs:
show-help:
if: vars.REVIEW_APP_PREFIX != ''
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Help message silently suppressed for standard setups

The updated docs explicitly say REVIEW_APP_PREFIX is optional and inferred from controlplane.yml, but the guard if: vars.REVIEW_APP_PREFIX != '' remains. Any repo that follows the new standard setup (leaving REVIEW_APP_PREFIX unset) will never see the help comment posted on opened PRs — the job is skipped entirely. The deploy workflow (cpflow-deploy-review-app.yml) has no such guard, so deploys work but onboarding help is silently absent.

Comment on lines 28 to 32
# `secrets: inherit` passes all caller repository secrets to the trusted
# upstream workflow. The upstream workflow only reads the named secrets it
# references, but GitHub does not enforce that boundary. Strict consumers can
# set CPFLOW_GITHUB_ACTIONS_REF to an immutable commit SHA.
secrets: inherit
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 security secrets: inherit exposes all repository secrets to the upstream workflow

The inline comment correctly notes that secrets: inherit passes every caller repository secret to the upstream reusable workflow, and that GitHub does not enforce the named-secrets boundary. In the current setup this includes CPLN_TOKEN_STAGING, any DOCKER_BUILD_SSH_KEY, and any other repository secrets. If the upstream SHA (db013e...) ever changes to include malicious or compromised code, those secrets are exposed during a production-promotion run. The PR already pins to an immutable SHA which limits supply-chain risk, but consider whether your org's policy requires explicit secret whitelisting via environment-level scoping rather than secrets: inherit.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.controlplane/readme.md:
- Around line 489-493: The README guidance and shakacode-team doc disagree about
review-app naming: update .controlplane/shakacode-team.md to match
.controlplane/readme.md by changing the instructions that set REVIEW_APP_PREFIX
to instead instruct leaving REVIEW_APP_PREFIX unset (or to document the inferred
name qa-react-webpack-rails-tutorial) and reference
.controlplane/controlplane.yml for app name alignment; ensure the text mentions
the generated review app pattern qa-react-webpack-rails-tutorial-<PR number> and
remove the conflicting example
REVIEW_APP_PREFIX=qa-react-webpack-rails-tutorial-pr so both docs are
consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 339f15eb-4b09-48f3-897d-86bcf9c18dec

📥 Commits

Reviewing files that changed from the base of the PR and between 1fb4cdd and d5e1fd6.

📒 Files selected for processing (9)
  • .controlplane/readme.md
  • .github/cpflow-help.md
  • .github/workflows/cpflow-cleanup-stale-review-apps.yml
  • .github/workflows/cpflow-delete-review-app.yml
  • .github/workflows/cpflow-deploy-review-app.yml
  • .github/workflows/cpflow-deploy-staging.yml
  • .github/workflows/cpflow-help-command.yml
  • .github/workflows/cpflow-promote-staging-to-production.yml
  • .github/workflows/cpflow-review-app-help.yml

Comment thread .controlplane/readme.md
@claude
Copy link
Copy Markdown

claude Bot commented May 24, 2026

Code Review: Document cpflow downstream setup

Overview

This PR improves the setup experience for downstream cpflow users by consolidating documentation and fixing the production token exposure model. The security change—moving CPLN_TOKEN_PRODUCTION from a repo secret to a protected GitHub Environment—is a meaningful improvement. The workflow pin bump is mechanical and applied consistently across all six files.


Security

Positive: Gating CPLN_TOKEN_PRODUCTION behind a protected GitHub Environment with required reviewers is the right approach. Before this PR, anyone who could trigger cpflow-promote-staging-to-production.yml could potentially exercise the production token. The environment gate closes that gap.

Concern — secrets: inherit on the promote workflow: The added comment correctly acknowledges that secrets: inherit passes all caller repository secrets (including CPLN_TOKEN_STAGING) to the upstream reusable workflow, not only explicitly named ones. GitHub has no enforcement boundary here. The mitigation offered is pinning both refs to an immutable SHA, which is already done. However, the comment could clarify that the environment-level CPLN_TOKEN_PRODUCTION secret is not passed via secrets: inherit—environment secrets are only injected when a job directly references that environment—so the production token isolation is actually stronger than the comment implies.


Breaking Change: Review App Naming Convention

The PR changes the review app naming scheme from qa-react-webpack-rails-tutorial-pr-<N> to qa-react-webpack-rails-tutorial-<N>. Any currently running review apps using the old -pr- convention will become orphaned—the cleanup workflows won't find them because they query by the new prefix. Teams should manually delete old-convention review apps before or shortly after merging. This should be called out explicitly in the PR description or a migration note.


Documentation Quality

The new ## GitHub Review App Setup section in readme.md is well-structured. The tables cleanly separate required vs. optional settings. One fragility worth noting: the docs state that the staging org and review app prefix are inferred when controlplane.yml defines "exactly one app with match_if_app_name_starts_with: true." If a second such app is ever added, inference silently breaks with no obvious error. A one-line note pointing readers to override CPLN_ORG_STAGING and REVIEW_APP_PREFIX in that scenario would make this more robust.

The advanced section in cpflow-help.md on pinning vs. CPFLOW_VERSION is genuinely useful and clearly written.


Workflow Changes

  • cpflow-review-app-help.yml: Removing if: vars.REVIEW_APP_PREFIX != '' is correct given that the prefix is now inferred rather than required. No issue.
  • cpflow-help-command.yml and cpflow-review-app-help.yml: These lack a with: control_plane_flow_ref: block. For help-display-only workflows this appears intentional (they don't invoke cpflow), but worth confirming with the upstream workflow definition that omitting control_plane_flow_ref is valid and has a safe default.
  • Consistent SHA bump: 3e0e7e1…db013e1… applied uniformly across all six workflow files. Good.

Summary

Area Assessment
Security (production token) Improvement
Breaking naming change Needs migration note
secrets: inherit scope Documented; clarification suggested
Inference fragility Minor; worth a note
Documentation clarity Good
Workflow consistency Good

Overall this is a solid improvement. Address the naming-convention migration note and clarify the secrets: inherit / environment-secret boundary before merging.

# references, but GitHub does not enforce that boundary. Strict consumers can
# keep both the `uses:` ref and `control_plane_flow_ref` pinned to an
# immutable commit SHA.
secrets: inherit
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The comment says the upstream workflow "only reads the named secrets it references," which is accurate for repository secrets. Worth clarifying here that environment secrets (e.g. CPLN_TOKEN_PRODUCTION) are not passed via secrets: inherit—they're only injected when the job itself directly references the production environment. So the production token isolation is actually stronger than this comment implies; a reader might incorrectly assume CPLN_TOKEN_PRODUCTION leaks through secrets: inherit.

Comment thread .controlplane/readme.md Outdated
`qa-react-webpack-rails-tutorial` and staging org
`shakacode-open-source-examples-staging` from `.controlplane/controlplane.yml`
because that file defines exactly one app with
`match_if_app_name_starts_with: true`.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This inference assumption is fragile: if controlplane.yml ever gains a second app entry with match_if_app_name_starts_with: true, the inference will fail (or pick the wrong one) with no clear error. Consider adding a sentence here directing readers to set CPLN_ORG_STAGING and REVIEW_APP_PREFIX explicitly if they hit ambiguous inference, so the failure mode is less opaque.

- Leave `REVIEW_APP_PREFIX` unset for the standard path. The workflow infers
`qa-react-webpack-rails-tutorial` from `.controlplane/controlplane.yml`, so
generated review apps use names like
`qa-react-webpack-rails-tutorial-1234`.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Breaking change — naming convention. The old scheme was qa-react-webpack-rails-tutorial-pr-<N>; the new scheme omits the -pr segment. Any live review apps created under the old convention become orphaned after this merges: the cleanup and delete workflows query by the new prefix and won't find them. Recommend adding a migration note (e.g. in the PR description or a one-time manual cleanup step) so operators know to delete old-style apps before merging.

@claude
Copy link
Copy Markdown

claude Bot commented May 24, 2026

Code Review: Document cpflow downstream setup

Overall assessment: Low-risk, well-structured documentation PR. The shift of `CPLN_TOKEN_PRODUCTION` from a repository secret to a protected GitHub Environment is a genuine security improvement. SHA pinning and the two-pin comment in the promotion workflow are both good practices.


✅ Strengths

  • Security uplift: Moving `CPLN_TOKEN_PRODUCTION` to a protected GitHub Environment (with required reviewers + prevent self-review) meaningfully narrows who can trigger production deploys vs. the old repo-secret approach.
  • SHA pinning: All reusable workflow `uses:` refs and `control_plane_flow_ref` inputs are pinned to the same immutable commit SHA — good supply-chain hygiene.
  • Two-pin invariant comment in the promotion workflow is clear and will prevent future drift.
  • `contents: write` explanation clarifies what would otherwise look like an overly broad permission grant.
  • Advanced testing section in `cpflow-help.md` is valuable operational documentation, especially the warning about never pinning to a moving branch.

Issues

1. Contradictory `Required` column for production variables in `cpflow-help.md`

The table rows for `CPLN_ORG_PRODUCTION` and `PRODUCTION_APP_NAME` say `yes (for promote)` in the Required column — implying repository variables — but the Notes column says "Prefer a `production` environment variable." The recommendation and the column label contradict each other. Readers who follow the `yes` column will put these in repo variables; readers who follow the note will put them in the environment. The table should be updated to say something like `yes (for promote) — as environment variable` or the Required column should use a different marker for environment variables. (See inline comment.)

2. `STAGING_APP_BRANCH` / `PRIMARY_WORKLOAD` required vs. optional discrepancy

`shakacode-team.md` lists both under "Required repository variables for staging deploys", while `cpflow-help.md` marks both as optional. At minimum `PRIMARY_WORKLOAD` defaults to `rails`, so listing it as required in one doc and optional in the other will confuse fork maintainers.

3. `SECRET_KEY_BASE` test placeholder

The readme documents that the review/staging template "currently contains a test placeholder for `SECRET_KEY_BASE`" and asks readers to replace it before production. This is a hard security requirement, not just guidance — a placeholder key in staging means any staging environment is running with a known, weak secret. Consider either removing the placeholder in a follow-up PR and replacing it with a proper secret reference, or at minimum adding a CI check that fails if the placeholder value is detected.

4. Minor `secrets: inherit` comment improvement

The acknowledgment in the promotion workflow is transparent and appreciated. One thing worth making explicit: because `CPLN_TOKEN_PRODUCTION` is now an environment secret (not a repo secret), `secrets: inherit` in the staging and review-app workflows won't inadvertently expose it — the environment gate is the actual isolation boundary, not just the upstream workflow's access pattern. Adding that note would help future readers understand why the security model holds.

Comment thread .github/cpflow-help.md Outdated
| `CPLN_ORG_STAGING` | yes | Control Plane org on controlplane.com for staging and review apps. |
| `CPLN_ORG_PRODUCTION` | yes (for promote) | Control Plane org on controlplane.com for production. |
| `CPLN_ORG_STAGING` | optional for review apps; yes for staging | Override the staging/review Control Plane org inferred from `controlplane.yml`. |
| `CPLN_ORG_PRODUCTION` | yes (for promote) | Control Plane org on controlplane.com for production. Prefer a `production` environment variable. |
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The Required column says yes (for promote) — which implies a repository variable — but the Notes column says "Prefer a production environment variable." These two signals contradict each other. Readers who scan the Required column will put this in repo variables; readers who follow the note will put it in the protected environment. Suggest picking one canonical placement and stating it clearly, e.g. updating the Required cell to yes — environment variable or splitting the secrets and environment-variable rows into separate tables.

Comment thread .github/cpflow-help.md Outdated
| `PRODUCTION_APP_NAME` | yes (for promote) | App name in `controlplane.yml` used as the production deploy target. |
| `REVIEW_APP_PREFIX` | yes | Prefix for per-PR review app names (e.g. `review-app`). |
| `REVIEW_APP_DEPLOYING_ICON_URL` | optional | Custom image URL for the animated deploying icon in review-app PR comments. Set to `none` to use the text fallback icon. |
| `PRODUCTION_APP_NAME` | yes (for promote) | App name in `controlplane.yml` used as the production deploy target. Prefer a `production` environment variable. |
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Same issue as CPLN_ORG_PRODUCTION above: yes (for promote) implies a repo variable, but the Notes column recommends a production environment variable. Both entries need a consistent placement signal.

Comment on lines +28 to +32
# `secrets: inherit` passes all caller repository secrets to the trusted
# upstream workflow. The upstream workflow only reads the named secrets it
# references, but GitHub does not enforce that boundary. Strict consumers can
# keep both the `uses:` ref and `control_plane_flow_ref` pinned to an
# immutable commit SHA.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The transparency here is good. One clarification worth adding to the comment: because CPLN_TOKEN_PRODUCTION is now an environment secret (not a repo secret), secrets: inherit in the staging/review-app caller workflows won't expose it — those jobs never acquire the production environment context, so GitHub never injects the environment secret into them. The environment gate is the actual isolation boundary, not just the upstream workflow's declared access pattern. This makes the security model more robust than the comment currently implies.

Comment thread .controlplane/readme.md Outdated

Generate `SECRET_KEY_BASE` with `openssl rand -hex 64` and
`RENDERER_PASSWORD` with `openssl rand -hex 32`. The review/staging template
currently contains a test placeholder for `SECRET_KEY_BASE`; replace it with a
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Documenting the placeholder is good, but this phrasing ("replace it with a secret-backed value before promoting production") leaves staging running with a known, weak SECRET_KEY_BASE. If the staging environment is internet-accessible (which review apps typically are), that's a real risk — anyone with the placeholder value can forge session cookies. Consider either removing the placeholder from the template in a follow-up and requiring an explicit secret reference, or adding a CI/readiness check that rejects deploys when SECRET_KEY_BASE matches the placeholder value.

@claude
Copy link
Copy Markdown

claude Bot commented May 24, 2026

Code Review

Overview: Documentation-heavy PR that improves the cpflow downstream setup story — moves the production token into a protected GitHub Environment, infers review-app config from controlplane.yml instead of requiring explicit variables, and repins all reusable workflows to a newer upstream commit SHA. The security posture improvements are real and the documentation is thorough.


Issues

1. control_plane_flow_ref missing from both help workflows

cpflow-help-command.yml and cpflow-review-app-help.yml both omit the with: control_plane_flow_ref: block that every other cpflow workflow passes. If those upstream reusable workflows have a setup action that checks out the gem source using that input, they'll silently fall back to whatever default the upstream YAML defines rather than the pinned SHA. All operational workflows (cleanup, delete, deploy, staging, promote) pass it consistently — the two help workflows should too, or there should be a comment explaining why they don't need it.

2. REVIEW_APP_PREFIX guard removal posts help on every PR open, including forks

Removing if: vars.REVIEW_APP_PREFIX != '' from cpflow-review-app-help.yml means the help comment now posts on every PR open event via pull_request_target. For repos or forks where review apps are not set up, contributors will see a help comment offering commands that won't work. Consider replacing the guard with a check the workflow can evaluate without requiring the variable to be pre-set (e.g., checking that the Control Plane token secret is configured, or accepting that noise on forks is an acceptable trade-off and documenting it).

3. Naming change from -pr-<N> to -<N> is a silent breaking change

The PR removes the -pr suffix from generated review app names (qa-react-webpack-rails-tutorial-pr-1234qa-react-webpack-rails-tutorial-1234) but provides no migration guidance. Any currently-running review apps under the old names, bookmarked URLs, or CI links pointing to old names will silently break. Even a one-paragraph note in the docs ("existing review apps under the old -pr naming must be deleted and redeployed") would prevent confusion.

4. secrets: inherit on the production promotion job

The inline comment acknowledges the issue but leaves it as-is. secrets: inherit sends all repository secrets — including CPLN_TOKEN_STAGING, any SSH keys, etc. — to the upstream workflow. The SHA pinning limits supply-chain risk, but a compromised or malicious upstream commit would have access to all of them, not just the production token. If the upstream workflow supports explicit secret passing, prefer it; if not, the current SHA-pinned approach is reasonable, but that trade-off is worth a word in the docs so future maintainers don't loosen the pin without realizing the exposure.


Minor

  • The contents: write permission on the promotion workflow is correctly explained in the new comment, but it applies at the job level to all callee jobs. If the upstream workflow uses separate jobs with narrower permissions, calling them from a workflow-level contents: write grants that permission to all of them. Worth verifying with the upstream workflow's job-level permissions: blocks.
  • .controlplane/readme.md duplicates some of the same table structure from .github/cpflow-help.md. Not a bug, but consider whether one can reference the other to reduce future drift.

Positives

  • Moving CPLN_TOKEN_PRODUCTION into a protected GitHub Environment with required reviewers is the right call and is a genuine security improvement over storing it as a repository secret.
  • SHA pinning for all uses: refs and control_plane_flow_ref inputs is correct practice for supply-chain safety.
  • The "Advanced: testing unreleased control-plane-flow changes" section is clear and practical — especially the guidance on not leaving downstream apps pinned to a moving branch.
  • Inline workflow comments explaining the pull_request_target rationale and secrets: inherit trade-offs are good practice.

contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) ||
github.event_name == 'workflow_dispatch'
uses: shakacode/control-plane-flow/.github/workflows/cpflow-help-command.yml@3e0e7e1f0a35c15648cc9254b573b058d77ca8c4
uses: shakacode/control-plane-flow/.github/workflows/cpflow-help-command.yml@cfe494bf32925d49508380e03856d97bd71f6689
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All the operational cpflow workflows (cleanup, delete, deploy, staging, promote) pass control_plane_flow_ref as a with: input alongside the uses: SHA. This one does not. If the upstream help workflow has a setup action that uses control_plane_flow_ref to check out and build the gem, it will silently fall back to its own default rather than the pinned SHA.

Unless the upstream cpflow-help-command.yml workflow is known to not have a gem-build step, add:

Suggested change
uses: shakacode/control-plane-flow/.github/workflows/cpflow-help-command.yml@cfe494bf32925d49508380e03856d97bd71f6689
uses: shakacode/control-plane-flow/.github/workflows/cpflow-help-command.yml@cfe494bf32925d49508380e03856d97bd71f6689
with:
control_plane_flow_ref: cfe494bf32925d49508380e03856d97bd71f6689

Or add a comment explaining why this workflow doesn't need it.

show-help:
if: vars.REVIEW_APP_PREFIX != ''
uses: shakacode/control-plane-flow/.github/workflows/cpflow-review-app-help.yml@3e0e7e1f0a35c15648cc9254b573b058d77ca8c4
uses: shakacode/control-plane-flow/.github/workflows/cpflow-review-app-help.yml@cfe494bf32925d49508380e03856d97bd71f6689
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Same as cpflow-help-command.yml — no with: block means control_plane_flow_ref is not passed, unlike all the operational workflows. If the upstream help workflow doesn't need it, a short comment here would prevent future maintainers from treating this as an oversight during the next SHA repin.

# references, but GitHub does not enforce that boundary. Strict consumers can
# keep both the `uses:` ref and `control_plane_flow_ref` pinned to an
# immutable commit SHA.
secrets: inherit
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

secrets: inherit sends all caller repository secrets — including CPLN_TOKEN_STAGING, SSH keys, and any other repository secrets — to the upstream reusable workflow. The SHA pin limits exposure to a known-good commit, but it is still a broader grant than strictly necessary for a production promotion job.

If the upstream cpflow-promote-staging-to-production.yml workflow supports receiving named secrets explicitly (e.g., secrets: { CPLN_TOKEN_PRODUCTION: ${{ secrets.CPLN_TOKEN_PRODUCTION }} }), that would be strictly tighter. If it requires secrets: inherit, the current approach is the practical maximum — just worth documenting explicitly so the next maintainer doesn't widen the SHA pin without realizing the implication.

Comment thread .controlplane/readme.md
`qa-react-webpack-rails-tutorial-pr-1234`.
The GitHub settings and Control Plane resources must match the app names in
`.controlplane/controlplane.yml`. For the standard review-app path, leave
`REVIEW_APP_PREFIX` unset and let the workflow infer
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This silently changes the naming convention from the previously documented qa-react-webpack-rails-tutorial-pr-<N> (with the -pr suffix) to qa-react-webpack-rails-tutorial-<N>. Any review apps currently running under the old names, bookmark links, or CI output referencing them will break without warning.

Consider adding a migration note here, even one sentence: "If you previously had REVIEW_APP_PREFIX set to qa-react-webpack-rails-tutorial-pr, delete existing review apps before switching — the old names will become orphaned resources in Control Plane."

@claude
Copy link
Copy Markdown

claude Bot commented May 25, 2026

Code Review: Document cpflow downstream setup

Overview

This PR improves the security posture of the cpflow GitHub Actions integration in three meaningful ways: (1) replaces broad secrets: inherit with named secrets on every workflow caller, (2) isolates CPLN_TOKEN_PRODUCTION in a protected GitHub Environment gated by required reviewers, and (3) updates pinned upstream workflow refs from 3e0e7e1f… to 7d9b80dc…. It also drops the legacy -pr- infix from review app names and adds comprehensive GitHub + Control Plane setup documentation.


Security — Positive Changes

  • Named secrets instead of secrets: inherit: each workflow now passes only the secrets the upstream reusable workflow actually needs. bin/test-cpflow-github-flow is updated to enforce this programmatically, so regressions will be caught automatically.
  • Production token in a protected Environment: CPLN_TOKEN_PRODUCTION is no longer a repository secret visible to all workflows; it lives only in the production GitHub Environment and requires reviewer approval before GitHub exposes it. This is the right approach.
  • Consistent ref pinning: all five cpflow-* wrappers now share a single upstream commit SHA, and the test script enforces cross-file consistency.

Issues

1. Implicit CPLN_TOKEN_PRODUCTION forwarding mechanism

In cpflow-promote-staging-to-production.yml, the production token is not in the secrets: block — it reaches the upstream reusable workflow only because production_environment: production is passed as a with: input, and the upstream workflow presumably applies environment: production to its production job, which causes GitHub to inject the environment secret there. This pattern is correct when the upstream workflow supports it, but it is entirely implicit. If the upstream workflow changes the input name or stops hoisting the environment, CPLN_TOKEN_PRODUCTION silently becomes unavailable and the promotion job fails at runtime, not at lint/validation time. Consider adding a comment that explains this forwarding chain (caller passes environment name → upstream job runs under that environment → GitHub injects the secret), and verify that cpflow github-flow-readiness catches misconfiguration of this path.

2. Breaking naming convention — no automated migration

The switch from qa-react-webpack-rails-tutorial-pr-1234 to qa-react-webpack-rails-tutorial-1234 changes the prefix the cleanup workflow uses. Existing review apps under the old prefix will never be cleaned up by cpflow-cleanup-stale-review-apps because the cleanup job now targets the new prefix. The docs say "delete them manually", but there is no inventory command shown. Worth adding a one-liner such as:

cpflow list-apps --org shakacode-open-source-examples-staging | grep 'qa-react-webpack-rails-tutorial-pr-'

to help operators find orphaned apps.

3. cpflow-review-app-help.yml guard removed

The old if: vars.REVIEW_APP_PREFIX != '' condition prevented the help-comment job from running when the prefix variable was absent (e.g., on forks). That guard is removed because the prefix is now inferred from controlplane.yml. This is logically sound for this repo, but it means the workflow fires on every PR open unconditionally. Worth confirming the upstream reusable workflow at 7d9b80dc… handles a missing or inferred prefix gracefully and does not post a confusing PR comment when inference yields nothing.

4. Minor: missing blank line in .controlplane/readme.md lines 76–77

Two conceptually separate paragraphs run together:

…so the production token is not exposed to ordinary
review-app or staging runs.
Generated caller workflows pass only the named secrets…

Add a blank line between them.


Nits

  • The "Generated caller workflows pass only…" paragraph appears verbatim in readme.md, shakacode-team.md, and cpflow-help.md. Centralising it (or linking) would prevent future drift.
  • Pre-existing commmand typo (triple-m) in .controlplane/controlplane.yml above the qa-react-webpack-rails-tutorial entry is easy to fix while touching this area.

Summary

The security improvements are correct and the documentation is thorough. The two functional items worth addressing before merge are: (a) documenting or testing the implicit production-secret forwarding chain via production_environment, and (b) providing tooling or a concrete command for operators to clean up orphaned old-prefix review apps. Everything else is polish.

Comment thread .controlplane/shakacode-team.md Outdated
Comment on lines +69 to +72
Current workflow wrappers are pinned to upstream `control-plane-flow` PR #318 at
`19ca93eadcba81e7438f26ab55a0f2ca7ace82b0` for downstream testing. After 5.0.1
ships, repin the wrappers to `v5.0.1`; do not treat the temporary SHA as the
steady-state master configuration.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This SHA is a temporary test pin and must be replaced with v5.0.1 once the upstream release ships. Please track this as a follow-up issue before merging — without an issue, the repin is easy to forget and the repo will stay on an unversioned pre-release commit indefinitely.

Comment on lines +17 to +19
# This is intentionally unconditional: adding this wrapper opts the repo in
# to PR-open help. Remove the wrapper or add a repo-specific `if:` guard if
# review apps should not be advertised before Control Plane is configured.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Removing the if: vars.REVIEW_APP_PREFIX != '' guard is fine for this repo since Control Plane is expected to be configured. The comment is accurate and clear.

Just note that any fork that clones this repo and hasn't yet set up CP will immediately start posting help banners on every PR open. The comment's suggestion to remove the wrapper or add an if: guard should probably be repeated in the setup docs for fork users.

@claude
Copy link
Copy Markdown

claude Bot commented May 25, 2026

Code Review — PR #747: Document cpflow downstream setup

Overview

This PR does three things together:

  1. Pins all generated workflow wrappers from 3e0e7e1fc0ca750c and drops the now-redundant control_plane_flow_ref input
  2. Hardens secret handling — replaces secrets: inherit with explicit named secrets and moves CPLN_TOKEN_PRODUCTION to a protected GitHub Environment
  3. Updates docs to trim repeated upstream content and document the naming-convention change (-pr- infix dropped from review-app names)

Overall direction is correct and the security posture improves meaningfully. A few specific notes below.


Security: Explicit Secrets ✅

Dropping secrets: inherit in favour of passing only CPLN_TOKEN_STAGING (and optionally DOCKER_BUILD_SSH_KEY) is a good tightening. The production token is now gated behind a protected GitHub Environment with required-reviewer approval, which is the right model.

One nuance: DOCKER_BUILD_SSH_KEY is passed unconditionally in both cpflow-deploy-review-app.yml and cpflow-deploy-staging.yml:

DOCKER_BUILD_SSH_KEY: ${{ secrets.DOCKER_BUILD_SSH_KEY }}

GitHub resolves a non-existent secret to an empty string rather than erroring, so repos without SSH build dependencies should be fine — but the upstream reusable workflow needs to handle an empty value gracefully (e.g. skip the --mount=type=ssh flag). Worth confirming that the upstream workflow does this correctly before merging.


bin/test-cpflow-github-flow: dropping bin/conductor-exec ⚠️

The script removes bin/conductor-exec from every internal invocation:

-bin/conductor-exec "${cpflow_cmd[@]}" github-flow-readiness
+"${cpflow_cmd[@]}" github-flow-readiness

-bin/conductor-exec ruby <<'RUBY'
+ruby <<'RUBY'

Per CLAUDE.md and the existing conductor-compatibility documentation in this repo, Conductor runs commands in a non-interactive shell that does not source .zshrc, so version-manager hooks (mise, asdf, rbenv) never fire. When the script is invoked via bin/conductor-exec bin/test-cpflow-github-flow (the documented call in the updated docs), conductor-exec sets up the outer process but the inner ruby and cpflow calls spawn new sub-processes without re-invoking the version manager. Concretely, ruby <<'RUBY' will hit whatever ruby is on PATH at that point — likely system Ruby — instead of the project Ruby.

The fix depends on what you want:

  • If the script is always called as bin/conductor-exec bin/test-cpflow-github-flow, then conductor-exec needs to propagate the correct PATH to child processes (check whether mise exec does this for the whole process tree).
  • Alternatively, keep bin/conductor-exec on each sub-invocation inside the script so the version context is guaranteed.

Temporary commit-SHA pin ⚠️

Multiple doc files explicitly note that c0ca750c4838dacf6a1d81d52cb151301516cb77 is a temporary test pin:

After 5.0.1 ships, repin the wrappers to v5.0.1; do not treat the temporary SHA as the steady-state master configuration.

If v5.0.1 is not yet published, this is fine to merge as a stepping stone — but it should be treated as a follow-up blocker, not an indefinite TODO. Consider opening a tracking issue or adding a # TODO: repin to v5.0.1 comment directly on the uses: lines so it's harder to forget.


Minor: non-deterministic Dir[] in bin/pin-cpflow-github-ref

-workflow_paths = Dir[root.join(".github/workflows/cpflow-*.yml")].sort
+workflow_paths = Dir[root.join(".github/workflows/cpflow-*.yml")]

.sort was removed. Dir[] returns files in filesystem order (which varies by OS and filesystem). The script's correctness doesn't depend on order, but the changed list printed at the end will be non-deterministically ordered, which can make diffs harder to read in CI output. Low priority, but restoring .sort costs nothing.


Docs trimming ✅

The refactored docs correctly distinguish between:

  • What lives upstream in the control-plane-flow CI guide
  • What is specific to this repo

The review-app naming change (-pr- removal) is well-documented, the migration command for finding old apps is included, and the manual-cleanup note is clear. No concerns here.


Summary

Finding Severity
bin/test-cpflow-github-flow drops conductor-exec — may hit wrong Ruby/cpflow in Conductor Medium
Temporary SHA c0ca750c needs tracking before it becomes permanent Medium
DOCKER_BUILD_SSH_KEY always forwarded — upstream workflow must tolerate empty value Low
Dir[] without .sort — non-deterministic output order Cosmetic

@@ -10,10 +10,10 @@ if [[ $# -gt 0 ]]; then
fi

echo "==> cpflow github-flow-readiness"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The outer bin/conductor-exec bin/test-cpflow-github-flow call sets up the environment for the outer process, but each ruby <<'RUBY' here spawns a new subprocess. Whether the correct Ruby is inherited depends on whether mise exec (or your version manager) rewrites PATH for the whole process tree or only for the immediate command.

If mise exec does propagate the correct PATH transitively, this is fine. If it doesn't, these inline ruby heredocs and the "${cpflow_cmd[@]}" call will hit system Ruby/cpflow. Worth a quick sanity-check: bin/conductor-exec bin/test-cpflow-github-flow → does ruby --version inside match .tool-versions?

Suggested change
echo "==> cpflow github-flow-readiness"
"${cpflow_cmd[@]}" github-flow-readiness

uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-review-app.yml@c0ca750c4838dacf6a1d81d52cb151301516cb77
secrets:
CPLN_TOKEN_STAGING: ${{ secrets.CPLN_TOKEN_STAGING }}
DOCKER_BUILD_SSH_KEY: ${{ secrets.DOCKER_BUILD_SSH_KEY }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

If DOCKER_BUILD_SSH_KEY is not configured as a repo secret, GitHub resolves it to an empty string and passes that through. Confirm the upstream cpflow-deploy-review-app.yml reusable workflow treats an empty value as "no SSH key" (i.e. skips --mount=type=ssh) rather than failing the build.

Comment thread .controlplane/shakacode-team.md Outdated
[`control-plane-flow` CI automation guide](https://github.com/shakacode/control-plane-flow/blob/main/docs/ci-automation.md).

Current workflow wrappers are pinned to merged upstream `control-plane-flow`
commit `c0ca750c4838dacf6a1d81d52cb151301516cb77` for downstream testing. After
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This SHA is a temporary test pin acknowledged as needing a follow-up repinning. Consider opening a tracking issue or adding a # TODO: repin to v5.0.1 comment directly on each uses: line in the workflow wrappers so the follow-up is harder to miss after v5.0.1 ships.

Comment thread bin/pin-cpflow-github-ref

root = Pathname.new(__dir__).join("..").expand_path
workflow_paths = Dir[root.join(".github/workflows/cpflow-*.yml")].sort
workflow_paths = Dir[root.join(".github/workflows/cpflow-*.yml")]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Removing .sort makes the changed list printed at the end non-deterministic across filesystems. No correctness impact, but CI output becomes harder to compare across runs.

Suggested change
workflow_paths = Dir[root.join(".github/workflows/cpflow-*.yml")]
workflow_paths = Dir[root.join(".github/workflows/cpflow-*.yml")].sort

@justin808
Copy link
Copy Markdown
Member Author

+review-app-deploy

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 25, 2026

🎉 Deploy Complete!

Open Review App

Deployment successful for PR #747, commit 9e5a0dd

🎮 Control Plane Console
📋 View Completed Action Build and Deploy Logs

@github-actions github-actions Bot temporarily deployed to review/qa-react-webpack-rails-tutorial-747 May 25, 2026 06:08 Inactive
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 25, 2026

🎉 Deploy Complete!

Open Review App

Deployment successful for PR #747, commit c659043

🎮 Control Plane Console
📋 View Completed Action Build and Deploy Logs

@github-actions github-actions Bot temporarily deployed to review/qa-react-webpack-rails-tutorial-747 May 25, 2026 07:18 Inactive
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c659043f00

ℹ️ 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".

Comment thread .github/cpflow-help.md
## Staging And Production

### GitHub Actions variables
Staging deploys use the same `CPLN_TOKEN_STAGING` secret plus `STAGING_APP_NAME`.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Document required staging org variable

Update this setup note to include CPLN_ORG_STAGING as required for staging deploys. The pinned upstream reusable workflow validates both CPLN_ORG_STAGING and STAGING_APP_NAME before running, so users who follow this text literally will configure only STAGING_APP_NAME and hit a hard validation failure in cpflow-deploy-staging.

Useful? React with 👍 / 👎.

@claude
Copy link
Copy Markdown

claude Bot commented May 25, 2026

Code Review - Overview: consolidates cpflow docs, replaces secrets:inherit with explicit secrets, gates CPLN_TOKEN_PRODUCTION behind protected GitHub Environment. Repinned from 3e0e7e1 to 54a6b8a.

@claude
Copy link
Copy Markdown

claude Bot commented May 25, 2026

Code Review - Full Report

Overview

This PR consolidates downstream cpflow setup documentation into .controlplane/readme.md and .controlplane/shakacode-team.md (deferring generic behavior to upstream), replaces secrets: inherit with explicit named secrets across all workflow wrappers, and gates the production token behind a protected GitHub Environment. All wrappers are repinned from 3e0e7e1 to 54a6b8a.


Security - Strong improvements

  • Replacing secrets: inherit with explicit named secrets limits blast radius: if an upstream workflow is ever compromised or accidentally logs its environment, only the explicitly listed secrets are exposed.
  • Moving CPLN_TOKEN_PRODUCTION from a repository secret to a protected GitHub Environment (with required reviewer approval) is a proper security boundary.
  • The test-cpflow-github-flow validation script now enforces both constraints in CI, which is excellent.

Issues

  1. Temporary SHA pin lacks a tracking mechanism. The docs acknowledge 54a6b8a is temporary (pending v5.0.1), but there is no linked issue tracking it. Temporary SHA pins have a history of lingering in master long after the upstream release ships. A follow-up issue would help.

  2. SHA-pinned documentation link (see inline comment on .github/cpflow-help.md)

  3. staging_app_branch_default behavior change. cpflow-deploy-staging.yml changes staging_app_branch_default from "" to "master". The empty string presumably caused the upstream to use its own default; worth confirming the upstream default was already master so this is not a silent behavior change.

  4. Non-deterministic output in bin/pin-cpflow-github-ref (see inline comment)


Minor / Positive

  • Narrowing the staging branch filter from ["main", "master"] to ["master"] is correct for this repo.
  • Removing inner bin/conductor-exec wrappers from test-cpflow-github-flow is correct since the script is invoked as bin/conductor-exec bin/test-cpflow-github-flow, which sets up the environment for the entire child shell.
  • The unconditional cpflow-review-app-help.yml is intentional and well-documented with a commented-out guard for forks.
  • Documentation is meaningfully shorter and better organized after deferring generic behavior upstream.

Comment thread .github/cpflow-help.md Outdated
You asked for review app help. These commands are generated by [cpflow](https://github.com/shakacode/control-plane-flow).
These commands are generated by [cpflow](https://github.com/shakacode/control-plane-flow).
For full setup, version-pinning, and troubleshooting details, see the upstream
[CI automation guide](https://github.com/shakacode/control-plane-flow/blob/54a6b8a066ac0a59c49e95a866e21b5633e2b1f9/docs/ci-automation.md).
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This documentation link is pinned to the same 54a6b8a commit SHA used in the workflow uses: refs. Unlike workflow pins, documentation links don't benefit from immutability — they just become stale. When the wrappers are eventually repinned to v5.0.1, this link will silently point to old docs. Consider linking to main instead:

Suggested change
[CI automation guide](https://github.com/shakacode/control-plane-flow/blob/54a6b8a066ac0a59c49e95a866e21b5633e2b1f9/docs/ci-automation.md).
[CI automation guide](https://github.com/shakacode/control-plane-flow/blob/main/docs/ci-automation.md).

Comment thread bin/pin-cpflow-github-ref

root = Pathname.new(__dir__).join("..").expand_path
workflow_paths = Dir[root.join(".github/workflows/cpflow-*.yml")].sort
workflow_paths = Dir[root.join(".github/workflows/cpflow-*.yml")]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The .sort was removed here, making the order in which files are processed — and the updated <path> lines printed to stdout — non-deterministic (filesystem order varies by OS and filesystem). The functional result is the same, but the output is less predictable, which can confuse diffs in CI logs. Consider restoring the sort:

Suggested change
workflow_paths = Dir[root.join(".github/workflows/cpflow-*.yml")]
workflow_paths = Dir[root.join(".github/workflows/cpflow-*.yml")].sort

if: github.event.inputs.confirm_promotion == 'promote'
uses: shakacode/control-plane-flow/.github/workflows/cpflow-promote-staging-to-production.yml@3e0e7e1f0a35c15648cc9254b573b058d77ca8c4
uses: shakacode/control-plane-flow/.github/workflows/cpflow-promote-staging-to-production.yml@54a6b8a066ac0a59c49e95a866e21b5633e2b1f9
with:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Good pattern. One thing to confirm: the upstream reusable workflow's production job reads CPLN_ORG_PRODUCTION and PRODUCTION_APP_NAME from Environment variables (not secrets), so GitHub will auto-inject those from the production Environment after the approval gate. This only works if those values are set as Environment variables on the production Environment (not as repository variables). The docs spell this out, but it's easy to misconfigure as repo-level variables and get a silent failure at promotion time.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 25, 2026

🎉 Deploy Complete!

Open Review App

Deployment successful for PR #747, commit 3319280

🎮 Control Plane Console
📋 View Completed Action Build and Deploy Logs

@claude
Copy link
Copy Markdown

claude Bot commented May 25, 2026

Code Review

Overview

This PR makes three coordinated changes: (1) repins all generated cpflow workflow wrappers from a temporary commit SHA to the v5.0.1 release tag, (2) hardens secret passing by replacing secrets: inherit with named secrets and moving the production token into a protected GitHub Environment, and (3) simplifies downstream docs by delegating generic mechanics to the upstream control-plane-flow CI guide.

The security direction is clearly correct. A few things worth noting:


Security: Production Token Gating ✅

Moving CPLN_TOKEN_PRODUCTION from a repo-level secret (accessible to any workflow) to a protected production GitHub Environment (accessible only after required reviewer approval) is a meaningful improvement. The cpflow-promote-staging-to-production.yml caller correctly passes only CPLN_TOKEN_STAGING and relies on production_environment: production to expose the production token through the environment gate. The validation in bin/test-cpflow-github-flow also actively rejects any wrapper that accidentally passes CPLN_TOKEN_PRODUCTION as a caller secret — good defense in depth.


Security: secrets: inherit → Named Secrets ✅

Switching from secrets: inherit to explicitly named secrets reduces the blast radius if a reusable workflow is ever compromised. The right secrets are scoped to the right workflows (staging token for deploy/cleanup, SSH key only for image-building workflows).


bin/pin-cpflow-github-ref: .sort removed from Dir[]

The .sort call was dropped from the workflow glob (line 50), so changed-file logging output is now non-deterministic across runs. The actual ref replacement is idempotent so there's no functional bug, but deterministic ordering made the "Changed:" output easier to review in CI logs. Worth restoring for auditability.


cpflow-deploy-staging.yml: staging_app_branch_default value change

staging_app_branch_default changed from "" (empty string) to "master". An empty string likely caused the upstream reusable workflow to fall back to its own default, whereas "master" now explicitly overrides it. For this repo the values presumably agree, but it's a subtle semantic shift — if the upstream default ever changes, the downstream behavior no longer tracks it automatically. This is probably the desired behavior (repo stays pinned to master regardless), just worth being aware of.


cpflow-review-app-help.yml: Unconditional show-help

The old if: vars.REVIEW_APP_PREFIX != '' guard was removed, making the job unconditional. The inline comment explains this clearly and provides a template guard for forks. The approach is intentional for a demo repo — just worth ensuring the upstream cpflow-review-app-help.yml@v5.0.1 workflow handles the case where no Control Plane variables are configured (e.g., a fresh fork), so it fails gracefully rather than posting a confusing comment with empty values.


bin/test-cpflow-github-flow: bin/conductor-exec removal from inner calls

Inner ruby invocations no longer prefix bin/conductor-exec. This is correct: when the script is invoked as bin/conductor-exec bin/test-cpflow-github-flow, the mise/rbenv environment is already active and the inner ruby calls inherit it. Removing the redundant prefix is cleaner.


Documentation: Delegating to upstream ✅

The trimmed docs are appropriate for a downstream tutorial repo. The canonical mechanics live upstream; local docs only list app-specific values and the canary checklist. The trade-off is that a broken or moved upstream link leaves local docs sparse — but that's acceptable for a demo repo.


Overall: Approve with minor nits. The security improvements are well-implemented and the validation script actively catches regressions. The .sort removal and staging_app_branch_default change are worth a follow-up look but neither is a blocker.

Comment thread bin/pin-cpflow-github-ref

root = Pathname.new(__dir__).join("..").expand_path
workflow_paths = Dir[root.join(".github/workflows/cpflow-*.yml")].sort
workflow_paths = Dir[root.join(".github/workflows/cpflow-*.yml")]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

.sort was removed, so workflow_paths is now in filesystem-dependent order. The replacement itself is idempotent, but sorted output made the "Changed:" log easier to audit in CI. Consider restoring it:

Suggested change
workflow_paths = Dir[root.join(".github/workflows/cpflow-*.yml")]
workflow_paths = Dir[root.join(".github/workflows/cpflow-*.yml")].sort

control_plane_flow_ref: 3e0e7e1f0a35c15648cc9254b573b058d77ca8c4
staging_app_branch_default: ""
secrets: inherit
staging_app_branch_default: "master"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Previously staging_app_branch_default: "" let the upstream reusable workflow use its own default. Now "master" is explicitly hardcoded, so this repo's staging branch no longer tracks the upstream default if it ever changes. That's almost certainly the right call for this repo — just flagging the subtle semantic shift so it's a conscious choice rather than an accidental one.

actionlint -ignore "SC2129" .github/workflows/cpflow-*.yml
actionlint \
-ignore "SC2129" \
-ignore 'property "workflow_(ref|sha|repository|file_path)" is not defined in object type' \
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The alternation in this actionlint -ignore pattern (workflow_(ref|sha|repository|file_path)) relies on Go's regexp package supporting |. That works fine — just noting it so future maintainers know why it's a regex string rather than four separate -ignore flags.

@justin808 justin808 merged commit 77eae2b into master May 25, 2026
13 checks passed
@justin808 justin808 deleted the jg-codex/downstream-cpflow-setup-docs branch May 25, 2026 08:59
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 25, 2026

✅ Review App Deleted

Review app for PR #747 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