cpflow 5.2.0 → 6.0.0.rc.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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.agents/agent-workflow.yml +26 -2
  3. data/.agents/bin/README.md +16 -4
  4. data/.agents/bin/docs +1 -1
  5. data/.agents/bin/lint +1 -1
  6. data/.agents/bin/setup +1 -1
  7. data/.agents/bin/test +1 -1
  8. data/.agents/bin/validate +2 -1
  9. data/.coderabbit.yaml +13 -0
  10. data/.github/actions/cpflow-delete-control-plane-app/action.yml +2 -1
  11. data/.github/actions/cpflow-setup-environment/action.yml +9 -7
  12. data/.github/actions/cpflow-wait-for-health/action.yml +87 -15
  13. data/.github/dependabot.yml +10 -0
  14. data/.github/pull_request_template.md +18 -0
  15. data/.github/workflows/check_cpln_links.yml +6 -1
  16. data/.github/workflows/claude-code-review.yml +5 -2
  17. data/.github/workflows/claude.yml +97 -4
  18. data/.github/workflows/coderabbit-lifecycle-review.yml +29 -0
  19. data/.github/workflows/command_docs.yml +7 -2
  20. data/.github/workflows/cpflow-cleanup-stale-review-apps.yml +12 -5
  21. data/.github/workflows/cpflow-delete-review-app.yml +638 -43
  22. data/.github/workflows/cpflow-deploy-review-app.yml +665 -36
  23. data/.github/workflows/cpflow-deploy-staging.yml +16 -10
  24. data/.github/workflows/cpflow-help-command.yml +3 -3
  25. data/.github/workflows/cpflow-promote-staging-to-production.yml +7 -7
  26. data/.github/workflows/cpflow-review-app-help.yml +6 -14
  27. data/.github/workflows/rspec-shared.yml +34 -26
  28. data/.github/workflows/rspec-specific.yml +10 -2
  29. data/.github/workflows/rspec.yml +71 -4
  30. data/.github/workflows/rubocop.yml +9 -2
  31. data/.github/workflows/trigger-docs-site.yml +2 -0
  32. data/.rubocop.yml +6 -1
  33. data/AGENTS.md +6 -49
  34. data/CHANGELOG.md +56 -1
  35. data/CONTRIBUTING.md +48 -3
  36. data/Gemfile.lock +1 -1
  37. data/README.md +6 -1
  38. data/cpflow.gemspec +3 -15
  39. data/docs/ai-github-flow-prompt.md +2 -2
  40. data/docs/ci-automation.md +216 -99
  41. data/docs/commands.md +36 -9
  42. data/docs/rds-private-networking.md +12 -12
  43. data/docs/releasing.md +15 -4
  44. data/docs/secrets-and-env-values.md +8 -0
  45. data/docs/tips.md +18 -0
  46. data/examples/controlplane.yml +5 -0
  47. data/lib/command/ai_github_flow_prompt.rb +1 -1
  48. data/lib/command/apply_template.rb +104 -2
  49. data/lib/command/base.rb +52 -3
  50. data/lib/command/cleanup_stale_apps.rb +28 -4
  51. data/lib/command/copy_image_from_upstream.rb +3 -0
  52. data/lib/command/deploy_image.rb +54 -3
  53. data/lib/command/generate_github_actions.rb +36 -12
  54. data/lib/command/run.rb +357 -44
  55. data/lib/command/setup_app.rb +10 -5
  56. data/lib/command/update_github_actions.rb +7 -6
  57. data/lib/core/controlplane.rb +179 -79
  58. data/lib/core/controlplane_api.rb +8 -0
  59. data/lib/core/controlplane_api_direct.rb +257 -63
  60. data/lib/core/shell.rb +39 -7
  61. data/lib/core/timed_command.rb +111 -0
  62. data/lib/cpflow/version.rb +1 -1
  63. data/lib/cpflow.rb +1 -1
  64. data/lib/github_flow_templates/.github/cpflow-help.md +24 -10
  65. data/lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml +10 -0
  66. data/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml +9 -0
  67. data/lib/github_flow_templates/.github/workflows/cpflow-promote-staging-to-production.yml +7 -7
  68. data/lib/github_flow_templates/bin/test-cpflow-github-flow +63 -3
  69. data/lib/patches/hash.rb +2 -2
  70. data/rakelib/create_release.rake +14 -14
  71. data/script/check_shell_scripts +66 -0
  72. metadata +12 -18
data/CHANGELOG.md CHANGED
@@ -12,6 +12,58 @@ In addition to the standard keepachangelog.com categories, this project uses a l
12
12
 
13
13
  ## [Unreleased]
14
14
 
