[codex] Regenerate cpflow review app feedback#741
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughMultiple cpflow workflows replace inline job steps with wrapper jobs that call upstream reusable workflows (passing refs/inputs and inheriting secrets), and ChangesWorkflow delegation & help documentation
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Review app commands
For setup details, comment |
Greptile SummaryThis PR regenerates cpflow-managed GitHub Actions workflows to pick up upstream
Confidence Score: 4/5Safe to merge; changes are purely additive workflow improvements with no logic regressions introduced. All workflow upgrades are mechanical version bumps or additive steps, and the new REVIEW_APP_DEPLOYING_ICON_URL feature includes https-only URL validation with a safe fallback. The one concern is that cpflow-help.md no longer tells contributors that composite actions still load from the default branch when testing via workflow_dispatch --ref, which could cause confusion during future workflow iteration. .github/cpflow-help.md — the revised testing guidance section warrants a second look to decide whether the removed composite-action caveat should be restored. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[issue_comment event\nor workflow_dispatch] --> B{event is\nissue_comment?}
B -- yes --> C[React to command\n👀 or 🚀\ncontinue-on-error: true]
B -- no --> D[Skip reaction]
C --> E[Checkout trusted\nworkflow sources\nactions/checkout@v6]
D --> E
E --> F[cpflow-setup-environment\ncomposite action]
F --> G{config.outputs.ready\n== 'true'?}
G -- no --> H[Stop - not configured]
G -- yes --> I[Checkout PR commit\nactions/checkout@v6]
I --> J[Build Docker image]
J --> K[Create initial PR comment\ngithub-script@v8]
K --> L[Deploy to Control Plane]
L --> M{REVIEW_APP_DEPLOYING\n_ICON_URL configured?}
M -- not set --> N[Use default pinned SVG URL]
M -- 'none' --> O[Use ⏳ text icon]
M -- valid https URL --> P[Use custom URL]
M -- invalid URL --> N
N --> Q[Update PR comment\nwith deploying icon]
O --> Q
P --> Q
Q --> R[Wait for health check]
R --> S{Deploy success?}
S -- yes --> T[🎉 Deploy Complete!\nwith app URL]
S -- no --> U[❌ Deployment Failed]
T --> V[Finalize GitHub Deployment status]
U --> V
Reviews (1): Last reviewed commit: "Regenerate cpflow review app feedback" | Re-trigger Greptile |
|
|
||
| `workflow_dispatch` runs use the workflow file from the `--ref` you pass, but workflows that intentionally check out trusted local actions from the default branch will still load those local composite actions from the default branch before using secrets. Treat this as a partial smoke test for top-level workflow edits. For changes under `.github/actions/`, merge the generated fix to the default branch and rerun a real review-app deploy. | ||
| `workflow_dispatch` runs use the workflow file from the `--ref` you pass, so this is the supported way to test PR-branch workflow edits before merge. After merge, comment triggers go back to running the default-branch workflow code as usual. | ||
|
|
||
| </details> |
There was a problem hiding this comment.
Removed caveat about composite action testing limitation
The updated paragraph now says workflow_dispatch with --ref is "the supported way to test PR-branch workflow edits before merge," but it silently drops the original warning that workflows which check out local composite actions still load those actions from the default branch. A contributor iterating on files under .github/actions/ could misread this as confirmation that their changes are fully exercised by dispatch, only to discover post-merge that the composite action behaviour was unchanged during their test run. The removed sentence (For changes under .github/actions/, merge the generated fix to the default branch and rerun a real review-app deploy) is useful operational guidance worth preserving.
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (1)
.github/workflows/cpflow-cleanup-stale-review-apps.yml (1)
25-25: ⚡ Quick winPin
actions/checkoutto an immutable commit SHA (when stricter supply-chain requirements apply).This repo’s templates intentionally use floating major tags (e.g.,
actions/...@vN) and note that immutable SHA pinning should be applied by repositories with stricter supply-chain requirements. If that applies to your environment, replaceactions/checkout@v6withactions/checkout@<40-hex-commit-sha>.Suggested change
- uses: actions/checkout@v6 + uses: actions/checkout@<FULL_LENGTH_SHA_FOR_V6> # v6🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/cpflow-cleanup-stale-review-apps.yml at line 25, Replace the floating tag reference "actions/checkout@v6" with an immutable 40-character commit SHA (e.g., "actions/checkout@<40-hex-commit-sha>") to pin the action; locate the usage of actions/checkout in the workflow file (the line containing actions/checkout@v6) and update it to the specific commit SHA you trust for supply-chain security.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/cpflow-delete-review-app.yml:
- Line 47: The workflow is using mutable action tags; replace each mutable
`uses:` entry like `actions/github-script@v8` and `actions/checkout@v6` with
their corresponding immutable commit SHAs (e.g.,
`actions/github-script@<full-sha>` and `actions/checkout@<full-sha>`) while
preserving the trailing `# v8` / `# v6` comment; update all occurrences (the
three `actions/github-script@v8` entries and the `actions/checkout@v6` entry) to
the full SHA commits and verify the workflow still runs by committing the
updated `uses:` lines.
In @.github/workflows/cpflow-deploy-review-app.yml:
- Line 57: Replace mutable action tags with immutable commit SHAs: find every
usage of actions/github-script@v8 and actions/checkout@v6 and pin them to the
full 40-character commit SHA from the corresponding GitHub Actions repository
(e.g., the latest vetted commit on actions/github-script and actions/checkout),
updating each occurrence to use the commit SHA ref instead of the short tag;
ensure you update all instances of the symbols actions/github-script@v8 and
actions/checkout@v6 in the workflow so they consistently reference the exact
commit SHA.
In @.github/workflows/cpflow-deploy-staging.yml:
- Line 58: Three steps use the mutable tag actions/checkout@v6; locate each
checkout step (the uses: "actions/checkout@v6" occurrences) and replace the tag
with the full commit SHA for the actions/checkout repository (e.g. uses:
actions/checkout@<full-commit-sha>) so the workflow is pinned immutably; update
all three occurrences (the ones currently set to actions/checkout@v6) to their
corresponding commit SHAs and verify the SHAs are valid by copying them from the
actions/checkout GitHub repo.
In @.github/workflows/cpflow-help-command.yml:
- Line 38: The workflow currently pins actions using tag refs
'actions/github-script@v8' and 'actions/checkout@v6'; replace each tag ref with
the corresponding full commit SHA (the exact commit SHA for the version you
intend to use) so the uses entries become commit-pinned (e.g.,
'actions/github-script@<full-sha>' and 'actions/checkout@<full-sha>'). Update
every occurrence of those strings in the workflow so both instances are
replaced, and verify the workflow still runs against the chosen SHAs.
In @.github/workflows/cpflow-promote-staging-to-production.yml:
- Line 55: Replace the mutable tag "actions/checkout@v6" with the repository's
full immutable commit SHA for that action (e.g., "actions/checkout@<full-sha> #
v6") so the workflow is deterministic; locate the uses: actions/checkout@v6
entry in the workflow and update it to the full SHA while optionally keeping a
trailing comment with "v6" for human readability.
In @.github/workflows/cpflow-review-app-help.yml:
- Line 25: Replace the floating actions/github-script@v8 reference with an
immutable commit SHA (or digest) to avoid drift: locate the workflow step that
currently says "uses: actions/github-script@v8" and change it to the
corresponding actions/github-script@<commit-sha> (or @{digest}) pinned value,
ensuring you reference the official GitHub Actions repository commit you want to
lock to and update any related comment to document the chosen SHA.
---
Nitpick comments:
In @.github/workflows/cpflow-cleanup-stale-review-apps.yml:
- Line 25: Replace the floating tag reference "actions/checkout@v6" with an
immutable 40-character commit SHA (e.g., "actions/checkout@<40-hex-commit-sha>")
to pin the action; locate the usage of actions/checkout in the workflow file
(the line containing actions/checkout@v6) and update it to the specific commit
SHA you trust for supply-chain security.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 433adebd-013b-49d2-9126-d537e2dc4296
📒 Files selected for processing (8)
.github/cpflow-help.md.github/workflows/cpflow-cleanup-stale-review-apps.yml.github/workflows/cpflow-delete-review-app.yml.github/workflows/cpflow-deploy-review-app.yml.github/workflows/cpflow-deploy-staging.yml.github/workflows/cpflow-help-command.yml.github/workflows/cpflow-promote-staging-to-production.yml.github/workflows/cpflow-review-app-help.yml
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.github/workflows/cpflow-cleanup-stale-review-apps.yml (1)
13-16: 🏗️ Heavy liftBranch reference should be pinned to a SHA or release tag before production use.
All seven cpflow workflow files in this PR reference the reusable workflows at
@jg-codex/reusable-github-actions, which is a mutable branch. While this appears intentional for testing the upstream changes from PRs#303/#304, ensure these references are updated to an immutable SHA or release tag before final merge tomasterfor production stability.The
secrets: inheritpattern is acceptable here since the called workflows are from the same organization's trusted repository.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/cpflow-cleanup-stale-review-apps.yml around lines 13 - 16, The workflow references a mutable branch in the uses line ("uses: shakacode/control-plane-flow/.github/workflows/cpflow-cleanup-stale-review-apps.yml@jg-codex/reusable-github-actions"); update that reference to an immutable identifier (a specific commit SHA or a release tag) in this file and the other six cpflow workflow files so CI uses a fixed version of shakacode/control-plane-flow; ensure you pick the exact SHA or tag you tested against (or create a release), replace the branch suffix with that SHA/tag, and keep "secrets: inherit" unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In @.github/workflows/cpflow-cleanup-stale-review-apps.yml:
- Around line 13-16: The workflow references a mutable branch in the uses line
("uses:
shakacode/control-plane-flow/.github/workflows/cpflow-cleanup-stale-review-apps.yml@jg-codex/reusable-github-actions");
update that reference to an immutable identifier (a specific commit SHA or a
release tag) in this file and the other six cpflow workflow files so CI uses a
fixed version of shakacode/control-plane-flow; ensure you pick the exact SHA or
tag you tested against (or create a release), replace the branch suffix with
that SHA/tag, and keep "secrets: inherit" unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f9ed0a80-9345-4890-84f4-a1a04c764b4a
📒 Files selected for processing (14)
.github/actions/cpflow-build-docker-image/action.yml.github/actions/cpflow-delete-control-plane-app/action.yml.github/actions/cpflow-delete-control-plane-app/delete-app.sh.github/actions/cpflow-detect-release-phase/action.yml.github/actions/cpflow-setup-environment/action.yml.github/actions/cpflow-validate-config/action.yml.github/actions/cpflow-wait-for-health/action.yml.github/workflows/cpflow-cleanup-stale-review-apps.yml.github/workflows/cpflow-delete-review-app.yml.github/workflows/cpflow-deploy-review-app.yml.github/workflows/cpflow-deploy-staging.yml.github/workflows/cpflow-help-command.yml.github/workflows/cpflow-promote-staging-to-production.yml.github/workflows/cpflow-review-app-help.yml
💤 Files with no reviewable changes (7)
- .github/actions/cpflow-setup-environment/action.yml
- .github/actions/cpflow-wait-for-health/action.yml
- .github/actions/cpflow-delete-control-plane-app/action.yml
- .github/actions/cpflow-delete-control-plane-app/delete-app.sh
- .github/actions/cpflow-detect-release-phase/action.yml
- .github/actions/cpflow-validate-config/action.yml
- .github/actions/cpflow-build-docker-image/action.yml
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2829287e64
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| comment_id: commentId, | ||
| body: success ? successBody : failureBody | ||
| }); | ||
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-review-app.yml@jg-codex/reusable-github-actions |
There was a problem hiding this comment.
Pin reusable workflow refs to an immutable revision
This change switches deployment automation to a reusable workflow referenced by the mutable branch @jg-codex/reusable-github-actions while also passing secrets: inherit; if that branch is updated, force-pushed, or removed, future runs can execute different code (with access to inherited secrets) or fail entirely, which is a production-impacting reliability and supply-chain regression compared to local, versioned workflow code. Use an immutable commit SHA (or a protected release tag) for the uses: and matching control_plane_flow_ref value.
Useful? React with 👍 / 👎.
2829287 to
85b4dc3
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.github/workflows/cpflow-promote-staging-to-production.yml (1)
12-12: ⚡ Quick winReassess
contents: writefor the promotion workflow
The reusablecpflow-promote-staging-to-production.ymlflow explicitly “creates a GitHub release after a successful promotion,” so grantingpermissions: contents: writeis consistent with the needs of release creation. Optional: if GitHub supports a narrower scope for the token in this setup (e.g.,releases: write), prefer that for least privilege.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/cpflow-promote-staging-to-production.yml at line 12, The workflow currently grants broad repo content permissions via the permissions key "contents: write"; update the permissions block in cpflow-promote-staging-to-production.yml to use the least-privilege scope required for creating a GitHub release—replace "contents: write" with "releases: write" if the runner supports that narrower scope, otherwise keep "contents: write" but add a comment referencing the release creation step to justify the permission; locate the permissions entry in the workflow and update the value accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In @.github/workflows/cpflow-promote-staging-to-production.yml:
- Line 12: The workflow currently grants broad repo content permissions via the
permissions key "contents: write"; update the permissions block in
cpflow-promote-staging-to-production.yml to use the least-privilege scope
required for creating a GitHub release—replace "contents: write" with "releases:
write" if the runner supports that narrower scope, otherwise keep "contents:
write" but add a comment referencing the release creation step to justify the
permission; locate the permissions entry in the workflow and update the value
accordingly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 911cc27c-f33c-42ce-8f26-0c553fac0ced
📒 Files selected for processing (14)
.github/actions/cpflow-build-docker-image/action.yml.github/actions/cpflow-delete-control-plane-app/action.yml.github/actions/cpflow-delete-control-plane-app/delete-app.sh.github/actions/cpflow-detect-release-phase/action.yml.github/actions/cpflow-setup-environment/action.yml.github/actions/cpflow-validate-config/action.yml.github/actions/cpflow-wait-for-health/action.yml.github/workflows/cpflow-cleanup-stale-review-apps.yml.github/workflows/cpflow-delete-review-app.yml.github/workflows/cpflow-deploy-review-app.yml.github/workflows/cpflow-deploy-staging.yml.github/workflows/cpflow-help-command.yml.github/workflows/cpflow-promote-staging-to-production.yml.github/workflows/cpflow-review-app-help.yml
💤 Files with no reviewable changes (7)
- .github/actions/cpflow-build-docker-image/action.yml
- .github/actions/cpflow-delete-control-plane-app/delete-app.sh
- .github/actions/cpflow-delete-control-plane-app/action.yml
- .github/actions/cpflow-detect-release-phase/action.yml
- .github/actions/cpflow-validate-config/action.yml
- .github/actions/cpflow-setup-environment/action.yml
- .github/actions/cpflow-wait-for-health/action.yml
972e90f to
f8d6682
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/cpflow-cleanup-stale-review-apps.yml:
- Around line 13-16: The workflow delegates to a mutable branch which, combined
with secrets: inherit, can run arbitrary changed code; update the "uses:"
reference and the "with.control_plane_flow_ref" value to the corresponding
immutable commit SHA for the shakacode/control-plane-flow reusable workflow
(replace jg-codex/reusable-github-actions with the exact commit SHA) so both the
delegated workflow invocation and the control_plane_flow_ref are pinned to the
same SHA; keep secrets: inherit only after pinning and update the other
cpflow-*.yml wrappers the same way to ensure consistent, immutable delegation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 121cd8da-2fbb-48ff-92e6-406bd10c55e0
📒 Files selected for processing (14)
.github/actions/cpflow-build-docker-image/action.yml.github/actions/cpflow-delete-control-plane-app/action.yml.github/actions/cpflow-delete-control-plane-app/delete-app.sh.github/actions/cpflow-detect-release-phase/action.yml.github/actions/cpflow-setup-environment/action.yml.github/actions/cpflow-validate-config/action.yml.github/actions/cpflow-wait-for-health/action.yml.github/workflows/cpflow-cleanup-stale-review-apps.yml.github/workflows/cpflow-delete-review-app.yml.github/workflows/cpflow-deploy-review-app.yml.github/workflows/cpflow-deploy-staging.yml.github/workflows/cpflow-help-command.yml.github/workflows/cpflow-promote-staging-to-production.yml.github/workflows/cpflow-review-app-help.yml
💤 Files with no reviewable changes (7)
- .github/actions/cpflow-validate-config/action.yml
- .github/actions/cpflow-detect-release-phase/action.yml
- .github/actions/cpflow-build-docker-image/action.yml
- .github/actions/cpflow-delete-control-plane-app/delete-app.sh
- .github/actions/cpflow-delete-control-plane-app/action.yml
- .github/actions/cpflow-wait-for-health/action.yml
- .github/actions/cpflow-setup-environment/action.yml
9a256a9 to
b35cb8c
Compare
Code ReviewOverviewThis PR consolidates six local workflow implementations into thin callers that delegate to upstream reusable workflows in The direction is sound — maintaining identical workflow logic in every downstream repo is a maintenance burden. However, there are several concerns worth addressing before merging. 🔴 Critical: Mutable branch ref +
|
| @@ -8,49 +8,9 @@ on: | |||
| permissions: | |||
| contents: read | |||
There was a problem hiding this comment.
Mutable ref + secrets: inherit: @jg-codex/reusable-github-actions is a branch name. Any force-push to that branch changes what runs here at next execution — with all repo secrets inherited. Pin to an immutable SHA or version tag before using in production:
| contents: read | |
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-cleanup-stale-review-apps.yml@<COMMIT-SHA-OR-TAG> |
| issue_number: context.issue.number, | ||
| body | ||
| }); | ||
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-review-app-help.yml@jg-codex/reusable-github-actions |
There was a problem hiding this comment.
Missing control_plane_flow_ref input: Same issue as cpflow-help-command.yml — this caller doesn't pass control_plane_flow_ref while every other caller does. Should be consistent:
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-review-app-help.yml@jg-codex/reusable-github-actions | |
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-review-app-help.yml@jg-codex/reusable-github-actions | |
| with: | |
| control_plane_flow_ref: jg-codex/reusable-github-actions |
| # Don't cancel an in-flight promotion: a half-finished `cpflow deploy-image` plus a | ||
| # rollback can leave production in a worse state than letting the first run finish. | ||
| cancel-in-progress: false | ||
| contents: write |
There was a problem hiding this comment.
Overly-broad permission: contents: write is now granted at the workflow level. Previously only the create-github-release job scoped up to contents: write; the promote-to-production job ran with contents: read. Granting write access to all jobs in the workflow is broader than necessary — if the upstream reusable workflow needs it for the release step, that permission should be scoped within the upstream workflow's job, not granted here blanket-wide.
| contents: write | |
| contents: read |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Help wrappers omit flow ref
- Added the same control_plane_flow_ref input to both help reusable-workflow callers so they use the intended upstream ref.
Or push these changes by commenting:
@cursor push 55b6f9ae42
Preview (55b6f9ae42)
diff --git a/.github/actions/cpflow-build-docker-image/action.yml b/.github/actions/cpflow-build-docker-image/action.yml
deleted file mode 100644
--- a/.github/actions/cpflow-build-docker-image/action.yml
+++ /dev/null
@@ -1,131 +1,0 @@
-name: Build Docker Image
-description: Builds and pushes the app image for a Control Plane workload
-
-inputs:
- app_name:
- description: Name of the application
- required: true
- org:
- description: Control Plane organization name
- required: true
- commit:
- description: Commit SHA to tag the image with
- required: true
- pr_number:
- description: Pull request number for status messaging
- required: false
- docker_build_extra_args:
- description: Optional newline-delimited extra docker build tokens. Use key=value forms like --build-arg=FOO=bar.
- required: false
- docker_build_ssh_key:
- description: Optional private SSH key used for Docker builds that fetch private dependencies with RUN --mount=type=ssh
- required: false
- docker_build_ssh_known_hosts:
- description: Optional SSH known_hosts entries used with docker_build_ssh_key. Defaults to pinned GitHub.com host keys.
- required: false
- working_directory:
- description: Directory containing the app .controlplane config and Docker build context
- required: false
- default: "."
-
-runs:
- using: composite
- steps:
- # Keep SSH key handling in a dedicated step so DOCKER_BUILD_SSH_KEY is never present
- # in the main build step's environment. ACTIONS_STEP_DEBUG=true dumps env before any
- # command runs, so keeping the key out of env there avoids even admin-triggered exposure.
- - name: Prepare SSH agent for Docker build
- if: ${{ inputs.docker_build_ssh_key != '' }}
- shell: bash
- env:
- # Pass the key via env so the file write is a single printf call rather than a
- # heredoc with a fixed terminator (a heredoc would silently truncate the key if
- # any line of the key value happened to match the terminator). Scope is still
- # this step only — the build step below does not receive DOCKER_BUILD_SSH_KEY.
- DOCKER_BUILD_SSH_KEY: ${{ inputs.docker_build_ssh_key }}
- DOCKER_BUILD_SSH_KNOWN_HOSTS: ${{ inputs.docker_build_ssh_known_hosts }}
- run: |
- set -euo pipefail
-
- umask 077
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
-
- if [[ -n "${DOCKER_BUILD_SSH_KNOWN_HOSTS}" ]]; then
- printf '%s\n' "${DOCKER_BUILD_SSH_KNOWN_HOSTS}" > ~/.ssh/known_hosts
- else
- printf '%s\n' \
- 'github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl' \
- 'github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=' \
- 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=' \
- > ~/.ssh/known_hosts
- fi
- chmod 600 ~/.ssh/known_hosts
-
- printf '%s\n' "${DOCKER_BUILD_SSH_KEY}" > ~/.ssh/cpflow_build_key
- chmod 600 ~/.ssh/cpflow_build_key
-
- - name: Build Docker image
- shell: bash
- env:
- APP_NAME: ${{ inputs.app_name }}
- COMMIT_SHA: ${{ inputs.commit }}
- CONTROL_PLANE_ORG: ${{ inputs.org }}
- DOCKER_BUILD_EXTRA_ARGS: ${{ inputs.docker_build_extra_args }}
- PR_NUMBER: ${{ inputs.pr_number }}
- WORKING_DIRECTORY: ${{ inputs.working_directory }}
- run: |
- set -euo pipefail
-
- PR_INFO=""
- docker_build_args=()
- ssh_agent_started=false
- build_ssh_prepped=false
-
- cleanup_build_ssh() {
- if [[ "${ssh_agent_started}" == "true" ]]; then
- ssh-agent -k >/dev/null || true
- fi
- rm -f "${HOME}/.ssh/cpflow_build_key"
- # Only remove known_hosts if this action's prep step wrote it. On self-hosted
- # or reused runners we must not touch a user-managed file we did not create,
- # so the flag is set inside the same prep-detection branch below.
- if [[ "${build_ssh_prepped}" == "true" ]]; then
- rm -f "${HOME}/.ssh/known_hosts"
- fi
- }
- trap cleanup_build_ssh EXIT
- cd "${WORKING_DIRECTORY}"
-
- if [[ -n "${PR_NUMBER}" ]]; then
- PR_INFO=" for PR #${PR_NUMBER}"
- fi
-
- if [[ -n "${DOCKER_BUILD_EXTRA_ARGS}" ]]; then
- while IFS= read -r arg; do
- arg="${arg%$'\r'}"
- [[ -n "${arg}" ]] || continue
-
- if [[ "${arg}" =~ [[:space:]] ]]; then
- echo "docker_build_extra_args entries must be single docker-build tokens. " \
- "Use key=value forms like --build-arg=FOO=bar." >&2
- exit 1
- fi
-
- docker_build_args+=("${arg}")
- done <<< "${DOCKER_BUILD_EXTRA_ARGS}"
- fi
-
- if [[ -f "${HOME}/.ssh/cpflow_build_key" ]]; then
- # Mark prep-step ownership so cleanup_build_ssh only removes known_hosts
- # when this action wrote it (see trap above).
- build_ssh_prepped=true
- eval "$(ssh-agent -s)"
- ssh_agent_started=true
- ssh-add "${HOME}/.ssh/cpflow_build_key"
- docker_build_args+=("--ssh=default")
- fi
-
- echo "🏗️ Building Docker image${PR_INFO} (commit ${COMMIT_SHA})..."
- cpflow build-image -a "${APP_NAME}" --commit="${COMMIT_SHA}" --org="${CONTROL_PLANE_ORG}" "${docker_build_args[@]}"
- echo "✅ Docker image build successful${PR_INFO} (commit ${COMMIT_SHA})"
\ No newline at end of file
diff --git a/.github/actions/cpflow-delete-control-plane-app/action.yml b/.github/actions/cpflow-delete-control-plane-app/action.yml
deleted file mode 100644
--- a/.github/actions/cpflow-delete-control-plane-app/action.yml
+++ /dev/null
@@ -1,24 +1,0 @@
-name: Delete Control Plane App
-description: Deletes a Control Plane app and all associated resources
-
-inputs:
- app_name:
- description: Name of the application to delete
- required: true
- cpln_org:
- description: Control Plane organization name
- required: true
- review_app_prefix:
- description: Prefix used for review app names
- required: true
-
-runs:
- using: composite
- steps:
- - name: Delete application
- shell: bash
- run: ${{ github.action_path }}/delete-app.sh
- env:
- APP_NAME: ${{ inputs.app_name }}
- CPLN_ORG: ${{ inputs.cpln_org }}
- REVIEW_APP_PREFIX: ${{ inputs.review_app_prefix }}
\ No newline at end of file
diff --git a/.github/actions/cpflow-delete-control-plane-app/delete-app.sh b/.github/actions/cpflow-delete-control-plane-app/delete-app.sh
deleted file mode 100644
--- a/.github/actions/cpflow-delete-control-plane-app/delete-app.sh
+++ /dev/null
@@ -1,50 +1,0 @@
-#!/bin/bash
-
-set -euo pipefail
-
-: "${APP_NAME:?APP_NAME environment variable is required}"
-: "${CPLN_ORG:?CPLN_ORG environment variable is required}"
-: "${REVIEW_APP_PREFIX:?REVIEW_APP_PREFIX environment variable is required}"
-
-expected_prefix="${REVIEW_APP_PREFIX}-"
-if [[ "$APP_NAME" != "${expected_prefix}"* ]]; then
- echo "❌ ERROR: refusing to delete an app outside the review app prefix" >&2
- echo "App name: $APP_NAME" >&2
- echo "Expected prefix: ${expected_prefix}" >&2
- exit 1
-fi
-
-echo "🔍 Checking if application exists: $APP_NAME"
-exists_output=""
-set +e
-exists_output="$(cpflow exists -a "$APP_NAME" --org "$CPLN_ORG" 2>&1)"
-exists_status=$?
-set -e
-
-case "$exists_status" in
- 0)
- ;;
- 3)
- if [[ -n "$exists_output" ]]; then
- printf '%s\n' "$exists_output"
- fi
- echo "⚠️ Application does not exist: $APP_NAME"
- exit 0
- ;;
- *)
- echo "❌ ERROR: failed to determine whether application exists: $APP_NAME" >&2
- if [[ -n "$exists_output" ]]; then
- printf '%s\n' "$exists_output" >&2
- fi
- exit "$exists_status"
- ;;
-esac
-
-if [[ -n "$exists_output" ]]; then
- printf '%s\n' "$exists_output"
-fi
-
-echo "🗑️ Deleting application: $APP_NAME"
-cpflow delete -a "$APP_NAME" --org "$CPLN_ORG" --yes
-
-echo "✅ Successfully deleted application: $APP_NAME"
\ No newline at end of file
diff --git a/.github/actions/cpflow-detect-release-phase/action.yml b/.github/actions/cpflow-detect-release-phase/action.yml
deleted file mode 100644
--- a/.github/actions/cpflow-detect-release-phase/action.yml
+++ /dev/null
@@ -1,62 +1,0 @@
-name: Detect release phase support
-description: >-
- Inspects .controlplane/controlplane.yml for an app and emits `flag=--run-release-phase`
- when a `release_script:` is configured. Outputs an empty `flag` otherwise.
-
-inputs:
- app_name:
- description: cpflow app name to inspect
- required: true
- working_directory:
- description: Directory containing .controlplane/controlplane.yml
- required: false
- default: "."
-
-outputs:
- flag:
- description: Either `--run-release-phase` or empty
- value: ${{ steps.detect.outputs.flag }}
-
-runs:
- using: composite
- steps:
- - name: Detect release phase support
- id: detect
- shell: bash
- env:
- APP_NAME: ${{ inputs.app_name }}
- WORKING_DIRECTORY: ${{ inputs.working_directory }}
- run: |
- set -euo pipefail
- cd "${WORKING_DIRECTORY}"
-
- release_script="$(ruby - "${APP_NAME}" <<'RUBY'
- require "yaml"
-
- app_name = ARGV.fetch(0)
- data = YAML.safe_load(File.read(".controlplane/controlplane.yml"), aliases: true)
- apps = data["apps"] || {}
- app_config = apps[app_name]
-
- unless app_config
- app_config = apps.find do |name, config|
- config.is_a?(Hash) &&
- config["match_if_app_name_starts_with"] &&
- app_name.start_with?(name)
- end&.last
- end
-
- unless app_config.is_a?(Hash)
- warn "Error: app '#{app_name}' is not defined under `apps:` in `.controlplane/controlplane.yml`."
- exit 1
- end
-
- puts app_config["release_script"].to_s
- RUBY
- )"
-
- if [[ -n "${release_script}" ]]; then
- echo "flag=--run-release-phase" >> "$GITHUB_OUTPUT"
- else
- echo "flag=" >> "$GITHUB_OUTPUT"
- fi
\ No newline at end of file
diff --git a/.github/actions/cpflow-setup-environment/action.yml b/.github/actions/cpflow-setup-environment/action.yml
deleted file mode 100644
--- a/.github/actions/cpflow-setup-environment/action.yml
+++ /dev/null
@@ -1,110 +1,0 @@
-name: Setup Control Plane Environment
-description: Sets up Ruby, installs the Control Plane CLI and cpflow gem, and configures a default profile
-
-inputs:
- token:
- description: Control Plane token
- required: true
- org:
- description: Control Plane organization
- required: true
- ruby_version:
- description: >-
- Ruby version used for cpflow. When empty (the default), ruby/setup-ruby auto-detects
- from .ruby-version, .tool-versions, or the Gemfile.
- required: false
- default: ""
- # GitHub parses double-brace expression snippets inside action metadata (including
- # `description:`) while loading the composite action, and the `vars` context is not
- # available in that phase. Keep these descriptions in plain prose - reference repo
- # variables by NAME only, never with literal GitHub Actions expression syntax.
- cpln_cli_version:
- description: >-
- @controlplane/cli version. Empty string falls back to the action's pinned default,
- so callers can wire this input to the CPLN_CLI_VERSION repository variable
- unconditionally.
- required: false
- default: ""
- cpflow_version:
- description: >-
- cpflow gem version. Empty string falls back to the action's pinned default,
- so callers can wire this input to the CPFLOW_VERSION repository variable
- unconditionally.
- required: false
- default: ""
-
-runs:
- using: composite
- # Third-party actions are pinned to floating major tags (`@v4`, `@v1`, `@v7`) rather than
- # immutable SHAs. SHA pinning is GitHub's stronger security recommendation, but for
- # generated templates that ship into many downstream repositories floating tags are
- # easier for users to keep current and Dependabot/Renovate already cover the SHA-pinning
- # workflow for repositories that opt in. Repositories with stricter supply-chain
- # requirements should replace each `uses: actions/...@vN` with the corresponding
- # immutable commit SHA.
- steps:
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- 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
-
- # Bump these defaults when a new release lands that you want to roll out by default.
- # Override per-repo by setting `CPLN_CLI_VERSION` / `CPFLOW_VERSION` repo variables;
- # an empty input falls back to the action's pinned default below.
- default_cpln_cli_version="3.3.1"
- default_cpflow_version="5.0.0.rc.1"
-
- CPLN_CLI_VERSION="${CPLN_CLI_VERSION:-${default_cpln_cli_version}}"
- CPFLOW_VERSION="${CPFLOW_VERSION:-${default_cpflow_version}}"
-
- npm_global_prefix="${HOME}/.npm-global"
- mkdir -p "${npm_global_prefix}"
- echo "${npm_global_prefix}/bin" >> "$GITHUB_PATH"
- export PATH="${npm_global_prefix}/bin:${PATH}"
-
- npm install --global --prefix "${npm_global_prefix}" "@controlplane/cli@${CPLN_CLI_VERSION}"
- cpln --version
-
- gem install cpflow -v "${CPFLOW_VERSION}" --no-document
- cpflow --version
-
- - name: Setup Control Plane profile and registry login
- shell: bash
- env:
- # Pass the token via CPLN_TOKEN so cpln picks it up from the environment
- # rather than `--token`, which would leak it into /proc/<pid>/cmdline and ps output.
- CPLN_TOKEN: ${{ inputs.token }}
- ORG: ${{ inputs.org }}
- run: |
- set -euo pipefail
-
- if [[ -z "$CPLN_TOKEN" ]]; then
- echo "Error: Control Plane token not provided" >&2
- exit 1
- fi
-
- if [[ -z "$ORG" ]]; then
- echo "Error: Control Plane organization not provided" >&2
- exit 1
- fi
-
- # Keep the service-account token available to later cpflow/cpln steps.
- # The profile stores org/default metadata, but cpflow direct API calls
- # read CPLN_TOKEN before falling back to `cpln profile token`.
- echo "::add-mask::${CPLN_TOKEN}"
- printf 'CPLN_TOKEN=%s\n' "${CPLN_TOKEN}" >> "${GITHUB_ENV}"
-
- # `cpln profile update` lists `create` as an alias (cpln profile --help) and is
- # idempotent: it creates the profile if missing and updates it otherwise. Calling
- # update directly avoids parsing the CLI's "already exists" English error text,
- # which would silently swallow a real failure if the wording ever changed.
- cpln profile update default --org "$ORG"
- cpln image docker-login --org "$ORG"
\ No newline at end of file
diff --git a/.github/actions/cpflow-validate-config/action.yml b/.github/actions/cpflow-validate-config/action.yml
deleted file mode 100644
--- a/.github/actions/cpflow-validate-config/action.yml
+++ /dev/null
@@ -1,85 +1,0 @@
-name: Validate cpflow GitHub configuration
-description: >-
- Validates that required secrets and repository variables are set before a workflow
- proceeds. Pass each value via `env:` with the same NAME as the secret or variable,
- then list the required entries in `required` as `type:NAME` pairs (type is `secret`
- or `variable`). When `pull_request_friendly: true` and the current event is a
- pull request event, missing config writes a step summary and exits 0 with
- `ready=false` instead of failing the job.
-
-inputs:
- required:
- description: |
- Newline-separated `type:NAME` pairs. Type is `secret` or `variable`. The
- caller MUST export the matching values via `env:` using the same NAME.
- required: true
- pull_request_friendly:
- description: When "true" and event is pull_request/pull_request_target, write summary and exit 0 with ready=false.
- required: false
- default: "false"
-
-outputs:
- ready:
- description: '"true" when all values are set, "false" when missing in PR-friendly mode.'
- value: ${{ steps.check.outputs.ready }}
-
-runs:
- using: composite
- steps:
- - name: Check required secrets and variables
- id: check
- shell: bash
- env:
- CPFLOW_REQUIRED: ${{ inputs.required }}
- CPFLOW_PR_FRIENDLY: ${{ inputs.pull_request_friendly }}
- CPFLOW_EVENT_NAME: ${{ github.event_name }}
- run: |
- set -euo pipefail
-
- missing=()
- while IFS= read -r entry; do
- entry="${entry%$'\r'}"
- entry="${entry## }"
- entry="${entry%% }"
- [[ -z "${entry}" ]] && continue
-
- type="${entry%%:*}"
- name="${entry#*:}"
-
- # Reject names that are not plain SHELL_VAR identifiers before doing the
- # indirect lookup below. Without this guard, ${!name} would expand whatever
- # bash nameref/transformation a hand-edited generated workflow snuck in
- # (e.g. `BASH_FUNC_foo%%`). Callers today are the generated templates, but
- # the generated file lives in the user's repo and can be hand-edited.
- if [[ ! "${name}" =~ ^[A-Z_][A-Z0-9_]*$ ]]; then
- echo "Invalid config entry name: ${name}" >&2
- exit 1
- fi
-
- # Indirect bash lookup: reads the env var named by ${name} (e.g. CPLN_TOKEN_STAGING)
- # so the value never has to round-trip through workflow logs.
- if [[ -z "${!name:-}" ]]; then
- missing+=("${type}:${name}")
- fi
- done <<< "${CPFLOW_REQUIRED}"
-
- if [[ ${#missing[@]} -eq 0 ]]; then
- echo "ready=true" >> "$GITHUB_OUTPUT"
- exit 0
- fi
-
- if [[ "${CPFLOW_PR_FRIENDLY}" == "true" && ( "${CPFLOW_EVENT_NAME}" == "pull_request" || "${CPFLOW_EVENT_NAME}" == "pull_request_target" ) ]]; then
- echo "ready=false" >> "$GITHUB_OUTPUT"
- {
- echo "Control Plane review app automation is not configured yet."
- echo
- echo "Missing required GitHub configuration:"
- printf -- '- `%s`\n' "${missing[@]}"
- echo
- echo "Pushes to this pull request will skip review app deploys until the repository is configured."
- } >> "$GITHUB_STEP_SUMMARY"
- exit 0
- fi
-
- printf 'Missing required GitHub configuration:\n- %s\n' "${missing[@]}" >&2
- exit 1
\ No newline at end of file
diff --git a/.github/actions/cpflow-wait-for-health/action.yml b/.github/actions/cpflow-wait-for-health/action.yml
deleted file mode 100644
--- a/.github/actions/cpflow-wait-for-health/action.yml
+++ /dev/null
@@ -1,92 +1,0 @@
-name: Wait for Control Plane workload health
-description: >-
- Polls the workload's status endpoint with curl and exits success when the
- HTTP response status is in the accepted list. Fails non-zero (and reports
- `healthy=false`) once retries are exhausted.
-
-inputs:
- workload_name:
- description: Workload to query (e.g. `rails`).
- required: true
- app_name:
- description: GVC / Control Plane app name the workload belongs to.
- required: true
- org:
- description: Control Plane organization.
- required: true
- max_retries:
- description: Number of attempts before giving up.
- required: false
- default: "24"
- interval_seconds:
- description: Seconds to sleep between attempts.
- required: false
- default: "15"
- accepted_statuses:
- description: >-
- Space-separated list of HTTP status codes considered healthy. The default
- `200 301 302` accepts redirects because curl is invoked without `-L`, so a
- root path that auth-redirects looks like a redirect, not a failure.
- required: false
- default: "200 301 302"
- curl_max_time:
- description: Per-request curl timeout, seconds.
- required: false
- default: "10"
-
-outputs:
- healthy:
- description: '"true" once a healthy response was observed; "false" otherwise.'
- value: ${{ steps.poll.outputs.healthy }}
-
-runs:
- using: composite
- steps:
- - name: Poll workload endpoint
- id: poll
- shell: bash
- env:
- CPFLOW_WORKLOAD_NAME: ${{ inputs.workload_name }}
- CPFLOW_APP_NAME: ${{ inputs.app_name }}
- CPFLOW_ORG: ${{ inputs.org }}
- CPFLOW_MAX_RETRIES: ${{ inputs.max_retries }}
- CPFLOW_INTERVAL_SECONDS: ${{ inputs.interval_seconds }}
- CPFLOW_ACCEPTED_STATUSES: ${{ inputs.accepted_statuses }}
- CPFLOW_CURL_MAX_TIME: ${{ inputs.curl_max_time }}
- run: |
- set -euo pipefail
-
- read -r -a accepted_statuses <<< "${CPFLOW_ACCEPTED_STATUSES}"
-
- for attempt in $(seq 1 "${CPFLOW_MAX_RETRIES}"); do
- echo "Health check attempt ${attempt}/${CPFLOW_MAX_RETRIES}"
-
- if ! workload_json="$(cpln workload get "${CPFLOW_WORKLOAD_NAME}" --gvc "${CPFLOW_APP_NAME}" --org "${CPFLOW_ORG}" -o json 2>&1)"; then
- echo "::error::Workload '${CPFLOW_WORKLOAD_NAME}' not found in GVC '${CPFLOW_APP_NAME}'. Set PRIMARY_WORKLOAD to the correct workload name." >&2
- printf '%s\n' "${workload_json}" >&2
- echo "healthy=false" >> "$GITHUB_OUTPUT"
- exit 1
- fi
-
- endpoint="$(echo "${workload_json}" | jq -r '.status.endpoint // empty')"
- if [[ -n "${endpoint}" ]]; then
- http_status="$(curl -s -o /dev/null -w '%{http_code}' --max-time "${CPFLOW_CURL_MAX_TIME}" "${endpoint}" 2>/dev/null || echo 000)"
- echo "Endpoint: ${endpoint}, HTTP status: ${http_status}"
-
- for accepted in "${accepted_statuses[@]}"; do
- if [[ "${http_status}" == "${accepted}" ]]; then
- echo "healthy=true" >> "$GITHUB_OUTPUT"
- exit 0
- fi
- done
- else
- echo "Workload '${CPFLOW_WORKLOAD_NAME}' has no endpoint yet; waiting for one to be assigned."
- fi
-
- if [[ "${attempt}" -lt "${CPFLOW_MAX_RETRIES}" ]]; then
- sleep "${CPFLOW_INTERVAL_SECONDS}"
- fi
- done
-
- echo "healthy=false" >> "$GITHUB_OUTPUT"
- exit 1
\ No newline at end of file
diff --git a/.github/workflows/cpflow-cleanup-stale-review-apps.yml b/.github/workflows/cpflow-cleanup-stale-review-apps.yml
--- a/.github/workflows/cpflow-cleanup-stale-review-apps.yml
+++ b/.github/workflows/cpflow-cleanup-stale-review-apps.yml
@@ -8,49 +8,9 @@
permissions:
contents: read
-concurrency:
- # Single global group: only one cleanup sweep at a time. Independent of review-app
- # deploy/delete groups (different keys), so cleanup will not block per-PR work.
- group: cpflow-cleanup-stale-review-apps
- # A cancelled `cpflow cleanup-stale-apps` can leave half-deleted review apps; let
- # the in-flight run finish before the next scheduled tick begins.
- cancel-in-progress: false
-
jobs:
cleanup:
- runs-on: ubuntu-latest
- timeout-minutes: 30
- steps:
- - name: Checkout repository
- uses: actions/checkout@v6
- with:
- persist-credentials: false
-
- - name: Validate required secrets and variables
- uses: ./.github/actions/cpflow-validate-config
- env:
- CPLN_TOKEN_STAGING: ${{ secrets.CPLN_TOKEN_STAGING }}
- CPLN_ORG_STAGING: ${{ vars.CPLN_ORG_STAGING }}
- REVIEW_APP_PREFIX: ${{ vars.REVIEW_APP_PREFIX }}
- with:
- required: |
- secret:CPLN_TOKEN_STAGING
- variable:CPLN_ORG_STAGING
- variable:REVIEW_APP_PREFIX
-
- - name: Setup environment
- uses: ./.github/actions/cpflow-setup-environment
- with:
- token: ${{ secrets.CPLN_TOKEN_STAGING }}
- org: ${{ vars.CPLN_ORG_STAGING }}
- cpln_cli_version: ${{ vars.CPLN_CLI_VERSION }}
- cpflow_version: ${{ vars.CPFLOW_VERSION }}
-
- - name: Remove stale review apps
- env:
- REVIEW_APP_PREFIX: ${{ vars.REVIEW_APP_PREFIX }}
- CPLN_ORG_STAGING: ${{ vars.CPLN_ORG_STAGING }}
- shell: bash
- run: |
- set -euo pipefail
- cpflow cleanup-stale-apps -a "${REVIEW_APP_PREFIX}" --org "${CPLN_ORG_STAGING}" --yes
+ uses: shakacode/control-plane-flow/.github/workflows/cpflow-cleanup-stale-review-apps.yml@jg-codex/reusable-github-actions
+ with:
+ control_plane_flow_ref: jg-codex/reusable-github-actions
+ secrets: inherit
diff --git a/.github/workflows/cpflow-delete-review-app.yml b/.github/workflows/cpflow-delete-review-app.yml
--- a/.github/workflows/cpflow-delete-review-app.yml
+++ b/.github/workflows/cpflow-delete-review-app.yml
@@ -17,17 +17,6 @@
issues: write
pull-requests: write
-concurrency:
- group: cpflow-delete-review-app-${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }}
- # Deletions must not cancel each other mid-flight — a cancelled `cpln` delete can leave
- # partial state behind. Let the in-progress deletion finish before the next run starts.
- cancel-in-progress: false
-
-env:
- APP_NAME: ${{ vars.REVIEW_APP_PREFIX }}-${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }}
- CPLN_ORG: ${{ vars.CPLN_ORG_STAGING }}
- PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }}
-
jobs:
delete-review-app:
if: |
@@ -37,147 +26,7 @@
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) ||
(github.event_name == 'pull_request_target' && github.event.action == 'closed') ||
github.event_name == 'workflow_dispatch'
- runs-on: ubuntu-latest
- timeout-minutes: 15
-
- steps:
- - name: React to delete command
- if: github.event_name == 'issue_comment'
- continue-on-error: true
- uses: actions/github-script@v8
- with:
- script: |
- try {
- await github.rest.reactions.createForIssueComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
- comment_id: context.payload.comment.id,
- content: "eyes"
- });
- } catch (error) {
- if (error.status === 422) {
- core.info("Delete command reaction already exists.");
- } else {
- throw error;
- }
- }
-
- # pull_request_target is intentional: PR-close events from forks need access
- # to staging secrets so this workflow can delete review apps and update PR
- # comments. This checkout is safe because it does not set `ref:`; GitHub checks
- # out the base branch's trusted workflow code, not the fork head. Do not add
- # `ref: ${{ github.event.pull_request.head.sha }}` here without re-evaluating
- # the trust boundary. All local composite actions below are therefore loaded from
- # trusted base-branch code; keep them that way when changing this workflow.
- - name: Checkout repository
- uses: actions/checkout@v6
- with:
- # Delete only invokes `cpln`/`cpflow`; no git push happens, so drop the
- # GITHUB_TOKEN credential helper to keep the token out of .git/config under
- # `pull_request_target`, which has access to repository secrets.
- persist-credentials: false
-
- - name: Validate required secrets and variables
- id: config
- uses: ./.github/actions/cpflow-validate-config
- env:
- CPLN_TOKEN_STAGING: ${{ secrets.CPLN_TOKEN_STAGING }}
- CPLN_ORG_STAGING: ${{ vars.CPLN_ORG_STAGING }}
- REVIEW_APP_PREFIX: ${{ vars.REVIEW_APP_PREFIX }}
- with:
- required: |
- secret:CPLN_TOKEN_STAGING
- variable:CPLN_ORG_STAGING
- variable:REVIEW_APP_PREFIX
- pull_request_friendly: "true"
-
- - name: Setup environment
- if: steps.config.outputs.ready == 'true'
- uses: ./.github/actions/cpflow-setup-environment
- with:
- token: ${{ secrets.CPLN_TOKEN_STAGING }}
- org: ${{ vars.CPLN_ORG_STAGING }}
- cpln_cli_version: ${{ vars.CPLN_CLI_VERSION }}
- cpflow_version: ${{ vars.CPFLOW_VERSION }}
-
- - name: Set workflow links
- if: steps.config.outputs.ready == 'true'
- uses: actions/github-script@v8
- with:
- script: |
- const workflowUrl = `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
- core.exportVariable("WORKFLOW_URL", workflowUrl);
- core.exportVariable(
- "CONSOLE_URL",
- `https://console.cpln.io/console/org/${process.env.CPLN_ORG}/-info`
- );
-
- - name: Create initial PR comment
- if: steps.config.outputs.ready == 'true'
- id: create-comment
- uses: actions/github-script@v8
- with:
- script: |
- const body = [
- "## 🗑️ Deleting review app...",
- "",
- `_Removing the review app for PR #${process.env.PR_NUMBER}_`
- ].join("\n");
-
- const comment = await github.rest.issues.createComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: Number(process.env.PR_NUMBER),
- body
- });
- core.setOutput("comment-id", comment.data.id);
-
- - name: Delete review app
- if: steps.config.outputs.ready == 'true'
- uses: ./.github/actions/cpflow-delete-control-plane-app
- with:
- app_name: ${{ env.APP_NAME }}
- cpln_org: ${{ vars.CPLN_ORG_STAGING }}
- review_app_prefix: ${{ vars.REVIEW_APP_PREFIX }}
-
- # Finalizer still runs after delete failures, but only after config validation
- # created the initial PR comment and workflow link env vars it updates.
- - name: Finalize delete status
- if: always() && steps.config.outputs.ready == 'true'
- uses: actions/github-script@v8
- env:
- COMMENT_ID: ${{ steps.create-comment.outputs.comment-id }}
- JOB_STATUS: ${{ job.status }}
- with:
- script: |
- const commentId = Number(process.env.COMMENT_ID);
... diff truncated: showing 800 of 2092 linesYou can send follow-ups to the cloud agent here.
| issue_number: prNumber, | ||
| body: helpText | ||
| }); | ||
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-help-command.yml@jg-codex/reusable-github-actions |
There was a problem hiding this comment.
Help wrappers omit flow ref
Medium Severity
The help reusable-workflow callers invoke shakacode/control-plane-flow at jg-codex/reusable-github-actions but, unlike every other regenerated cpflow-* wrapper, they do not pass control_plane_flow_ref. If the upstream help workflows use that input to check out shared actions or scripts, help runs can default to a different ref than deploy/delete and miss the intended Node 24 or reaction behavior.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit b35cb8c. Configure here.
| issue_number: prNumber, | ||
| body: helpText | ||
| }); | ||
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-help-command.yml@jg-codex/reusable-github-actions |
There was a problem hiding this comment.
Missing control_plane_flow_ref input: Every other caller explicitly passes control_plane_flow_ref: jg-codex/reusable-github-actions, but this workflow omits it. If the upstream workflow uses that input to resolve nested action refs, this caller may silently use a different (possibly main) branch. Should be consistent with the other callers:
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-help-command.yml@jg-codex/reusable-github-actions | |
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-help-command.yml@jg-codex/reusable-github-actions | |
| with: | |
| control_plane_flow_ref: jg-codex/reusable-github-actions |
b35cb8c to
3462b56
Compare
Code Review: Regenerate cpflow review app feedbackOverviewThis PR migrates all 🔴 Critical: Pinning to a development branchEvery reusable-workflow call pins to uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-review-app.yml@jg-codex/reusable-github-actionsThis is the single biggest concern:
Before merging, this should be changed to a pinned release tag (e.g. 🔴 Critical:
|
| # | Severity | Item |
|---|---|---|
| 1 | 🔴 Critical | All external refs point to a feature branch, not a tag/SHA |
| 2 | 🔴 Critical | secrets: inherit passes production credentials to an unpinned branch |
| 3 | 🟡 Medium | contents: write escalation in promote workflow may be unneeded |
| 4 | 🟡 Medium | Concurrency guards removed — need upstream confirmation they exist |
| 5 | 🟡 Medium | cpflow-help-command.yml missing with: control_plane_flow_ref: |
| 6 | 🟢 Low | PR description says cpflow-setup-environment was kept; diff deletes it |
The overall direction is sound — centralising these workflows upstream reduces duplication. The blocking items are the branch pinning and the secrets: inherit surface area. Recommend merging only after the upstream PRs land on a stable tag/SHA and the ref is updated here accordingly.
| @@ -8,49 +8,9 @@ on: | |||
| permissions: | |||
| contents: read | |||
There was a problem hiding this comment.
Supply chain risk: This ref points to a feature branch (jg-codex/reusable-github-actions), not an immutable tag or SHA. Any force-push to that branch in the upstream repo silently changes the behaviour of this workflow. Combined with secrets: inherit below, a compromised or accidentally modified branch can exfiltrate CPLN_TOKEN_STAGING.
Please pin to a release tag (e.g. @v1.2.3) or a full commit SHA once the upstream PRs (#303, #304) land on a stable ref.
| contents: read | |
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-cleanup-stale-review-apps.yml@<REPLACE_WITH_TAG_OR_SHA> |
| # Don't cancel an in-flight promotion: a half-finished `cpflow deploy-image` plus a | ||
| # rollback can leave production in a worse state than letting the first run finish. | ||
| cancel-in-progress: false | ||
| contents: write |
There was a problem hiding this comment.
Permission escalation: The previous code used contents: read at the top level and scoped contents: write only to the create-github-release job. Now contents: write is granted to the entire workflow at the top level. If the upstream reusable workflow handles release creation internally that's fine, but it should be documented. If not, this should revert to contents: read.
| contents: write | |
| contents: read |
| issue_number: prNumber, | ||
| body: helpText | ||
| }); | ||
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-help-command.yml@jg-codex/reusable-github-actions |
There was a problem hiding this comment.
Inconsistency with other callers: Every other reusable-workflow call in this PR includes a with: control_plane_flow_ref: block, but this caller does not. If the upstream cpflow-help-command.yml accepts that input it will silently use a default that may not match jg-codex/reusable-github-actions. Align with the other callers for consistency and to avoid silent default mismatch.
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-help-command.yml@jg-codex/reusable-github-actions | |
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-help-command.yml@jg-codex/reusable-github-actions | |
| with: | |
| control_plane_flow_ref: jg-codex/reusable-github-actions |
3462b56 to
f2246c2
Compare
Code ReviewOverviewThis PR consolidates cpflow CI by delegating all review-app, staging, and production workflow logic to reusable workflows in the upstream The direction is sound — upstream-owned reusable workflows are easier to maintain and keep in sync. However there are a few concerns worth addressing before merge. Critical: Supply-chain / secret exposure riskAll seven reusable-workflow calls are pinned to a mutable branch ref ( A mutable branch can be force-pushed at any time, silently changing what runs in your CI without any PR or review in this repo. Combined with Recommendation: Pin to an immutable commit SHA (e.g. High:
|
| @@ -8,49 +8,9 @@ on: | |||
| permissions: | |||
| contents: read | |||
There was a problem hiding this comment.
All seven workflow calls use @jg-codex/reusable-github-actions — a mutable branch — combined with secrets: inherit. A force-push to that branch in the upstream repo would silently change what code runs against your secrets (CPLN_TOKEN_STAGING, DOCKER_BUILD_SSH_KEY, etc.) with no PR in this repository.
Pin to an immutable SHA instead:
| contents: read | |
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-cleanup-stale-review-apps.yml@<commit-sha> |
Or at minimum pin to a release tag (@v1, @v2.x) so updates require a deliberate bump. The same applies to every other uses: line in this PR.
| comment_id: commentId, | ||
| body: success ? successBody : failureBody | ||
| }); | ||
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-review-app.yml@jg-codex/reusable-github-actions |
There was a problem hiding this comment.
Passing the branch name as control_plane_flow_ref multiplies the mutable-ref risk: if the upstream reusable workflow uses this input to check out further code or call nested workflows, the attack surface widens. It also makes the behaviour of this input entirely opaque to this repo — a future upstream change to how control_plane_flow_ref is consumed would silently change CI without any review here.
| @@ -14,129 +14,10 @@ on: | |||
| permissions: | |||
| contents: read | |||
|
|
|||
There was a problem hiding this comment.
The concurrency: block that prevented mid-flight deploy cancellations (cancel-in-progress: false) was removed. The old comment explained the risk clearly: a cancelled cpflow deploy-image mid-rollout can leave staging in a partially-deployed state. Confirm the upstream reusable workflow implements equivalent concurrency guards, otherwise a rapid push sequence could trigger this failure mode.
| # Don't cancel an in-flight promotion: a half-finished `cpflow deploy-image` plus a | ||
| # rollback can leave production in a worse state than letting the first run finish. | ||
| cancel-in-progress: false | ||
| contents: write |
There was a problem hiding this comment.
The top-level permissions: changed from contents: read to contents: write. Previously, contents: write was scoped only to the create-github-release child job. Now the entire workflow — and therefore the upstream reusable workflow — runs with write access to repository contents.
Consider keeping contents: read here and letting the upstream reusable workflow request contents: write only for the job that needs it, or confirm that the upstream workflow re-scopes permissions at the job level.
f2246c2 to
37222b2
Compare
Code Review: PR #741 — Regenerate cpflow review-app workflowsOverviewThis PR replaces all local composite actions ( Critical: Mutable upstream refEvery workflow in this PR uses the same external ref: uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-review-app.yml@jg-codex/reusable-github-actions
Recommendation: Before merging, pin to a commit SHA or a semantically versioned tag (e.g. High:
|
| Concern | Severity |
|---|---|
| Mutable branch ref for external workflows | Critical |
secrets: inherit to external mutable code |
High |
contents: write scoped too broadly |
Medium |
| Concurrency controls may be silently dropped | Medium |
| Security comment removed | Low |
The approach of delegating to upstream reusable workflows is reasonable as a long-term architecture, but the current implementation should be tightened — at minimum, pin the upstream ref to an immutable SHA or tag before merging.
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-review-app.yml@jg-codex/reusable-github-actions | ||
| with: | ||
| control_plane_flow_ref: jg-codex/reusable-github-actions | ||
| secrets: inherit |
There was a problem hiding this comment.
Critical: mutable branch ref
@jg-codex/reusable-github-actions is a branch, not a tag or immutable commit SHA. Any force-push to that branch immediately changes what runs in production and review-app deployments — including steps that receive secrets: inherit.
Pin to an immutable SHA or a semantically versioned tag before merging:
| secrets: inherit | |
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-review-app.yml@<commit-sha-or-vX.Y.Z> |
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: |
There was a problem hiding this comment.
Medium: concurrency controls removed
This concurrency: block (with cancel-in-progress: false) prevented overlapping cleanup sweeps that could leave review apps in a half-deleted state. It's removed from all caller workflows in this PR.
Before merging, verify that the upstream reusable workflows replicate equivalent concurrency groups — or add concurrency: back to the caller side. A missing concurrency guard here is a correctness issue, not just a performance one.
| # checked out — the job only calls `actions/github-script` with a hardcoded message. | ||
| # Do not switch this to `pull_request` or add a checkout step without re-evaluating. | ||
| # checked out — the job only calls the upstream reusable workflow with a hardcoded | ||
| # message. |
There was a problem hiding this comment.
The previous comment included an explicit warning: "Do not switch this to pull_request or add a checkout step without re-evaluating." The checkout-step part of that guidance is the most actionable and was removed in this edit. Consider restoring it so future contributors understand the trust boundary.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 37222b29b0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| gh release create "${release_tag}" \ | ||
| --title "Production Release ${release_date} ${timestamp}" \ | ||
| --notes "Promoted ${STAGING_APP_NAME} to ${PRODUCTION_APP_NAME} on ${release_date} at ${timestamp}." | ||
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-promote-staging-to-production.yml@jg-codex/reusable-github-actions |
There was a problem hiding this comment.
Pin production reusable workflow to immutable SHA
Reference the called workflow by full commit SHA instead of the mutable branch @jg-codex/reusable-github-actions. This production promotion job now executes whatever code that branch points to at runtime while inheriting repository secrets, so a force-push or branch deletion in shakacode/control-plane-flow can either run unexpected deployment logic or break promotions entirely; pinning to an immutable revision restores deterministic and auditable behavior.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Pinned upstream feature branch ref
- Updated all cpflow reusable workflow callers and control_plane_flow_ref inputs from the feature branch to the upstream main branch.
Or push these changes by commenting:
@cursor push e92e7b1ec9
Preview (e92e7b1ec9)
diff --git a/.github/workflows/cpflow-cleanup-stale-review-apps.yml b/.github/workflows/cpflow-cleanup-stale-review-apps.yml
--- a/.github/workflows/cpflow-cleanup-stale-review-apps.yml
+++ b/.github/workflows/cpflow-cleanup-stale-review-apps.yml
@@ -10,7 +10,7 @@
jobs:
cleanup:
- uses: shakacode/control-plane-flow/.github/workflows/cpflow-cleanup-stale-review-apps.yml@jg-codex/reusable-github-actions
+ uses: shakacode/control-plane-flow/.github/workflows/cpflow-cleanup-stale-review-apps.yml@main
with:
- control_plane_flow_ref: jg-codex/reusable-github-actions
+ control_plane_flow_ref: main
secrets: inherit
diff --git a/.github/workflows/cpflow-delete-review-app.yml b/.github/workflows/cpflow-delete-review-app.yml
--- a/.github/workflows/cpflow-delete-review-app.yml
+++ b/.github/workflows/cpflow-delete-review-app.yml
@@ -26,7 +26,7 @@
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) ||
(github.event_name == 'pull_request_target' && github.event.action == 'closed') ||
github.event_name == 'workflow_dispatch'
- uses: shakacode/control-plane-flow/.github/workflows/cpflow-delete-review-app.yml@jg-codex/reusable-github-actions
+ uses: shakacode/control-plane-flow/.github/workflows/cpflow-delete-review-app.yml@main
with:
- control_plane_flow_ref: jg-codex/reusable-github-actions
+ control_plane_flow_ref: main
secrets: inherit
diff --git a/.github/workflows/cpflow-deploy-review-app.yml b/.github/workflows/cpflow-deploy-review-app.yml
--- a/.github/workflows/cpflow-deploy-review-app.yml
+++ b/.github/workflows/cpflow-deploy-review-app.yml
@@ -30,7 +30,7 @@
github.event.issue.pull_request &&
contains(fromJson('["+review-app-deploy","+review-app-deploy\n","+review-app-deploy\r\n"]'), github.event.comment.body) &&
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association))
- uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-review-app.yml@jg-codex/reusable-github-actions
+ uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-review-app.yml@main
with:
- control_plane_flow_ref: jg-codex/reusable-github-actions
+ control_plane_flow_ref: main
secrets: inherit
diff --git a/.github/workflows/cpflow-deploy-staging.yml b/.github/workflows/cpflow-deploy-staging.yml
--- a/.github/workflows/cpflow-deploy-staging.yml
+++ b/.github/workflows/cpflow-deploy-staging.yml
@@ -16,8 +16,8 @@
jobs:
deploy-staging:
- uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-staging.yml@jg-codex/reusable-github-actions
+ uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-staging.yml@main
with:
- control_plane_flow_ref: jg-codex/reusable-github-actions
+ control_plane_flow_ref: main
staging_app_branch_default: ""
secrets: inherit
diff --git a/.github/workflows/cpflow-help-command.yml b/.github/workflows/cpflow-help-command.yml
--- a/.github/workflows/cpflow-help-command.yml
+++ b/.github/workflows/cpflow-help-command.yml
@@ -23,4 +23,4 @@
contains(fromJson('["+review-app-help","+review-app-help\n","+review-app-help\r\n"]'), github.event.comment.body) &&
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) ||
github.event_name == 'workflow_dispatch'
- uses: shakacode/control-plane-flow/.github/workflows/cpflow-help-command.yml@jg-codex/reusable-github-actions
+ uses: shakacode/control-plane-flow/.github/workflows/cpflow-help-command.yml@main
diff --git a/.github/workflows/cpflow-promote-staging-to-production.yml b/.github/workflows/cpflow-promote-staging-to-production.yml
--- a/.github/workflows/cpflow-promote-staging-to-production.yml
+++ b/.github/workflows/cpflow-promote-staging-to-production.yml
@@ -14,7 +14,7 @@
jobs:
promote-to-production:
if: github.event.inputs.confirm_promotion == 'promote'
- uses: shakacode/control-plane-flow/.github/workflows/cpflow-promote-staging-to-production.yml@jg-codex/reusable-github-actions
+ uses: shakacode/control-plane-flow/.github/workflows/cpflow-promote-staging-to-production.yml@main
with:
- control_plane_flow_ref: jg-codex/reusable-github-actions
+ control_plane_flow_ref: main
secrets: inherit
diff --git a/.github/workflows/cpflow-review-app-help.yml b/.github/workflows/cpflow-review-app-help.yml
--- a/.github/workflows/cpflow-review-app-help.yml
+++ b/.github/workflows/cpflow-review-app-help.yml
@@ -15,4 +15,4 @@
jobs:
show-help:
if: vars.REVIEW_APP_PREFIX != ''
- uses: shakacode/control-plane-flow/.github/workflows/cpflow-review-app-help.yml@jg-codex/reusable-github-actions
+ uses: shakacode/control-plane-flow/.github/workflows/cpflow-review-app-help.yml@mainYou can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit 37222b2. Configure here.
Code Review: Regenerate cpflow review app feedbackOverviewThis PR consolidates ~1,800 lines of inline CI/CD logic (6 composite actions + in-workflow steps) into thin delegating wrappers that call pinned upstream reusable workflows from Several items below warrant attention before merging. Security:
|
| # Don't cancel an in-flight promotion: a half-finished `cpflow deploy-image` plus a | ||
| # rollback can leave production in a worse state than letting the first run finish. | ||
| cancel-in-progress: false | ||
| contents: write |
There was a problem hiding this comment.
The old file scoped contents: write to just the create-github-release job. This top-level declaration now grants write access for the entire workflow (including the production promotion job). The permission is necessary for GitHub release creation, but a comment explaining the reason would prevent a future reviewer from narrowing it back to read.
| contents: write | |
| contents: write # required for gh release create in the upstream promote workflow |
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-promote-staging-to-production.yml@2db67abcfc0041ec155203f81d19d28aaeb784b5 | ||
| with: | ||
| control_plane_flow_ref: 2db67abcfc0041ec155203f81d19d28aaeb784b5 | ||
| secrets: inherit |
There was a problem hiding this comment.
secrets: inherit forwards every repository secret to the upstream reusable workflow, not just the Control Plane tokens. This is the broadest possible grant. For a production promotion workflow this is especially sensitive — if the upstream is ever compromised all secrets (staging token, production token, any other repo secrets) are exposed.
If the upstream workflow documents which secrets it consumes, consider whether it supports explicit secret mappings instead, or add a comment acknowledging the accepted surface.
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-staging.yml@2db67abcfc0041ec155203f81d19d28aaeb784b5 | ||
| with: | ||
| control_plane_flow_ref: 2db67abcfc0041ec155203f81d19d28aaeb784b5 | ||
| staging_app_branch_default: "" |
There was a problem hiding this comment.
What does the upstream workflow do when staging_app_branch_default is ""? If it means "no custom branch — use main/master," the empty string is correct but the intent isn't obvious. A brief comment would help:
| staging_app_branch_default: "" | |
| staging_app_branch_default: "" # empty = no override; upstream defaults to main/master |
25d1f36 to
6b5760d
Compare
| # Don't cancel an in-flight promotion: a half-finished `cpflow deploy-image` plus a | ||
| # rollback can leave production in a worse state than letting the first run finish. | ||
| cancel-in-progress: false | ||
| contents: write |
There was a problem hiding this comment.
Permission scope expanded — contents: write was previously narrowly scoped to the create-github-release job only. Now it's granted at the top-level workflow, so the promote-to-production job also runs with contents: write.
GitHub doesn't let a calling workflow restrict permissions below what a reusable workflow declares — but it can be no broader than what the caller grants here. If the upstream reusable workflow actually needs contents: write only for the release step, consider whether the promotion job itself should have that permission. Verify the upstream workflow's permissions: block to confirm this isn't unnecessarily broad.
| issue_number: prNumber, | ||
| body: helpText | ||
| }); | ||
| uses: shakacode/control-plane-flow/.github/workflows/cpflow-help-command.yml@8e9c0c5e9991ac8651ae2721830bf5231f34de5c |
There was a problem hiding this comment.
Inconsistent with other delegating workflows — Five of the seven refactored workflows pass control_plane_flow_ref via with:, but this one (and cpflow-review-app-help.yml) omit the with: block entirely.
If the upstream workflow accepts a control_plane_flow_ref input, omitting it here means any sub-workflows it calls might not be pinned to the same SHA. If it's genuinely not needed for these two workflows, a brief comment explaining why would prevent future readers from adding it unnecessarily — or missing a real gap.
Code ReviewOverviewThis PR replaces ~1,800 lines of in-repo composite actions and workflow steps with thin delegating wrappers that call SHA-pinned reusable workflows from Strengths
Concerns1.
|



