Skip to content

Commit e2ef356

Browse files
pranaygpclaude
andauthored
CI script improvements (vercel#1826)
* CI script improvements Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * address codex feedback: harden remaining workflows - add allowlist regex in prepare-workbench-path to block path traversal - move matrix/input values to env vars across e2e-vercel-prod, benchmarks (local/postgres/vercel), and the reusable community-world workflows - validate app-name/world-id/world-package inputs in the reusable community-world workflows - pipe getCommunityWorldsMatrix script output through jq -c to prevent \$GITHUB_OUTPUT injection Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 354840e commit e2ef356

6 files changed

Lines changed: 155 additions & 52 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

.github/actions/prepare-workbench-path/action.yml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,24 @@ runs:
1616
steps:
1717
- id: prepare
1818
shell: bash
19+
env:
20+
APP_NAME: ${{ inputs.app-name }}
1921
run: |
20-
if [[ "${{ inputs.app-name }}" == "nextjs-turbopack" || "${{ inputs.app-name }}" == "nextjs-webpack" ]]; then
22+
if [[ ! "$APP_NAME" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ ]]; then
23+
echo "Invalid app-name: $APP_NAME" >&2
24+
exit 1
25+
fi
26+
if [[ "$APP_NAME" == "nextjs-turbopack" || "$APP_NAME" == "nextjs-webpack" ]]; then
2127
STAGE_LOG="$(mktemp)"
22-
node scripts/stage-workbench-with-tarballs.mjs "workbench/${{ inputs.app-name }}" | tee "$STAGE_LOG"
28+
node scripts/stage-workbench-with-tarballs.mjs "workbench/$APP_NAME" | tee "$STAGE_LOG"
2329
WORKBENCH_APP_PATH="$(sed -n 's/^Staged workbench: //p' "$STAGE_LOG" | tail -n 1)"
2430
if [ -z "$WORKBENCH_APP_PATH" ]; then
2531
echo "Failed to parse staged workbench path from stage-workbench-with-tarballs output"
2632
exit 1
2733
fi
2834
else
29-
./scripts/resolve-symlinks.sh "workbench/${{ inputs.app-name }}"
30-
WORKBENCH_APP_PATH="$GITHUB_WORKSPACE/workbench/${{ inputs.app-name }}"
35+
./scripts/resolve-symlinks.sh "workbench/$APP_NAME"
36+
WORKBENCH_APP_PATH="$GITHUB_WORKSPACE/workbench/$APP_NAME"
3137
fi
3238
3339
echo "workbench_app_path=$WORKBENCH_APP_PATH" >> "$GITHUB_OUTPUT"

.github/workflows/benchmark-community-world.yml

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,37 +91,70 @@ jobs:
9191
with:
9292
build-packages: 'true'
9393

94+
- name: Validate inputs
95+
env:
96+
APP_NAME: ${{ inputs.app-name }}
97+
WORLD_ID: ${{ inputs.world-id }}
98+
WORLD_PACKAGE: ${{ inputs.world-package }}
99+
run: |
100+
if [[ ! "$APP_NAME" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ ]]; then
101+
echo "Invalid app-name: $APP_NAME" >&2
102+
exit 1
103+
fi
104+
if [[ ! "$WORLD_ID" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ ]]; then
105+
echo "Invalid world-id: $WORLD_ID" >&2
106+
exit 1
107+
fi
108+
if [[ ! "$WORLD_PACKAGE" =~ ^(@[a-zA-Z0-9][a-zA-Z0-9_.-]*/)?[a-zA-Z0-9][a-zA-Z0-9_.-]*(@[a-zA-Z0-9][a-zA-Z0-9_.+-]*)?$ ]]; then
109+
echo "Invalid world-package: $WORLD_PACKAGE" >&2
110+
exit 1
111+
fi
112+
94113
- name: Install ${{ inputs.world-name }} World
95-
run: pnpm --filter ${{ inputs.app-name }} add ${{ inputs.world-package }}
114+
env:
115+
APP_NAME: ${{ inputs.app-name }}
116+
WORLD_PACKAGE: ${{ inputs.world-package }}
117+
run: pnpm --filter "$APP_NAME" add "$WORLD_PACKAGE"
96118

97119
- name: Run setup command
98120
if: ${{ inputs.setup-command != '' }}
99-
run: ${{ inputs.setup-command }}
100-
working-directory: workbench/${{ inputs.app-name }}
121+
env:
122+
APP_NAME: ${{ inputs.app-name }}
123+
SETUP_COMMAND: ${{ inputs.setup-command }}
124+
run: |
125+
cd "workbench/$APP_NAME"
126+
eval "$SETUP_COMMAND"
101127
102128
- name: Resolve symlinks
103-
run: ./scripts/resolve-symlinks.sh workbench/${{ inputs.app-name }}
129+
env:
130+
APP_NAME: ${{ inputs.app-name }}
131+
run: ./scripts/resolve-symlinks.sh "workbench/$APP_NAME"
104132

105133
- name: Set environment variables
134+
env:
135+
ENV_VARS_JSON: ${{ inputs.env-vars }}
106136
run: |
107-
echo '${{ inputs.env-vars }}' | jq -r 'to_entries[] | "\(.key)=\(.value)"' >> $GITHUB_ENV
137+
printf '%s' "$ENV_VARS_JSON" | jq -r 'to_entries[] | "\(.key)=\(.value)"' >> "$GITHUB_ENV"
108138
109139
- name: Build workbench
110-
run: pnpm turbo run build --filter='./workbench/${{ inputs.app-name }}'
140+
env:
141+
APP_NAME: ${{ inputs.app-name }}
142+
run: pnpm turbo run build --filter="./workbench/$APP_NAME"
111143

112144
- name: Run benchmarks
113145
env:
114146
DEPLOYMENT_URL: "http://localhost:3000"
115147
APP_NAME: ${{ inputs.app-name }}
148+
WORLD_ID: ${{ inputs.world-id }}
116149
WORKFLOW_BENCH_BACKEND: ${{ inputs.world-id }}
117150
BENCHMARK_FULL_SUITE: ${{ inputs.full-suite }}
118151
run: |
119-
cd workbench/${{ inputs.app-name }}
152+
cd "workbench/$APP_NAME"
120153
pnpm start &
121154
echo "Waiting for server to start..."
122155
sleep 15
123-
cd ../..
124-
pnpm vitest bench packages/core/e2e/bench.bench.ts --run --outputJson=bench-results-${{ inputs.app-name }}-${{ inputs.world-id }}.json
156+
cd "$GITHUB_WORKSPACE"
157+
pnpm vitest bench packages/core/e2e/bench.bench.ts --run "--outputJson=bench-results-$APP_NAME-$WORLD_ID.json"
125158
126159
- name: Render benchmark results
127160
uses: ./.github/actions/render-benchmarks

.github/workflows/benchmarks.yml

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,9 @@ jobs:
194194
if_no_artifact_found: warn
195195

196196
- name: Build workbench
197-
run: pnpm turbo run build --filter='./workbench/${{ matrix.app }}'
197+
env:
198+
APP_NAME: ${{ matrix.app }}
199+
run: pnpm turbo run build --filter="./workbench/$APP_NAME"
198200

199201
- name: Run benchmarks
200202
env:
@@ -203,12 +205,12 @@ jobs:
203205
# Run full suite on nextjs-turbopack only (stress tests are too slow to run on all apps)
204206
BENCHMARK_FULL_SUITE: ${{ matrix.app == 'nextjs-turbopack' && ((github.event_name == 'workflow_dispatch' && inputs.full_suite) || contains(github.event.pull_request.labels.*.name, 'stress-test')) }}
205207
run: |
206-
cd workbench/${{ matrix.app }}
208+
cd "workbench/$APP_NAME"
207209
pnpm start &
208210
echo "Waiting for server to start..."
209211
sleep 15
210-
cd ../..
211-
pnpm vitest bench packages/core/e2e/bench.bench.ts --run --outputJson=bench-results-${{ matrix.app }}-local.json
212+
cd "$GITHUB_WORKSPACE"
213+
pnpm vitest bench packages/core/e2e/bench.bench.ts --run "--outputJson=bench-results-$APP_NAME-local.json"
212214
213215
- name: Render benchmark results
214216
uses: ./.github/actions/render-benchmarks
@@ -296,7 +298,9 @@ jobs:
296298

297299
# Build workbench with postgres world (build output differs based on target world)
298300
- name: Build workbench for postgres
299-
run: pnpm turbo run build --filter='./workbench/${{ matrix.app }}'
301+
env:
302+
APP_NAME: ${{ matrix.app }}
303+
run: pnpm turbo run build --filter="./workbench/$APP_NAME"
300304

301305
- name: Run benchmarks
302306
env:
@@ -305,12 +309,12 @@ jobs:
305309
# Run full suite on nextjs-turbopack only (stress tests are too slow to run on all apps)
306310
BENCHMARK_FULL_SUITE: ${{ matrix.app == 'nextjs-turbopack' && ((github.event_name == 'workflow_dispatch' && inputs.full_suite) || contains(github.event.pull_request.labels.*.name, 'stress-test')) }}
307311
run: |
308-
cd workbench/${{ matrix.app }}
312+
cd "workbench/$APP_NAME"
309313
pnpm start &
310314
echo "Waiting for server to start..."
311315
sleep 15
312-
cd ../..
313-
pnpm vitest bench packages/core/e2e/bench.bench.ts --run --outputJson=bench-results-${{ matrix.app }}-postgres.json
316+
cd "$GITHUB_WORKSPACE"
317+
pnpm vitest bench packages/core/e2e/bench.bench.ts --run "--outputJson=bench-results-$APP_NAME-postgres.json"
314318
315319
- name: Render benchmark results
316320
uses: ./.github/actions/render-benchmarks
@@ -404,7 +408,7 @@ jobs:
404408
# Run full suite on nextjs-turbopack only (stress tests are too slow to run on all apps)
405409
BENCHMARK_FULL_SUITE: ${{ matrix.app.name == 'nextjs-turbopack' && ((github.event_name == 'workflow_dispatch' && inputs.full_suite) || contains(github.event.pull_request.labels.*.name, 'stress-test')) }}
406410
run: |
407-
pnpm vitest bench packages/core/e2e/bench.bench.ts --run --outputJson=bench-results-${{ matrix.app.name }}-vercel.json
411+
pnpm vitest bench packages/core/e2e/bench.bench.ts --run "--outputJson=bench-results-$APP_NAME-vercel.json"
408412
409413
- name: Render benchmark results
410414
uses: ./.github/actions/render-benchmarks
@@ -439,7 +443,9 @@ jobs:
439443
build-packages: 'false'
440444

441445
- id: set-matrix
442-
run: echo "matrix=$(node ./scripts/create-community-worlds-matrix.mjs)" >> $GITHUB_OUTPUT
446+
run: |
447+
MATRIX_JSON="$(node ./scripts/create-community-worlds-matrix.mjs | jq -c .)"
448+
echo "matrix=$MATRIX_JSON" >> "$GITHUB_OUTPUT"
443449
444450
benchmark-community:
445451
name: Benchmark Community World (${{ matrix.world.name }})

.github/workflows/e2e-community-world.yml

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -87,37 +87,72 @@ jobs:
8787
with:
8888
build-packages: 'true'
8989

90+
- name: Validate inputs
91+
env:
92+
APP_NAME: ${{ inputs.app-name }}
93+
WORLD_ID: ${{ inputs.world-id }}
94+
WORLD_PACKAGE: ${{ inputs.world-package }}
95+
run: |
96+
if [[ ! "$APP_NAME" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ ]]; then
97+
echo "Invalid app-name: $APP_NAME" >&2
98+
exit 1
99+
fi
100+
if [[ ! "$WORLD_ID" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ ]]; then
101+
echo "Invalid world-id: $WORLD_ID" >&2
102+
exit 1
103+
fi
104+
if [[ ! "$WORLD_PACKAGE" =~ ^(@[a-zA-Z0-9][a-zA-Z0-9_.-]*/)?[a-zA-Z0-9][a-zA-Z0-9_.-]*(@[a-zA-Z0-9][a-zA-Z0-9_.+-]*)?$ ]]; then
105+
echo "Invalid world-package: $WORLD_PACKAGE" >&2
106+
exit 1
107+
fi
108+
90109
- name: Install ${{ inputs.world-name }} World
91-
run: pnpm --filter ${{ inputs.app-name }} add ${{ inputs.world-package }}
110+
env:
111+
APP_NAME: ${{ inputs.app-name }}
112+
WORLD_PACKAGE: ${{ inputs.world-package }}
113+
run: pnpm --filter "$APP_NAME" add "$WORLD_PACKAGE"
92114

93115
- name: Run setup command
94116
if: ${{ inputs.setup-command != '' }}
95-
run: ${{ inputs.setup-command }}
96-
working-directory: workbench/${{ inputs.app-name }}
117+
env:
118+
APP_NAME: ${{ inputs.app-name }}
119+
SETUP_COMMAND: ${{ inputs.setup-command }}
120+
run: |
121+
cd "workbench/$APP_NAME"
122+
eval "$SETUP_COMMAND"
97123
98124
- name: Resolve symlinks
99-
run: ./scripts/resolve-symlinks.sh workbench/${{ inputs.app-name }}
125+
env:
126+
APP_NAME: ${{ inputs.app-name }}
127+
run: ./scripts/resolve-symlinks.sh "workbench/$APP_NAME"
100128

101129
- name: Set environment variables
130+
env:
131+
ENV_VARS_JSON: ${{ inputs.env-vars }}
102132
run: |
103-
echo '${{ inputs.env-vars }}' | jq -r 'to_entries[] | "\(.key)=\(.value)"' >> $GITHUB_ENV
133+
printf '%s' "$ENV_VARS_JSON" | jq -r 'to_entries[] | "\(.key)=\(.value)"' >> "$GITHUB_ENV"
104134
105135
- name: Run E2E Tests
106-
run: |
107-
cd workbench/${{ inputs.app-name }} && pnpm dev &
108-
echo "Waiting for dev server to start..." && sleep 15
109-
pnpm vitest run packages/core/e2e/dev.test.ts --reporter=default --reporter=json --reporter=./packages/core/e2e/github-reporter.ts --outputFile=e2e-community-${{ inputs.world-id }}-dev.json || true
110-
sleep 10
111-
pnpm vitest run packages/core/e2e/e2e.test.ts --reporter=default --reporter=json --reporter=./packages/core/e2e/github-reporter.ts --outputFile=e2e-community-${{ inputs.world-id }}.json || true
112136
env:
113137
NODE_OPTIONS: "--enable-source-maps"
114138
APP_NAME: ${{ inputs.app-name }}
139+
WORLD_ID: ${{ inputs.world-id }}
115140
DEPLOYMENT_URL: "http://localhost:3000"
116-
DEV_TEST_CONFIG: '{"name":"${{ inputs.app-name }}","project":"workbench-${{ inputs.app-name }}-workflow","generatedStepPath":"app/.well-known/workflow/v1/step/route.js","generatedWorkflowPath":"app/.well-known/workflow/v1/flow/route.js","apiFilePath":"app/api/chat/route.ts","apiFileImportPath":"../../.."}'
141+
run: |
142+
DEV_TEST_CONFIG="$(jq -nc --arg name "$APP_NAME" '{name:$name,project:"workbench-\($name)-workflow",generatedStepPath:"app/.well-known/workflow/v1/step/route.js",generatedWorkflowPath:"app/.well-known/workflow/v1/flow/route.js",apiFilePath:"app/api/chat/route.ts",apiFileImportPath:"../../.."}')"
143+
export DEV_TEST_CONFIG
144+
cd "workbench/$APP_NAME" && pnpm dev &
145+
cd "$GITHUB_WORKSPACE"
146+
echo "Waiting for dev server to start..." && sleep 15
147+
pnpm vitest run packages/core/e2e/dev.test.ts --reporter=default --reporter=json --reporter=./packages/core/e2e/github-reporter.ts "--outputFile=e2e-community-$WORLD_ID-dev.json" || true
148+
sleep 10
149+
pnpm vitest run packages/core/e2e/e2e.test.ts --reporter=default --reporter=json --reporter=./packages/core/e2e/github-reporter.ts "--outputFile=e2e-community-$WORLD_ID.json" || true
117150
118151
- name: Generate E2E summary
119152
if: always()
120-
run: node .github/scripts/aggregate-e2e-results.js . --job-name "E2E Tests (${{ inputs.world-name }})" >> $GITHUB_STEP_SUMMARY || true
153+
env:
154+
WORLD_NAME: ${{ inputs.world-name }}
155+
run: node .github/scripts/aggregate-e2e-results.js . --job-name "E2E Tests ($WORLD_NAME)" >> $GITHUB_STEP_SUMMARY || true
121156

122157
- name: Upload E2E results
123158
uses: actions/upload-artifact@v4

0 commit comments

Comments
 (0)