Skip to content

Modernize Control Plane GitHub flow#725

Open
justin808 wants to merge 3 commits intomasterfrom
add-cpflow-github-flow
Open

Modernize Control Plane GitHub flow#725
justin808 wants to merge 3 commits intomasterfrom
add-cpflow-github-flow

Conversation

@justin808
Copy link
Copy Markdown
Member

@justin808 justin808 commented Apr 15, 2026

Summary

  • replace the legacy review-app and promote workflows with the shared cpflow-* workflow set
  • update Control Plane docs to match the new workflow names, commands, secrets, and trusted commenter rules
  • document the review app prefix and fork PR limitations for this tutorial repo

Testing

  • ruby /Users/justin/codex/control-plane-flow/cpflow config -a react-webpack-rails-tutorial-staging
  • ruby -e 'Dir[".github/actions/**/.yml",".github/workflows/.yml"].each { |path| YAML.load_file(path, aliases: true) }' -r yaml
  • git diff --check

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-image with optional SSH/extra build args, and safer cpflow-delete-control-plane-app prefix 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_packs before 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

    • Enhanced CI/CD: added workflows for review app deploy/delete/help, scheduled cleanup, staging deploys, and manual promote-to-production.
    • Improved environment setup in actions with configurable runtimes and optional SSH support for builds.
  • Chores

    • Reorganized and replaced several composite actions; removed older/deprecated workflows.
    • Updated deployment documentation and Docker build to include React asset generation before Rails asset precompilation.

cpflow_version:
description: cpflow gem version
required: false
default: "__CPFLOW_VERSION__"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Suggested change
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")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Suggested change
docker_build_args+=("--ssh default")
docker_build_args+=("--ssh" "default")


on:
push:
branches: ["**"]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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:

Suggested change
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.

Comment on lines +19 to +27
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

@claude
Copy link
Copy Markdown

claude bot commented Apr 15, 2026

Code Review — Modernize Control Plane GitHub Flow

Overall this is a solid modernization. The new cpflow-* workflow set is cleaner, more consistent, and fixes several real problems in the old code (no author-association check on /deploy-review-app, no prefix guard on deletion, no fork-PR detection, set -e vs set -euo pipefail, etc.). A few issues need addressing before merge.


🔴 Must fix

1. __CPFLOW_VERSION__ placeholder is never replaced (see inline comment on cpflow-setup-environment/action.yml:22).
Every workflow that calls cpflow-setup-environment will fail immediately with a RubyGems version-not-found error. The old action had 4.1.1 hardcoded; this needs a real version.

2. --ssh default is a single shell token, not two arguments (see inline comment on cpflow-build-docker-image/action.yml:62).
docker_build_args+=("--ssh default") passes one argument to cpflow. It should be docker_build_args+=("--ssh" "default").


🟡 Should fix

3. Staging deploy triggers on every branch push.
branches: ["**"] in cpflow-deploy-staging.yml causes a runner to spin up for every push to every branch. The validate-branch job exits quickly with is_deployable=false for non-master branches, but it still consumes a runner slot and shows up as a workflow run in the Actions tab. If the staging branch will always be master for this repo, branches: ["master", "main"] eliminates the noise. If STAGING_APP_BRANCH truly needs to be arbitrary at runtime, leave a comment explaining why.

4. cpflow exists disambiguation relies on undocumented behavior (see inline comment on delete-app.sh:19-27).
The script assumes cpflow exists exits non-zero with empty output when the app is absent, but non-zero with non-empty output for real errors. This works today but is not a guaranteed contract — worth a comment at minimum.


🟢 Noteworthy improvements

  • Prefix guard on deletion: the new delete-app.sh refuses to delete anything outside REVIEW_APP_PREFIX-*, which is a meaningful safety rail the old script lacked (it only blocked production/staging by name pattern).
  • Author-association gating: /deploy-review-app and /delete-review-app now require OWNER, MEMBER, or COLLABORATOR — the old workflow was open to any commenter.
  • Fork PR handling: secrets are correctly withheld for fork PRs on pull_request events; the Validate review app deployment source step handles the issue_comment case where secrets are available but the PR head is from a fork.
  • GitHub Deployments API integration: the new deploy workflow creates real deployment + deployment status records, which shows up properly in the PR timeline and branch protection rules.
  • Rollback on production promotion failure: the Roll back on failure step restores previous workload images if the health check doesn't pass — a significant operational safety improvement.
  • set -euo pipefail throughout new shell steps vs. the bare set -e (or nothing) in the old ones.
  • pull_request_target for delete-on-close: switching from pull_request to pull_request_target for the closed-PR auto-delete means the workflow can access secrets regardless of fork origin, which is the correct event for this use case.

