Externalize audit pipeline services
This commit is contained in:
73
tests/audits-auth-source.test.ts
Normal file
73
tests/audits-auth-source.test.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
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.",
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user