- 零第三方依赖,Node >=20 原生 ESM - 团队式编排引擎:拆解/路由/执行/审查/合并全真实 LLM - 阶段心跳、单一权威清单守卫、all-keys-failed 如实上报 - H4 会话视图/amend/watchdog 有界重试/产物区 artifacts.json - H5 零依赖三栏控制台
40 lines
1.5 KiB
JavaScript
40 lines
1.5 KiB
JavaScript
// 交付前 key 明文扫描:任何 sk- 开头、长度>=20 的串都报;允许占位 sk-xxxx / sk-***
|
|
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
import { join, relative } from "node:path";
|
|
const root = process.argv[2] || ".";
|
|
const skipDirs = new Set(["node_modules", ".git"]);
|
|
const hits = [];
|
|
let scanned = 0;
|
|
function walk(d) {
|
|
for (const name of readdirSync(d)) {
|
|
if (skipDirs.has(name)) continue;
|
|
const p = join(d, name);
|
|
const st = statSync(p);
|
|
if (st.isDirectory()) { walk(p); continue; }
|
|
scanned++;
|
|
let buf;
|
|
try { buf = readFileSync(p); } catch { continue; }
|
|
// 二进制安全:抽出 ASCII sk- 串
|
|
const s = buf.toString("latin1");
|
|
const re = /(^|[^A-Za-z0-9_-])sk-[A-Za-z0-9][A-Za-z0-9_\-]{6,}/g;
|
|
let m;
|
|
while ((m = re.exec(s))) {
|
|
const tok = m[0].replace(/^[^A-Za-z0-9_-]/, "");
|
|
if (/^sk-x+$/.test(tok)) continue; // sk-xxxx 占位
|
|
if (tok.startsWith("sk-***")) continue; // 脱敏
|
|
if (/FAKE|UNITTEST|RED-ZONE|^sk-abcdef|^sk-abc123/.test(tok)) continue; // 确定性测试假 key
|
|
if (/^sk-[A-Z]+$/.test(tok)) continue; // 正则里的检测前缀(如 /sk-PRIMARY/),非 key
|
|
hits.push({ file: relative(root, p), token: tok.slice(0, 8) + "…(len=" + tok.length + ")" });
|
|
}
|
|
}
|
|
}
|
|
walk(root);
|
|
console.log("scanned files:", scanned);
|
|
if (hits.length) {
|
|
console.log("KEY HITS:");
|
|
for (const h of hits) console.log(" -", h.file, h.token);
|
|
process.exit(1);
|
|
} else {
|
|
console.log("NO real key plaintext found");
|
|
}
|