Minor observations

  • actions/github-script@v7 and ruby/setup-ruby@v1 use floating version tags. Pinning to a commit SHA is the gold standard for supply-chain security, though it adds maintenance overhead.
  • The production health check accepts HTTP 301/302 as "healthy". That's reasonable (the server is responding), but a misconfigured app that redirects everything to a maintenance page would pass. Worth noting in a comment if the team ever wonders why a broken deploy was considered healthy.
  • The Resolve production app workloads step in cpflow-promote-staging-to-production.yml embeds an inline Ruby one-liner that parses controlplane.yml. If app_workloads key is ever renamed in the config schema, this step silently falls back to ["rails"]. A comment tying it to the config schema version would help future maintainers.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 15, 2026

Greptile Summary

This PR replaces the legacy Control Plane GitHub Actions workflows and composite actions with a new cpflow-* prefixed set, adding fork-PR safety, trusted-commenter guards, multi-workload rollback, and a GitHub Deployments API integration. Two defects in the new actions need to be fixed before these workflows will run reliably:

  • cpflow-setup-environment/action.yml line 22: the cpflow_version default is the unreplaced placeholder \"__CPFLOW_VERSION__\", causing gem install cpflow -v __CPFLOW_VERSION__ to fail for all five workflows that rely on it.
  • cpflow-build-docker-image/action.yml line 285: \"--ssh default\" is pushed as a single array element instead of two (\"--ssh\" \"default\"), breaking Docker SSH-mount builds.

Confidence Score: 4/5

Mergeable 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

Filename Overview
.github/actions/cpflow-setup-environment/action.yml New action replacing setup-environment; adds versioned inputs for Ruby, cpln CLI, and cpflow gem — but the cpflow_version default is an unreplaced placeholder CPFLOW_VERSION that will break gem installation for every caller that relies on it.
.github/actions/cpflow-build-docker-image/action.yml New action replacing build-docker-image; adds SSH key and extra-args support, but --ssh default is pushed as a single string to the args array instead of two separate elements, breaking SSH mount for Docker builds.
.github/actions/cpflow-delete-control-plane-app/delete-app.sh New delete script replacing the old one; switches from a name-contains check to a prefix-based guard, which is more precise.
.github/workflows/cpflow-deploy-review-app.yml New deploy-review-app workflow; correctly gates auto-deploys for fork PRs via same_repo check and requires trusted-commenter role for /deploy-review-app comments.
.github/workflows/cpflow-delete-review-app.yml New delete-review-app workflow; upgrades trigger from pull_request to pull_request_target and adds OWNER/MEMBER/COLLABORATOR guard for /delete-review-app comments.
.github/workflows/cpflow-promote-staging-to-production.yml New promote workflow; adds multi-workload rollback state and contents:write permission for GitHub Releases.
.github/workflows/cpflow-cleanup-stale-review-apps.yml New cleanup workflow; replaces hardcoded app name with REVIEW_APP_PREFIX variable and adds secret/variable validation.
.controlplane/readme.md Documentation updated to reference new cpflow-* workflow names, required secrets/variables, and review-app prefix behavior.

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]
Loading

Comments Outside Diff (1)

  1. .github/actions/cpflow-build-docker-image/action.yml, line 285 (link)

    P1 --ssh default passed as a single array element

    docker_build_args+=("--ssh default") inserts the string "--ssh default" as one element. When the array is expanded with "${docker_build_args[@]}", it is forwarded to cpflow build-image as a single argument containing a space — not as the two separate tokens --ssh and default that Docker and cpflow expect. The SSH mount will be silently ignored or will cause a parse error.

