Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 103 additions & 5 deletions .controlplane/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,104 @@ In a real app, you would likely use persistent, external resources, such as AWS

You can see the definition of Postgres and Redis in the `.controlplane/templates` directory.

## GitHub Review App Setup

For normal generated review apps in this repo, GitHub needs only one repository
secret:

| Secret | Notes |
| --- | --- |
| `CPLN_TOKEN_STAGING` | Control Plane service-account token for `shakacode-open-source-examples-staging`. |

No GitHub repository variables are required for the standard review-app path.
The generated workflow infers the review app prefix
`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.


Optional review-app variables:

| Variable | Notes |
| --- | --- |
| `CPLN_ORG_STAGING` | Override the inferred staging org. |
| `REVIEW_APP_PREFIX` | Override or disambiguate the inferred review app prefix. |
| `PRIMARY_WORKLOAD` | Public workload name used to discover the review URL; defaults to `rails`. |

For staging auto-deploys, also configure:

| Secret or variable | Value |
| --- | --- |
| `CPLN_TOKEN_STAGING` | Same staging Control Plane token used by review apps. |
| `CPLN_ORG_STAGING` | `shakacode-open-source-examples-staging` |
| `STAGING_APP_NAME` | `react-webpack-rails-tutorial-staging` |

For production promotion, configure a protected GitHub Environment named
`production`:

| Secret or variable | Value |
| --- | --- |
| `CPLN_TOKEN_PRODUCTION` | Environment secret on `production`, not a repository or organization secret. |
| `CPLN_ORG_PRODUCTION` | Environment variable on `production`: `shakacode-open-source-examples-production` |
| `PRODUCTION_APP_NAME` | Environment variable on `production`: `react-webpack-rails-tutorial-production` |

Protect the `production` environment with required reviewers, enable prevent
self-review, and consider disabling administrator bypass. Only release managers
or similarly trusted maintainers should be able to approve the promotion job.
The promotion workflow uses that environment before it can access
`CPLN_TOKEN_PRODUCTION`, so the production token is not exposed to ordinary
review-app or staging runs.

Advanced optional variables:

| Name | Notes |
| --- | --- |
| `REVIEW_APP_DEPLOYING_ICON_URL` | Cosmetic custom animated icon for review-app comments. Ignore this for the standard setup. |
| `CPLN_CLI_VERSION` | Pin only when Control Plane CLI compatibility requires it. |
| `CPFLOW_VERSION` | Runtime gem override. Leave unset when workflow wrappers are pinned to a GitHub commit SHA for upstream PR testing. |

## Control Plane Setup

The GitHub secret is only the automation credential. The Control Plane org also
needs the app resources and runtime secrets that the workloads read at boot.

For review-app testing, the standard setup is:

| Control Plane item | Where | Notes |
| --- | --- | --- |
| Staging/review org | `shakacode-open-source-examples-staging` | The `CPLN_TOKEN_STAGING` service account must be able to create and update GVCs, workloads, images, identities, policies, and secrets in this org. |
| Review app prefix | `qa-react-webpack-rails-tutorial` | Review apps are named `qa-react-webpack-rails-tutorial-<PR number>`. This is inferred from `.controlplane/controlplane.yml`. |
| Review app secret dictionary | `qa-react-webpack-rails-tutorial-secrets` | Shared by generated review apps because the QA app entry uses `match_if_app_name_starts_with: true`. |

For staging deploys later, also use:

| Control Plane item | Where | Notes |
| --- | --- | --- |
| Staging app | `react-webpack-rails-tutorial-staging` | The `CPLN_TOKEN_STAGING` token deploys this app from `master`. |
| Staging app secret dictionary | `react-webpack-rails-tutorial-staging-secrets` | Same required keys as the review app secret dictionary. |

For production promotion later, use a separate production org and token:

| Control Plane item | Where | Notes |
| --- | --- | --- |
| Production org | `shakacode-open-source-examples-production` | Do not give the staging token access to this org. |
| Production app | `react-webpack-rails-tutorial-production` | Promotion copies the staging image into this app. |
| Production app secret dictionary | `react-webpack-rails-tutorial-production-secrets` | Create before the first promotion. Use production-only values. |
| Production service-account token | GitHub Environment secret `CPLN_TOKEN_PRODUCTION` | Keep this token in the protected `production` GitHub Environment only. |

The app secret dictionaries must include:

- `SECRET_KEY_BASE`
- `RENDERER_PASSWORD`
- `REACT_ON_RAILS_PRO_LICENSE`

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.

secret-backed value before promoting production. The demo Postgres and Redis
workloads are useful for review apps and staging demos. For real production,
prefer managed services and update `DATABASE_URL` and `REDIS_URL` accordingly.

## Prerequisites

1. Ensure your [Control Plane](https://shakacode.controlplane.com) account is set up.
Expand Down Expand Up @@ -388,11 +486,11 @@ The production promotion workflow checks that production has all environment
variable names present in staging; it does not compare secret values, workload
environment variables, or Control Plane secret references.

The repository variables and secrets must match the app names in
`.controlplane/controlplane.yml`. In particular, `REVIEW_APP_PREFIX` should
include the `-pr` suffix for this app, such as
`qa-react-webpack-rails-tutorial-pr`, so generated review apps are named
`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."