Summary
Regenerates the generated cpflow review-app workflows after upstream
shakacode/control-plane-flowPRs #303 and #304 merged.This rolls out:
actions/checkout@v6,actions/github-script@v8) in generated cpflow workflows+review-app-deploy,+review-app-delete, or+review-app-helpcommands are picked upREVIEW_APP_DEPLOYING_ICON_URL, withnoneas the text fallbackI intentionally kept the existing downstream
cpflow-setup-environmentaction unchanged because upstream PR #297 is still open; regenerating it from current upstreammainwould reintroduce literal${{ vars.* }}examples in composite action descriptions.Testing
git diff --cached --checkbin/conductor-exec ruby -e 'require "yaml"; paths = Dir[".github/workflows/cpflow-*.yml", ".github/actions/cpflow-*/*.yml", ".github/actions/cpflow-*/action.yml"].sort; paths.each { |path| YAML.load_file(path, aliases: true) }; puts "parsed #{paths.size} workflow/action YAML files"'actionlint -ignore 'SC2129' .github/workflows/cpflow-cleanup-stale-review-apps.yml .github/workflows/cpflow-delete-review-app.yml .github/workflows/cpflow-deploy-review-app.yml .github/workflows/cpflow-deploy-staging.yml .github/workflows/cpflow-help-command.yml .github/workflows/cpflow-promote-staging-to-production.yml .github/workflows/cpflow-review-app-help.ymlAfter this merges to
master, open or reuse a fresh test PR and comment+review-app-deploy; issue-comment workflows load from the default branch, so merging this PR first is the meaningful test path.Note
Medium Risk
Switches the repo’s deploy/promote/review-app automation to reusable workflows from
shakacode/control-plane-flow, changing critical CI/CD behavior and introducing an external pinned dependency. Risk is moderated by SHA pinning but failures/mismatches could break deployments or PR automation.Overview
Refactors the generated
cpflow-*GitHub Actions automation to delegate almost all logic to upstream reusable workflows inshakacode/control-plane-flow(pinned by SHA) withsecrets: inherit, replacing the previously in-repo step implementations.Removes the local composite actions/scripts that handled config validation, environment setup, Docker image builds (incl. SSH key handling), app deletion, release-phase detection, and health polling.
Updates
.github/cpflow-help.mdto document the new optionalREVIEW_APP_DEPLOYING_ICON_URLvariable and clarifies PR-branch workflow testing guidance; adjusts workflow permissions (notably promotion now requestscontents: write).Reviewed by Cursor Bugbot for commit 6b5760d. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit
New Features
nonefor a text fallback.Documentation
Chores