Reviews (1): Last reviewed commit: "Modernize Control Plane GitHub flow" | Re-trigger Greptile

cpflow_version:
description: cpflow gem version
required: false
default: "__CPFLOW_VERSION__"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 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.

Suggested change
default: "__CPFLOW_VERSION__"
default: "4.1.1"

(Replace with the actual intended version.)

Comment thread .github/actions/cpflow-setup-environment/action.yml Outdated
Comment thread .github/actions/cpflow-build-docker-image/action.yml Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 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__"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge 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 👍 / 👎.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 15, 2026

Walkthrough

Replaces 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 react_on_rails:generate_packs before resource build and Rails asset precompile, and refreshes documentation to describe the new cpflow workflow model.

Changes

Cohort / File(s) Summary
Docker & Entrypoint
​.controlplane/Dockerfile, ​.controlplane/entrypoint.sh
Added bundle exec rake react_on_rails:generate_packs before JS/resource build and assets precompile; changed entrypoint completion log from $@ to $* @ while still execing original args.
Docs
​.controlplane/readme.md, README.md
Rewrote deployment documentation to describe new cpflow-* workflows, commands, required secrets/variables, and changed example deploy commands/targets.
New cpflow Composite Actions
​.github/actions/cpflow-build-docker-image/action.yml, ​.github/actions/cpflow-setup-environment/action.yml, ​.github/actions/cpflow-delete-control-plane-app/action.yml, ​.github/actions/cpflow-delete-control-plane-app/delete-app.sh
Added composite actions for building images (SSH/key support, extra args), environment setup (Ruby/CLI/gem versions, profile setup, docker login), and safe delete action with prefix validation script.
Removed Legacy Composite Actions / Scripts
​.github/actions/build-docker-image/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
Removed older composite actions and scripts that the new cpflow-* actions replace.
New cpflow Workflows
​.github/workflows/cpflow-deploy-review-app.yml, ​.github/workflows/cpflow-deploy-staging.yml, ​.github/workflows/cpflow-promote-staging-to-production.yml, ​.github/workflows/cpflow-delete-review-app.yml, ​.github/workflows/cpflow-cleanup-stale-review-apps.yml, ​.github/workflows/cpflow-help-command.yml, ​.github/workflows/cpflow-review-app-help.yml
Added new cpflow-prefixed workflows: review-app/staging deploys, production promotion, delete/cleanup flows, help command and review-app help; include PR/comment/manual triggers, concurrency, validation, deployment status/comments, release-phase detection, health checks and optional rollback.
Removed Legacy Workflows
​.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.yml, ​.github/workflows/deploy-to-control-plane-review-app.yml
Deleted legacy workflows implementing previous deployment/help/promotion/cleanup patterns; replaced by the cpflow-* workflows above.

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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I hopped through CI fields where old workflows lay,

I stitched cpflow paths by night and day,
Packs now generate before the assets sing,
Review apps bloom and staging takes wing,
A carrot of deploys — hop, build, and play!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Modernize Control Plane GitHub flow' directly and clearly summarizes the main change: replacing legacy review-app/promotion workflows with modern cpflow-* workflows and reusable composite actions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-cpflow-github-flow

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

wait_for_service $(echo $REDIS_URL | sed -e 's|redis://||' -e 's|/.*$||')

echo " -- Finishing entrypoint.sh, executing '$@'"
echo " -- Finishing entrypoint.sh, executing '$*'@'"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 @'.

Suggested change
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__"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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:

Suggested change
default: "__CPFLOW_VERSION__"
default: "4.1.1"

@claude
Copy link
Copy Markdown

claude bot commented Apr 15, 2026

Code Review - PR 725: Modernize Control Plane GitHub Flow

Overview

Replaces 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 @' at the end of the echo message. Inside the outer double-quoted string, after $* expands, the literal characters '@' are appended to every container-start log line. An inline suggestion has been left on the diff line.

2. Unreplaced template placeholder in cpflow-setup-environment/action.yml

The cpflow_version input defaults to __CPFLOW_VERSION__, a scaffolding sentinel that was never substituted. gem install cpflow -v __CPFLOW_VERSION__ will fail with a gem-not-found error at runtime, breaking every workflow that uses this composite action. The previous setup-environment action pinned 4.1.1. An inline suggestion has been left on that line.