`qa-react-webpack-rails-tutorial`; generated review apps are named
`qa-react-webpack-rails-tutorial-<PR number>`.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

This allows teams to:
- Preview changes in a production-like environment
Expand Down
32 changes: 21 additions & 11 deletions .controlplane/shakacode-team.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ Deployments are handled by Control Plane configuration in this repo and GitHub A

### Review Apps
- Add a comment `+review-app-deploy` to any PR to deploy a review app
- The generated app name is `${REVIEW_APP_PREFIX}-${PR_NUMBER}`. Keep
`REVIEW_APP_PREFIX` set to `qa-react-webpack-rails-tutorial-pr` so review
apps use names like `qa-react-webpack-rails-tutorial-pr-1234`, matching the
prefix-backed config in `.controlplane/controlplane.yml`.
- 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.

- New pushes to a PR redeploy only after the review app already exists.
- Add `+review-app-delete` to delete a review app manually; closing the PR also
deletes it automatically. Use `+review-app-help` for the command reference.
Expand All @@ -30,21 +30,31 @@ Deployments are handled by Control Plane configuration in this repo and GitHub A

### GitHub Repository Settings

Required repository secrets:
Required repository secret for review apps and staging:

- `CPLN_TOKEN_STAGING`
- `CPLN_TOKEN_PRODUCTION`

Required repository variables:
Required repository variables for staging deploys:

- `CPLN_ORG_STAGING=shakacode-open-source-examples-staging`
- `CPLN_ORG_PRODUCTION=shakacode-open-source-examples-production`
- `STAGING_APP_NAME=react-webpack-rails-tutorial-staging`
- `PRODUCTION_APP_NAME=react-webpack-rails-tutorial-production`
- `REVIEW_APP_PREFIX=qa-react-webpack-rails-tutorial-pr`
- `STAGING_APP_BRANCH=master`
- `PRIMARY_WORKLOAD=rails`

Review apps infer `CPLN_ORG_STAGING`, `REVIEW_APP_PREFIX`, and
`PRIMARY_WORKLOAD` from `.controlplane/controlplane.yml` and workflow defaults,
so those values do not need to be set just to test review apps.

Production promotion uses a protected GitHub Environment named `production`:

- Environment secret `CPLN_TOKEN_PRODUCTION`
- Environment variable `CPLN_ORG_PRODUCTION=shakacode-open-source-examples-production`
- Environment variable `PRODUCTION_APP_NAME=react-webpack-rails-tutorial-production`

Protect the `production` environment with required reviewers, enable prevent
self-review, and consider disabling administrator bypass. Do not store
`CPLN_TOKEN_PRODUCTION` as a repository or organization secret.

Optional repository settings:

