Skip to content

Commit 090c4df

Browse files
Programcodeclaude
andcommitted
fix(lint): read dollar-quoted privilege arguments
Codex review of fc713aa: `$$SELECT,INSERT$$` passed as a privilege list. Dollar-quoted strings now count as arguments, and their parentheses no longer end the argument scan. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent fc713aa commit 090c4df

1 file changed

Lines changed: 13 additions & 4 deletions

File tree

‎scripts/check-repo-rules.mjs‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,18 @@ function blankComments(source) {
121121
const isNegated = (before) => /\bNOT[\s(]*$/i.test(before);
122122

123123
// Arguments of the call whose opening parenthesis is at `open`, up to its
124-
// matching close, skipping parentheses inside string literals.
124+
// matching close, skipping parentheses inside quoted and dollar-quoted strings.
125125
function callArguments(source, open) {
126126
let depth = 0;
127127
let quoted = false;
128128
for (let index = open; index < source.length; index += 1) {
129129
const char = source[index];
130-
if (char === "'") quoted = !quoted;
130+
const dollar = quoted ? null : source.slice(index).match(/^\$[A-Za-z_]*\$/);
131+
if (dollar) {
132+
const end = source.indexOf(dollar[0], index + dollar[0].length);
133+
if (end === -1) break;
134+
index = end + dollar[0].length - 1;
135+
} else if (char === "'") quoted = !quoted;
131136
else if (!quoted && char === "(") depth += 1;
132137
else if (!quoted && char === ")" && --depth === 0) return source.slice(open + 1, index);
133138
}
@@ -144,8 +149,12 @@ function checkPgTapPrivileges() {
144149
for (const file of listFiles("supabase/tests", [".sql"])) {
145150
const source = blankComments(readFileSync(path.join(root, file), "utf8"));
146151
for (const match of source.matchAll(call)) {
147-
const literals = [...callArguments(source, match.index + match[0].length - 1).matchAll(/'((?:[^']|'')*)'/g)];
148-
const privilege = literals.at(-1)?.[1] ?? "";
152+
// String arguments, single- or dollar-quoted; the privilege is the last.
153+
const literals = [
154+
...callArguments(source, match.index + match[0].length - 1).matchAll(/'((?:[^']|'')*)'|\$([A-Za-z_]*)\$([\s\S]*?)\$\2\$/g),
155+
];
156+
const last = literals.at(-1);
157+
const privilege = last?.[1] ?? last?.[3] ?? "";
149158
if (privilege.includes(",") && !isNegated(source.slice(0, match.index))) {
150159
report(file, lineOf(source, match.index), "a privilege list means \"any of\": check one privilege per call, or write a negative check as NOT has_*_privilege(...)");
151160
}

0 commit comments

Comments
 (0)