15
+ ## [6.0.0.rc.0] - 2026-09-06
16
+
17
+ ### Breaking Changes
18
+
19
+ - BREAKING CHANGE: Raised the minimum supported Ruby version from 3.0 to 3.2. Users on Ruby 3.0 or 3.1 must upgrade Ruby before installing the next major cpflow release. CI now tests each supported Ruby minor from 3.2 through 3.4. [PR 464](https://github.com/shakacode/control-plane-flow/pull/464) by [Justin Gordon](https://github.com/justin808).
20
+
21
+ ### Changed
22
+
23
+ - **Bumped the pinned GitHub Actions in the generated production-promotion workflow and this repository's reusable workflows to `actions/checkout` 7.0.1, `actions/github-script` 9.0.0, and `docker/setup-buildx-action` 4.3.0.** Downstream repositories pick up the template change with `cpflow update-github-actions`. [PR 460](https://github.com/shakacode/control-plane-flow/pull/460) by [Justin Gordon](https://github.com/justin808). Fixes [issue 459](https://github.com/shakacode/control-plane-flow/issues/459).
24
+ - **Changed generated GitHub Actions to check in cpflow's composite actions under `.github/actions/cpflow-*` and refresh them with `cpflow update-github-actions`.** Reusable workflows now load those local actions from the caller repository's trusted event revision, while the separately pinned checkout at `.cpflow` supplies the cpflow runtime source. Downstream repositories must commit generated workflows and local actions together when upgrading. [PR 451](https://github.com/shakacode/control-plane-flow/pull/451) by [Justin Gordon](https://github.com/justin808). Part of [issue 375](https://github.com/shakacode/control-plane-flow/issues/375).
25
+ - **Trimmed the RubyGems post-install message to a three-line generated-workflow reminder with a link to the full update and validation instructions.** [PR 447](https://github.com/shakacode/control-plane-flow/pull/447) by [Justin Gordon](https://github.com/justin808). Fixes [issue 377](https://github.com/shakacode/control-plane-flow/issues/377).
26
+
27
+ ### Fixed
28
+
29
+ - **Kept no-argument releases pinned to the latest changelog version during retries, and blocked implicit prerelease-to-stable promotion.** If an interrupted release already bumped the gem version or created its tag, rerunning `bundle exec rake release` no longer falls through to a stable release that is absent from the changelog. [PR 472](https://github.com/shakacode/control-plane-flow/pull/472) by [Justin Gordon](https://github.com/justin808).
30
+ - **Loaded the caller's generated `.github/actions/cpflow-*` through `actions/checkout`'s trusted default in the reusable review-app deploy, delete, and stale-cleanup workflows.** Dropping the explicit `ref:` still resolves to the revision GitHub already recorded for the triggering event (`GITHUB_SHA`, the base-branch tip under `pull_request_target`), and a default checkout is never inspected by the fork-PR checkout guard added in `actions/checkout` 7.0.0. The previous explicit `github.event.pull_request.base.sha` pin in the delete workflow could trip that guard, and fail teardown, when a fork PR was closed by a manual fast-forward that left the recorded base SHA equal to the PR head. Review-app teardown consequently runs the base-tip copy of the generated actions rather than the pull request's recorded pre-merge base, which matters only if the merge itself changed those actions. Downstream repositories pick up the change when `cpflow update-github-actions` bumps the reusable-workflow ref. [PR 467](https://github.com/shakacode/control-plane-flow/pull/467) by [Justin Gordon](https://github.com/justin808). Fixes [issue 463](https://github.com/shakacode/control-plane-flow/issues/463).
31
+ - **Gave `pull_request_target` an explicit branch in the reusable review-app deploy source validator.** The reusable workflow's event allowlist admits `pull_request_target`, but the deploy source validator handled only `pull_request` and `issue_comment`. It now treats `pull_request_target` exactly like `pull_request`, skipping fork pull requests with the documented deploy-skipped summary, as defence-in-depth for callers that rewire the deploy trigger. The shipped caller templates never send that event, so no existing deployment behavior changes and same-repository pull requests are unaffected. [PR 467](https://github.com/shakacode/control-plane-flow/pull/467) by [Justin Gordon](https://github.com/justin808). Fixes [issue 462](https://github.com/shakacode/control-plane-flow/issues/462).
32
+ - **Prevented shell interpretation of dynamic Control Plane CLI and Docker arguments.** Resource names, image references, container names, locations, and other dynamic values now remain literal argv elements; output suppression and stderr capture use process redirection options without rebuilding a shell command. Fixes [issue 452](https://github.com/shakacode/control-plane-flow/issues/452). [PR 458](https://github.com/shakacode/control-plane-flow/pull/458) by [Justin Gordon](https://github.com/justin808).
33
+ - **Fixed scheduled slow-suite regressions in stale-app workload suspension, invalid upstream-token handling, transient workload image deployment, and delayed one-off job output.** `cleanup-stale-apps --mode=stop` now skips configured workloads absent from a stale app, upstream authorization failures cleanly remove their temporary profile and stderr capture, workload image updates retry for a bounded window before failing, and non-interactive `cpflow run` commands drain logs for a bounded post-terminal window so delayed ingestion does not drop completed job output. Slow-suite command logs and failure artifacts now redact token options and explicitly supplied sensitive values. [PR 413](https://github.com/shakacode/control-plane-flow/pull/413) by [Justin Gordon](https://github.com/justin808). Addresses [issue 409](https://github.com/shakacode/control-plane-flow/issues/409).
34
+ - **Queued every pending shared-org Slow and Specific RSpec run instead of letting GitHub replace an older waiter.** Fast runs keep their per-PR or per-ref queue, while the domain-mutating suites use GitHub's bounded `queue: max` behavior in one repository-wide concurrency group. [PR 457](https://github.com/shakacode/control-plane-flow/pull/457) by [Justin Gordon](https://github.com/justin808). Fixes [issue 403](https://github.com/shakacode/control-plane-flow/issues/403).
35
+ - **Bounded `cpflow run` status reconciliation after a non-interactive command finishes.** When Control Plane keeps reporting a cron job as active or pending after the command completion marker, `cpflow run` now waits up to a configurable 20-minute grace period and then exits nonzero with the job, replica, and last observed status instead of polling forever. Addresses the bounded-reconciliation portion of [HiChee issue 10375](https://github.com/shakacode/hichee/issues/10375). [PR 453](https://github.com/shakacode/control-plane-flow/pull/453) by [Justin Gordon](https://github.com/justin808).
36
+
37
+ ## [5.3.0] - 2026-09-02
38
+
39
+ ### Added
40
+
41
+ - **Added an early diagnostic warning when a `shared_secret_grants` target still uses the generated Postgres password placeholder.** `setup-app` and `deploy-image` now identify the affected grant and secret before release or deployment work without printing secret values. [PR 441](https://github.com/shakacode/control-plane-flow/pull/441) by [Justin Gordon](https://github.com/justin808). Fixes [issue 421](https://github.com/shakacode/control-plane-flow/issues/421).
42
+ - **Added `CPFLOW_GVC_ID` and `CPFLOW_GVC_CREATED` to the environment of one-off jobs started by `cpflow run`, exposing the app's immutable GVC identity so that a release script can tell which GVC incarnation it is running in.** [PR 433](https://github.com/shakacode/control-plane-flow/pull/433) by [Justin Gordon](https://github.com/justin808). Fixes [issue 432](https://github.com/shakacode/control-plane-flow/issues/432). Unlike the mutable `CPLN_GVC_ALIAS`, these values identify the GVC incarnation itself, so they change only when a GVC is deleted and recreated under the same name. `CPFLOW_GVC_CREATED` is an ISO 8601 UTC timestamp with millisecond precision and a `Z` suffix. Both variables are always set and are empty when the GVC cannot be read, so a consumer can fail closed; they are never omitted, because the runner inherits the original workload's environment and an omitted variable could otherwise expose a stale inherited value.
43
+ - **Added bounded retry with exponential backoff to direct Control Plane API requests.** [PR 416](https://github.com/shakacode/control-plane-flow/pull/416) by [Justin Gordon](https://github.com/justin808). Fixes [issue 383](https://github.com/shakacode/control-plane-flow/issues/383). With the default request policy, `GET` requests retry transient network errors and retryable HTTP responses for up to three attempts; another attempt is approved only when the retry decision occurs before a 120-second deadline. Delta-seconds `Retry-After` values are honored up to a 10-second cap; HTTP-date values fall back to jittered backoff. Under that policy, explicit HTTP 429 responses are retried for every method. Best-effort sensitive requests disable all transient retries. Mutating requests are not retried after ambiguous transport failures once they may have reached the server. Net::HTTP's hidden resend of `PUT` and `DELETE` requests is disabled. A failed `cpln profile token` lookup now raises an actionable error instead of continuing with unusable output.
44
+
45
+ ### Changed
46
+
47
+ - **Simplified generated review-app help comments to a three-command quick reference, moved setup behind expandable details, and clarified GitHub Actions secret and variable terminology.** [PR 410](https://github.com/shakacode/control-plane-flow/pull/410) by [Justin Gordon](https://github.com/justin808).
48
+ - **Updated reusable GitHub Actions setup to install Control Plane CLI 3.11.0 by default.** [PR 423](https://github.com/shakacode/control-plane-flow/pull/423) by [Justin Gordon](https://github.com/justin808).
49
+
50
+ ### Fixed
51
+
52
+ - **Fixed `cpflow run` runner observation so a missing replica no longer relies on the generic 1,001-poll retry loop or exits without the cron status.** [PR 435](https://github.com/shakacode/control-plane-flow/pull/435) by [Justin Gordon](https://github.com/justin808). Replica observation now uses a monotonic deadline capped by the smaller of `runner_job_timeout` and 1,000 seconds, stops polling when that deadline is reached, fails immediately on terminal non-success, and preserves replica-found and success-before-replica behavior.
53
+ - **Fixed review-app deploy and delete authorization failing while recording accepted intent comments.** [PR 449](https://github.com/shakacode/control-plane-flow/pull/449) by [Justin Gordon](https://github.com/justin808). The authorization job now has the PR write permission GitHub requires to post bot-owned comments on pull requests. Follow-up to [issue 442](https://github.com/shakacode/control-plane-flow/issues/442).
54
+ - **Made successful review-app checks report when they skipped the Docker image build.** [PR 444](https://github.com/shakacode/control-plane-flow/pull/444) by [Justin Gordon](https://github.com/justin808). Fixes [issue 412](https://github.com/shakacode/control-plane-flow/issues/412). The reusable workflow now writes a prominent no-build summary and exposes `image_built=false`, while generated guidance explains that repositories needing Dockerfile validation should use a separate required build gate.
55
+ - **Fixed `cpflow run` argument corruption and shell interpolation when command arguments contain spaces, quotes, dollar signs, backticks, or semicolons.** [PR 443](https://github.com/shakacode/control-plane-flow/pull/443) by [Justin Gordon](https://github.com/justin808). Fixes [issue 381](https://github.com/shakacode/control-plane-flow/issues/381). Separately supplied arguments are shell-escaped at the remote runner boundary, while one quoted command string remains an explicit opt-in to shell syntax; the local `cpln workload exec` invocation now uses process argv instead of a shell-built command string.
56
+ - **Fixed generated review-app deploy and delete commands so only the newest accepted operation can mutate an app, even when GitHub replaces a pending concurrency run or authorization finishes out of order.** [PR 440](https://github.com/shakacode/control-plane-flow/pull/440) by [Justin Gordon](https://github.com/justin808). Fixes [issue 427](https://github.com/shakacode/control-plane-flow/issues/427). GitHub now verifies manual actors have current `write`, `maintain`, or `admin` repository permission both before and after queueing, rejects closed-PR deploys before recording, records accepted triggers as durable bot-owned intents, authenticates each intent against its originating Actions run and successful recording step, binds internal redispatches to the workflow-run ID returned by GitHub and its exact successful dispatch step, and fails closed on lookup or ledger inconsistencies. Edits or deletion of the original command, mixed-case command admission, manual dispatch, and GitHub's single replaceable pending concurrency slot can no longer make an older deploy override a newer delete (or the reverse). After upgrading, run `cpflow update-github-actions` so the generated deploy and delete caller workflows adopt the new `run-name` and `reconcile_intent_run_id` contract; a caller that only bumps the `uses:` ref is rejected during provenance reconciliation.
57
+ - **Fixed direct Control Plane API retries so HTTP 429 responses retry every request method and honor `Retry-After`, while 5xx retries remain limited to idempotent methods.** [PR 439](https://github.com/shakacode/control-plane-flow/pull/439) by [Justin Gordon](https://github.com/justin808). Fixes [issue 417](https://github.com/shakacode/control-plane-flow/issues/417).
58
+ - **Fixed the spec suite leaking `dummy-test-*` GVCs that exhausted the CI org's GVC quota and blocked later runs.** [PR 434](https://github.com/shakacode/control-plane-flow/pull/434) by [Justin Gordon](https://github.com/justin808). Fixes [issue 399](https://github.com/shakacode/control-plane-flow/issues/399). Apps are now registered for `after(:suite)` cleanup by the command runner before an app-creating command runs, so a command that fails after creating the GVC, or an example that fails before its own teardown, no longer leaves the app behind. A `before(:suite)` sweep additionally reclaims apps leaked by runs that were killed before cleanup could run. The sweep is confined to the suite's own org and to the anchored `dummy-test-*` fixture naming boundary, never touches an app younger than 12 hours or one belonging to the current run, keeps anything it cannot positively identify as stale, and reports rather than raises on failure. This change is limited to the spec suite; no gem behavior changes.
59
+ - **Fixed review-app deletion leaving successful GitHub deployments active after the Control Plane app was removed.** [PR 430](https://github.com/shakacode/control-plane-flow/pull/430) by [Justin Gordon](https://github.com/justin808).
60
+ - **Fixed template refreshes for existing apps whose workload-list response omits readiness status by consulting each workload's detailed state before selecting a safe fallback image.** [PR 429](https://github.com/shakacode/control-plane-flow/pull/429) by [Justin Gordon](https://github.com/justin808).
61
+ - **Fixed reusable deployment health checks on BYOK locations by falling back from a disabled standard workload endpoint only after every location is settled, while preserving configured `app_domain` review-app links and using the verified location endpoint as the final URL fallback.** [PR 426](https://github.com/shakacode/control-plane-flow/pull/426) by [Justin Gordon](https://github.com/justin808).
62
+ - **Fixed template refresh recovery for unhealthy or partially deployed review apps by preserving each workload's configured app image independently, while limiting missing-image fallbacks to one unambiguous image from ready workloads.** [PR 425](https://github.com/shakacode/control-plane-flow/pull/425) by [Justin Gordon](https://github.com/justin808).
63
+ - **Fixed reusable review-app deployments so existing apps receive changes from configured `setup_app_templates` before the new image is deployed, without deleting the GVC, rerunning post-creation hooks, replacing deployed images before rollout gates pass, or modifying existing secret resources.** [PR 424](https://github.com/shakacode/control-plane-flow/pull/424) by [Justin Gordon](https://github.com/justin808).
64
+ - **Fixed `cpflow deploy-image` crashing when an internal-only workload has no public endpoint.** Deployments now consult the existing deployment fallback and report when no public endpoint is available. [PR 423](https://github.com/shakacode/control-plane-flow/pull/423) by [Justin Gordon](https://github.com/justin808).
65
+ - **Fixed generated review-app status links so reusable deployments prefer the deployed app domain instead of the raw Control Plane workload endpoint.** [PR 395](https://github.com/shakacode/control-plane-flow/pull/395) by [Justin Gordon](https://github.com/justin808).
66
+
15
67
  ## [5.2.0] - 2026-07-10
16
68
 
17
69
  ### Added
@@ -19,6 +71,7 @@ In addition to the standard keepachangelog.com categories, this project uses a l
19
71
  - **Added ordered per-workload deploys with repeatable `cpflow deploy-image -w/--workload` filtering and optional `deploy_order` groups in `controlplane.yml`.** [PR 397](https://github.com/shakacode/control-plane-flow/pull/397) by [Justin Gordon](https://github.com/justin808). Fixes [issue 396](https://github.com/shakacode/control-plane-flow/issues/396). `cpflow deploy-image` can now deploy selected app workloads, and production promotion inherits `deploy_order` so workloads such as a Node renderer can roll out and become ready before Rails.
20
72
  - **Added generic telemetry documentation for deploying an OpenTelemetry Collector with Control Plane Flow, including collector workload templates, application instrumentation, telemetry pipelines, review-app isolation, and troubleshooting guidance.** [PR 369](https://github.com/shakacode/control-plane-flow/pull/369) by [Justin Gordon](https://github.com/justin808).
21
73
  - **Added a Rails-focused Grafana and OpenTelemetry guide for building Control Plane dashboards from generated span and log metrics, including collector workload guidance, spanmetrics setup, rollout order, alerting, and validation checklists.** [PR 352](https://github.com/shakacode/control-plane-flow/pull/352) by [Justin Gordon](https://github.com/justin808).
74
+ - **Added review-app security documentation for repositories with external contributors, covering disposable secrets, PR-controlled identity and policy templates, and staging-token least privilege.** [PR 350](https://github.com/shakacode/control-plane-flow/pull/350) by [Justin Gordon](https://github.com/justin808).
22
75
 
23
76
  ### Changed
24
77
 
@@ -443,7 +496,9 @@ Deprecated `cpl` gem. New gem is `cpflow`.
443
496
 
444
497
  First release.
445
498
 
446
- [Unreleased]: https://github.com/shakacode/control-plane-flow/compare/v5.2.0...main
499
+ [Unreleased]: https://github.com/shakacode/control-plane-flow/compare/v6.0.0.rc.0...main
500
+ [6.0.0.rc.0]: https://github.com/shakacode/control-plane-flow/compare/v5.3.0...v6.0.0.rc.0
501
+ [5.3.0]: https://github.com/shakacode/control-plane-flow/compare/v5.2.0...v5.3.0
447
502
  [5.2.0]: https://github.com/shakacode/control-plane-flow/compare/v5.1.1...v5.2.0
448
503
  [5.1.1]: https://github.com/shakacode/control-plane-flow/compare/v5.1.0...v5.1.1
449
504
  [5.1.0]: https://github.com/shakacode/control-plane-flow/compare/v5.0.4...v5.1.0
data/CONTRIBUTING.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Contributing
2
2
 
3
+ ## Before Opening a Pull Request
4
+
5
+ Please start with an open issue labeled `good first issue` or `help wanted`, or discuss the proposed change in an issue before investing significant work. Pull requests should link the accepted issue and explain the user problem or regression they address.
6
+
7
+ Small typo fixes are welcome without prior discussion. Unsolicited coverage-only changes, refactors, formatting or generated-file churn, dependency or workflow changes, and broad documentation rewrites may be closed when they do not address an accepted issue, a demonstrated regression, or a maintainer request.
8
+
9
+ Keep each pull request focused, include the relevant validation, and update tests, documentation, and `CHANGELOG.md` when the change affects them. Contributors remain responsible for reviewing and understanding everything they submit, including AI-assisted content and automated review suggestions.
10
+
3
11
  ## Installation
4
12
 
5
13
  Rather than installing `cpflow` as a Ruby gem, install this repo locally and alias the `cpflow` command globally for easier
@@ -27,6 +35,43 @@ gem install overcommit
27
35
  overcommit --install
28
36
  ```
29
37
 
38
+ ## GitHub Actions Dependencies
39
+
40
+ Every repository-based external `uses:` entry under `.github/workflows/` or `.github/actions/` must use an immutable,
41
+ lowercase 40-character commit SHA followed by the exact release tag in a same-line comment. Do not use moving
42
+ major-version tags or branch names. New action repositories also require explicit review before they are added to
43
+ `trusted_actions` in `.agents/agent-workflow.yml`. Docker actions must use an exact `sha256:` image digest; manually
44
+ review the registry, image, and digest because Docker references are outside the repository allowlist.
45
+ Generated downstream calls to Control Plane Flow's cross-repository reusable workflows are the deliberate exception:
46
+ they use an exact `vX.Y.Z` release tag so the workflow source stays aligned with the released `cpflow` gem.
47
+
48
+ Dependabot checks GitHub Actions dependencies weekly. For each proposed update, verify that the release tag resolves to
49
+ the proposed commit, review the upstream release and diff, and keep the version comment synchronized with the pin.
50
+ Dependabot-authored runs receive no repository secrets, so `RSpec (Fast)` fails at `Setup Control Plane tools`. The
51
+ credential-free `Ruby 3.3 compatibility` and `Ruby 3.4 compatibility` jobs do run
52
+ `spec/github_actions_dependency_policy_spec.rb`, so a bump that leaves the generated templates or the
53
+ `EXPECTED_CPFLOW_CHECKOUT_ACTION` constant behind still fails there, even on a Dependabot-authored pull request that
54
+ cannot run the credentialed suite. A Dependabot bump is therefore never merged directly: a maintainer opens a pull
55
+ request that supersedes it and lands the same pin. That maintainer pull request must update the pin in all four places,
56
+ or CI fails:
57
+
58
+ - `.github/workflows/**` and `.github/actions/**` — the workflows that actually run in this repository.
59
+ - `lib/github_flow_templates/.github/workflows/**` — the workflows generated into downstream repositories.
60
+ - `lib/github_flow_templates/bin/test-cpflow-github-flow` — the `EXPECTED_CPFLOW_CHECKOUT_ACTION` constant.
61
+ - `spec/command/generate_github_actions_spec.rb` and `spec/github_workflows_spec.rb` — the assertions that hard-code
62
+ the expected SHA.
63
+
64
+ `spec/github_actions_dependency_policy_spec.rb` guards the first three. It fails when a template occurrence's commit
65
+ SHA or version comment drifts from the repository pin for the same action, when a template `uses:` entry is left on a
66
+ mutable ref such as `@v7` or `@main`, or when a template pins an external action that the repository workflows do not
67
+ use. Only script constants such as `EXPECTED_CPFLOW_CHECKOUT_ACTION` and `docker://` image references may omit the
68
+ version comment, because neither is a workflow step with somewhere to hang a same-line release tag. Calls to cpflow's
69
+ own reusable workflows under `.github/workflows/` are the one exception to the commit-pin rule, and only for the
70
+ `@__CPFLOW_GITHUB_ACTIONS_REF__` generator placeholder or an exact release tag. `@main` and `@v5` fail, and so does any
71
+ other `shakacode/control-plane-flow` reference, such as `shakacode/control-plane-flow/some-action@v6.0.0` or the bare
72
+ repository, which must be commit-pinned like any external action. The literal `vX.Y.Z` is accepted only in the verifier
73
+ script's `EXPECTED_PROMOTE_WORKFLOW_REF_FORMAT` constant, never in a workflow step.
74
+
30
75
  ## Docs Site Dispatch
31
76
 
32
77
  The `trigger-docs-site.yml` workflow notifies `shakacode/controlplaneflow-com` when docs-related files change on `main`.
@@ -105,9 +150,9 @@ cpflow test
105
150
 
106
151
  ## Developing the GitHub flow generator
107
152
 
108
- `cpflow generate-github-actions` copies templates from `lib/github_flow_templates/` into a target repo's `.github/` directory. To work on this feature:
153
+ `cpflow generate-github-actions` copies workflow templates in `lib/github_flow_templates/` and canonical composite actions in `.github/actions/cpflow-*` into a target repo's `.github/` directory. To work on this feature:
109
154
 
110
- - **Edit the templates in place.** The generator does no string-mangling beyond a small set of substitutions handled in `lib/command/generate_github_actions.rb`; what you put in `lib/github_flow_templates/.github/` is (almost) exactly what ships into a generated repo. Make changes there, not in a generated copy.
155
+ - **Edit each canonical source in place.** The generator does no string-mangling beyond a small set of substitutions handled in `lib/command/generate_github_actions.rb`; what you put in `lib/github_flow_templates/.github/` is (almost) exactly what ships into a generated repo. Edit composite actions in the root `.github/actions/cpflow-*` directories. Make changes in those canonical sources, not in a generated copy.
111
156
  - **Surface area to keep consistent.** A change to a PR command (e.g. `+review-app-deploy`) usually touches three places: the trigger workflow (`lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml`), the PR-open quick reference (`cpflow-review-app-help.yml`), and the long-form help (`lib/github_flow_templates/.github/cpflow-help.md`). The AI flow prompt (`lib/command/ai_github_flow_prompt.rb`) also names commands and should be kept in sync.
112
157
  - **Run the generator spec on every change:**
113
158
 
@@ -117,7 +162,7 @@ cpflow test
117
162
 
118
163
  It generates the templates into a tmp playground and asserts on their contents — most regressions in the templates will fail there.
119
164
  - **Lint the templates.** Generated workflows are checked with `actionlint` in CI. Install it locally and run `actionlint lib/github_flow_templates/.github/workflows/*.yml` to catch issues before pushing.
120
- - **Test PR-branch workflow edits in a real repo.** Comment-triggered runs (`+review-app-deploy`, `+review-app-delete`, `+review-app-help`) execute the workflow code from the repository's default branch, so they will not exercise your PR-branch changes. Generate the workflows into a downstream test repo, push to a feature branch, then dispatch each affected workflow with `gh`:
165
+ - **Advanced: testing changes to generated workflows.** Comment-triggered runs (`+review-app-deploy`, `+review-app-delete`, `+review-app-help`) execute the workflow code from the repository's default branch, so they will not exercise your PR-branch changes. Generate the workflows into a downstream test repo, push to a feature branch, then dispatch each affected workflow with `gh`:
121
166
 
122
167
  ```sh
123
168
  gh workflow run cpflow-deploy-review-app.yml --ref <your-pr-branch> -f pr_number=<pr-number>
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cpflow (5.2.0)
4
+ cpflow (6.0.0.rc.0)
5
5
  dotenv (~> 3.1)
6
6
  jwt (~> 3.1)
7
7
  psych (~> 5.2)
data/README.md CHANGED
@@ -307,6 +307,11 @@ aliases:
307
307
  # If not specified, defaults to 21600 (6 hours).
308
308
  runner_job_timeout: 1000
309
309
 
310
+ # Sets how long `cpflow run` waits for Control Plane to reconcile a cron job status
311
+ # after the non-interactive command prints its completion marker.
312
+ # If not specified, defaults to 1200 (20 minutes).
313
+ runner_job_status_reconciliation_timeout: 1200
314
+
310
315
  # Apps with a deployed image, or an image-less GVC, created before this amount of days
311
316
  # will be listed for deletion when running the command `cpflow cleanup-stale-apps`.
312
317
  stale_app_image_deployed_days: 5
@@ -393,7 +398,7 @@ cpflow generate-github-actions
393
398
  bin/test-cpflow-github-flow
394
399
  ```
395
400
 
396
- `cpflow github-flow-readiness` exits non-zero when it finds blockers such as unpublished exact-pinned packages or a missing production Dockerfile, so use it as the gate before generation. Then review the generated `.controlplane/controlplane.yml` entries, adjust any app-specific workloads, and configure the GitHub repository variables and secrets described in [CI automation](./docs/ci-automation.md), including the optional Docker build settings for private GitHub dependencies and custom SSH known hosts. `cpflow generate-github-actions` also writes `bin/test-cpflow-github-flow` for local validation and `bin/pin-cpflow-github-ref` for temporarily pinning downstream wrappers to an upstream commit SHA during pre-release testing. `cpflow generate` already switches to persistent `db` and `storage` volumes when `config/database.yml` shows SQLite in production and preserves detected frontend precompile hooks, but you should still confirm that the generated Dockerfile picked a Ruby base image compatible with the app's declared Ruby requirement and that the emitted workload set matches the real app. If you want an AI agent to do this end to end, give it the [AI rollout prompt](./docs/ai-github-flow-prompt.md) rather than a vague "set up CI" request.
401
+ `cpflow github-flow-readiness` exits non-zero when it finds blockers such as unpublished exact-pinned packages or a missing production Dockerfile, so use it as the gate before generation. Then review the generated `.controlplane/controlplane.yml` entries, adjust any app-specific workloads, and configure the GitHub repository variables and secrets described in [CI automation](./docs/ci-automation.md), including the optional Docker build settings for private GitHub dependencies and custom SSH known hosts. `cpflow generate-github-actions` checks in the local `.github/actions/cpflow-*` implementations alongside the workflows, and also writes `bin/test-cpflow-github-flow` for local validation and `bin/pin-cpflow-github-ref` for temporarily pinning downstream wrappers to an upstream commit SHA during pre-release testing. `cpflow generate` already switches to persistent `db` and `storage` volumes when `config/database.yml` shows SQLite in production and preserves detected frontend precompile hooks, but you should still confirm that the generated Dockerfile picked a Ruby base image compatible with the app's declared Ruby requirement and that the emitted workload set matches the real app. If you want an AI agent to do this end to end, give it the [AI rollout prompt](./docs/ai-github-flow-prompt.md) rather than a vague "set up CI" request.
397
402
 
398
403
  For a live example, see the [react-webpack-rails-tutorial](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/readme.md) repository.
399
404
 
data/cpflow.gemspec CHANGED
@@ -14,23 +14,11 @@ Gem::Specification.new do |spec|
14
14
  spec.license = "MIT"
15
15
  spec.post_install_message = <<~MESSAGE
16
16
  cpflow #{Cpflow::VERSION} installed.
17
-
18
- If this repository already uses generated cpflow GitHub Actions, update the
19
- checked-in wrappers so GitHub loads the matching control-plane-flow release tag:
20
-
21
- cpflow update-github-actions
22
- bin/test-cpflow-github-flow
23
-
24
- If you run cpflow through Bundler:
25
-
26
- bundle exec cpflow update-github-actions
27
- bin/test-cpflow-github-flow bundle exec cpflow
28
-
29
- New repository? Run `cpflow generate-github-actions` first to create the
30
- wrappers (and the `bin/test-cpflow-github-flow` script referenced above).
17
+ Generated GitHub Actions users: run `cpflow update-github-actions` after upgrading.
18
+ Docs: https://github.com/shakacode/control-plane-flow/blob/main/docs/ci-automation.md#updating-generated-github-actions-after-gem-updates
31
19
  MESSAGE
32
20
 
33
- spec.required_ruby_version = ">= 3.0.0"
21
+ spec.required_ruby_version = ">= 3.2"
34
22
 
35
23
  spec.add_dependency "dotenv", "~> 3.1"
36
24
  spec.add_dependency "jwt", "~> 3.1"
@@ -10,7 +10,7 @@ first.
10
10
  ```text
11
11
  Set up Control Plane GitHub Flow for this repo. First make sure the `cpflow` CLI is available: use the repo's existing `bundle exec cpflow` if present, otherwise install the published `cpflow` Ruby gem with `gem install cpflow`; if neither is possible, stop and report that blocker. Use the same `cpflow` invocation for the rest of the rollout. 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.
12
12
 
13
- 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 normal generated review-app setup simple: review apps require only `CPLN_TOKEN_STAGING` when the generated review app config can be inferred. For public demos, starter staging apps, and long-lived review apps, keep the app workload `type: standard` with one warm replica, set its autoscaling metric to `disabled`, and enable `capacityAI: true` so Control Plane can right-size CPU and memory allocation at that fixed replica count. Shared Postgres and other stateful workloads are the usual exceptions and should stay manually sized; Capacity AI is for supported stateless app/service workloads. If true idle scale-to-zero is explicitly required, create a separate `serverless` workload before first deploy or plan a delete/recreate migration because Control Plane will not change an existing `standard` workload to `serverless` in place. 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.
13
+ 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. Keep every generated Control Plane Flow source pin synchronized at the same `vX.Y.Z`: each reusable-workflow `uses: ...@vX.Y.Z` ref, the production promotion `.cpflow` checkout ref, and its `control_plane_flow_ref` setup input. By default, `cpflow generate-github-actions` derives these values from the installed `cpflow` gem version; temporary explicit ref overrides are for unreleased testing and must keep all three values synchronized. Keep the generated `.github/actions/cpflow-*` files from that same gem unchanged; upstream reusable workflows invoke those checked-in local actions and separately check out the matching runtime source at `.cpflow`. 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 workflows and local actions move together. Keep the normal generated review-app setup simple: review apps require only `CPLN_TOKEN_STAGING` when the generated review app config can be inferred. For public demos, starter staging apps, and long-lived review apps, keep the app workload `type: standard` with one warm replica, set its autoscaling metric to `disabled`, and enable `capacityAI: true` so Control Plane can right-size CPU and memory allocation at that fixed replica count. Shared Postgres and other stateful workloads are the usual exceptions and should stay manually sized; Capacity AI is for supported stateless app/service workloads. If true idle scale-to-zero is explicitly required, create a separate `serverless` workload before first deploy or plan a delete/recreate migration because Control Plane will not change an existing `standard` workload to `serverless` in place. 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.
14
14
 
15
15
  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`.
16
16
 
@@ -46,7 +46,7 @@ Stop and report the blocker instead of generating `cpflow-*` workflow files when
46
46
  The rollout is done when all of the following are true:
47
47
 
48
48
  - `.controlplane/` exists and matches the actual app shape
49
- - `.github/cpflow-help.md` and `.github/workflows/cpflow-*` wrappers are in place
49
+ - `.github/cpflow-help.md`, `.github/workflows/cpflow-*`, and `.github/actions/cpflow-*` are in place
50
50
  - review apps are opt-in, staging auto-deploys from one branch, and production promotion is manual
51
51
  - required GitHub secrets and variables are documented for the repo
52
52
  - the production image build path is validated for the real app