- `DOCKER_BUILD_SSH_KEY`: secret for private SSH dependencies during Docker builds.
Expand All @@ -66,7 +76,7 @@ filter in `.github/workflows/cpflow-deploy-staging.yml`.
When the upstream `control-plane-flow` repo changes the generated GitHub Actions
flow, regenerate the `cpflow-*` actions/workflows in this repo from the target
`cpflow` version or branch using `--staging-branch master`, review the diff, and
keep the repository variables above aligned with `.controlplane/controlplane.yml`. Validate with
keep the GitHub settings above aligned with `.controlplane/controlplane.yml`. Validate with
`cpflow github-flow-readiness`, `actionlint .github/workflows/cpflow-*.yml`, and
the normal CI checks before merging. For review-app workflow changes, remember
that the deploy workflow checks out trusted local actions from `master` before
Expand Down
65 changes: 58 additions & 7 deletions .github/cpflow-help.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,77 @@ You asked for review app help. These commands are generated by [cpflow](https://
| Name | Required | Notes |
| --- | --- | --- |
| `CPLN_TOKEN_STAGING` | yes | Service-account token scoped to the staging Control Plane org on controlplane.com. |
| `CPLN_TOKEN_PRODUCTION` | yes (for promote) | Service-account token scoped to the production Control Plane org on controlplane.com. |
| `CPLN_TOKEN_PRODUCTION` | yes (for promote) | Store this as a secret on the protected `production` GitHub Environment, not as a repository or organization secret. |
| `DOCKER_BUILD_SSH_KEY` | optional | Private SSH key used when Docker builds fetch private deps via `RUN --mount=type=ssh`. |

For normal generated review apps, `CPLN_TOKEN_STAGING` is the only required
GitHub setting. The review app prefix and staging org are inferred from
`.controlplane/controlplane.yml` when it defines exactly one app with
`match_if_app_name_starts_with: true`.

For production promotion, create a GitHub Environment named `production`, add
required reviewers, enable prevent self-review, and store
`CPLN_TOKEN_PRODUCTION` as an environment secret there. The generated promotion
workflow uses that environment before it can access production secrets.

### GitHub Actions variables

| Name | Required | Notes |
| --- | --- | --- |
| `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.

| `STAGING_APP_NAME` | yes | App name in `controlplane.yml` used as the staging deploy target. |
| `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.

| `REVIEW_APP_PREFIX` | optional | Override or disambiguate the review app prefix inferred from `controlplane.yml`. |
| `REVIEW_APP_DEPLOYING_ICON_URL` | optional, advanced | Cosmetic custom image URL for the animated deploying icon in review-app PR comments. Set to `none` to use the text fallback icon. |
| `STAGING_APP_BRANCH` | optional | Custom staging branch. Custom branches must also appear in `cpflow-deploy-staging.yml`'s push filter. |
| `PRIMARY_WORKLOAD` | optional | Workload polled for health and rollback (defaults to `rails`). |
| `DOCKER_BUILD_EXTRA_ARGS` | optional | Newline-delimited extra docker build tokens (e.g. `--build-arg=FOO=bar`). |
| `DOCKER_BUILD_SSH_KNOWN_HOSTS` | optional | SSH known_hosts entries when SSH build hosts are not GitHub.com. |
| `HEALTH_CHECK_ACCEPTED_STATUSES` | optional | Space-separated HTTP statuses considered healthy on promote (default `200 301 302`). |
| `CPLN_CLI_VERSION` | optional | Pin a specific `@controlplane/cli` version; falls back to the action default when unset. |
| `CPFLOW_VERSION` | optional | Runtime gem-install override. When unset, cpflow is built from the pinned upstream workflow ref. When set, use the RubyGems version without a leading `v`. |
| `CPFLOW_VERSION` | optional | Pin a published RubyGems version such as `5.0.0` or `5.0.0.rc.1`. Leave unset for normal generated workflows so the setup action builds `cpflow` from the same `control-plane-flow` GitHub ref used by the reusable workflow. |

</details>

<details>
<summary>Advanced: testing unreleased control-plane-flow changes</summary>

Generated workflow wrappers have two related pins:

- The `uses: shakacode/control-plane-flow/...@<ref>` GitHub ref selects the reusable workflow code.
- The `control_plane_flow_ref: <ref>` input tells the setup action which `control-plane-flow` source to check out and build when `CPFLOW_VERSION` is empty.

The GitHub ref is the runtime lock for workflow and action behavior. The
RubyGems version is used to generate/update these wrappers and, only when
`CPFLOW_VERSION` is set, to install the `cpflow` CLI at runtime. A downstream
repo cannot rely on the gem alone because GitHub loads reusable workflow YAML
from `shakacode/control-plane-flow`, not from RubyGems.

For normal releases, point both pins at a release tag such as `v5.0.0`.
You may leave `CPFLOW_VERSION` unset, or set it to the matching RubyGems version
without the leading `v`, such as `5.0.0`. If you set `CPFLOW_VERSION` for a
prerelease, use RubyGems dot syntax such as `5.0.0.rc.1`; the release tag may
use either `v5.0.0.rc.1` or `v5.0.0-rc.1`.

To update to a new stable release, install or bundle the new `cpflow` gem, run
`cpflow generate-github-actions`, and commit the regenerated wrappers. Use
`bin/pin-cpflow-github-ref vX.Y.Z` only when the generated files are already
current and you only need to move the upstream GitHub ref.

For temporary downstream testing of an upstream PR before a gem is released, pin
both values to the exact 40-character commit SHA and leave `CPFLOW_VERSION`
unset:

```sh
bin/pin-cpflow-github-ref <40-character-control-plane-flow-commit-sha>
bin/test-cpflow-github-flow ruby /path/to/control-plane-flow/bin/cpflow
```

Do not leave downstream apps pinned to a moving branch such as `main`. A branch
can pick up beta or work-in-progress changes without a downstream PR changing.
Use commit SHAs for short-lived PR testing, then switch to the release tag once
the gem and tag exist.

</details>

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/cpflow-cleanup-stale-review-apps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ permissions:

jobs:
cleanup:
uses: shakacode/control-plane-flow/.github/workflows/cpflow-cleanup-stale-review-apps.yml@3e0e7e1f0a35c15648cc9254b573b058d77ca8c4
uses: shakacode/control-plane-flow/.github/workflows/cpflow-cleanup-stale-review-apps.yml@db013e139af4ee8741f791c14ff825f13c0a1021
with:
control_plane_flow_ref: 3e0e7e1f0a35c15648cc9254b573b058d77ca8c4
control_plane_flow_ref: db013e139af4ee8741f791c14ff825f13c0a1021
secrets: inherit
4 changes: 2 additions & 2 deletions .github/workflows/cpflow-delete-review-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) ||
(github.event_name == 'pull_request_target' && github.event.action == 'closed') ||
github.event_name == 'workflow_dispatch'
uses: shakacode/control-plane-flow/.github/workflows/cpflow-delete-review-app.yml@3e0e7e1f0a35c15648cc9254b573b058d77ca8c4
uses: shakacode/control-plane-flow/.github/workflows/cpflow-delete-review-app.yml@db013e139af4ee8741f791c14ff825f13c0a1021
with:
control_plane_flow_ref: 3e0e7e1f0a35c15648cc9254b573b058d77ca8c4
control_plane_flow_ref: db013e139af4ee8741f791c14ff825f13c0a1021
secrets: inherit
4 changes: 2 additions & 2 deletions .github/workflows/cpflow-deploy-review-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
github.event.issue.pull_request &&
contains(fromJson('["+review-app-deploy","+review-app-deploy\n","+review-app-deploy\r\n"]'), github.event.comment.body) &&
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association))
uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-review-app.yml@3e0e7e1f0a35c15648cc9254b573b058d77ca8c4
uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-review-app.yml@db013e139af4ee8741f791c14ff825f13c0a1021
with:
control_plane_flow_ref: 3e0e7e1f0a35c15648cc9254b573b058d77ca8c4
control_plane_flow_ref: db013e139af4ee8741f791c14ff825f13c0a1021
secrets: inherit
4 changes: 2 additions & 2 deletions .github/workflows/cpflow-deploy-staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ permissions:

