Conversation
| cpflow_version: | ||
| description: cpflow gem version | ||
| required: false | ||
| default: "__CPFLOW_VERSION__" |
There was a problem hiding this comment.
Bug: unreplaced placeholder will break every workflow run.
gem install cpflow -v __CPFLOW_VERSION__ will fail because RubyGems will try to find a gem with the literal version string __CPFLOW_VERSION__.
The old setup-environment action had 4.1.1 hardcoded. This needs a real version before merging.
| default: "__CPFLOW_VERSION__" | |
| default: "4.1.1" |
(replace 4.1.1 with whatever the current target cpflow version is)
| eval "$(ssh-agent -s)" | ||
| trap 'ssh-agent -k >/dev/null' EXIT | ||
| ssh-add - <<< "${{ inputs.docker_build_ssh_key }}" | ||
| docker_build_args+=("--ssh default") |
There was a problem hiding this comment.
Bug: --ssh default is added as a single array element instead of two.
When "${docker_build_args[@]}" is expanded, cpflow will receive the argument --ssh default as one token rather than --ssh and default as two separate flags. Docker's --ssh flag expects id[=socket] as its value in the next argument.
| docker_build_args+=("--ssh default") | |
| docker_build_args+=("--ssh" "default") |
|
|
||
| on: | ||
| push: | ||
| branches: ["**"] |
There was a problem hiding this comment.
Unnecessary job runs on every branch push.
branches: ["**"] causes the validate-branch job to spin up a runner for every push to any branch in the repo, even though all non-master/non-staging branches immediately output is_deployable=false and stop. Consider narrowing the trigger to only the branches that will actually deploy:
| branches: ["**"] | |
| branches: ["master", "main"] |
Or, if STAGING_APP_BRANCH must remain configurable to an arbitrary branch at runtime, document this trade-off and accept the cost. But if the staging branch is always master for this repo, restricting the filter avoids the noise and wasted runner minutes.
| if ! exists_output="$(cpflow exists -a "$APP_NAME" --org "$CPLN_ORG" 2>&1)"; then | ||
| if [[ -z "$exists_output" ]]; then | ||
| echo "⚠️ Application does not exist: $APP_NAME" | ||
| exit 0 | ||
| fi | ||
|
|
||
| echo "❌ ERROR: failed to determine whether application exists: $APP_NAME" >&2 | ||
| printf '%s\n' "$exists_output" >&2 | ||
| exit 1 |
There was a problem hiding this comment.
The "does not exist vs. real error" disambiguation here relies on cpflow exists emitting nothing to stdout/stderr when the app is absent but emitting text when a genuine error occurs. That's a reasonable assumption given how cpflow is written, but it's not a documented contract — a future cpflow version that prints "App not found" to stderr would silently route the "not found" path into the error branch instead.
A more defensive approach would be to check the exit code meaning explicitly, e.g. by looking at cpflow exists's documented exit codes, or by passing a flag like --quiet. If cpflow doesn't expose that, at minimum add a comment explaining the assumption so the next reader doesn't have to guess.
Code Review — Modernize Control Plane GitHub FlowOverall this is a solid modernization. The new 🔴 Must fix1. 2. 🟡 Should fix3. Staging deploy triggers on every branch push. 4. 🟢 Noteworthy improvements
Minor observations
|
Greptile SummaryThis PR replaces the legacy Control Plane GitHub Actions workflows and composite actions with a new
Confidence Score: 4/5Mergeable after fixing the two P1 defects; the rest of the workflow logic is correct and well-structured. Two P1 issues exist: an unreplaced version placeholder that will break every cpflow-* workflow on first run, and a mis-formed SSH args array that silently breaks Docker SSH builds. Both are straightforward one-line fixes. .github/actions/cpflow-setup-environment/action.yml (placeholder version) and .github/actions/cpflow-build-docker-image/action.yml (SSH args array) Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[PR opened] -->|pull_request_target| B[cpflow-review-app-help\npost /deploy-review-app hint]
A2[PR push synchronize/reopened] -->|pull_request| C[cpflow-deploy-review-app]
A3[PR comment /deploy-review-app\nOWNER/MEMBER/COLLABORATOR] -->|issue_comment| C
A4[workflow_dispatch] --> C
C --> D{same_repo?}
D -->|no + pull_request| E[Skip: fork PR]
D -->|yes| F[cpflow-setup-environment\nRuby + cpln CLI + cpflow gem]
F --> G[setup-review-app if not exists]
G --> H[cpflow-build-docker-image\nDocker build + push]
H --> I[cpflow deploy-image]
I --> J[GitHub Deployment status\n+ PR comment]
K[PR closed] -->|pull_request_target| L[cpflow-delete-review-app]
K2[comment /delete-review-app\nOWNER/MEMBER/COLLABORATOR] -->|issue_comment| L
L --> M[cpflow-delete-control-plane-app\nprefix-safety check + delete]
N[push to master/STAGING_APP_BRANCH] -->|push| O[cpflow-deploy-staging\nbuild + deploy]
P[workflow_dispatch\nconfirm=promote] --> Q[cpflow-promote-staging-to-production\ncopy image + health check + rollback]
R[nightly cron 00:00] --> S[cpflow-cleanup-stale-review-apps\ncpflow cleanup-stale-apps]
|
| cpflow_version: | ||
| description: cpflow gem version | ||
| required: false | ||
| default: "__CPFLOW_VERSION__" |
There was a problem hiding this comment.
Unreplaced template placeholder breaks gem install
"__CPFLOW_VERSION__" is an unresolved placeholder. Every workflow that calls this action without an explicit cpflow_version input will fail at gem install cpflow -v __CPFLOW_VERSION__ because that string is not a valid gem version. All five callers (cpflow-cleanup-stale-review-apps.yml, cpflow-delete-review-app.yml, cpflow-deploy-review-app.yml, cpflow-deploy-staging.yml, cpflow-promote-staging-to-production.yml) rely on this default.
| default: "__CPFLOW_VERSION__" | |
| default: "4.1.1" |
(Replace with the actual intended version.)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eb3d861d56
ℹ️ 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".
| cpflow_version: | ||
| description: cpflow gem version | ||
| required: false | ||
| default: "__CPFLOW_VERSION__" |
There was a problem hiding this comment.
Replace placeholder cpflow gem version
The cpflow_version input default is still the template token __CPFLOW_VERSION__, and every new cpflow-* workflow invokes this action without overriding that input. That means the setup step runs gem install cpflow -v __CPFLOW_VERSION__, which RubyGems treats as an invalid requirement and exits non-zero, so review-app deploy/delete, staging deploy, production promotion, and cleanup workflows all fail before doing any Control Plane work.
Useful? React with 👍 / 👎.
WalkthroughReplaces legacy Control Plane GitHub Actions and composite actions with a new set of cpflow-* workflows and actions, adds safer delete script, updates Docker build to run Changes
Sequence Diagram(s)sequenceDiagram
participant User as Developer (PR / Comment)
participant GH as GitHub Actions Workflow
participant Composite as cpflow-* Composite Actions
participant CLI as cpflow / cpln CLI
participant CP as Control Plane (org)
User->>GH: open PR / post command / push
GH->>Composite: run setup (token/org, ruby, cli)
Composite->>CLI: install / configure profile
GH->>Composite: build image (with optional SSH)
Composite->>CLI: cpflow build-image --org --commit
CLI->>CP: push image / register
GH->>CLI: cpflow deploy-image (--run-release-phase?)
CLI->>CP: deploy image -> workload
CLI->>GH: return endpoint / status
GH->>User: update PR comment / Deployment status / Notifications
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 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 |
| wait_for_service $(echo $REDIS_URL | sed -e 's|redis://||' -e 's|/.*$||') | ||
|
|
||
| echo " -- Finishing entrypoint.sh, executing '$@'" | ||
| echo " -- Finishing entrypoint.sh, executing '$*'@'" |
There was a problem hiding this comment.
Bug: typo corrupts the echo output.
The change from '$@' to '$*'@' introduces a stray @' literal at the end of the string. Inside the outer double-quotes, the shell sees '$*'@' which expands to the arguments followed by the literal characters @'.
| echo " -- Finishing entrypoint.sh, executing '$*'@'" | |
| echo " -- Finishing entrypoint.sh, executing '$*'" |
While you're here: $* (space-joined) is fine for an echo message, but the actual exec "$@" below must stay with "$@" (array-safe) — that part is correct.
| cpflow_version: | ||
| description: cpflow gem version | ||
| required: false | ||
| default: "__CPFLOW_VERSION__" |
There was a problem hiding this comment.
Unreplaced template placeholder — will break at runtime.
__CPFLOW_VERSION__ is a scaffolding sentinel that was never substituted with a real version. gem install cpflow -v __CPFLOW_VERSION__ will fail with a gem-not-found error the first time any workflow runs.
The old setup-environment action pinned 4.1.1. Either restore that value or pick the version you want to pin:
| default: "__CPFLOW_VERSION__" | |
| default: "4.1.1" |
Code Review - PR 725: Modernize Control Plane GitHub FlowOverviewReplaces the legacy review-app / promote workflows with a cohesive cpflow-* suite. The overall design is solid and a clear improvement over what it replaces. Bugs (must fix)1. entrypoint.sh typo - stray characters appended to echo output The change introduces a stray 2. Unreplaced template placeholder in cpflow-setup-environment/action.yml The Security observations3. pull_request event runs with staging secrets
4. New cpflow-delete-review-app.yml uses pull_request_target The switch from Quality and minor issues5. Expensive tooling setup runs before the app-existence check In 6. Health check accepts only 200/301/302 In 7. Inconsistent fetch-depth between build and deploy jobs in cpflow-deploy-staging.yml The build job uses 8. Typo in .controlplane/readme.md "Pomote latest image" should be "Promote latest image". What is well done
|
| wait_for_service $(echo $REDIS_URL | sed -e 's|redis://||' -e 's|/.*$||') | ||
|
|
||
| echo " -- Finishing entrypoint.sh, executing '$@'" | ||
| echo " -- Finishing entrypoint.sh, executing '$*'@'" |
There was a problem hiding this comment.
Bug: garbled echo output
The change from '$@' to '$*'@' introduces a typo — the closing ' ends the $* expansion prematurely and the literal @' is appended to the output.
Current output at runtime: -- Finishing entrypoint.sh, executing 'arg1 arg2'@'
| echo " -- Finishing entrypoint.sh, executing '$*'@'" | |
| echo " -- Finishing entrypoint.sh, executing '$@'" |
($@ and $* produce the same result in an echo context, so restoring $@ keeps the intent clear.)
| { | ||
| echo "Review app deploys are skipped for fork pull requests." | ||
| echo "This workflow builds Docker images with repository secrets, so review app deploys only run for branches in the base repository." | ||
| } >> "$GITHUB_STEP_SUMMARY" |
There was a problem hiding this comment.
Unquoted expression may cause shell word-splitting
${{ steps.release-phase.outputs.flag }} is interpolated directly into the shell command without quoting. When the flag is non-empty (--run-release-phase) it works fine, but any unexpected whitespace in the output would split it into multiple tokens.
Consider quoting or using an intermediate variable:
| } >> "$GITHUB_STEP_SUMMARY" | |
| cpflow deploy-image -a "${APP_NAME}" ${RELEASE_PHASE_FLAG} --org "${CPLN_ORG}" --verbose |
And populate the variable earlier:
RELEASE_PHASE_FLAG="${{ steps.release-phase.outputs.flag }}"The same pattern applies to the identical line in cpflow-deploy-staging.yml.
| ruby-version: ${{ inputs.ruby_version }} | ||
|
|
||
| - name: Install Control Plane CLI and cpflow gem | ||
| shell: bash |
There was a problem hiding this comment.
Unquoted interpolated values in install commands
The cpln_cli_version and cpflow_version inputs are interpolated without quoting. For semver strings this is low-risk, but consistent quoting is a good habit in case inputs ever contain unexpected characters:
| shell: bash | |
| sudo npm install -g "@controlplane/cli@${{ inputs.cpln_cli_version }}" | |
| cpln --version | |
| gem install cpflow -v "${{ inputs.cpflow_version }}" | |
| cpflow --version |
Code ReviewOverviewThis PR replaces the legacy Critical Bug
SecurityPositive changes:
Observation:
Minor Issues (inline comments posted)
Quality
SummaryOne bug to fix before merging (the |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (4)
.github/workflows/cpflow-promote-staging-to-production.yml (3)
159-187: Health check timeout may be insufficient for production workloads.With 12 retries at 10-second intervals, the total timeout is 2 minutes. Production applications with slow startup times (e.g., Rails apps loading large codebases, running migrations) may need longer.
Consider:
- Making
HEALTH_CHECK_RETRIESandHEALTH_CHECK_INTERVALconfigurable via repository variables- Increasing the default timeout to 5+ minutes for production
💡 Make health check configurable
env: - HEALTH_CHECK_RETRIES: 12 - HEALTH_CHECK_INTERVAL: 10 + HEALTH_CHECK_RETRIES: ${{ vars.HEALTH_CHECK_RETRIES || 30 }} + HEALTH_CHECK_INTERVAL: ${{ vars.HEALTH_CHECK_INTERVAL || 10 }} PRIMARY_WORKLOAD: ${{ vars.PRIMARY_WORKLOAD }}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/cpflow-promote-staging-to-production.yml around lines 159 - 187, The health-check loop currently uses HEALTH_CHECK_RETRIES and HEALTH_CHECK_INTERVAL with a short default that can time out production apps; update the workflow to make HEALTH_CHECK_RETRIES and HEALTH_CHECK_INTERVAL configurable via repository or workflow-level inputs/vars (and document sensible production defaults), and increase the default total wait to at least ~5 minutes (for example set HEALTH_CHECK_RETRIES and/or HEALTH_CHECK_INTERVAL so retries*interval ≳ 300s) so the health-check step (id: health-check) that reads workload_name/PRIMARY_WORKLOAD and polls endpoint with curl has enough time before writing healthy=true/false to GITHUB_OUTPUT.
1-23: Consider adding concurrency control to prevent parallel promotions.This workflow lacks a concurrency group, which could allow multiple simultaneous promotion attempts. For production deployments, this is risky.
🔒 Add concurrency control
permissions: contents: write +concurrency: + group: cpflow-promote-staging-to-production + cancel-in-progress: false + env: HEALTH_CHECK_RETRIES: 12🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/cpflow-promote-staging-to-production.yml around lines 1 - 23, Add a top-level concurrency block to prevent parallel runs of the "Promote Staging to Production" workflow: create a stable group name (e.g., using the workflow name and environment/ref) and set cancel-in-progress: true so only one promote-to-production run executes at a time; update the workflow's top-level (not inside the job) with a concurrency group like "promote-staging-to-production-${{ github.ref }}" to tie concurrency to the target ref/environment and avoid overlapping promotions.
46-57: Complex Ruby one-liner for workload extraction.The inline Ruby code is functional but hard to read and maintain. Consider extracting to a separate script or simplifying.
ruby -e 'require "yaml"; app = ARGV.fetch(0); data = YAML.load_file(".controlplane/controlplane.yml", aliases: true); app_config = data.fetch("apps").fetch(app); workloads = Array(app_config["app_workloads"]); workloads = ["rails"] if workloads.empty?; puts workloads.join(",")'The logic correctly falls back to
["rails"]whenapp_workloadsis not defined.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/cpflow-promote-staging-to-production.yml around lines 46 - 57, The inline Ruby one-liner in the "Resolve production app workloads" step is hard to maintain; move the logic into a small script (e.g., scripts/get_workloads.rb) that implements the same behavior: load ".controlplane/controlplane.yml" with YAML.load_file(..., aliases: true), fetch the app via ARGV[0], read apps -> app_config -> "app_workloads", coerce to Array and default to ["rails"] when empty, then print the comma-joined workloads; update the workflow step to call that script (ruby scripts/get_workloads.rb "${{ vars.PRODUCTION_APP_NAME }}"), preserving the surrounding shell boilerplate (set -euo pipefail) and the final echo "names=${workloads}" >> "$GITHUB_OUTPUT"..github/workflows/cpflow-deploy-staging.yml (1)
107-123: Release phase detection may miss edge cases.The grep pattern
release_script:matches anywhere in the config output, which could produce false positives ifrelease_script:appears in comments or nested under a different key. Consider using a more specific pattern or YAML parsing.However, given that this matches the pattern used in the review-app and production workflows, this is acceptable for consistency.
💡 Alternative: Use YAML parsing for more robust detection
- name: Detect release phase support id: release-phase shell: bash run: | set -euo pipefail - if cpflow config -a "${APP_NAME}" | grep -q "release_script:"; then + release_script="$(cpflow config -a "${APP_NAME}" | ruby -ryaml -e 'puts YAML.safe_load(ARGF.read).dig("release_script") rescue nil')" + if [[ -n "${release_script}" ]]; then echo "flag=--run-release-phase" >> "$GITHUB_OUTPUT" else echo "flag=" >> "$GITHUB_OUTPUT" fi🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/cpflow-deploy-staging.yml around lines 107 - 123, The release-phase detection currently uses cpflow config output with grep "release_script:" which can match comments or nested keys; update the release-phase step so the detection is stricter by either parsing YAML (e.g., pipe cpflow config into a YAML-aware tool) or by changing the grep to an anchored pattern that only matches a top-level key (e.g., anchor for line start with optional whitespace before release_script:); adjust the logic around the release-phase step and the cpflow deploy-image invocation to use the new detection method so behavior remains consistent with the release-phase output flag.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.controlplane/entrypoint.sh:
- Line 24: The log line in entrypoint.sh uses echo " -- Finishing entrypoint.sh,
executing '$*'@'" which flattens arguments and leaves a stray "@'"; replace this
with a printf-based quoted expansion to preserve argument boundaries and remove
the stray characters: use printf with %q to quote each positional argument
(e.g., build a quoted-args string via printf '%q ' "$@" ) and include that in
the log message instead of '$*' and the trailing "@'".
In @.github/actions/cpflow-delete-control-plane-app/delete-app.sh:
- Around line 19-33: The current exists check for cpflow (the cpflow exists
invocation assigning to exists_output) treats any non-zero exit that doesn't
match a small set of error patterns as "app does not exist" and returns success;
instead, change the logic so that any non-zero exit from cpflow exists fails by
default unless the output explicitly indicates the app is missing (match the
exact "not found"/"does not exist"/"Application not found" message your cpflow
CLI returns) — i.e., after running cpflow exists (the exists_output variable for
APP_NAME and CPLN_ORG), check for the explicit "app not found" text and exit 0
only for that case, otherwise log exists_output and exit 1 to surface
auth/API/network errors.
In @.github/actions/cpflow-setup-environment/action.yml:
- Around line 19-23: The action input cpflow_version in action.yml currently
uses the placeholder default "__CPFLOW_VERSION__"; update the cpflow_version
input default to a real version string (or a sensible fallback like a known
stable version or empty to force callers to supply it) so gem install cpflow -v
uses a valid version; modify the cpflow_version default value in the action.yml
input block (the cpflow_version description/default entry) and ensure any
workflow callers that rely on it either pass an explicit cpflow_version or work
with the new default.
In @.github/workflows/cpflow-deploy-review-app.yml:
- Around line 278-288: The YAML run: | block inside the composite action
cpflow-build-docker-image has mis-indented here-doc lines; fix the indentation
in the action.yml run block so that the here-doc content (including the ${ {
inputs.docker_build_ssh_known_hosts } } token and the EOF terminator) is
indented to the same level as the surrounding bash lines within the run: |
literal block, preserving the current here-doc syntax and ensuring YAML treats
those lines as part of the multi-line scalar.
In @.github/workflows/cpflow-deploy-staging.yml:
- Around line 83-91: The composite action
.github/actions/cpflow-build-docker-image/action.yml has a YAML parsing error
because the heredoc/literal block used for the run: script contains a line
starting with ${{ inputs.docker_build_ssh_known_hosts }} that is not
indented/quoted properly; fix the action by correcting the indentation of the
multiline run: block or wrapping the interpolation in quotes so the YAML parser
treats it as scalar (e.g., ensure the heredoc content is indented under run: and
the ${ { inputs.docker_build_ssh_known_hosts } } line is indented the same, or
replace the heredoc with a quoted string), targeting the action.yml entry that
reads inputs.docker_build_ssh_known_hosts and the run: step in the
cpflow-build-docker-image composite action.
---
Nitpick comments:
In @.github/workflows/cpflow-deploy-staging.yml:
- Around line 107-123: The release-phase detection currently uses cpflow config
output with grep "release_script:" which can match comments or nested keys;
update the release-phase step so the detection is stricter by either parsing
YAML (e.g., pipe cpflow config into a YAML-aware tool) or by changing the grep
to an anchored pattern that only matches a top-level key (e.g., anchor for line
start with optional whitespace before release_script:); adjust the logic around
the release-phase step and the cpflow deploy-image invocation to use the new
detection method so behavior remains consistent with the release-phase output
flag.
In @.github/workflows/cpflow-promote-staging-to-production.yml:
- Around line 159-187: The health-check loop currently uses HEALTH_CHECK_RETRIES
and HEALTH_CHECK_INTERVAL with a short default that can time out production
apps; update the workflow to make HEALTH_CHECK_RETRIES and HEALTH_CHECK_INTERVAL
configurable via repository or workflow-level inputs/vars (and document sensible
production defaults), and increase the default total wait to at least ~5 minutes
(for example set HEALTH_CHECK_RETRIES and/or HEALTH_CHECK_INTERVAL so
retries*interval ≳ 300s) so the health-check step (id: health-check) that reads
workload_name/PRIMARY_WORKLOAD and polls endpoint with curl has enough time
before writing healthy=true/false to GITHUB_OUTPUT.
- Around line 1-23: Add a top-level concurrency block to prevent parallel runs
of the "Promote Staging to Production" workflow: create a stable group name
(e.g., using the workflow name and environment/ref) and set cancel-in-progress:
true so only one promote-to-production run executes at a time; update the
workflow's top-level (not inside the job) with a concurrency group like
"promote-staging-to-production-${{ github.ref }}" to tie concurrency to the
target ref/environment and avoid overlapping promotions.
- Around line 46-57: The inline Ruby one-liner in the "Resolve production app
workloads" step is hard to maintain; move the logic into a small script (e.g.,
scripts/get_workloads.rb) that implements the same behavior: load
".controlplane/controlplane.yml" with YAML.load_file(..., aliases: true), fetch
the app via ARGV[0], read apps -> app_config -> "app_workloads", coerce to Array
and default to ["rails"] when empty, then print the comma-joined workloads;
update the workflow step to call that script (ruby scripts/get_workloads.rb "${{
vars.PRODUCTION_APP_NAME }}"), preserving the surrounding shell boilerplate (set
-euo pipefail) and the final echo "names=${workloads}" >> "$GITHUB_OUTPUT".
🪄 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: d8326129-1b6a-414e-878e-1c57e7b86ca6
📒 Files selected for processing (26)
.controlplane/Dockerfile.controlplane/entrypoint.sh.controlplane/readme.md.github/actions/build-docker-image/action.yml.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-setup-environment/action.yml.github/actions/delete-control-plane-app/action.yml.github/actions/delete-control-plane-app/delete-app.sh.github/actions/setup-environment/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.github/workflows/delete-review-app.yml.github/workflows/deploy-to-control-plane-review-app.yml.github/workflows/deploy-to-control-plane-staging.yml.github/workflows/help-command.yml.github/workflows/nightly-remove-stale-review-apps.yml.github/workflows/promote-staging-to-production.yml.github/workflows/review-app-help.ymlREADME.md
💤 Files with no reviewable changes (11)
- .github/workflows/nightly-remove-stale-review-apps.yml
- .github/workflows/review-app-help.yml
- .github/actions/delete-control-plane-app/delete-app.sh
- .github/actions/delete-control-plane-app/action.yml
- .github/actions/setup-environment/action.yml
- .github/workflows/help-command.yml
- .github/workflows/delete-review-app.yml
- .github/workflows/promote-staging-to-production.yml
- .github/workflows/deploy-to-control-plane-staging.yml
- .github/workflows/deploy-to-control-plane-review-app.yml
- .github/actions/build-docker-image/action.yml
| wait_for_service $(echo $REDIS_URL | sed -e 's|redis://||' -e 's|/.*$||') | ||
|
|
||
| echo " -- Finishing entrypoint.sh, executing '$@'" | ||
| echo " -- Finishing entrypoint.sh, executing '$*'@'" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify current log line in the repo
rg -n 'Finishing entrypoint\.sh' .controlplane/entrypoint.sh
# Demonstrate why $* is ambiguous vs argv-safe rendering
bash -lc '
set -- "bundle" "exec rails s" "--port=3000"
echo "with \$*: <$*>"
printf "with %%q:"
printf " %q" "$@"
printf "\n"
'Repository: shakacode/react-webpack-rails-tutorial
Length of output: 339
Fix misleading command logging output—$* flattens arguments and @' appears unintentional.
The $* expansion in the log loses argument boundaries (e.g., "exec rails s" becomes indistinguishable from separate words), making startup logs harder to debug. The trailing @' looks like a stray literal. Use printf with %q formatting to properly quote and preserve argument structure in logs.
Suggested patch
-echo " -- Finishing entrypoint.sh, executing '$*'@'"
+printf ' -- Finishing entrypoint.sh, executing'
+printf ' %q' "$@"
+printf '\n'📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| echo " -- Finishing entrypoint.sh, executing '$*'@'" | |
| printf ' -- Finishing entrypoint.sh, executing' | |
| printf ' %q' "$@" | |
| printf '\n' |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.controlplane/entrypoint.sh at line 24, The log line in entrypoint.sh uses
echo " -- Finishing entrypoint.sh, executing '$*'@'" which flattens arguments
and leaves a stray "@'"; replace this with a printf-based quoted expansion to
preserve argument boundaries and remove the stray characters: use printf with %q
to quote each positional argument (e.g., build a quoted-args string via printf
'%q ' "$@" ) and include that in the log message instead of '$*' and the
trailing "@'".
| if ! exists_output="$(cpflow exists -a "$APP_NAME" --org "$CPLN_ORG" 2>&1)"; then | ||
| case "$exists_output" in | ||
| *"Double check your org"*|*"Unknown API token format"*|*"ERROR"*|*"Error:"*|*"Traceback"*|*"Net::"*) | ||
| echo "❌ ERROR: failed to determine whether application exists: $APP_NAME" >&2 | ||
| printf '%s\n' "$exists_output" >&2 | ||
| exit 1 | ||
| ;; | ||
| esac | ||
|
|
||
| if [[ -n "$exists_output" ]]; then | ||
| printf '%s\n' "$exists_output" | ||
| fi | ||
|
|
||
| echo "⚠️ Application does not exist: $APP_NAME" | ||
| exit 0 |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
For the cpflowCLI commandcpflow exists`, what are the documented exit codes and output patterns for:
- app exists,
- app does not exist,
- auth/token/org errors,
- network/API failures?
Please include authoritative docs or source references.`
💡 Result:
The cpflow CLI is part of the Control Plane Flow project (https://github.com/shakacode/control-plane-flow), a Ruby gem providing Heroku-like deployment to Control Plane Kubernetes. For cpflow exists (checks if an application/GVC exists, used in scripts like if cpflow exists -a
Citations:
- 1: https://github.com/shakacode/heroku-to-control-plane/blob/main/docs/commands.md
- 2: https://www.shakacode.com/control-plane-flow/docs/
- 3: https://github.com/shakacode/control-plane-flow
- 4: https://www.shakacode.com/control-plane-flow/docs/commands/
- 5: https://rubygems.org/gems/cpflow
- 6: https://github.com/shakacode/control-plane-flow/blob/main/cpflow.gemspec
🏁 Script executed:
#!/bin/bash
# First, let's check if we can find the cpflow source code online
# cpflow is at https://github.com/shakacode/control-plane-flow
# Let's look for documentation and source code information
curl -s "https://raw.githubusercontent.com/shakacode/control-plane-flow/main/README.md" | head -100
# Also try to find the exists command implementation
curl -s "https://api.github.com/repos/shakacode/control-plane-flow/contents/lib/cpflow/commands" | jq -r '.[].name' 2>/dev/null || echo "API call details will be checked via web"Repository: shakacode/react-webpack-rails-tutorial
Length of output: 6076
🌐 Web query:
cpflow exists command implementation shakacode/control-plane-flow github exit code
💡 Result:
The cpflow exists command in the shakacode/control-plane-flow GitHub repository is a shell-check utility that verifies if a specified application (GVC, or Global Virtual Cluster) exists on Control Plane. It is designed for use in scripts. Usage example from official docs: if [ cpflow exists -a $APP_NAME ]; then # app exists else # app does not exist fi It requires the -a or --app flag with the app reference name. Exit code: Follows standard shell conventions for script-friendly use (0 if the app exists, non-zero if it does not), consistent with cpflow's general behavior where failures exit non-zero (e.g., code 64 for command failures per CHANGELOG). The incomplete [ cpflow exists -a $APP_NAME ] syntax in docs implies the command returns a shell-true/false value based on exit code for conditional checks. Implementation: Part of the Ruby-based cpflow CLI gem (primary language Ruby, 93.6%). Exact source code not surfaced in search results, but defined as a command in docs/commands.md. Likely uses cpln CLI internally to query GVC existence (e.g., cpln gvc get), exiting 0/1 accordingly. Repository last updated 2026-04-06.
Citations:
- 1: https://www.shakacode.com/control-plane-flow/docs/commands/
- 2: https://github.com/shakacode/heroku-to-control-plane/blob/main/docs/commands.md
- 3: https://www.shakacode.com/control-plane-flow/docs/
- 4: https://github.com/shakacode/control-plane-flow
- 5: https://github.com/shakacode/control-plane-flow/blob/main/CHANGELOG.md
- 6: https://shakacode.com/control-plane-flow/docs/commands
🏁 Script executed:
#!/bin/bash
# Search for the cpflow exists command implementation
# First, check if we can access the GitHub API for file listing
curl -s "https://api.github.com/repos/shakacode/control-plane-flow/git/trees/main?recursive=1" | \
jq -r '.tree[] | select(.path | contains("command") and contains("exist")) | .path' 2>/dev/null | head -20Repository: shakacode/react-webpack-rails-tutorial
Length of output: 131
🏁 Script executed:
#!/bin/bash
# Try to find documentation or tests for exists command
curl -s "https://raw.githubusercontent.com/shakacode/control-plane-flow/main/docs/commands.md" | \
grep -A 30 "exists" | head -50Repository: shakacode/react-webpack-rails-tutorial
Length of output: 1979
🏁 Script executed:
#!/bin/bash
# Search the GitHub repo for exists.rb file
curl -s "https://api.github.com/search/code?q=repo:shakacode/control-plane-flow+exists+filename:exists.rb" | \
jq '.items[0].download_url' 2>/dev/null || echo "Not found via API"
# Alternative: try direct URL to common locations
curl -s "https://raw.githubusercontent.com/shakacode/control-plane-flow/main/lib/cpflow/commands/exists.rb" 2>/dev/null | head -100Repository: shakacode/react-webpack-rails-tutorial
Length of output: 101
🏁 Script executed:
#!/bin/bash
# Try alternative path for exists command
curl -s "https://raw.githubusercontent.com/shakacode/control-plane-flow/main/lib/command/exists.rb" | head -100Repository: shakacode/react-webpack-rails-tutorial
Length of output: 637
🏁 Script executed:
#!/bin/bash
# Also try the spec file to understand expected behavior
curl -s "https://raw.githubusercontent.com/shakacode/control-plane-flow/main/spec/command/exists_spec.rb" | head -150Repository: shakacode/react-webpack-rails-tutorial
Length of output: 643
🏁 Script executed:
#!/bin/bash
# Search for "does not exist" and error patterns in cpflow repo
curl -s "https://api.github.com/search/code?q=repo:shakacode/control-plane-flow+%22does+not+exist%22" 2>/dev/null | jq '.items[] | {path: .path, name: .name}' | head -30Repository: shakacode/react-webpack-rails-tutorial
Length of output: 139
🏁 Script executed:
#!/bin/bash
# Search for fetch_gvc implementation
curl -s "https://raw.githubusercontent.com/shakacode/control-plane-flow/main/lib/cpflow/cp.rb" | grep -A 20 "def fetch_gvc" | head -30Repository: shakacode/react-webpack-rails-tutorial
Length of output: 64
🏁 Script executed:
#!/bin/bash
# Search for error messages in the codebase to understand what cpflow outputs
curl -s "https://api.github.com/search/code?q=repo:shakacode/control-plane-flow+%22ERROR%22+%22Error:%22" 2>/dev/null | jq '.items[0:3] | .[].path' 2>/dev/nullRepository: shakacode/react-webpack-rails-tutorial
Length of output: 64
🏁 Script executed:
#!/bin/bash
# Look at the base command class to understand error handling
curl -s "https://raw.githubusercontent.com/shakacode/control-plane-flow/main/lib/command/base.rb" | head -150Repository: shakacode/react-webpack-rails-tutorial
Length of output: 4308
🏁 Script executed:
#!/bin/bash
# Search for error handling, rescue blocks, or exception patterns in cpflow
curl -s "https://raw.githubusercontent.com/shakacode/control-plane-flow/main/lib/cpflow/cp.rb" | head -200Repository: shakacode/react-webpack-rails-tutorial
Length of output: 96
🏁 Script executed:
#!/bin/bash
# Search for what happens when cpln (the underlying CLI) fails
curl -s "https://raw.githubusercontent.com/shakacode/control-plane-flow/main/lib/cpflow/runner.rb" | grep -A 10 -B 5 "raise\|rescue\|Error" | head -80Repository: shakacode/react-webpack-rails-tutorial
Length of output: 64
🏁 Script executed:
#!/antml:bin/bash
# Look for CHANGELOG to understand what errors cpflow has
curl -s "https://raw.githubusercontent.com/shakacode/control-plane-flow/main/CHANGELOG.md" | grep -i "error\|exit\|fail" | head -40Repository: shakacode/react-webpack-rails-tutorial
Length of output: 4048
🏁 Script executed:
#!/bin/bash
# Search for all error/exception messages in cpflow to see what strings might be output
curl -s "https://api.github.com/search/code?q=repo:shakacode/control-plane-flow+raise+Error+language:ruby" 2>/dev/null | jq '.items[0:5] | .[].path' 2>/dev/null
# Also search for what strings cpflow actually outputs
curl -s "https://raw.githubusercontent.com/shakacode/control-plane-flow/main/lib/cpflow/runner.rb" | head -100Repository: shakacode/react-webpack-rails-tutorial
Length of output: 96
🏁 Script executed:
#!/bin/bash
# Look for all puts/warn/print statements in cpflow that might output errors
curl -s "https://api.github.com/search/code?q=repo:shakacode/control-plane-flow+%22puts%22+%22Error%22+language:ruby" 2>/dev/null | jq '.items[] | select(.path | contains("core") or contains("runner")) | .path' | head -10Repository: shakacode/react-webpack-rails-tutorial
Length of output: 139
🏁 Script executed:
#!/bin/bash
# Search for error handling in the cp.rb file that wraps cpln
curl -s "https://raw.githubusercontent.com/shakacode/control-plane-flow/main/lib/cpflow/core/cp.rb" 2>/dev/null | head -200Repository: shakacode/react-webpack-rails-tutorial
Length of output: 96
Fail closed on unknown cpflow exists errors.
The script assumes that any non-zero exit from cpflow exists that doesn't match hardcoded error patterns means the app doesn't exist and exits successfully. However, cpflow exists can return non-zero for actual errors—auth failures, API errors, network issues—with error messages that might not match your patterns. This masks real failures and could leave resources undeleted. Consider instead explicitly checking for the "app not found" condition or fail on any unrecognized error.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/actions/cpflow-delete-control-plane-app/delete-app.sh around lines
19 - 33, The current exists check for cpflow (the cpflow exists invocation
assigning to exists_output) treats any non-zero exit that doesn't match a small
set of error patterns as "app does not exist" and returns success; instead,
change the logic so that any non-zero exit from cpflow exists fails by default
unless the output explicitly indicates the app is missing (match the exact "not
found"/"does not exist"/"Application not found" message your cpflow CLI returns)
— i.e., after running cpflow exists (the exists_output variable for APP_NAME and
CPLN_ORG), check for the explicit "app not found" text and exit 0 only for that
case, otherwise log exists_output and exit 1 to surface auth/API/network errors.
| - name: Build Docker image | ||
| if: steps.config.outputs.ready == 'true' && steps.source.outputs.allowed == 'true' && (steps.check-app.outputs.exists == 'true' || steps.setup-review-app.outcome == 'success') | ||
| uses: ./.github/actions/cpflow-build-docker-image | ||
| with: | ||
| app_name: ${{ env.APP_NAME }} | ||
| org: ${{ vars.CPLN_ORG_STAGING }} | ||
| commit: ${{ env.PR_SHA }} | ||
| pr_number: ${{ env.PR_NUMBER }} | ||
| docker_build_extra_args: ${{ vars.DOCKER_BUILD_EXTRA_ARGS }} | ||
| docker_build_ssh_key: ${{ secrets.DOCKER_BUILD_SSH_KEY }} | ||
| docker_build_ssh_known_hosts: ${{ vars.DOCKER_BUILD_SSH_KNOWN_HOSTS }} |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if the composite action file exists and examine the problematic area
if [[ -f ".github/actions/cpflow-build-docker-image/action.yml" ]]; then
echo "=== Lines 55-70 of action.yml ==="
sed -n '55,70p' .github/actions/cpflow-build-docker-image/action.yml
echo ""
echo "=== YAML validation ==="
python3 -c "import yaml; yaml.safe_load(open('.github/actions/cpflow-build-docker-image/action.yml'))" 2>&1 && echo "YAML is valid" || echo "YAML parsing failed"
else
echo "File not found: .github/actions/cpflow-build-docker-image/action.yml"
fiRepository: shakacode/react-webpack-rails-tutorial
Length of output: 4679
🏁 Script executed:
cat -n .github/actions/cpflow-build-docker-image/action.yml | head -80Repository: shakacode/react-webpack-rails-tutorial
Length of output: 3768
Fix YAML indentation in the cpflow-build-docker-image composite action.
Lines 62-63 in .github/actions/cpflow-build-docker-image/action.yml lack proper indentation within the run: | literal block scalar. Lines 62 (${{ inputs.docker_build_ssh_known_hosts }}) and 63 (EOF) must be indented to match the surrounding bash script content.
🧰 Tools
🪛 actionlint (1.7.12)
[error] 280-280: could not parse action metadata in "/home/jailuser/git/.github/actions/cpflow-build-docker-image": yaml: line 62: could not find expected ':'
(action)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/cpflow-deploy-review-app.yml around lines 278 - 288, The
YAML run: | block inside the composite action cpflow-build-docker-image has
mis-indented here-doc lines; fix the indentation in the action.yml run block so
that the here-doc content (including the ${ {
inputs.docker_build_ssh_known_hosts } } token and the EOF terminator) is
indented to the same level as the surrounding bash lines within the run: |
literal block, preserving the current here-doc syntax and ensuring YAML treats
those lines as part of the multi-line scalar.
| - name: Build Docker image | ||
| uses: ./.github/actions/cpflow-build-docker-image | ||
| with: | ||
| app_name: ${{ env.APP_NAME }} | ||
| org: ${{ vars.CPLN_ORG_STAGING }} | ||
| commit: ${{ github.sha }} | ||
| docker_build_extra_args: ${{ vars.DOCKER_BUILD_EXTRA_ARGS }} | ||
| docker_build_ssh_key: ${{ secrets.DOCKER_BUILD_SSH_KEY }} | ||
| docker_build_ssh_known_hosts: ${{ vars.DOCKER_BUILD_SSH_KNOWN_HOSTS }} |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify YAML syntax of the composite action file
cat .github/actions/cpflow-build-docker-image/action.yml | head -70 | tail -20
echo "---"
# Try to parse the YAML
python3 -c "import yaml; yaml.safe_load(open('.github/actions/cpflow-build-docker-image/action.yml'))" 2>&1 || echo "YAML parsing failed"Repository: shakacode/react-webpack-rails-tutorial
Length of output: 4778
🏁 Script executed:
cat -n .github/actions/cpflow-build-docker-image/action.yml | sed -n '55,70p'Repository: shakacode/react-webpack-rails-tutorial
Length of output: 1381
🏁 Script executed:
cat -n .github/actions/cpflow-build-docker-image/action.yml | sed -n '40,65p'Repository: shakacode/react-webpack-rails-tutorial
Length of output: 1061
🏁 Script executed:
cat -n .github/actions/cpflow-build-docker-image/action.yml | sed -n '25,70p'Repository: shakacode/react-webpack-rails-tutorial
Length of output: 2319
Fix YAML syntax error in composite action file.
The composite action .github/actions/cpflow-build-docker-image/action.yml has a YAML parsing error at line 62 that prevents execution. The YAML parser fails with "could not find expected ':'" because line 62 begins with ${{ inputs.docker_build_ssh_known_hosts }} without proper indentation in the literal block context. Ensure the heredoc content is correctly indented within the run: literal block, or use alternative quoting to prevent the YAML parser from interpreting the template variable as a key.
🧰 Tools
🪛 actionlint (1.7.12)
[error] 84-84: could not parse action metadata in "/home/jailuser/git/.github/actions/cpflow-build-docker-image": yaml: line 62: could not find expected ':'
(action)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/cpflow-deploy-staging.yml around lines 83 - 91, The
composite action .github/actions/cpflow-build-docker-image/action.yml has a YAML
parsing error because the heredoc/literal block used for the run: script
contains a line starting with ${{ inputs.docker_build_ssh_known_hosts }} that is
not indented/quoted properly; fix the action by correcting the indentation of
the multiline run: block or wrapping the interpolation in quotes so the YAML
parser treats it as scalar (e.g., ensure the heredoc content is indented under
run: and the ${ { inputs.docker_build_ssh_known_hosts } } line is indented the
same, or replace the heredoc with a quoted string), targeting the action.yml
entry that reads inputs.docker_build_ssh_known_hosts and the run: step in the
cpflow-build-docker-image composite action.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is ON, but it could not run because on-demand usage is turned off. To enable Bugbot Autofix, turn on on-demand usage and set a spend limit in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0e5f9e9. Configure here.
| wait_for_service $(echo $REDIS_URL | sed -e 's|redis://||' -e 's|/.*$||') | ||
|
|
||
| echo " -- Finishing entrypoint.sh, executing '$@'" | ||
| echo " -- Finishing entrypoint.sh, executing '$*'@'" |
There was a problem hiding this comment.
Stray characters in entrypoint log message
Low Severity
The echo statement has a stray @' inside the double-quoted string. The old line was executing '$@'" and the intent was to change $@ to $*, but the replacement left behind the @ character and an extra single quote, producing output like executing 'rails server'@' instead of executing 'rails server'.
Reviewed by Cursor Bugbot for commit 0e5f9e9. Configure here.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0e5f9e95c5
ℹ️ 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".
|
|
||
| if [[ -n "${{ inputs.docker_build_ssh_known_hosts }}" ]]; then | ||
| cat <<'EOF' > ~/.ssh/known_hosts | ||
| ${{ inputs.docker_build_ssh_known_hosts }} |
There was a problem hiding this comment.
Indent heredoc body in Docker build action
This line is flush-left instead of being indented within the run: | block, which makes .github/actions/cpflow-build-docker-image/action.yml invalid YAML (parsers raise could not find expected ':' at this section). Since both cpflow-deploy-review-app.yml and cpflow-deploy-staging.yml call this composite action, those workflows will fail to load/execute before the Docker build step runs.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/actions/cpflow-build-docker-image/action.yml:
- Around line 68-70: The heredoc lines for writing known_hosts are not indented
to live inside the YAML run: | block, causing the action to fail parsing; fix by
placing the entire heredoc (the line starting with cat <<'EOF' >
~/.ssh/known_hosts, the interpolated ${ { inputs.docker_build_ssh_known_hosts }
} content, and the closing EOF) as an indented block under the existing run: |
scalar so the opening command and the terminating EOF align with the run block
indentation; ensure the EOF marker is at the same indentation as the heredoc
start and that the ${ { inputs.docker_build_ssh_known_hosts } } token remains
inside the heredoc content.
🪄 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: ddb39b8f-21f7-4d48-9600-31521e8ab534
📒 Files selected for processing (2)
.github/actions/cpflow-build-docker-image/action.yml.github/actions/cpflow-setup-environment/action.yml
✅ Files skipped from review due to trivial changes (1)
- .github/actions/cpflow-setup-environment/action.yml
| cat <<'EOF' > ~/.ssh/known_hosts | ||
| ${{ inputs.docker_build_ssh_known_hosts }} | ||
| EOF |
There was a problem hiding this comment.
❓ Verification inconclusive
🏁 Script executed:
#!/bin/bash
python -m pip -q install pyyaml
python - <<'PY'
from pathlib import Path
import yaml
p = Path(".github/actions/cpflow-build-docker-image/action.yml")
yaml.safe_load(p.read_text())
print("YAML parses successfully.")
PYRepository: shakacode/react-webpack-rails-tutorial
Length of output: 1818
🏁 Script executed:
#!/bin/bash
# Try to access the file and check YAML syntax
cd /tmp && git clone https://github.com/shakacode/react-webpack-rails-tutorial.git repo 2>&1 | tail -20 && cd repo && cat -n .github/actions/cpflow-build-docker-image/action.yml | sed -n '65,80p'Repository: shakacode/react-webpack-rails-tutorial
Length of output: 1939
Fix YAML block parsing around heredoc content (currently breaks action loading).
Lines 68-70 and Lines 72-76 require attention for proper YAML run: | block structure, which appears to be causing parsing issues based on linter feedback.
Proposed fix
- if [[ -n "${{ inputs.docker_build_ssh_known_hosts }}" ]]; then
- cat <<'EOF' > ~/.ssh/known_hosts
-${{ inputs.docker_build_ssh_known_hosts }}
-EOF
- else
- cat <<'EOF' > ~/.ssh/known_hosts
-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=
-EOF
- fi
+ if [[ -n "${{ inputs.docker_build_ssh_known_hosts }}" ]]; then
+ printf '%s\n' "${{ inputs.docker_build_ssh_known_hosts }}" > ~/.ssh/known_hosts
+ else
+ {
+ printf '%s\n' 'github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl'
+ printf '%s\n' 'github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg='
+ printf '%s\n' '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🧰 Tools
🪛 YAMLlint (1.38.0)
[error] 70-70: syntax error: could not find expected ':'
(syntax)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/actions/cpflow-build-docker-image/action.yml around lines 68 - 70,
The heredoc lines for writing known_hosts are not indented to live inside the
YAML run: | block, causing the action to fail parsing; fix by placing the entire
heredoc (the line starting with cat <<'EOF' > ~/.ssh/known_hosts, the
interpolated ${ { inputs.docker_build_ssh_known_hosts } } content, and the
closing EOF) as an indented block under the existing run: | scalar so the
opening command and the terminating EOF align with the run block indentation;
ensure the EOF marker is at the same indentation as the heredoc start and that
the ${ { inputs.docker_build_ssh_known_hosts } } token remains inside the
heredoc content.


Summary
Testing
Note
Medium Risk
Medium risk because it replaces the CI/CD deployment workflows (review apps, staging deploys, production promotion), so misconfiguration could block or mis-deploy environments; also tweaks Docker asset build ordering.
Overview
Modernizes the Control Plane automation by replacing the legacy GitHub Actions and scripts with a new shared
cpflow-*workflow set for opt-in review apps, automatic staging deploys, manual staging→production promotion, and nightly stale review-app cleanup, including trusted-commenter gating and fork-PR safeguards.Adds new reusable composite actions (
cpflow-setup-environment,cpflow-build-docker-imagewith optional SSH/extra build args, and safercpflow-delete-control-plane-appprefix checks) and updates docs/README to match the new secrets/vars and operational flow.Updates the Control Plane Docker build to run
react_on_rails:generate_packsbefore asset precompile, and makes a small logging change in.controlplane/entrypoint.sh.Reviewed by Cursor Bugbot for commit 0e5f9e9. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit
New Features
Chores