Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .agents/agent-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@
base_branch: master
merge_submission:
mode: direct
trusted_actions:
- actions/checkout
- actions/github-script
- actions/setup-node
- anthropics/claude-code-action
- browser-actions/setup-chrome
- coactions/setup-xvfb
- docker/setup-buildx-action
- ruby/setup-ruby
- shakacode/control-plane-flow
- shakacode/react_on_rails
follow_up_prefix: 'Follow-up:'
review_gate: n/a
approval_exempt: n/a
Expand Down
5 changes: 5 additions & 0 deletions .controlplane/controlplane.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,10 @@ apps:
<<: *common
# match_if_app_name_starts_with is used to identify these "qa" apps.
match_if_app_name_starts_with: true
# These review-app one-off defaults request app-sized resources and set a
# 15-minute server-side active deadline.
runner_job_default_cpu: "300m"
runner_job_default_memory: "1Gi"
runner_job_timeout: 900
Comment thread
justin808 marked this conversation as resolved.
Comment thread
justin808 marked this conversation as resolved.
image_retention_days: 5
stale_app_image_deployed_days: 5 # If the app is older than 5 days, the nightly automations will clean stale apps.
66 changes: 51 additions & 15 deletions .controlplane/docs/testing-cpflow-github-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,71 @@ Use this repo note only as the canary checklist for

## Local Checks

After regenerating the generated `cpflow-*` wrappers, run:
Install the pinned dependencies, then validate the released review-app pair and
all existing generated-workflow checks without network access:

```sh
bin/conductor-exec bin/test-cpflow-github-flow
bin/conductor-exec bundle check
bin/conductor-exec ruby bin/check-cpflow-review-app-contract
bin/conductor-exec bundle exec rspec spec/cpflow_review_app_contract_spec.rb
bin/conductor-exec bin/test-cpflow-github-flow --offline
```

When testing an unreleased upstream `control-plane-flow` checkout, pass that
checkout's `bin/cpflow`:
`--offline` explicitly skips public package-registry readiness checks. It still
checks the release contract, renderer resources/probes, YAML, existing wrapper
consistency, and actionlint. It does not contact the deployment platform, prove
an image builds, or prove deployment readiness. For registry readiness as well:

```sh
bin/conductor-exec bin/test-cpflow-github-flow ruby /path/to/control-plane-flow/bin/cpflow
bin/conductor-exec bin/test-cpflow-github-flow bundle exec cpflow
```

## Testing An Upstream PR Downstream
The full helper requires `actionlint` on `PATH` in addition to the installed
Ruby bundle. Ordinary RSpec contract tests need only Ruby and the bundle; they
exercise the pure-Ruby validator, not the external lint executable. Run the full
helper separately when validating workflow changes.

Use an immutable upstream commit SHA, not a branch:
## Released Review-App Pair

```sh
bin/pin-cpflow-github-ref <40-character-control-plane-flow-commit-sha>
bin/conductor-exec bin/test-cpflow-github-flow ruby /path/to/control-plane-flow/bin/cpflow
```
The deploy/delete callers and local CLI use cpflow **5.3.0**. Both callers pin
`b1e5ff4a04adfccfd8b59996e8abdbb5defb3fd6` with a readable `v5.3.0`
comment. Other generated callers intentionally remain on their existing
**5.2.0** cohort; their migration is separate scope.
Comment thread
justin808 marked this conversation as resolved.

The pair is inseparable: both need the generated authenticated redispatch
input, exact run/job names, and matching permissions. A pin-only upgrade or a
single divergent canary is rejected. The offline validator reads the installed
5.3.0 gem's caller templates as its source of truth, without loading cpflow code.

Leave `CPFLOW_VERSION` unset while testing a commit SHA. After the upstream PR
ships in a release tag, repin wrappers to that tag. Use `v5.2.0` for the
promotion-hardening and release-runner timeout fixes; use immutable commit SHAs
only for future unreleased upstream PR tests.
Leave `CPFLOW_VERSION` unset for these SHA-pinned callers: upstream builds the
CLI from the same pinned source. The variable-based RubyGems override requires
a release-tag ref and cannot be combined with a commit SHA.

