cpflow 5.0.4 → 5.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/actions/cpflow-wait-for-health/action.yml +11 -4
- data/.github/workflows/cpflow-promote-staging-to-production.yml +269 -43
- data/.github/workflows/rspec-shared.yml +8 -1
- data/CHANGELOG.md +28 -1
- data/Gemfile.lock +1 -1
- data/README.md +36 -11
- data/docs/ai-github-flow-prompt.md +1 -1
- data/docs/assets/logo/favicon.ico +0 -0
- data/docs/assets/logo/icon-1024.png +0 -0
- data/docs/assets/logo/icon-128.png +0 -0
- data/docs/assets/logo/icon-16.png +0 -0
- data/docs/assets/logo/icon-192.png +0 -0
- data/docs/assets/logo/icon-24.png +0 -0
- data/docs/assets/logo/icon-32.png +0 -0
- data/docs/assets/logo/icon-48.png +0 -0
- data/docs/assets/logo/icon-512.png +0 -0
- data/docs/assets/logo/icon-64.png +0 -0
- data/docs/assets/logo/icon-tile.svg +17 -0
- data/docs/assets/logo/mark-transparent.svg +16 -0
- data/docs/ci-automation.md +137 -47
- data/docs/commands.md +13 -3
- data/docs/postgres.md +6 -0
- data/docs/rds-private-networking.md +649 -0
- data/docs/secrets-and-env-values.md +49 -0
- data/docs/tips.md +256 -10
- data/examples/controlplane.yml +8 -0
- data/lib/command/ai_github_flow_prompt.rb +1 -1
- data/lib/command/apply_template.rb +3 -0
- data/lib/command/base.rb +69 -0
- data/lib/command/cleanup_stale_apps.rb +1 -1
- data/lib/command/delete.rb +85 -10
- data/lib/command/deploy_image.rb +30 -8
- data/lib/command/generate_github_actions.rb +6 -0
- data/lib/command/maintenance_off.rb +1 -0
- data/lib/command/maintenance_on.rb +1 -0
- data/lib/command/run.rb +25 -5
- data/lib/command/setup_app.rb +11 -2
- data/lib/core/config.rb +81 -0
- data/lib/core/controlplane.rb +15 -5
- data/lib/core/maintenance_mode.rb +93 -6
- data/lib/core/template_parser.rb +4 -0
- data/lib/cpflow/version.rb +1 -1
- data/lib/generator_templates/controlplane.yml +7 -0
- data/lib/generator_templates_sqlite/controlplane.yml +7 -0
- data/lib/github_flow_templates/.github/cpflow-help.md +48 -13
- data/lib/github_flow_templates/.github/workflows/cpflow-promote-staging-to-production.yml +768 -15
- data/lib/github_flow_templates/bin/pin-cpflow-github-ref +17 -3
- data/lib/github_flow_templates/bin/test-cpflow-github-flow +61 -9
- metadata +15 -2
|
@@ -20,7 +20,7 @@ prompt tells the agent to stop on.
|
|
|
20
20
|
```text
|
|
21
21
|
Set up Control Plane GitHub Flow for this repo. Start with `cpflow github-flow-readiness` and stop on any reported blockers. The repo must be deployable from a clean clone: published package versions, complete runtime scaffold, and a production Dockerfile that can build the app. If any package version is unpublished, inaccessible from CI, or requires credentials that are not already modeled in the repo or GitHub settings, stop and report the blocker instead of generating workflow files. If the repo is a legacy sample pinned to an obsolete Ruby or Bundler toolchain, if it does not even have a production Dockerfile yet, or if it is a monorepo without an already-decided single app boundary for this flow, stop and report that as a prerequisite instead of forcing the rollout.
|
|
22
22
|
|
|
23
|
-
If `.controlplane/` is missing, run `cpflow generate`. Treat the generated app names as the repo-name default and rename them only if the project needs a different prefix. Then run `cpflow generate-github-actions` (or `cpflow generate-github-actions --staging-branch BRANCH` when staging should deploy from a branch other than `main`/`master`), keep review apps opt-in via `+review-app-deploy`, make sure any `STAGING_APP_BRANCH` repository variable is also present in the generated staging workflow's `on.push.branches` filter, and list the GitHub secrets and variables that must be configured. Do not hand-edit duplicated upstream refs into the generated wrappers: the only downstream Control Plane Flow pin should be the reusable workflow `uses: ...@vX.Y.Z` value generated from the installed `cpflow` gem version, and upstream workflows load their matching shared actions automatically. When bumping the `cpflow` gem in a downstream repo, run `cpflow update-github-actions` (or `bundle exec cpflow update-github-actions`) and validate with `bin/test-cpflow-github-flow` in the same PR so the checked-in wrappers move to the matching release tag. Keep the standard path simple: review apps require only `CPLN_TOKEN_STAGING` when the generated review app config can be inferred. Document the one-time Control Plane bootstrap command for persistent staging and production apps with `cpflow setup-app --skip-post-creation-hook`; for existing apps or later template updates, document `cpflow apply-template` and the need for the app identity to have `reveal` on the app secret policy. Do not imply the staging deploy or promotion workflows create those persistent GVCs. For production promotion, document a protected `production` GitHub Environment with required reviewers, prevent self-review, and `CPLN_TOKEN_PRODUCTION` stored as an environment secret, not as a repository or organization secret.
|
|
23
|
+
If `.controlplane/` is missing, run `cpflow generate`. Treat the generated app names as the repo-name default and rename them only if the project needs a different prefix. Then run `cpflow generate-github-actions` (or `cpflow generate-github-actions --staging-branch BRANCH` when staging should deploy from a branch other than `main`/`master`), keep review apps opt-in via `+review-app-deploy`, make sure any `STAGING_APP_BRANCH` repository variable is also present in the generated staging workflow's `on.push.branches` filter, and list the GitHub secrets and variables that must be configured. Do not hand-edit duplicated upstream refs into the generated wrappers: the only downstream Control Plane Flow pin should be the reusable workflow `uses: ...@vX.Y.Z` value generated from the installed `cpflow` gem version, and upstream workflows load their matching shared actions automatically. When bumping the `cpflow` gem in a downstream repo, run `cpflow update-github-actions` (or `bundle exec cpflow update-github-actions`) and validate with `bin/test-cpflow-github-flow` in the same PR so the checked-in wrappers move to the matching release tag. Keep the standard path simple: review apps require only `CPLN_TOKEN_STAGING` when the generated review app config can be inferred. For shared review-app resources such as one staging database, use `shared_secret_grants` and `{{SHARED_SECRET_DATABASE}}` placeholders instead of hardcoding the base app secret name; this keeps review-app policy binding and cleanup automatic while avoiding per-PR database cost. Document the one-time Control Plane bootstrap command for persistent staging and production apps with `cpflow setup-app --skip-post-creation-hook`; for existing apps or later template updates, document `cpflow apply-template` and the need for the app identity to have `reveal` on the app secret policy. Do not imply the staging deploy or promotion workflows create those persistent GVCs. For production promotion, document a protected `production` GitHub Environment with required reviewers, prevent self-review, and `CPLN_TOKEN_PRODUCTION` stored as an environment secret, not as a repository or organization secret.
|
|
24
24
|
|
|
25
25
|
Keep Node available in the final image if asset compilation or SSR depends on ExecJS, Yarn, `pnpm`, or npm after the main install layer. Make sure the generated Dockerfile uses a Ruby base image compatible with the app's declared Ruby requirement. Preserve repo-defined frontend build hooks: if `config/shakapacker.yml` defines a `precompile_hook`, or React on Rails enables `config.auto_load_bundle = true`, confirm the generated Dockerfile runs that codegen step before `rails assets:precompile`. If `config/database.yml` shows SQLite in production, confirm that the generated scaffold uses persistent `db` and `storage` volumes plus a release script that runs `rails db:prepare`; otherwise keep the default Postgres workload. If the public workload is not named `rails`, set `PRIMARY_WORKLOAD` or adjust the generated workflows. Inspect the Dockerfile and package sources for private GitHub dependencies or `RUN --mount=type=ssh`; if present, wire `DOCKER_BUILD_SSH_KEY`, optionally set `DOCKER_BUILD_SSH_KNOWN_HOSTS` for non-GitHub SSH hosts, and keep `DOCKER_BUILD_EXTRA_ARGS` to newline-delimited single tokens such as `--build-arg=FOO=bar`.
|
|
26
26
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" role="img" aria-label="Control Plane Flow icon">
|
|
2
|
+
<title>Control Plane Flow icon</title>
|
|
3
|
+
<rect x="64" y="64" width="896" height="896" rx="192" fill="#0B1118" stroke="#26313D" stroke-width="12"/>
|
|
4
|
+
<g fill="none" stroke-linecap="round" stroke-linejoin="round">
|
|
5
|
+
<path d="M290 650 C330 500 435 430 512 512 C600 606 704 560 746 390" stroke="#2BD7FF" stroke-width="68"/>
|
|
6
|
+
<path d="M746 390 L688 397" stroke="#2BD7FF" stroke-width="68"/>
|
|
7
|
+
<path d="M746 390 L731 446" stroke="#2BD7FF" stroke-width="68"/>
|
|
8
|
+
</g>
|
|
9
|
+
<circle cx="290" cy="650" r="92" fill="#8973FF"/>
|
|
10
|
+
<circle cx="512" cy="512" r="92" fill="#70D187"/>
|
|
11
|
+
<circle cx="746" cy="390" r="92" fill="#FFB000"/>
|
|
12
|
+
<circle cx="290" cy="650" r="32" fill="#0B1118" opacity="0.88"/>
|
|
13
|
+
<circle cx="512" cy="512" r="32" fill="#0B1118" opacity="0.88"/>
|
|
14
|
+
<circle cx="746" cy="390" r="32" fill="#0B1118" opacity="0.88"/>
|
|
15
|
+
<path d="M390 730 H612" stroke="#2BD7FF" stroke-width="40" stroke-linecap="round" opacity="0.86"/>
|
|
16
|
+
<path d="M612 730 L555 692 M612 730 L555 768" stroke="#2BD7FF" stroke-width="40" stroke-linecap="round" stroke-linejoin="round" opacity="0.86"/>
|
|
17
|
+
</svg>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" role="img" aria-label="Control Plane Flow icon transparent mark">
|
|
2
|
+
<title>Control Plane Flow icon transparent mark</title>
|
|
3
|
+
<g fill="none" stroke-linecap="round" stroke-linejoin="round">
|
|
4
|
+
<path d="M290 650 C330 500 435 430 512 512 C600 606 704 560 746 390" stroke="#2BD7FF" stroke-width="68"/>
|
|
5
|
+
<path d="M746 390 L688 397" stroke="#2BD7FF" stroke-width="68"/>
|
|
6
|
+
<path d="M746 390 L731 446" stroke="#2BD7FF" stroke-width="68"/>
|
|
7
|
+
</g>
|
|
8
|
+
<circle cx="290" cy="650" r="92" fill="#8973FF"/>
|
|
9
|
+
<circle cx="512" cy="512" r="92" fill="#70D187"/>
|
|
10
|
+
<circle cx="746" cy="390" r="92" fill="#FFB000"/>
|
|
11
|
+
<circle cx="290" cy="650" r="32" fill="#0B1118" opacity="0.88"/>
|
|
12
|
+
<circle cx="512" cy="512" r="32" fill="#0B1118" opacity="0.88"/>
|
|
13
|
+
<circle cx="746" cy="390" r="32" fill="#0B1118" opacity="0.88"/>
|
|
14
|
+
<path d="M390 730 H612" stroke="#2BD7FF" stroke-width="40" stroke-linecap="round" opacity="0.86"/>
|
|
15
|
+
<path d="M612 730 L555 692 M612 730 L555 768" stroke="#2BD7FF" stroke-width="40" stroke-linecap="round" stroke-linejoin="round" opacity="0.86"/>
|
|
16
|
+
</svg>
|
data/docs/ci-automation.md
CHANGED
|
@@ -16,7 +16,7 @@ End-to-end rollout in one view:
|
|
|
16
16
|
|
|
17
17
|
1. `cpflow github-flow-readiness` — exits non-zero if the repo is not ready to deploy.
|
|
18
18
|
2. `cpflow generate` — creates `.controlplane/` if missing.
|
|
19
|
-
3. `cpflow generate-github-actions` — adds
|
|
19
|
+
3. `cpflow generate-github-actions` — adds `cpflow-*` workflow wrappers. Review-app, staging, cleanup, and helper workflows call upstream reusable workflows; production promotion is a normal caller-repo job so it can own the protected production Environment.
|
|
20
20
|
4. Configure the GitHub [repository secrets and variables](#required-github-repository-settings) the workflows expect.
|
|
21
21
|
5. Push the branch, then comment `+review-app-deploy` on a PR to spin up a review environment.
|
|
22
22
|
|
|
@@ -196,23 +196,62 @@ For production promotion, also configure:
|
|
|
196
196
|
- `CPLN_ORG_PRODUCTION` as a production environment variable, for example `company-production`
|
|
197
197
|
- `PRODUCTION_APP_NAME` as a production environment variable, for example `my-app-production`
|
|
198
198
|
|
|
199
|
+
Enter GitHub variables such as `CPLN_ORG_STAGING`,
|
|
200
|
+
`CPLN_ORG_PRODUCTION`, `STAGING_APP_NAME`, and `PRODUCTION_APP_NAME`
|
|
201
|
+
as plain single-line values. The generated production promotion workflow trims
|
|
202
|
+
accidental leading/trailing whitespace and line endings from Control Plane org
|
|
203
|
+
names before building registry URLs, but embedded line breaks are rejected
|
|
204
|
+
because they could change the target org name after normalization.
|
|
205
|
+
|
|
206
|
+
Production promotion copies the exact image currently deployed on the selected
|
|
207
|
+
staging workload. If that staging image is digest-pinned, the digest is used for
|
|
208
|
+
the source copy while the production tag is derived from the tag portion. Tags
|
|
209
|
+
with a `_<commit>` suffix keep that suffix in production; plain numeric tags are
|
|
210
|
+
also valid and promote to the next plain production tag. The copy step uses
|
|
211
|
+
`docker buildx imagetools create --prefer-index=false --tag` with isolated
|
|
212
|
+
Docker credentials, which preserves multi-architecture manifests, preserves
|
|
213
|
+
single-platform manifest format when supported, and avoids pulling image layers
|
|
214
|
+
onto the GitHub Actions runner.
|
|
215
|
+
|
|
216
|
+
Before copying the image, production promotion compares the environment variable
|
|
217
|
+
names exposed by staging and production at both the GVC level and each configured
|
|
218
|
+
app workload's container level. Variables present in staging are treated as
|
|
219
|
+
required for production, while production-only variables emit warnings. A missing
|
|
220
|
+
production workload variable such as a renderer password or runtime secret fails
|
|
221
|
+
the promotion before the image copy starts.
|
|
222
|
+
|
|
199
223
|
Do not put `CPLN_TOKEN_PRODUCTION` in repository or organization secrets for
|
|
200
|
-
sensitive production systems.
|
|
201
|
-
`environment: production
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
224
|
+
sensitive production systems. Production promotion intentionally runs as a
|
|
225
|
+
normal caller-repo workflow job with `environment: production`, then checks out
|
|
226
|
+
the pinned `control-plane-flow` release for shared actions. GitHub exposes the
|
|
227
|
+
production token to that job only after the `production` environment gate.
|
|
228
|
+
GitHub does not expose which secret scope supplied a nonempty value at runtime,
|
|
229
|
+
so a broader repository or organization secret with the same name can mask a
|
|
230
|
+
missing environment secret. Keep the production token absent from broader secret
|
|
231
|
+
scopes.
|
|
232
|
+
|
|
233
|
+
Do not move production promotion behind a cross-repo reusable workflow. GitHub
|
|
234
|
+
does not expose the caller repository's environment secrets to that called
|
|
235
|
+
workflow, so `secrets.CPLN_TOKEN_PRODUCTION` remains empty even when the
|
|
236
|
+
`production` Environment contains the secret. Generated reusable-workflow
|
|
237
|
+
callers still pass only the named secrets each upstream workflow needs and do
|
|
238
|
+
not use `secrets: inherit`; production promotion is the caller-owned exception.
|
|
239
|
+
|
|
240
|
+
If promotion fails in the `Validate production token` step with
|
|
241
|
+
`CPLN_TOKEN_PRODUCTION is not set. Add it as a secret on the 'production' GitHub Environment.`,
|
|
242
|
+
check the environment scope first. Also verify that the `promote-to-production`
|
|
243
|
+
job declares `environment: production` and that no same-named repository or
|
|
244
|
+
organization secret exists. Create or verify the environment secret with:
|
|
245
|
+
You need permission to manage repository environments and secrets to run these
|
|
246
|
+
commands.
|
|
247
|
+
|
|
248
|
+
```sh
|
|
249
|
+
gh secret set CPLN_TOKEN_PRODUCTION --repo OWNER/REPO --env production
|
|
250
|
+
# Paste the token value when prompted.
|
|
251
|
+
gh secret list --repo OWNER/REPO --env production
|
|
252
|
+
gh secret list --repo OWNER/REPO
|
|
253
|
+
gh secret list --org OWNER | grep '^CPLN_TOKEN_PRODUCTION[[:space:]]' || true
|
|
254
|
+
```
|
|
216
255
|
|
|
217
256
|
## First-Time Control Plane Bootstrap
|
|
218
257
|
|
|
@@ -256,6 +295,12 @@ cpflow setup-app -a my-app-production --org my-org-production --skip-post-creati
|
|
|
256
295
|
Use production-only runtime secrets and values for the production app. The
|
|
257
296
|
protected GitHub Environment controls who can run the promotion workflow, but
|
|
258
297
|
the production app resources still need to exist before the first promotion.
|
|
298
|
+
After bootstrap, populate the production app secret dictionary with the values
|
|
299
|
+
referenced by `.controlplane/templates`, then run `cpflow apply-template` against
|
|
300
|
+
production when templates change so the workload env references remain persisted.
|
|
301
|
+
Production promotion checks for missing GVC and workload container env names
|
|
302
|
+
before copying the staging image, so a staging-only runtime variable will stop
|
|
303
|
+
the run early instead of deploying an image that cannot boot.
|
|
259
304
|
|
|
260
305
|
Review apps are different: the generated `+review-app-deploy` workflow creates
|
|
261
306
|
temporary PR apps as needed, including the identity and secret policy binding.
|
|
@@ -264,6 +309,28 @@ templates, and the staging token must have access to create and update
|
|
|
264
309
|
review-app GVCs, workloads, images, identities, policies, and secrets in the
|
|
265
310
|
staging org.
|
|
266
311
|
|
|
312
|
+
If review apps share an existing staging database or another existing secret,
|
|
313
|
+
declare it with `shared_secret_grants` on the review app config entry. The
|
|
314
|
+
deploy workflow runs `setup-app` for new review apps and `deploy-image` for
|
|
315
|
+
image updates; those commands bind or repair the review app identity's `reveal`
|
|
316
|
+
permission on each configured shared policy. The delete and cleanup workflows
|
|
317
|
+
call `cpflow delete`, which removes those bindings as review apps go away. This
|
|
318
|
+
lets one shared database or license secret serve many short-lived review apps
|
|
319
|
+
without granting every review identity access to unrelated app secrets.
|
|
320
|
+
|
|
321
|
+
```yaml
|
|
322
|
+
apps:
|
|
323
|
+
my-app-review:
|
|
324
|
+
match_if_app_name_starts_with: true
|
|
325
|
+
shared_secret_grants:
|
|
326
|
+
- name: database
|
|
327
|
+
secret_name: my-app-review-database-secrets
|
|
328
|
+
policy_name: my-app-review-database-secrets-policy
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Then reference `cpln://secret/{{SHARED_SECRET_DATABASE}}.DATABASE_URL` from the
|
|
332
|
+
workload template.
|
|
333
|
+
|
|
267
334
|
### Production Promotion Safety
|
|
268
335
|
|
|
269
336
|
`CPLN_TOKEN_PRODUCTION` can change live production workloads, images, releases,
|
|
@@ -279,12 +346,25 @@ The standard path is:
|
|
|
279
346
|
7. Store `CPLN_ORG_PRODUCTION` and `PRODUCTION_APP_NAME` as `production`
|
|
280
347
|
environment variables, or as repository variables only when those names are
|
|
281
348
|
intentionally non-sensitive.
|
|
349
|
+
8. Keep GitHub variable values single-line; a pasted trailing newline is trimmed
|
|
350
|
+
for Control Plane org names, but embedded line breaks are rejected before
|
|
351
|
+
deployment, copy, health-check, or rollback steps run.
|
|
352
|
+
9. Bootstrap or re-apply the persistent production app templates before first
|
|
353
|
+
promotion so app workload container env references and Control Plane secret
|
|
354
|
+
dictionaries exist in production.
|
|
355
|
+
10. Expect promotion to preserve the selected staging image reference. Digest
|
|
356
|
+
references are copied by digest, commit-suffixed tags keep the commit suffix,
|
|
357
|
+
and plain numeric tags remain valid.
|
|
358
|
+
11. Expect production health and rollback readiness polling to require Control
|
|
359
|
+
Plane `status.ready` and `status.readyLatest` before checking the endpoint.
|
|
282
360
|
|
|
283
361
|
GitHub only exposes environment secrets to jobs that reference the environment
|
|
284
|
-
after configured protection rules pass. GitHub
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
362
|
+
after configured protection rules pass. GitHub does not allow a caller job that
|
|
363
|
+
directly invokes a reusable workflow to set `environment`, and cross-repo
|
|
364
|
+
reusable workflows do not receive the caller repository's environment secrets.
|
|
365
|
+
For that reason, generated production promotion stays as a normal caller-repo
|
|
366
|
+
job with `environment: production`. See GitHub's docs for
|
|
367
|
+
[managing environments](https://docs.github.com/en/actions/how-tos/deploy/configure-and-manage-deployments/manage-environments),
|
|
288
368
|
[deployment protection rules](https://docs.github.com/en/actions/reference/workflows-and-actions/deployments-and-environments),
|
|
289
369
|
and [reusable workflow limitations](https://docs.github.com/en/actions/reference/reusable-workflows-reference#supported-keywords-for-jobs-that-call-a-reusable-workflow).
|
|
290
370
|
|
|
@@ -376,8 +456,8 @@ The action will start an SSH agent, add the key, write `known_hosts`, and pass `
|
|
|
376
456
|
|
|
377
457
|
- Manually promotes the staging artifact to production with a confirmation input.
|
|
378
458
|
- Runs the production job in the `production` GitHub Environment, so configured reviewers approve the job before production environment secrets are available.
|
|
379
|
-
- Verifies that production has the env var names staging expects.
|
|
380
|
-
- Runs a health check against `PRIMARY_WORKLOAD
|
|
459
|
+
- Verifies that production has the GVC and app workload container env var names staging expects.
|
|
460
|
+
- Runs a health check against `PRIMARY_WORKLOAD` only after Control Plane reports the latest workload version ready.
|
|
381
461
|
- Attempts a rollback of every configured application workload if the new production image does not come up healthy.
|
|
382
462
|
- Creates a GitHub release after a successful promotion.
|
|
383
463
|
|
|
@@ -405,32 +485,37 @@ or clones that copy the workflow before configuring Control Plane can remove
|
|
|
405
485
|
wrapper-level `if:` guard shown in that file, for example
|
|
406
486
|
`vars.REVIEW_APP_PREFIX != '' || vars.CPLN_ORG_STAGING != ''`.
|
|
407
487
|
|
|
408
|
-
## Upstream
|
|
488
|
+
## Upstream Workflows And Actions
|
|
409
489
|
|
|
410
|
-
|
|
411
|
-
comment formatting, Control Plane CLI setup, Docker image build, and
|
|
412
|
-
live in upstream reusable workflows and composite actions in
|
|
490
|
+
Most generated workflows are intentionally small wrappers. The deployment
|
|
491
|
+
logic, comment formatting, Control Plane CLI setup, Docker image build, and
|
|
492
|
+
cleanup helpers live in upstream reusable workflows and composite actions in
|
|
493
|
+
this repository. Production promotion is expanded into the caller repository so
|
|
494
|
+
it can own `environment: production`, but it still checks out the same upstream
|
|
495
|
+
ref for shared composite actions.
|
|
413
496
|
|
|
414
|
-
- `cpflow-setup-environment`: installs Ruby, the Control Plane CLI, and `cpflow`, then logs into the target org. By default it builds `cpflow` from the checked-out upstream
|
|
497
|
+
- `cpflow-setup-environment`: installs Ruby, the Control Plane CLI, and `cpflow`, then logs into the target org. By default it builds `cpflow` from the checked-out upstream `control-plane-flow` ref; set the `CPFLOW_VERSION` repository variable only when you want to force a published RubyGems release.
|
|
415
498
|
- `cpflow-build-docker-image`: builds and pushes the app image with the desired commit SHA
|
|
416
499
|
- `cpflow-delete-control-plane-app`: safely deletes temporary apps and refuses to touch names outside the configured review-app prefix
|
|
417
500
|
|
|
418
501
|
## Version Pins: GitHub Ref vs RubyGems
|
|
419
502
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
GitHub ref:
|
|
503
|
+
Generated `cpflow-*` workflow files pin `shakacode/control-plane-flow` from
|
|
504
|
+
GitHub, not from the Ruby gem. Reusable workflow wrappers pin that source with
|
|
505
|
+
an upstream `uses:` ref:
|
|
424
506
|
|
|
425
507
|
```yaml
|
|
426
508
|
uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-review-app.yml@<ref>
|
|
427
509
|
```
|
|
428
510
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
511
|
+
Production promotion pins the same source in its `Checkout control-plane-flow
|
|
512
|
+
actions` step because it is a caller-owned job, not a reusable workflow caller.
|
|
513
|
+
Those refs are the downstream lock. GitHub exposes a reusable workflow's own
|
|
514
|
+
repository, ref, and SHA to called jobs, so reusable upstream workflows check out
|
|
515
|
+
matching `control-plane-flow` source automatically from that context. Downstream
|
|
516
|
+
reusable-workflow wrappers should not pass `control_plane_flow_ref`; if you see
|
|
517
|
+
that input outside the production promotion setup step, regenerate with a newer
|
|
518
|
+
`cpflow`.
|
|
434
519
|
|
|
435
520
|
There are two locks, and they protect different things:
|
|
436
521
|
|
|
@@ -528,10 +613,12 @@ releasing it. Use an immutable commit SHA from the upstream PR branch:
|
|
|
528
613
|
bin/pin-cpflow-github-ref <upstream-pr-sha>
|
|
529
614
|
```
|
|
530
615
|
|
|
531
|
-
The helper updates every generated `
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
616
|
+
The helper updates every generated reusable-workflow `uses:` ref plus the
|
|
617
|
+
production workflow's pinned `control-plane-flow` checkout and setup
|
|
618
|
+
validation ref. It accepts release tags and full commit SHAs by default,
|
|
619
|
+
rejects branch names such as `main` or `feature/foo`, and requires
|
|
620
|
+
`--allow-moving-ref` for short-lived local experiments that should not be
|
|
621
|
+
committed.
|
|
535
622
|
|
|
536
623
|
3. Keep `CPFLOW_VERSION` unset so the workflow builds `cpflow` from the same
|
|
537
624
|
upstream SHA that supplies the reusable workflow and composite actions. If
|
|
@@ -566,9 +653,10 @@ releasing it. Use an immutable commit SHA from the upstream PR branch:
|
|
|
566
653
|
`bin/pin-cpflow-github-ref vX.Y.Z` only for a ref-only update when the
|
|
567
654
|
generated templates are already current.
|
|
568
655
|
|
|
569
|
-
This tests the real reusable
|
|
570
|
-
`cpflow` gem from one immutable
|
|
571
|
-
|
|
656
|
+
This tests the real reusable workflows, the production workflow's checked-out
|
|
657
|
+
shared composite actions, and the source-built `cpflow` gem from one immutable
|
|
658
|
+
upstream commit. It avoids merging upstream blind and avoids running production
|
|
659
|
+
automation against a moving branch.
|
|
572
660
|
|
|
573
661
|
## Local Generated-Flow Checks
|
|
574
662
|
|
|
@@ -580,9 +668,11 @@ bin/test-cpflow-github-flow
|
|
|
580
668
|
|
|
581
669
|
The helper runs `cpflow github-flow-readiness`, parses generated workflow YAML,
|
|
582
670
|
checks composite action metadata for literal GitHub expressions in descriptions,
|
|
583
|
-
checks that all generated wrappers
|
|
584
|
-
|
|
585
|
-
|
|
671
|
+
checks that all generated wrappers and the production `control-plane-flow`
|
|
672
|
+
checkout use one upstream ref consistently, rejects broad `secrets: inherit`
|
|
673
|
+
usage in generated cpflow wrappers, rejects obsolete `control_plane_flow_ref`
|
|
674
|
+
wrapper inputs, verifies production promotion remains a caller-owned
|
|
675
|
+
`environment: production` job, and runs
|
|
586
676
|
`actionlint` against `.github/workflows/cpflow-*.yml`. Its `actionlint` command
|
|
587
677
|
keeps the existing shellcheck ignore and also ignores stale local `actionlint`
|
|
588
678
|
false positives for GitHub's newer reusable-workflow `job.workflow_*` fields.
|
data/docs/commands.md
CHANGED
|
@@ -41,6 +41,9 @@ cpflow ai-github-flow-prompt
|
|
|
41
41
|
{{APP_IMAGE_LINK}} - full link for latest app image, ready to be used for the value of `containers[].image` in the templates
|
|
42
42
|
{{APP_IDENTITY}} - default identity
|
|
43
43
|
{{APP_IDENTITY_LINK}} - full link for identity, ready to be used for the value of `identityLink` in the templates
|
|
44
|
+
{{APP_SECRETS}} - app secret dictionary name
|
|
45
|
+
{{APP_SECRETS_POLICY}} - app secret policy name
|
|
46
|
+
{{SHARED_SECRET_<NAME>}} - shared secret dictionary name from `shared_secret_grants`
|
|
44
47
|
```
|
|
45
48
|
|
|
46
49
|
```sh
|
|
@@ -79,7 +82,7 @@ cpflow cleanup-images -a $APP_NAME
|
|
|
79
82
|
### `cleanup-stale-apps`
|
|
80
83
|
|
|
81
84
|
- Acts on stale apps based on the creation date of the latest image, or the GVC if no images exist
|
|
82
|
-
- With `--mode=delete` (default): deletes the whole app (GVC with all workloads, all volumesets and all images), and unbinds the app from the secrets policy as long as both the identity and
|
|
85
|
+
- With `--mode=delete` (default): deletes the whole app (GVC with all workloads, all volumesets and all images), and unbinds the app from the secrets policy and any configured `shared_secret_grants` policies as long as both the identity and each policy exist (and are bound)
|
|
83
86
|
- With `--mode=stop`: suspends all workloads via `cpflow ps:stop` — no GVC, volumeset, or image is removed; resume with `cpflow ps:start`
|
|
84
87
|
- `--mode=stop` only suspends workloads listed in `app_workloads` + `additional_workloads`; workloads present in the live GVC but missing from the config are skipped silently
|
|
85
88
|
- `--mode=stop` returns once each workload is marked suspended; it does not wait for the workload to reach a not-ready state
|
|
@@ -128,7 +131,8 @@ cpflow copy-image-from-upstream -a $APP_NAME --upstream-token $UPSTREAM_TOKEN --
|
|
|
128
131
|
### `delete`
|
|
129
132
|
|
|
130
133
|
- Deletes the whole app (GVC with all workloads, all volumesets and all images) or a specific workload
|
|
131
|
-
- Also unbinds the app from the secrets policy, as long as both the identity and
|
|
134
|
+
- Also unbinds the app from the secrets policy and any configured `shared_secret_grants` policies, as long as both the identity and each policy exist (and are bound)
|
|
135
|
+
- For the app-specific secrets policy, removes every permission held by the app identity; for `shared_secret_grants`, removes only `reveal`
|
|
132
136
|
- Will ask for explicit user confirmation
|
|
133
137
|
- Runs a pre-deletion hook before the app is deleted if `hooks.pre_deletion` is specified in the `.controlplane/controlplane.yml` file
|
|
134
138
|
- If the hook exits with a non-zero code, the command will stop executing and also exit with a non-zero code
|
|
@@ -149,6 +153,7 @@ cpflow delete -a $APP_NAME -w $WORKLOAD_NAME
|
|
|
149
153
|
- The release script is run in the context of `cpflow run` with the latest image
|
|
150
154
|
- If the release script exits with a non-zero code, the command will stop executing and also exit with a non-zero code
|
|
151
155
|
- If `use_digest_image_ref` is `true` in the `.controlplane/controlplane.yml` file or `--use-digest-image-ref` option is provided, deployed image's reference will include its digest
|
|
156
|
+
- Repairs missing `shared_secret_grants` policy bindings before running a release phase or updating workloads
|
|
152
157
|
|
|
153
158
|
```sh
|
|
154
159
|
cpflow deploy-image -a $APP_NAME
|
|
@@ -310,6 +315,7 @@ cpflow maintenance -a $APP_NAME
|
|
|
310
315
|
### `maintenance:off`
|
|
311
316
|
|
|
312
317
|
- Disables maintenance mode for an app
|
|
318
|
+
- Safe to re-run: if a previous run timed out after switching the domain but before stopping the maintenance workload, re-running while maintenance mode is already disabled stops the maintenance workload to finish it (so it is not a pure no-op)
|
|
313
319
|
- Specify the one-off workload through `one_off_workload` in the `.controlplane/controlplane.yml` file
|
|
314
320
|
- Optionally specify the maintenance workload through `maintenance_workload` in the `.controlplane/controlplane.yml` file (defaults to 'maintenance')
|
|
315
321
|
- Maintenance mode is only supported for domains that use path based routing mode and have a route configured for the prefix '/' on either port 80 or 443
|
|
@@ -321,6 +327,7 @@ cpflow maintenance:off -a $APP_NAME
|
|
|
321
327
|
### `maintenance:on`
|
|
322
328
|
|
|
323
329
|
- Enables maintenance mode for an app
|
|
330
|
+
- Safe to re-run: if a previous run timed out after switching the domain but before stopping the app workloads, re-running while maintenance mode is already enabled stops the app workloads to finish it (so it is not a pure no-op)
|
|
324
331
|
- Specify the one-off workload through `one_off_workload` in the `.controlplane/controlplane.yml` file
|
|
325
332
|
- Optionally specify the maintenance workload through `maintenance_workload` in the `.controlplane/controlplane.yml` file (defaults to 'maintenance')
|
|
326
333
|
- Maintenance mode is only supported for domains that use path based routing mode and have a route configured for the prefix '/' on either port 80 or 443
|
|
@@ -461,6 +468,8 @@ timeout 300 cpflow ps:wait -a $APP_NAME
|
|
|
461
468
|
and also overridden per job through `--cpu` and `--memory`)
|
|
462
469
|
- By default, the job is stopped if it takes longer than 6 hours to finish
|
|
463
470
|
(can be configured though `runner_job_timeout` in `controlplane.yml`)
|
|
471
|
+
- Non-interactive jobs return the Control Plane cron job status even when the job finishes before
|
|
472
|
+
Control Plane exposes a runner replica to attach logs to
|
|
464
473
|
|
|
465
474
|
```sh
|
|
466
475
|
# Opens shell (bash by default).
|
|
@@ -513,6 +522,7 @@ cpflow run -a $APP_NAME --entrypoint /app/alternative-entrypoint.sh -- rails db:
|
|
|
513
522
|
- Configures app to have org-level secrets with default name `"{APP_PREFIX}-secrets"`
|
|
514
523
|
using org-level policy with default name `"{APP_PREFIX}-secrets-policy"` (names can be customized, see docs)
|
|
515
524
|
- Creates identity for secrets if it does not exist
|
|
525
|
+
- Binds the app identity to any configured `shared_secret_grants` policies as part of the secrets setup flow; skipped when `--skip-secrets-setup` or `--skip-secret-access-binding` is provided, or `skip_secrets_setup` is set
|
|
516
526
|
- Use `--skip-secrets-setup` to prevent the automatic setup of secrets,
|
|
517
527
|
or set it through `skip_secrets_setup` in the `.controlplane/controlplane.yml` file
|
|
518
528
|
- Runs a post-creation hook after the app is created if `hooks.post_creation` is specified in the `.controlplane/controlplane.yml` file
|
|
@@ -544,7 +554,7 @@ cpflow terraform import
|
|
|
544
554
|
Regenerates the generated cpflow GitHub Actions wrappers and helper files
|
|
545
555
|
from the currently installed cpflow gem. Use this after updating the
|
|
546
556
|
cpflow gem so checked-in workflow wrappers move to the matching upstream
|
|
547
|
-
release tag, for example `v5.0
|
|
557
|
+
release tag, for example `v5.1.0`.
|
|
548
558
|
|
|
549
559
|
If the existing generated staging workflow uses a custom single staging
|
|
550
560
|
branch, the command preserves it. Pass `--staging-branch BRANCH` to set or
|
data/docs/postgres.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Migrating Postgres database from Heroku infrastructure
|
|
2
2
|
|
|
3
|
+
> **Networking note.** This guide is written against a *publicly reachable* RDS instance for simplicity of the
|
|
4
|
+
> Bucardo migration steps. For production, you almost certainly want RDS/Aurora in private subnets reached from
|
|
5
|
+
> Control Plane workloads via the Cloud Wormhole agent — see
|
|
6
|
+
> [Connecting Control Plane workloads to a private AWS RDS/Aurora database](./rds-private-networking.md). The
|
|
7
|
+
> Bucardo migration here still works against a private RDS once the network path is set up.
|
|
8
|
+
|
|
3
9
|
If you are replacing Heroku Postgres or another pre-provisioned database service, also review the
|
|
4
10
|
[Control Plane PostgreSQL Template Catalog page](https://shakadocs.controlplane.com/template-catalog/templates/postgres). The
|
|
5
11
|
catalog template covers a single-instance PostgreSQL workload with persistent storage, optional PgBouncer, and optional
|