48 lines
1.3 KiB
JavaScript
48 lines
1.3 KiB
JavaScript
import path from "node:path";
|
|||
|
|
import {
|
||
|
|
readTextFileIfSmall,
|
||
|
|
relative,
|
||
|
|
walkFiles,
|
||
|
|
} from "./repository-files.mjs";
|
||
|
|
|
||
|
|
const patterns = [
|
||
|
|
["private key block", /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/u],
|
||
|
|
["GitHub token", /\bgh[pousr]_[A-Za-z0-9]{30,}\b/u],
|
||
|
|
["OpenAI-style key", /\bsk-[A-Za-z0-9_-]{20,}\b/u],
|
||
|
|
["Google API key", /\bAIza[0-9A-Za-z_-]{35}\b/u],
|
||
|
|
["AWS access key", /\bAKIA[0-9A-Z]{16}\b/u],
|
||
|
|
];
|
||
|
|
|
||
|
|
const excludedExtensions = new Set([
|
||
|
|
".gif",
|
||
|
|
".ico",
|
||
|
|
".jpeg",
|
||
|
|
".jpg",
|
||
|
|
".pdf",
|
||
|
|
".png",
|
||
|
|
".webp",
|
||
|
|
".zip",
|
||
|
|
]);
|
||
|
|
|
||
|
|
const findings = [];
|
||
|
|
for (const file of await walkFiles()) {
|
||
|
|
if (excludedExtensions.has(path.extname(file).toLowerCase())) continue;
|
||
|
|
const content = await readTextFileIfSmall(file);
|
||
|
|
if (content === null) continue;
|
||
|
|
|
||
|
|
for (const [label, pattern] of patterns) {
|
||
|
|
const match = pattern.exec(content);
|
||
|
|
if (!match) continue;
|
||
|
|
const line = content.slice(0, match.index).split(/\r?\n/u).length;
|
||
|
|
findings.push(`${relative(file)}:${line} (${label})`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (findings.length > 0) {
|
||
|
|
console.error("Potential secrets found; values are intentionally redacted:");
|
||
|
|
for (const finding of findings) console.error(`- ${finding}`);
|
||
|
|
process.exitCode = 1;
|
||
|
|
} else {
|
||
|
|
console.log("High-confidence secret scan passed.");
|
||
|
|
}
|