Skip to content

Commit 50e04fe

Browse files
committed
Sync Control Plane flow hardening
1 parent eb3d861 commit 50e04fe

File tree

9 files changed

+72
-15
lines changed

9 files changed

+72
-15
lines changed

.controlplane/Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ RUN SECRET_KEY_BASE=precompile_placeholder bin/rails react_on_rails:locale
7272
# and /app/client/app are the client assets that are bundled, so not needed once built
7373
# Helps to have smaller images b/c of smaller Docker Layer Caches and smaller final images
7474
# SECRET_KEY_BASE is required for asset precompilation but is not persisted in the image
75-
RUN SECRET_KEY_BASE=precompile_placeholder yarn res:build && \
75+
RUN SECRET_KEY_BASE=precompile_placeholder bundle exec rake react_on_rails:generate_packs && \
76+
SECRET_KEY_BASE=precompile_placeholder yarn res:build && \
7677
SECRET_KEY_BASE=precompile_placeholder bin/rails assets:precompile && \
7778
rm -rf /app/lib/bs /app/client/app
7879

.controlplane/entrypoint.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ echo " -- Waiting for services"
2121
wait_for_service $(echo $DATABASE_URL | sed -e 's|^.*@||' -e 's|/.*$||')
2222
wait_for_service $(echo $REDIS_URL | sed -e 's|redis://||' -e 's|/.*$||')
2323

24-
echo " -- Finishing entrypoint.sh, executing '$@'"
24+
echo " -- Finishing entrypoint.sh, executing '$*'@'"
2525

2626
# Run the main command
2727
exec "$@"

.github/actions/cpflow-build-docker-image/action.yml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ inputs:
2020
docker_build_ssh_key:
2121
description: Optional private SSH key used for Docker builds that fetch private dependencies with RUN --mount=type=ssh
2222
required: false
23+
docker_build_ssh_known_hosts:
24+
description: Optional SSH known_hosts entries used with docker_build_ssh_key. Defaults to pinned GitHub.com host keys.
25+
required: false
2326

2427
outputs:
2528
image_tag:
@@ -53,13 +56,25 @@ runs:
5356
if [[ -n "${{ inputs.docker_build_ssh_key }}" ]]; then
5457
mkdir -p ~/.ssh
5558
chmod 700 ~/.ssh
56-
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
59+
60+
if [[ -n "${{ inputs.docker_build_ssh_known_hosts }}" ]]; then
61+
cat <<'EOF' > ~/.ssh/known_hosts
62+
${{ inputs.docker_build_ssh_known_hosts }}
63+
EOF
64+
else
65+
cat <<'EOF' > ~/.ssh/known_hosts
66+
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
67+
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
68+
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=
69+
EOF
70+
fi
71+
5772
chmod 600 ~/.ssh/known_hosts
5873

5974
eval "$(ssh-agent -s)"
6075
trap 'ssh-agent -k >/dev/null' EXIT
6176
ssh-add - <<< "${{ inputs.docker_build_ssh_key }}"
62-
docker_build_args+=("--ssh default")
77+
docker_build_args+=("--ssh" "default")
6378
fi
6479

6580
echo "🏗️ Building Docker image${PR_INFO} (commit ${{ inputs.commit }})..."

.github/actions/cpflow-delete-control-plane-app/delete-app.sh

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,20 @@ fi
1717
echo "🔍 Checking if application exists: $APP_NAME"
1818
exists_output=""
1919
if ! exists_output="$(cpflow exists -a "$APP_NAME" --org "$CPLN_ORG" 2>&1)"; then
20-
if [[ -z "$exists_output" ]]; then
21-
echo "⚠️ Application does not exist: $APP_NAME"
22-
exit 0
20+
case "$exists_output" in
21+
*"Double check your org"*|*"Unknown API token format"*|*"ERROR"*|*"Error:"*|*"Traceback"*|*"Net::"*)
22+
echo "❌ ERROR: failed to determine whether application exists: $APP_NAME" >&2
23+
printf '%s\n' "$exists_output" >&2
24+
exit 1
25+
;;
26+
esac
27+
28+
if [[ -n "$exists_output" ]]; then
29+
printf '%s\n' "$exists_output"
2330
fi
2431

25-
echo "❌ ERROR: failed to determine whether application exists: $APP_NAME" >&2
26-
printf '%s\n' "$exists_output" >&2
27-
exit 1
32+
echo "⚠️ Application does not exist: $APP_NAME"
33+
exit 0
2834
fi
2935

3036
if [[ -n "$exists_output" ]]; then

.github/workflows/cpflow-delete-review-app.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ permissions:
1717
issues: write
1818
pull-requests: write
1919

20+
concurrency:
21+
group: cpflow-review-app-${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }}
22+
cancel-in-progress: true
23+
2024
env:
2125
APP_NAME: ${{ vars.REVIEW_APP_PREFIX }}-${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }}
2226
CPLN_ORG: ${{ vars.CPLN_ORG_STAGING }}
@@ -95,6 +99,7 @@ jobs:
9599
uses: actions/github-script@v7
96100
with:
97101
script: |
102+
const commentId = Number("${{ steps.create-comment.outputs.comment-id }}");
98103
const success = "${{ job.status }}" === "success";
99104
const body = success
100105
? [
@@ -110,9 +115,14 @@ jobs:
110115
`[View workflow logs](${process.env.WORKFLOW_URL})`
111116
].join("\n");
112117
118+
if (!Number.isFinite(commentId) || commentId <= 0) {
119+
core.warning("Skipping delete status comment update because no comment id was created.");
120+
return;
121+
}
122+
113123
await github.rest.issues.updateComment({
114124
owner: context.repo.owner,
115125
repo: context.repo.repo,
116-
comment_id: Number("${{ steps.create-comment.outputs.comment-id }}"),
126+
comment_id: commentId,
117127
body
118128
});