Security observations

3. pull_request event runs with staging secrets

cpflow-deploy-review-app.yml triggers on pull_request: [synchronize, reopened]. For non-fork PRs this runs with access to CPLN_TOKEN_STAGING and builds/deploys the PR author code. The fork guard prevents external contributors from reaching the secret, but any MEMBER or COLLABORATOR with push access can trigger a deploy - which is the intended behavior. Worth documenting explicitly in a workflow-level comment so future maintainers understand why the fork check exists and do not accidentally remove it.

4. New cpflow-delete-review-app.yml uses pull_request_target

The switch from pull_request to pull_request_target for the closed event is correct since no untrusted code is executed. Heads-up for the future: any step added that checks out PR head code in a pull_request_target context would be a pwn-request risk.


Quality and minor issues

5. Expensive tooling setup runs before the app-existence check

In cpflow-deploy-review-app.yml, for pull_request events the workflow installs Ruby + cpln CLI + cpflow gem before discovering whether a review app exists (it exits early with a summary if not). Moving the existence check before Setup environment would skip the ~60-90 second install for the common case of a PR with no review app deployed.

6. Health check accepts only 200/301/302

In cpflow-promote-staging-to-production.yml the health check will time out and trigger a rollback if the root path returns 303, 307, or 308. Consider broadening the check to cover all 3xx codes.

7. Inconsistent fetch-depth between build and deploy jobs in cpflow-deploy-staging.yml

The build job uses fetch-depth: 0 (full history) while the deploy job uses the default shallow clone. Both should be consistent, or a comment should explain why one needs full history.

8. Typo in .controlplane/readme.md

"Pomote latest image" should be "Promote latest image".


What is well done

  • Prefix-guarded deletion (delete-app.sh) is a meaningful safety improvement over the old name-blacklist approach.
  • Robust error-pattern matching when parsing cpflow exists output.
  • Automatic rollback on production promotion failure is a great addition.
  • set -euo pipefail consistently applied across all new shell scripts.
  • Trusting commenter role (OWNER/MEMBER/COLLABORATOR) instead of a separate allowlist is a cleaner security model.

wait_for_service $(echo $REDIS_URL | sed -e 's|redis://||' -e 's|/.*$||')

echo " -- Finishing entrypoint.sh, executing '$@'"
echo " -- Finishing entrypoint.sh, executing '$*'@'"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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'@'

Suggested change
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"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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:

Suggested change
} >> "$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
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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:

Suggested change
shell: bash
sudo npm install -g "@controlplane/cli@${{ inputs.cpln_cli_version }}"
cpln --version
gem install cpflow -v "${{ inputs.cpflow_version }}"
cpflow --version

@claude
Copy link
Copy Markdown

claude bot commented Apr 15, 2026

Code Review

Overview

This PR replaces the legacy review-app / promote GitHub Actions with a new cpflow-* workflow set. It adds three reusable composite actions (cpflow-setup-environment, cpflow-build-docker-image, cpflow-delete-control-plane-app), seven new workflow files, and updates docs + the Dockerfile build order. The overall architecture is solid and the security posture is meaningfully improved over the previous implementation.


Critical Bug

.controlplane/entrypoint.sh line 24 — the logging statement was accidentally corrupted. '$@' became '$*'@', which emits a stray @' suffix on every container startup. See inline comment.


Security

Positive changes:

  • cpflow-delete-control-plane-app/delete-app.sh replaces the old grep -iqE '(production|staging)' guard with a strict prefix check (APP_NAME must start with ${REVIEW_APP_PREFIX}-). This is a meaningful safety improvement — the old guard could be bypassed with creative app names.
  • Fork PRs are correctly blocked from building Docker images with repository secrets. The same_repo check in cpflow-deploy-review-app.yml is well-implemented.
  • pull_request_target is used only for workflows that don't check out PR code in a sensitive way (help comments, delete-on-close). This is the correct pattern.
  • Trusted-commenter gating (OWNER, MEMBER, COLLABORATOR) is applied consistently across issue_comment triggers.

