Skip to content

Commit 09f4083

Browse files
committed
feat(webapp): CI guard for unindexed onDelete cascade FK columns
A relation with onDelete Cascade/SetNull whose child FK column has no index makes every parent delete fire a cascade that sequentially scans the whole child table. This shipped three times recently (ProjectAlert.channelId, EnvironmentVariableValue.valueReferenceId, PersonalAccessToken.userId). Adds a schema-aware guard (modeled on runOpsLegacyGuard) that parses both Prisma schemas and flags any cascade/SetNull FK whose leading scalar is not the leading column of an index. Whether a missing index is a live bug depends on whether the parent is hard- or soft-deleted, which is not in the schema, so the guard carries a baseline of the 72 currently-accepted cases and only fails --check on new un-baselined violations. Wired into pr_checks as fk-cascade-guard.
1 parent c4b5e27 commit 09f4083

5 files changed

Lines changed: 754 additions & 0 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: "🛡️ FK Cascade Index Guard"
2+
3+
on:
4+
workflow_call:
5+
6+
permissions:
7+
contents: read
8+
9+
jobs:
10+
fk-cascade-guard:
11+
runs-on: warp-ubuntu-latest-x64-16x
12+
13+
steps:
14+
- name: ⬇️ Checkout repo
15+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
16+
with:
17+
fetch-depth: 0
18+
persist-credentials: false
19+
20+
- name: ⎔ Setup pnpm
21+
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
22+
with:
23+
version: 10.33.2
24+
25+
- name: ⎔ Setup node
26+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
27+
with:
28+
node-version: 24.18.0
29+
cache: "pnpm"
30+
31+
- name: 📥 Download deps
32+
run: pnpm install --frozen-lockfile
33+
34+
- name: 🛡️ FK cascade index guard
35+
run: pnpm --filter webapp run guard:fk-cascade-index -- --check

.github/workflows/pr_checks.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ jobs:
5858
- '.github/workflows/unit-tests-webapp.yml'
5959
- '.github/workflows/e2e-webapp.yml'
6060
- '.github/workflows/runops-guard.yml'
61+
- '.github/workflows/fk-cascade-guard.yml'
6162
- '.configs/**'
6263
- 'package.json'
6364
- 'pnpm-lock.yaml'
@@ -150,6 +151,11 @@ jobs:
150151
if: needs.changes.outputs.webapp == 'true'
151152
uses: ./.github/workflows/runops-guard.yml
152153

154+
fk-cascade-guard:
155+
needs: changes
156+
if: needs.changes.outputs.webapp == 'true'
157+
uses: ./.github/workflows/fk-cascade-guard.yml
158+
153159
webapp:
154160
needs: changes
155161
if: needs.changes.outputs.webapp == 'true'
@@ -206,6 +212,7 @@ jobs:
206212
- code-quality
207213
- typecheck
208214
- runops-guard
215+
- fk-cascade-guard
209216
- webapp
210217
- e2e-webapp
211218
- packages

apps/webapp/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"start:local": "cross-env node --max-old-space-size=8192 ./build/server.js",
1818
"typecheck": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" tsc --noEmit -p ./tsconfig.check.json",
1919
"guard:runops-legacy": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" tsx ./scripts/runOpsLegacyGuard.ts",
20+
"guard:fk-cascade-index": "tsx ./scripts/fkCascadeIndexGuard.ts",
2021
"db:seed": "tsx seed.ts",
2122
"db:seed:ai-spans": "tsx seed-ai-spans.mts",
2223
"db:seed:queue-metrics": "tsx seed-queue-metrics.mts",

0 commit comments

Comments
 (0)