jobs:
deploy-staging:
uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-staging.yml@3e0e7e1f0a35c15648cc9254b573b058d77ca8c4
uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-staging.yml@db013e139af4ee8741f791c14ff825f13c0a1021
with:
control_plane_flow_ref: 3e0e7e1f0a35c15648cc9254b573b058d77ca8c4
control_plane_flow_ref: db013e139af4ee8741f791c14ff825f13c0a1021
staging_app_branch_default: ""
secrets: inherit
2 changes: 1 addition & 1 deletion .github/workflows/cpflow-help-command.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ jobs:
contains(fromJson('["+review-app-help","+review-app-help\n","+review-app-help\r\n"]'), github.event.comment.body) &&
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@db013e139af4ee8741f791c14ff825f13c0a1021
17 changes: 15 additions & 2 deletions .github/workflows/cpflow-promote-staging-to-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,25 @@ on:
type: string

permissions:
# The upstream reusable workflow's create-github-release job needs
# contents: write, and callers must grant the union of callee permissions.
contents: write

jobs:
promote-to-production:
if: github.event.inputs.confirm_promotion == 'promote'
uses: shakacode/control-plane-flow/.github/workflows/cpflow-promote-staging-to-production.yml@3e0e7e1f0a35c15648cc9254b573b058d77ca8c4
# Keep the @ref in `uses:` and `control_plane_flow_ref` below in sync: the
# first selects the reusable workflow, the second selects its shared actions.

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 contents: write permission is correctly documented here, but it is the only permission listed. The upstream reusable workflow may also require pull-requests: write or id-token: write depending on how it creates the GitHub Release and authenticates. Confirm the permission set matches what the upstream workflow actually requires; missing a permission causes a confusing 403 rather than a clear error.

uses: shakacode/control-plane-flow/.github/workflows/cpflow-promote-staging-to-production.yml@db013e139af4ee8741f791c14ff825f13c0a1021
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.

control_plane_flow_ref: 3e0e7e1f0a35c15648cc9254b573b058d77ca8c4
control_plane_flow_ref: db013e139af4ee8741f791c14ff825f13c0a1021
# Keep CPLN_TOKEN_PRODUCTION as a secret on this protected GitHub
# Environment. Required reviewers approve the job before GitHub exposes
# environment secrets to the upstream reusable workflow.
production_environment: production

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 approach — passing production_environment: production lets the upstream reusable workflow run under the GitHub Environment approval gate so CPLN_TOKEN_PRODUCTION stays protected.

One runtime risk: if the production GitHub Environment doesn't exist yet, this job fails with an opaque API error rather than a clear "environment not configured" message. The docs explain the setup, but a pre-job step in the upstream workflow (or a note in the docs pointing to the exact GitHub error to expect) would help first-time operators diagnose it faster.

# `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.

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.

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.

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.

Loading
Loading