-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlint.mjs
More file actions
80 lines (76 loc) · 2.36 KB
/
Copy pathlint.mjs
File metadata and controls
80 lines (76 loc) · 2.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import { readdir, readFile } from "node:fs/promises";
import { extname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { inspectSource } from "./lint-source.mjs";
const root = resolve(fileURLToPath(new URL("..", import.meta.url)));
const ignored = new Set([
".git",
".next",
".omo",
"coverage",
"dist",
"node_modules",
".turbo",
".vercel",
]);
const sourceExtensions = new Set([".cjs", ".js", ".mjs", ".ts", ".tsx"]);
const generatedPackageSidecar = /(?:\.d\.ts|\.js)(?:\.map)?$/u;
const forbidden = [
{ label: "ts-ignore suppression", expression: /@ts-(?:ignore|expect-error)/ },
{
label: "raw secret assignment",
expression: /(?:api[_-]?key|secret|password)\s*[:=]\s*["'][^"']{12,}["']/i,
},
];
async function filesIn(directory) {
const entries = await readdir(directory, { withFileTypes: true });
const files = [];
for (const entry of entries) {
if (ignored.has(entry.name)) continue;
const pathname = resolve(directory, entry.name);
if (entry.isDirectory()) files.push(...(await filesIn(pathname)));
else if (
sourceExtensions.has(extname(entry.name)) ||
generatedPackageSidecar.test(entry.name)
)
files.push(pathname);
}
return files;
}
const findings = [];
for (const pathname of await filesIn(root)) {
if (pathname === fileURLToPath(import.meta.url)) continue;
const projectPath = pathname
.slice(root.length + 1)
.split("\\")
.join("/");
if (
/^packages\/[^/]+\/src\//u.test(projectPath) &&
generatedPackageSidecar.test(projectPath)
) {
findings.push(
`${pathname}:1 generated JavaScript or declaration sidecar in package source`,
);
continue;
}
const content = await readFile(pathname, "utf8");
findings.push(...inspectSource({ root, pathname, content }));
for (const rule of forbidden) {
const match = rule.expression.exec(content);
if (match?.index !== undefined) {
const line = content.slice(0, match.index).split("\n").length;
findings.push(`${pathname}:${line} ${rule.label}`);
}
}
}
if (findings.length > 0) {
console.error(
"Lint failed. Remove unsafe type escapes and credential-like source text.",
);
for (const finding of findings) console.error(finding);
process.exitCode = 1;
} else {
console.log(
"Lint passed. No forbidden type escapes or credential-like source text found.",
);
}