Skip to content

Commit 0910a27

Browse files
committed
Sync Control Plane flow hardening
1 parent 957b012 commit 0910a27

9 files changed

Lines changed: 69 additions & 14 deletions

File tree

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

Lines changed: 16 additions & 1 deletion
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,7 +56,19 @@ 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)"

.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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ jobs:
8888
commit: ${{ github.sha }}
8989
docker_build_extra_args: ${{ vars.DOCKER_BUILD_EXTRA_ARGS }}
9090
docker_build_ssh_key: ${{ secrets.DOCKER_BUILD_SSH_KEY }}
91+
docker_build_ssh_known_hosts: ${{ vars.DOCKER_BUILD_SSH_KNOWN_HOSTS }}
9192

9293
deploy:
9394
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

package-lock.json

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
"@types/webpack": "^5.28.5",
2222
"babel-loader": "^8.4.1",
2323
"babel-plugin-macros": "^3.1.0",
24-
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
2524
"compression-webpack-plugin": "^9.2.0",
2625
"css-loader": "^7.1.2",
2726
"css-minimizer-webpack-plugin": "^7.0.2",
@@ -42,6 +41,7 @@
4241
},
4342
"devDependencies": {
4443
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.1",
44+
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
4545
"puppeteer": "^24.19.0",
4646
"react-refresh": "^0.17.0",
4747
"webpack-dev-server": "^4.15.2"

0 commit comments

Comments
 (0)