Files
pitchfast/tests/audits-auth-source.test.ts

74 lines
2.5 KiB
TypeScript

import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
import test from "node:test";
const source = async (relativePath: string) => {
return await readFile(
join(process.cwd(), ...relativePath.split("/")),
"utf8",
);
};
function extractExportSource(sourceText: string, name: string) {
const marker = `export const ${name} = `;
const declarationIndex = sourceText.indexOf(marker);
assert.notEqual(declarationIndex, -1, `Expected declaration for ${name}.`);
const openBraceIndex = sourceText.indexOf("{", declarationIndex);
let depth = 0;
let end = -1;
for (let index = openBraceIndex; index < sourceText.length; index += 1) {
const char = sourceText[index];
if (char === "{") {
depth += 1;
} else if (char === "}") {
depth -= 1;
if (depth === 0) {
end = index;
break;
}
}
}
assert.notEqual(end, -1, `Expected balanced braces for ${name}.`);
return sourceText.slice(openBraceIndex, end + 1);
}
test("audit admin APIs require operator auth before database access", async () => {
const auditsSource = await source("convex/audits.ts");
assert.match(
auditsSource,
/const requireOperator\s*=\s*async\s*\(\s*ctx:\s*(?:MutationCtx\s*\|\s*QueryCtx|QueryCtx\s*\|\s*MutationCtx)\s*\)[\s\S]*ctx\.auth\.getUserIdentity\(\)[\s\S]*throw new Error\(["']Nicht autorisiert\.["']\)/,
"audits should define the local requireOperator auth guard.",
);
for (const name of ["create", "getDetail", "get", "getBySlug", "list"]) {
const exportSource = extractExportSource(auditsSource, name);
const authIndex = exportSource.indexOf("await requireOperator(ctx)");
const dbIndex = exportSource.indexOf("ctx.db");
assert.notEqual(authIndex, -1, `${name} should require operator auth.`);
assert.notEqual(dbIndex, -1, `${name} should access ctx.db.`);
assert.equal(
authIndex < dbIndex,
true,
`${name} should require operator auth before accessing ctx.db.`,
);
}
});
test("public audit slug lookup remains unauthenticated", async () => {
const auditsSource = await source("convex/audits.ts");
const publicSource = extractExportSource(auditsSource, "getPublicBySlug");
assert.match(publicSource, /ctx\.db/, "public audit lookup should keep reading public audit data.");
assert.doesNotMatch(
publicSource,
/requireOperator\(ctx\)/,
"getPublicBySlug should remain public and unauthenticated.",
);
});