cpflow 5.3.0 → 6.0.0
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/.agents/agent-workflow.yml +16 -25
- data/.agents/bin/README.md +19 -9
- data/.agents/bin/docs +1 -1
- data/.agents/bin/lint +1 -1
- data/.agents/bin/setup +1 -1
- data/.agents/bin/test +1 -1
- data/.agents/bin/validate +2 -1
- data/.agents/legacy-workflow-policy.yml +11 -0
- data/.agents/shaka.md +20 -0
- data/.agents/trusted-actions.yml +12 -0
- data/.coderabbit.yaml +14 -0
- data/.github/actions/cpflow-build-docker-image/action.yml +153 -22
- data/.github/actions/cpflow-delete-control-plane-app/action.yml +2 -1
- data/.github/actions/cpflow-delete-control-plane-app/delete-app.sh +3 -0
- data/.github/actions/cpflow-preview-promotion/action.yml +82 -0
- data/.github/actions/cpflow-preview-promotion/preview-promotion.sh +90 -0
- data/.github/actions/cpflow-setup-environment/action.yml +8 -6
- data/.github/dependabot.yml +10 -0
- data/.github/workflows/check_cpln_links.yml +6 -1
- data/.github/workflows/claude-code-review.yml +5 -2
- data/.github/workflows/claude.yml +6 -4
- data/.github/workflows/coderabbit-lifecycle-review.yml +29 -0
- data/.github/workflows/command_docs.yml +7 -2
- data/.github/workflows/cpflow-cleanup-stale-review-apps.yml +12 -5
- data/.github/workflows/cpflow-delete-review-app.yml +18 -11
- data/.github/workflows/cpflow-deploy-review-app.yml +38 -17
- data/.github/workflows/cpflow-deploy-staging.yml +28 -11
- data/.github/workflows/cpflow-help-command.yml +3 -3
- data/.github/workflows/cpflow-promote-staging-to-production.yml +135 -16
- data/.github/workflows/cpflow-review-app-help.yml +1 -1
- data/.github/workflows/rspec-shared.yml +34 -26
- data/.github/workflows/rspec-specific.yml +10 -2
- data/.github/workflows/rspec.yml +95 -4
- data/.github/workflows/rubocop.yml +9 -2
- data/.github/workflows/trigger-docs-site.yml +2 -0
- data/.rubocop.yml +6 -1
- data/AGENTS.md +18 -3
- data/CHANGELOG.md +39 -1
- data/CONTRIBUTING.md +39 -2
- data/Gemfile.lock +1 -1
- data/README.md +10 -2
- data/cpflow.gemspec +3 -15
- data/docs/ai-github-flow-prompt.md +3 -3
- data/docs/ci-automation.md +284 -68
- data/docs/commands.md +38 -15
- data/docs/postgres-review-apps.md +90 -0
- data/docs/postgres.md +233 -375
- data/docs/rds-private-networking.md +12 -12
- data/docs/releasing.md +15 -4
- data/docs/secrets-and-env-values.md +42 -0
- data/docs/sidebars.ts +1 -0
- data/examples/controlplane.yml +5 -0
- data/lib/command/ai_github_flow_prompt.rb +2 -2
- data/lib/command/apply_template.rb +36 -4
- data/lib/command/base.rb +56 -3
- data/lib/command/cleanup_stale_apps.rb +28 -4
- data/lib/command/copy_image_from_upstream.rb +3 -0
- data/lib/command/delete.rb +174 -4
- data/lib/command/deploy_image.rb +44 -1
- data/lib/command/generate.rb +247 -3
- data/lib/command/generate_github_actions.rb +43 -13
- data/lib/command/run.rb +224 -34
- data/lib/command/setup_app.rb +92 -10
- data/lib/command/update_github_actions.rb +82 -43
- data/lib/core/config.rb +73 -0
- data/lib/core/controlplane.rb +167 -80
- data/lib/core/controlplane_api.rb +28 -2
- data/lib/core/controlplane_api_direct.rb +17 -0
- data/lib/core/disposable_postgres_helpers.rb +167 -0
- data/lib/core/doctor_service.rb +7 -0
- data/lib/core/github_flow_readiness/checks.rb +2 -1
- data/lib/core/github_flow_readiness_service.rb +4 -0
- data/lib/core/repo_introspection.rb +112 -2
- data/lib/core/shell.rb +35 -10
- data/lib/core/timed_command.rb +111 -0
- data/lib/cpflow/version.rb +1 -1
- data/lib/cpflow.rb +1 -1
- data/lib/generator_templates/.dockerignore +16 -0
- data/lib/generator_templates/Dockerfile +9 -5
- data/lib/generator_templates/entrypoint.sh +2 -0
- data/lib/generator_templates/templates/postgres.yml +9 -0
- data/lib/generator_templates_sqlite/controlplane.yml +2 -1
- data/lib/generator_templates_sqlite/release_script.sh +1 -1
- data/lib/generator_templates_sqlite/templates/rails.yml +2 -1
- data/lib/github_flow_templates/.github/cpflow-help.md +39 -12
- data/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml +1 -0
- data/lib/github_flow_templates/.github/workflows/cpflow-deploy-staging.yml +1 -0
- data/lib/github_flow_templates/.github/workflows/cpflow-promote-staging-to-production.yml +135 -16
- data/lib/github_flow_templates/bin/pin-cpflow-github-ref +37 -13
- data/lib/github_flow_templates/bin/test-cpflow-github-flow +125 -46
- data/lib/patches/hash.rb +2 -2
- data/rakelib/create_release.rake +14 -14
- data/script/check_shell_scripts +66 -0
- metadata +18 -17
data/docs/commands.md
CHANGED
|
@@ -30,6 +30,7 @@ cpflow ai-github-flow-prompt
|
|
|
30
30
|
- Picks templates from the `.controlplane/templates` directory
|
|
31
31
|
- Templates are ordinary Control Plane templates but with variable preprocessing
|
|
32
32
|
- Use `--preserve-existing-runtime` to retain each workload container's configured app image, even when the workload is unready, and skip existing secret resources entirely while applying other template changes
|
|
33
|
+
- Use `--exclude-secret-template NAME` and `--exclude-policy-template NAME` to exclude exact named templates without changing workload image handling
|
|
33
34
|
- Missing or invalid workload images use only an unambiguous app image from ready workloads; refresh fails before applying templates when no safe fallback exists
|
|
34
35
|
|
|
35
36
|
**Preprocessed template variables:**
|
|
@@ -85,7 +86,7 @@ cpflow cleanup-images -a $APP_NAME
|
|
|
85
86
|
|
|
86
87
|
- Acts on stale apps based on the creation date of the latest image, or the GVC if no images exist
|
|
87
88
|
- 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)
|
|
88
|
-
- With `--mode=stop`: suspends
|
|
89
|
+
- With `--mode=stop`: suspends configured workloads that exist in the live GVC through Control Plane — no GVC, volumeset, or image is removed; resume with `cpflow ps:start`
|
|
89
90
|
- `--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
|
|
90
91
|
- `--mode=stop` returns once each workload is marked suspended; it does not wait for the workload to reach a not-ready state
|
|
91
92
|
- Specify the amount of days after an app should be considered stale through `stale_app_image_deployed_days` in the `.controlplane/controlplane.yml` file
|
|
@@ -135,6 +136,7 @@ cpflow copy-image-from-upstream -a $APP_NAME --upstream-token $UPSTREAM_TOKEN --
|
|
|
135
136
|
- Deletes the whole app (GVC with all workloads, all volumesets and all images) or a specific workload
|
|
136
137
|
- 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)
|
|
137
138
|
- For the app-specific secrets policy, removes every permission held by the app identity; for `shared_secret_grants`, removes only `reveal`
|
|
139
|
+
- Removes a marked per-app dictionary and exact-target unbound policy for generated review credentials, including after the opt-in is removed from a dynamically matched review-app entry
|
|
138
140
|
- Will ask for explicit user confirmation
|
|
139
141
|
- Runs a pre-deletion hook before the app is deleted if `hooks.pre_deletion` is specified in the `.controlplane/controlplane.yml` file
|
|
140
142
|
- If the hook exits with a non-zero code, the command will stop executing and also exit with a non-zero code
|
|
@@ -217,7 +219,7 @@ Creates base Control Plane config and template files for a Rails project:
|
|
|
217
219
|
- infers the app prefix from the current directory and wires staging, review, and production entries
|
|
218
220
|
- infers the Docker base Ruby version from `.ruby-version`, `.tool-versions`, or the app's `Gemfile`
|
|
219
221
|
- preserves repo-defined asset precompile hooks, including React on Rails auto bundle generation
|
|
220
|
-
- detects SQLite in `config/database.yml` and generates persistent `
|
|
222
|
+
- detects SQLite in `config/database.yml` and generates persistent `/app/data` and `/app/storage` volume templates without hiding image migrations under `/app/db`
|
|
221
223
|
|
|
222
224
|
```sh
|
|
223
225
|
# Creates .controlplane directory with Control Plane config and starter templates
|
|
@@ -232,6 +234,9 @@ Creates GitHub Actions templates for a Heroku Flow style Control Plane pipeline:
|
|
|
232
234
|
- manual promotion from staging to production
|
|
233
235
|
- nightly cleanup and PR help workflows
|
|
234
236
|
|
|
237
|
+
It also copies cpflow's composite actions into `.github/actions/cpflow-*`
|
|
238
|
+
so every local `uses:` target is checked in and can be audited directly.
|
|
239
|
+
|
|
235
240
|
Pass `--staging-branch BRANCH` when staging should auto-deploy from a branch
|
|
236
241
|
other than `main` or `master`; the generator will bake that branch into the
|
|
237
242
|
GitHub Actions push trigger and use it as the default STAGING_APP_BRANCH.
|
|
@@ -240,13 +245,13 @@ Pass `--force` to overwrite existing generated files. Prefer
|
|
|
240
245
|
repo.
|
|
241
246
|
|
|
242
247
|
```sh
|
|
243
|
-
# Creates
|
|
248
|
+
# Creates workflow wrappers, local composite actions, and validation helpers
|
|
244
249
|
cpflow generate-github-actions
|
|
245
250
|
|
|
246
251
|
# Creates the flow with staging deploys triggered from develop
|
|
247
252
|
cpflow generate-github-actions --staging-branch develop
|
|
248
253
|
|
|
249
|
-
# Overwrites existing generated
|
|
254
|
+
# Overwrites existing generated GitHub Actions files from the installed cpflow gem
|
|
250
255
|
cpflow generate-github-actions --force
|
|
251
256
|
```
|
|
252
257
|
|
|
@@ -483,6 +488,12 @@ timeout 300 cpflow ps:wait -a $APP_NAME
|
|
|
483
488
|
(can be configured though `runner_job_timeout` in `controlplane.yml`)
|
|
484
489
|
- Waiting for a runner replica is limited to the smaller of `runner_job_timeout` and 1000 seconds.
|
|
485
490
|
A terminal cron status fails immediately, and reaching the observation deadline reports the last safe status
|
|
491
|
+
- With non-interactive log methods 2 and 3, after a command prints its completion marker, Control Plane
|
|
492
|
+
has up to 20 minutes to reconcile the cron job to a terminal status. This can be configured through
|
|
493
|
+
`runner_job_status_reconciliation_timeout` in `controlplane.yml`; timing out exits nonzero and reports
|
|
494
|
+
the job, replica, and last observed status
|
|
495
|
+
- Log method 1 does not emit a completion marker, so its job-status polling is not covered by the
|
|
496
|
+
post-command reconciliation timeout
|
|
486
497
|
- Non-interactive jobs return the Control Plane cron job status even when the job finishes before
|
|
487
498
|
Control Plane exposes a runner replica to attach logs to
|
|
488
499
|
- Injects `CPFLOW_GVC_ID` and `CPFLOW_GVC_CREATED` into the job, exposing the app's immutable GVC
|
|
@@ -549,13 +560,14 @@ cpflow run -a $APP_NAME --entrypoint /app/alternative-entrypoint.sh -- rails db:
|
|
|
549
560
|
- Configures app to have org-level secrets with default name `"{APP_PREFIX}-secrets"`
|
|
550
561
|
using org-level policy with default name `"{APP_PREFIX}-secrets-policy"` (names can be customized, see docs)
|
|
551
562
|
- Creates identity for secrets if it does not exist
|
|
563
|
+
- For dynamically named review apps with `generated_review_secret_keys`, checks an existing policy before writing credentials, creates a per-app dictionary, skips its secret template during initial setup, and fills missing disposable keys without printing or rotating values
|
|
552
564
|
- 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
|
|
553
565
|
- Use `--skip-secrets-setup` to prevent the automatic setup of secrets,
|
|
554
566
|
or set it through `skip_secrets_setup` in the `.controlplane/controlplane.yml` file
|
|
555
567
|
- Runs a post-creation hook after the app is created if `hooks.post_creation` is specified in the `.controlplane/controlplane.yml` file
|
|
556
568
|
- If the hook exits with a non-zero code, the command will stop executing and also exit with a non-zero code
|
|
557
569
|
- Use `--skip-post-creation-hook` to skip the hook if specified in `controlplane.yml`
|
|
558
|
-
- Use `--refresh-templates` to apply configured templates noninteractively to an existing app while preserving each workload's configured app image even when workloads are unready or use mixed image versions, skipping existing secret
|
|
570
|
+
- Use `--refresh-templates` to apply configured templates noninteractively to an existing app while preserving each workload's configured app image even when workloads are unready or use mixed image versions, skipping existing secret templates (but filling missing opt-in generated review keys), repairing secrets access bindings, and skipping the post-creation hook
|
|
559
571
|
|
|
560
572
|
```sh
|
|
561
573
|
cpflow setup-app -a $APP_NAME
|
|
@@ -579,24 +591,35 @@ cpflow terraform import
|
|
|
579
591
|
|
|
580
592
|
### `update-github-actions`
|
|
581
593
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
594
|
+
Refreshes local composite actions and helper files from the installed gem.
|
|
595
|
+
All top-level workflows are preserved by default, including their refs,
|
|
596
|
+
triggers, permissions, and deployment ownership. Use --workflows FILE...
|
|
597
|
+
to explicitly add or replace named generated workflows. Replacement resets
|
|
598
|
+
each selected workflow to its template and matching v6.0.0 ref;
|
|
599
|
+
review and reapply any downstream customizations in the same PR.
|
|
600
|
+
|
|
601
|
+
Selecting cpflow-deploy-staging.yml preserves a single existing push branch
|
|
602
|
+
or the default main/master pair. Missing or ambiguous branches require
|
|
603
|
+
--staging-branch BRANCH. This option requires selecting the staging workflow.
|
|
586
604
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
605
|
+
A differing existing bin/test-cpflow-github-flow blocks all writes. Move
|
|
606
|
+
downstream checks to executable bin/test-cpflow-github-flow-custom and
|
|
607
|
+
remove or rename the old validator before updating. The generated validator
|
|
608
|
+
invokes that extension after its baseline checks; the extension is never
|
|
609
|
+
generated or overwritten. See docs/ci-automation.md for migration guidance.
|
|
590
610
|
|
|
591
611
|
```sh
|
|
592
|
-
#
|
|
612
|
+
# Refresh actions/helpers while preserving downstream workflows
|
|
593
613
|
cpflow update-github-actions
|
|
594
614
|
|
|
595
615
|
# When running cpflow through Bundler
|
|
596
616
|
bundle exec cpflow update-github-actions
|
|
597
617
|
|
|
598
|
-
#
|
|
599
|
-
cpflow update-github-actions --
|
|
618
|
+
# Explicitly replace the review-app wrapper
|
|
619
|
+
cpflow update-github-actions --workflows cpflow-deploy-review-app.yml
|
|
620
|
+
|
|
621
|
+
# Explicitly add or replace staging deployment from develop
|
|
622
|
+
cpflow update-github-actions --workflows cpflow-deploy-staging.yml --staging-branch develop
|
|
600
623
|
```
|
|
601
624
|
|
|
602
625
|
### `version`
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# PostgreSQL for disposable review apps
|
|
2
|
+
|
|
3
|
+
Use the generated `.controlplane/templates/postgres.yml` for a PostgreSQL workload
|
|
4
|
+
that belongs to one disposable review app. For production database migration, see
|
|
5
|
+
[Migrating PostgreSQL from Heroku to RDS](./postgres.md).
|
|
6
|
+
|
|
7
|
+
## Enable cleanup for new review apps
|
|
8
|
+
|
|
9
|
+
The generated template marks three helper resources:
|
|
10
|
+
|
|
11
|
+
| Resource | Purpose |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| `<APP>-pg` | Credential dictionary |
|
|
14
|
+
| `<APP>-pg-script` | Initialization-script secret |
|
|
15
|
+
| `<APP>-pg-access` | Policy granting access to those secrets |
|
|
16
|
+
|
|
17
|
+
Each helper template carries this tag:
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
tags:
|
|
21
|
+
cpflow-disposable-postgres-app: "{{APP_NAME}}"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`cpflow apply-template` retains the tag for dynamically named review apps and removes
|
|
25
|
+
it for persistent apps. In an existing project, add the tag to all three helper
|
|
26
|
+
**templates before creating new review apps**. Reapplying a marked template to an
|
|
27
|
+
existing unmarked resource is refused; it does not adopt that resource.
|
|
28
|
+
|
|
29
|
+
Before opting in, check that your deployment token can:
|
|
30
|
+
|
|
31
|
+
- Read and delete the three helper resources.
|
|
32
|
+
- Read each secret's effective access report (`viewAccessReport` on the org).
|
|
33
|
+
|
|
34
|
+
A missing or incomplete access report blocks cleanup before app data is deleted.
|
|
35
|
+
|
|
36
|
+
## Delete an app
|
|
37
|
+
|
|
38
|
+
Run the normal app deletion command:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
cpflow delete -a APP_NAME
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Cleanup validates the helpers before deleting app data. It removes the marked
|
|
45
|
+
policy and secrets before deleting the GVC. Deleting a single workload with
|
|
46
|
+
`cpflow delete -a APP_NAME -w WORKLOAD_NAME` preserves the helpers.
|
|
47
|
+
|
|
48
|
+
The ownership checks require:
|
|
49
|
+
|
|
50
|
+
- The same app marker on every surviving helper.
|
|
51
|
+
- A policy targeting exactly the two helper secrets.
|
|
52
|
+
- Only `reveal` grants in that policy, for the app and PostgreSQL identities in the
|
|
53
|
+
app's GVC.
|
|
54
|
+
- No helper listed in `shared_secret_grants`.
|
|
55
|
+
- No effective secret access through another application policy or identity.
|
|
56
|
+
|
|
57
|
+
Reapplying marked helpers with `cpflow apply-template` uses the same checks.
|
|
58
|
+
|
|
59
|
+
## Understand a cleanup refusal
|
|
60
|
+
|
|
61
|
+
Cleanup preserves resources when a marker, policy, or access report cannot establish
|
|
62
|
+
exclusive ownership. A refusal aborts whole-app deletion before live app data is
|
|
63
|
+
deleted. Fix the reported condition before retrying; do not remove a
|
|
64
|
+
sharing grant until you know which applications depend on it.
|
|
65
|
+
|
|
66
|
+
| Condition | Result |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| All helpers are unmarked legacy resources | App deletion proceeds; helpers are preserved |
|
|
69
|
+
| Marked and unmarked helpers coexist | Cleanup refuses deletion |
|
|
70
|
+
| A marker names another app | Cleanup refuses deletion |
|
|
71
|
+
| Policy targets or principals differ from the expected app scope | Cleanup refuses deletion |
|
|
72
|
+
| A helper is configured as shared | Cleanup refuses deletion |
|
|
73
|
+
| Secret access reports are unavailable or incomplete | Cleanup refuses deletion |
|
|
74
|
+
|
|
75
|
+
The access checks include permissions implied by `edit` or `manage`. Global `manage`
|
|
76
|
+
grants to org groups, users, or service accounts count as org administration.
|
|
77
|
+
Targeted or query grants, and grants to other GVC identities, block cleanup.
|
|
78
|
+
|
|
79
|
+
For shared staging credentials, use the
|
|
80
|
+
[shared-secret configuration guide](./secrets-and-env-values.md#shared-secrets-for-review-apps)
|
|
81
|
+
instead of marking them as disposable helpers.
|
|
82
|
+
|
|
83
|
+
## Recover after interruption
|
|
84
|
+
|
|
85
|
+
Repeat `cpflow delete` with the same app name. Cleanup tolerates an already absent
|
|
86
|
+
GVC, policy, or secret and rechecks the surviving helpers before deleting them.
|
|
87
|
+
|
|
88
|
+
Unmarked legacy helpers need manual cleanup after you establish that no other app
|
|
89
|
+
uses them. Rolling back to an older cpflow version leaves the tags in place but
|
|
90
|
+
stops automatic helper cleanup.
|