Do not run the all-wrapper pin helper or blindly regenerate over the customized
validation script for this split migration. A future upgrade must update both
callers, the local dependency/lockfile, validator release constants, and fixture
tests together. Preserve the renderer assertions and separately review any
changes to other caller cohorts.

## Review App Canary

Deployment requires explicit authorization. A push is not unconditionally safe:
the released workflow deploys existing apps, and its intent reconciliation can
honor a newer accepted manual request even if the app was previously absent.
Before any publication under a no-deployment constraint, verify fresh app
absence and the absence of competing accepted intents or queued/running work;
otherwise hold publication. PR body edits alone are not a deploy trigger.

An absent app with a reconciled `pull_request` intent skips creation/build/deploy
and reports `image_built=false`; this is a skip, not a successful canary. The
cross-operation handoff targets default-branch wrappers, so validating a branch
alone does not prove end-to-end deploy/delete reconciliation before merge.

The 5.3.0 integration repair does not establish the cause of the previously
observed active runner with no replica. The existing resource/deadline settings
are preserved; that platform failure remains unresolved until separately
authorized evidence establishes its cause.

1. Open or reuse a same-repository PR.
2. Comment exactly `+review-app-deploy`.
3. Confirm the deploy job checks out the expected upstream Control Plane Flow
Expand Down
66 changes: 40 additions & 26 deletions .controlplane/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -630,33 +630,47 @@ React on Rails docs reference:

