Skip to content

Commit d902a82

Browse files
committed
fix(db): paren-insensitive constraint-drift comparison
pg_get_constraintdef's AND-chain grouping changed between Postgres minors: 17.4 prints left-associated parentheses, 17.6 flattens the chain. The pinned definitions came from the 17.4 production dump, so the drift check false-fired on a fresh 17.6 project (and would fire on production after its next minor upgrade). Comparing both sides with parentheses stripped keeps the check's purpose — operator, literal, and regex changes still surface.
1 parent 7bd5524 commit d902a82

1 file changed

Lines changed: 13 additions & 1 deletion

File tree

scripts/supabase-target/invariants.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,15 @@ export async function validateIntegrityConstraints(client: PgClient): Promise<st
181181
CANONICAL_PROVIDER_KEY_CONSTRAINT,
182182
]) {
183183
const row = result.rows.find((candidate) => candidate["conname"] === contract.name);
184-
if (row && normalizedSqlDefinition(row["definition"]) !== contract.definition) {
184+
// pg_get_constraintdef's AND-chain grouping changed between Postgres
185+
// minors (17.4 prints left-associated parentheses, 17.6 flattens), so the
186+
// comparison ignores parentheses. Operator, literal, and regex changes
187+
// still surface, which is what this drift check exists to catch.
188+
if (
189+
row &&
190+
parenInsensitiveSqlDefinition(row["definition"]) !==
191+
parenInsensitiveSqlDefinition(contract.definition)
192+
) {
185193
issues.push(`Security check public.${contract.tableName}.${contract.name} has drifted.`);
186194
}
187195
}
@@ -261,3 +269,7 @@ function stringField(row: Record<string, unknown>, key: string): string | undefi
261269
function normalizedSqlDefinition(value: unknown): string {
262270
return typeof value === "string" ? value.replaceAll(/\s+/g, " ").trim() : "";
263271
}
272+
273+
function parenInsensitiveSqlDefinition(value: unknown): string {
274+
return normalizedSqlDefinition(value).replaceAll(/[()]/g, "").replaceAll(/\s+/g, " ").trim();
275+
}

0 commit comments

Comments
 (0)