.github/workflows/cpflow-deploy-review-app.yml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,12 @@ jobs:
254254
uses: actions/github-script@v7
255255
with:
256256
script: |
257+
const commentId = Number("${{ steps.create-comment.outputs.comment-id }}");
258+
if (!Number.isFinite(commentId) || commentId <= 0) {
259+
core.warning("Skipping PR comment update because no comment id was created.");
260+
return;
261+
}
262+
257263
const body = [
258264
`🏗️ Building Docker image for PR #${process.env.PR_NUMBER}, commit ${process.env.PR_SHA}`,
259265
"",
@@ -265,7 +271,7 @@ jobs:
265271
await github.rest.issues.updateComment({
266272
owner: context.repo.owner,
267273
repo: context.repo.repo,
268-
comment_id: Number("${{ steps.create-comment.outputs.comment-id }}"),
274+
comment_id: commentId,
269275
body
270276
});
271277
@@ -279,12 +285,19 @@ jobs:
279285
pr_number: ${{ env.PR_NUMBER }}
280286
docker_build_extra_args: ${{ vars.DOCKER_BUILD_EXTRA_ARGS }}
281287
docker_build_ssh_key: ${{ secrets.DOCKER_BUILD_SSH_KEY }}
288+
docker_build_ssh_known_hosts: ${{ vars.DOCKER_BUILD_SSH_KNOWN_HOSTS }}
282289

283290
- name: Update PR comment with deploy status
284291
if: steps.config.outputs.ready == 'true' && steps.source.outputs.allowed == 'true' && (steps.check-app.outputs.exists == 'true' || steps.setup-review-app.outcome == 'success')
285292
uses: actions/github-script@v7
286293
with:
287294
script: |
295+
const commentId = Number("${{ steps.create-comment.outputs.comment-id }}");
296+
if (!Number.isFinite(commentId) || commentId <= 0) {
297+
core.warning("Skipping PR comment update because no comment id was created.");
298+
return;
299+
}
300+
288301
const body = [
289302
"🚀 Deploying review app to Control Plane...",
290303
"",
@@ -296,7 +309,7 @@ jobs:
296309
await github.rest.issues.updateComment({
297310
owner: context.repo.owner,
298311
repo: context.repo.repo,
299-
comment_id: Number("${{ steps.create-comment.outputs.comment-id }}"),
312+
comment_id: commentId,
300313
body
301314
});
302315
@@ -356,6 +369,11 @@ jobs:
356369
`[View workflow logs](${process.env.WORKFLOW_URL})`
357370
].join("\n");
358371
372+
if (!Number.isFinite(commentId) || commentId <= 0) {
373+
core.warning("Skipping PR comment update because no comment id was created.");
374+
return;
375+
}
376+
359377
await github.rest.issues.updateComment({
360378
owner: context.repo.owner,
361379
repo: context.repo.repo,

.github/workflows/cpflow-deploy-staging.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ run-name: Deploy Control Plane staging app
44

55
on:
66
push:
7+
# GitHub does not allow repository vars in branch filters, so this workflow listens to
8+
# every branch and exits early unless the ref matches STAGING_APP_BRANCH/main/master.
79
branches: ["**"]
810
workflow_dispatch:
911

@@ -86,6 +88,7 @@ jobs:
8688
commit: ${{ github.sha }}
8789
docker_build_extra_args: ${{ vars.DOCKER_BUILD_EXTRA_ARGS }}
8890
docker_build_ssh_key: ${{ secrets.DOCKER_BUILD_SSH_KEY }}
91+
docker_build_ssh_known_hosts: ${{ vars.DOCKER_BUILD_SSH_KNOWN_HOSTS }}
8992

9093
deploy:
9194
needs: [validate-branch, build]

.github/workflows/cpflow-help-command.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ jobs:
1919
if: |
2020
(github.event_name == 'issue_comment' &&
2121
github.event.issue.pull_request &&
22-
github.event.comment.body == '/help') ||
22+
github.event.comment.body == '/help' &&
23+
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) ||
2324
github.event_name == 'workflow_dispatch'
2425
runs-on: ubuntu-latest
2526

@@ -46,6 +47,7 @@ jobs:
4647
"",
4748
"- `CPLN_TOKEN_STAGING`",
4849
"- `CPLN_TOKEN_PRODUCTION`",
50+
"- `DOCKER_BUILD_SSH_KEY` (optional, when Docker builds fetch private dependencies over SSH)",
4951
"",
5052
"## Repository variables",
5153
"",
@@ -56,6 +58,8 @@ jobs:
5658
"- `REVIEW_APP_PREFIX`",
5759
"- `STAGING_APP_BRANCH` (optional, defaults to `main` or `master`)",
5860
"- `PRIMARY_WORKLOAD` (optional, defaults to `rails`)",
61+
"- `DOCKER_BUILD_EXTRA_ARGS` (optional Docker build flags)",
62+
"- `DOCKER_BUILD_SSH_KNOWN_HOSTS` (optional when SSH build hosts are not GitHub.com)",
5963
"",
6064
"## Workflow behavior",
6165
"",

.github/workflows/cpflow-promote-staging-to-production.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ jobs:
187187
exit 1
188188
189189
- name: Roll back on failure
190-
if: failure() && steps.capture-current.outputs.rollback_state != ''
190+
if: failure() && steps.capture-current.outputs.rollback_state != '{}'
191191
env:
192192
ROLLBACK_STATE: ${{ steps.capture-current.outputs.rollback_state }}
193193
shell: bash

0 commit comments

Comments
 (0)