Keep the reusable-workflow mechanics in the upstream
[`control-plane-flow` CI automation guide](https://github.com/shakacode/control-plane-flow/blob/v5.2.0/docs/ci-automation.md).
For this repo, the update loop is:

1. Update the bundled `cpflow` gem to the desired release.
2. Refresh generated wrappers from that release with `--staging-branch master`.
3. Keep generated refs on the same release tag as the bundled `cpflow` gem.
This branch pins refs to `v5.2.0`, which includes upstream promotion
hardening and the release-runner timeout fix. Use a full commit SHA only for
short-lived upstream testing and leave `CPFLOW_VERSION` unset in that case.
4. Keep app names and GitHub settings aligned with `.controlplane/controlplane.yml`.
5. Validate locally:

```bash
bin/conductor-exec bundle update cpflow
bin/conductor-exec bundle exec cpflow update-github-actions --staging-branch master
bin/conductor-exec bin/test-cpflow-github-flow bundle exec cpflow
```

Then open a normal PR, wait for GitHub Actions, and test a real review-app
deploy. Comment-triggered workflows run from `master`; for PR-branch workflow
edits, dispatch the workflow explicitly:
This repo deliberately keeps two release cohorts:

- The review-app deploy/delete callers pin cpflow `v5.3.0` at
`b1e5ff4a04adfccfd8b59996e8abdbb5defb3fd6`. The bundled `cpflow` gem and
lockfile use `5.3.0`.
- Staging, cleanup, help, and promotion retain `v5.2.0` at
`1d1ec7f7af181c5c6cf07f512ce336dbdb367246`. Their migration is separate
scope, not an automatic consequence of updating the local gem.

Full commit SHAs are the normal release contract, not just a testing option.
Leave `CPFLOW_VERSION` unset: SHA-pinned workflows build the CLI from their
pinned source, and the runtime version override requires a release-tag ref.
Promotion must keep its action refs, `.cpflow` checkout, and setup provenance
on the same `v5.2.0` SHA. Its setup-only `GIT_DIR` binding supplies that
checkout's metadata when packaging the downloaded action source.

Do not run blanket `cpflow update-github-actions` regeneration or
`bin/pin-cpflow-github-ref` for this split. They can overwrite the separate
Comment on lines +649 to +650

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Align the remaining split-migration instructions

Although this guide now warns against blanket regeneration, a repo-wide search still finds .github/testing-github-actions.md:27-35 directing prerelease testers to pin all generated reusable workflows to one SHA via bin/pin-cpflow-github-ref, while .controlplane/shakacode-team.md:131-145 still says every wrapper is on v5.2.0 and should be regenerated together. Following either guide overwrites the intentional v5.3.0 review-app/v5.2.0 non-review split and produces a state the new validators reject, so these remaining instructions need the same exception or a link to this section.

Useful? React with 👍 / 👎.

cohorts and caller customizations. For a future review-app upgrade, update both
callers, the local gem and lockfile, validator release constants, and fixture
tests together in a reviewed PR. Preserve the renderer assertions and review
changes to other cohorts separately. Keep the staging branch `master` and
the settings in `.controlplane/controlplane.yml` intact.

After installing the pinned dependencies, run these local checks:

```bash
gh workflow run cpflow-deploy-review-app.yml --ref <branch> -f pr_number=<pr-number>
bin/conductor-exec bundle check
bin/conductor-exec ruby bin/check-cpflow-review-app-contract
bin/conductor-exec bundle exec rspec spec/cpflow_review_app_contract_spec.rb
bin/conductor-exec bin/test-cpflow-github-flow --offline
```

This loads the workflow file from `<branch>`, but trusted local composite
actions still come from the default branch before secrets are used. Treat it as
a partial smoke test, then verify a real deploy after the workflow changes land
on `master`. See the short
[testing checklist](docs/testing-cpflow-github-actions.md) for the canary steps.
These checks do not deploy or prove deployment readiness. The full helper needs
`actionlint`; ordinary contract specs need only Ruby and the bundle. See the
[testing checklist and split-migration exception](docs/testing-cpflow-github-actions.md#released-review-app-pair).

Deployment needs separate, explicit authorization. Do not treat publication or
a green local check as permission to dispatch a workflow or retry a deployment.
A push can itself deploy an existing app or honor an accepted deployment
intent. Follow the checklist's publication guard before pushing under a
no-deployment constraint. Comment-triggered runs and cross-operation handoffs
use default-branch wrappers, so a branch-only smoke test does not prove the
complete deploy/delete flow.
3 changes: 2 additions & 1 deletion .github/actions/cpflow-delete-control-plane-app/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ runs:
steps:
- name: Delete application
shell: bash
run: ${{ github.action_path }}/delete-app.sh
run: '"$ACTION_PATH/delete-app.sh"'
env:
ACTION_PATH: ${{ github.action_path }}
APP_NAME: ${{ inputs.app_name }}
CPLN_ORG: ${{ inputs.cpln_org }}
REVIEW_APP_PREFIX: ${{ inputs.review_app_prefix }}
15 changes: 9 additions & 6 deletions .github/actions/cpflow-setup-environment/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,32 @@ runs:
using: composite
steps:
- name: Set up Ruby
uses: ruby/setup-ruby@v1
uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
with:
ruby-version: ${{ inputs.ruby_version }}

- name: Install Control Plane CLI and cpflow gem
shell: bash
env:
CPLN_CLI_VERSION: ${{ inputs.cpln_cli_version }}
CPFLOW_VERSION: ${{ inputs.cpflow_version }}
run: |
set -euo pipefail

sudo npm install -g @controlplane/cli@${{ inputs.cpln_cli_version }}
sudo npm install -g "@controlplane/cli@$CPLN_CLI_VERSION"
cpln --version

gem install cpflow -v ${{ inputs.cpflow_version }}
gem install cpflow -v "$CPFLOW_VERSION"
cpflow --version

- name: Setup Control Plane profile and registry login
shell: bash
env:
TOKEN: ${{ inputs.token }}
ORG: ${{ inputs.org }}
run: |
set -euo pipefail

TOKEN="${{ inputs.token }}"
ORG="${{ inputs.org }}"

if [[ -z "$TOKEN" ]]; then
echo "Error: Control Plane token not provided" >&2
exit 1
Expand Down
62 changes: 30 additions & 32 deletions .github/cpflow-help.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,42 +129,40 @@ production org, using production-only secrets and values.

## Version Locking

Generated wrappers pin Control Plane Flow with a release tag, for example
`v5.2.0`. Reusable review-app, staging, cleanup, and
helper workflows pin the tag in their `uses:` ref. Production promotion pins
the same tag in the `Checkout control-plane-flow actions` step so the
caller-owned job can keep `environment: production` and receive production
environment secrets directly.

Leave `CPFLOW_VERSION` unset so the workflow builds cpflow from the same
checked-out upstream source. If you set `CPFLOW_VERSION`, it must match the
release tag your wrappers are pinned to: a `CPFLOW_VERSION=5.2.x` runtime
override goes with a wrapper pinned to `uses: ...@v5.2.x` (substitute the
release you pinned above).

After updating the `cpflow` gem in this repo, update the generated wrappers in
the same PR:
This repo uses immutable release SHAs and deliberately separates two cohorts:

- Review-app deploy/delete callers: `v5.3.0` at
`b1e5ff4a04adfccfd8b59996e8abdbb5defb3fd6`, with the local `cpflow` gem
and lockfile on `5.3.0`. Upgrade the two callers together.
- Staging, cleanup, help, and promotion: `v5.2.0` at
`1d1ec7f7af181c5c6cf07f512ce336dbdb367246`. Keep this cohort unchanged
unless its migration is separately reviewed.

Leave `CPFLOW_VERSION` unset. Each SHA-pinned workflow builds cpflow from its
own pinned upstream source; a runtime version override requires a release-tag
ref and is incompatible with these SHAs. Promotion keeps its action refs,
`.cpflow` source checkout, and setup provenance on the same `v5.2.0` SHA.
The setup-only `GIT_DIR` binding provides matching checkout metadata for
packaging the action archive. Preserve the caller-owned
`environment: production` job.

Do not run blanket `cpflow update-github-actions` regeneration or
`bin/pin-cpflow-github-ref` over this split. A review-app upgrade must update
both callers, the local dependency and lockfile, validator release constants,
and fixture tests together. See the
[split-migration exception and local checks](../.controlplane/docs/testing-cpflow-github-actions.md#released-review-app-pair).

After installing the pinned dependencies, validate locally without deploying:

```sh
cpflow update-github-actions
bin/test-cpflow-github-flow
bin/conductor-exec ruby bin/check-cpflow-review-app-contract
bin/conductor-exec bundle exec rspec spec/cpflow_review_app_contract_spec.rb
bin/conductor-exec bin/test-cpflow-github-flow --offline
```

If `cpflow` is bundled by the app, use:

```sh
bundle exec cpflow update-github-actions
bin/test-cpflow-github-flow bundle exec cpflow
```

Do not leave downstream apps pinned to a moving branch such as `main`. For a
short-lived test of an unreleased upstream PR, pin to a full 40-character commit
SHA and leave `CPFLOW_VERSION` unset:

```sh
bin/pin-cpflow-github-ref <40-character-control-plane-flow-commit-sha>
bin/test-cpflow-github-flow ruby /path/to/control-plane-flow/bin/cpflow
```
Deployment, manual dispatch, and deployment retries need explicit authorization.
A push can also deploy; follow the testing checklist's publication guard under
any no-deployment constraint. Local validation does not authorize a canary.

## Advanced Variables

Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:

jobs:
claude-review:
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
permissions:
contents: read
Expand All @@ -15,13 +16,14 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
with:
fetch-depth: 1
persist-credentials: false

- name: Run Claude Code Review
id: claude-review
uses: anthropics/claude-code-action@v1
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1.0.216
env:
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
with:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,14 @@ jobs:
statuses: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
fetch-depth: 1
persist-credentials: false

- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@v1
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1.0.216
env:
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
with:
Expand All @@ -145,4 +146,3 @@ jobs:
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://code.claude.com/docs/en/cli-reference for available options
# claude_args: '--allowed-tools Bash(gh pr:*)'

2 changes: 1 addition & 1 deletion .github/workflows/cpflow-cleanup-stale-review-apps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ jobs:
cleanup:
# Cleanup targets the current inferred review-app prefix. If you changed
# naming conventions, manually delete review apps under the old prefix.
uses: shakacode/control-plane-flow/.github/workflows/cpflow-cleanup-stale-review-apps.yml@v5.2.0
uses: shakacode/control-plane-flow/.github/workflows/cpflow-cleanup-stale-review-apps.yml@1d1ec7f7af181c5c6cf07f512ce336dbdb367246 # v5.2.0
secrets:
CPLN_TOKEN_STAGING: ${{ secrets.CPLN_TOKEN_STAGING }}
Loading
Loading