68 lines
2.3 KiB
TypeScript
68 lines
2.3 KiB
TypeScript
/**
|
|
* No-disallowed audit: verify that non-deterministic global APIs
|
|
* (`Date`, `Math.random`, `crypto.randomUUID`) are only used in the
|
|
* approved files listed below and never leak into business-logic modules.
|
|
*
|
|
* Approved list (files that legitimately need these APIs):
|
|
* - src/utils/format.ts (generateUuid, generateNanoid, formatDate)
|
|
* - src/plugins/dynamic/DateTimePlugin.ts (uses Date via clock fallback)
|
|
* - src/plugins/dynamic/UuidPlugin.ts (delegates to format.ts)
|
|
* - src/base/suaveplan-error.ts (error timestamp)
|
|
*/
|
|
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { describe, expect, it } from "@suaveplan/testing/runner";
|
|
|
|
const SRC_ROOT = join(import.meta.dirname ?? __dirname, "../src");
|
|
|
|
const APPROVED = new Set([
|
|
join(SRC_ROOT, "utils/format.ts"),
|
|
join(SRC_ROOT, "plugins/dynamic/DateTimePlugin.ts"),
|
|
join(SRC_ROOT, "plugins/dynamic/UuidPlugin.ts"),
|
|
join(SRC_ROOT, "otel/templates-otel.ts"),
|
|
]);
|
|
|
|
// Patterns that indicate direct usage of non-deterministic globals
|
|
const DISALLOWED = [
|
|
/\bDate\.now\b/,
|
|
/\bnew Date\(\)/,
|
|
/\bMath\.random\b/,
|
|
/\bcrypto\.randomUUID\b/,
|
|
];
|
|
|
|
function collectTs(dir: string): string[] {
|
|
const results: string[] = [];
|
|
for (const entry of readdirSync(dir)) {
|
|
const full = join(dir, entry);
|
|
const stat = statSync(full);
|
|
if (stat.isDirectory()) {
|
|
results.push(...collectTs(full));
|
|
} else if (
|
|
entry.endsWith(".ts") &&
|
|
!entry.endsWith(".test.ts") &&
|
|
!entry.endsWith(".bench.ts")
|
|
) {
|
|
results.push(full);
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
describe("no-disallowed globals in non-approved files", () => {
|
|
const files = collectTs(SRC_ROOT).filter((f) => !APPROVED.has(f));
|
|
|
|
for (const file of files) {
|
|
it(`${file.replace(SRC_ROOT, "src")} has no direct Date/Math.random usage`, {
|
|
timeout: 5000,
|
|
}, () => {
|
|
const src = readFileSync(file, "utf-8");
|
|
for (const pattern of DISALLOWED) {
|
|
expect(
|
|
pattern.test(src),
|
|
`Found disallowed pattern ${pattern} in ${file}`
|
|
).toBe(false);
|
|
}
|
|
});
|
|
}
|
|
});
|