Observation:

  • Pinned GitHub SSH known-host keys in cpflow-build-docker-image/action.yml are a good security practice, but they will need manual updates if GitHub ever rotates those keys.

Minor Issues (inline comments posted)

  1. cpflow-deploy-review-app.yml / cpflow-deploy-staging.yml${{ steps.release-phase.outputs.flag }} is unquoted in the cpflow deploy-image shell command. Safe today (value is empty or a single flag), but worth quoting defensively.
  2. cpflow-setup-environment/action.yml — version inputs are interpolated without quotes in the npm install and gem install commands.

Quality

  • Dockerfile change (add react_on_rails:generate_packs before yarn res:build) is a correct build-ordering fix.
  • set -euo pipefail is consistently applied across all new shell scripts — good.
  • The cpflow-promote-staging-to-production.yml rollback-on-failure logic is a nice addition and looks correct.
  • cpflow-cleanup-stale-review-apps.yml nightly cron is a welcome operational improvement.
  • Docs in .controlplane/readme.md are thorough and accurate.

Summary

One bug to fix before merging (the entrypoint.sh echo corruption). The minor quoting issues are low-risk but worth addressing. Everything else looks well-considered.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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_RETRIES and HEALTH_CHECK_INTERVAL configurable 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"] when app_workloads is 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 if release_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

📥 Commits

Reviewing files that changed from the base of the PR and between 5cf245f and 50e04fe.

📒 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.yml
  • README.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 '$*'@'"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 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.

Suggested change
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 "@'".

Comment on lines +19 to +33
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

For the cpflowCLI commandcpflow exists`, what are the documented exit codes and output patterns for:

  1. app exists,
  2. app does not exist,
  3. auth/token/org errors,
  4. 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 $APP_NAME; then ...): No official documentation specifies exact exit codes or output patterns beyond general CLI conventions. Authoritative sources (project docs at shakacode.com/control-plane-flow/docs/commands/ and GitHub READMEs) describe it as a shell-check command but do not detail outputs. Inferred from documentation and standard CLI practices (e.g., similar to heroku apps:exists or Unix tools): 1) App exists: Exit code 0 (success), minimal/no stdout (silent success for scripting). 2) App does not exist: Exit code non-zero (likely 1), error message on stderr (e.g., "App does not exist"). 3) Auth/token/org errors: Non-zero exit (e.g., 1), error on stderr (e.g., "Authentication failed" or "Invalid org"). 4) Network/API failures: Non-zero exit (e.g., 1 or network-specific), error on stderr (e.g., "Network error" or "API unavailable"). Many cpflow commands exit non-zero on hook failures or errors, propagating exit codes. Check $? after running. Primary sources: GitHub repo (result 5,12,21,33), Shakacode docs (7,21), RubyGems (32). Source code inspection recommended for precise details (lib/cpflow/commands likely contains Exists command implementation).

Citations:


🏁 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:


🏁 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 -20

Repository: 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 -50

Repository: 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 -100

Repository: 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 -100

Repository: 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 -150

Repository: 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 -30

Repository: 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 -30

Repository: 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/null

Repository: 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 -150

Repository: 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 -200

Repository: 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 -80

Repository: 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 -40

Repository: 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 -100

Repository: 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 -10

Repository: 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 -200

Repository: 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.

Comment thread .github/actions/cpflow-setup-environment/action.yml
Comment on lines +278 to +288
- 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 }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 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"
fi

Repository: shakacode/react-webpack-rails-tutorial

Length of output: 4679


🏁 Script executed:

cat -n .github/actions/cpflow-build-docker-image/action.yml | head -80

Repository: 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.

Comment on lines +83 to +91
- 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 }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 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.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

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 '$*'@'"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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'.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 0e5f9e9. Configure here.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 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 }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge 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 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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

📥 Commits

Reviewing files that changed from the base of the PR and between 50e04fe and 0e5f9e9.

📒 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

Comment on lines +68 to +70
cat <<'EOF' > ~/.ssh/known_hosts
${{ inputs.docker_build_ssh_known_hosts }}
EOF
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

❓ 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.")
PY

Repository: 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant