The sweep (main's item 1): 199 tracked text files, 783 lines. The founder's full name, first name and possessive become "the founder" (sentence starts capitalised); the lowercase operating-system user name in WSL paths and commands becomes <user>; the second owner login becomes "the second owner login"; the three earlier businesses and the two other brands become "the other business", "the earlier entity", "the earlier business" and "another brand"; the Chrome profile rule names the igneum.network profile, not the profile's label. The standing commit login igneum-labs is not a founder term here: the fresh-repository step renames it in the history (docs/plans/history-rewrite.md, tools/repo/fresh-repo.sh). The patterns never appear in plain text in the tree (a plaintext list would be the hit): tools/ci/founder-strings.b64 (perl regex, tab, a sample per row) is read by tools/ci/founder-strings-check.sh (every tracked text file, perl, known-failed first: the self-test plants each row's sample in a fixture and the hit must name the file), by tools/community/discord-hooks.mjs (the guard's founder and business rows; the test takes its fixtures from the samples) and by tools/repo/fresh-repo.sh (the business names of the rewrite rules). site/forbidden-strings.txt carries the same patterns as b64: lines, decoded case-insensitive by site/scrub.mjs and tools/ci/launch-gates-check.mjs (whose fixture now plants an encoded made-up name). The check runs in the gate's tree checks on every merge. Not in this commit, by main's word: the 105 commit messages and 40 personal-identity commits that need the history rewrite (listed, not run), and the secrets found by gitleaks over the history (reported with owners). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
71 lines
4.1 KiB
JavaScript
71 lines
4.1 KiB
JavaScript
// Scrub for the public /bench page (review round 4, R4.6.1). The same rules the public repository export applies
|
|
// (its sync.sh generic scrub and bench-log rules, and the maintainers' local rules), plus site-only ones, in plain Node
|
|
// so the build runs the same on this Mac, on Vercel and on the CI runner. The build fails if any pattern in
|
|
// site/forbidden-strings.txt survives, so a private name, host or address can never reach the page.
|
|
import { readFileSync } from 'node:fs';
|
|
import { join, dirname } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
const utc = (h, m, s) => `${String((Number(h) + 23) % 24).padStart(2, '0')}:${m}${s || ''} UTC`;
|
|
const RULES = [
|
|
// machines: model names only (6 October 2026, site audit: the two Windows machines are described, never numbered)
|
|
[/\bPC 1's\b/g, "the three-card Windows rig's"],
|
|
[/\bPC 1\b/g, 'the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT)'],
|
|
[/\bPC 2's\b/g, "the RTX 5090 Windows rig's"],
|
|
[/\bPC 2\b/g, 'the RTX 5090 Windows rig'],
|
|
[/the PC node at 192\.168\.[0-9.]+/g, 'the RTX 5090 node on the LAN'],
|
|
[/\bthe PC node\b/g, 'the RTX 5090 node'],
|
|
[/\bWindows PC\b/g, 'an RTX 5090 on Windows'],
|
|
[/\bthe PC's\b/g, "the RTX 5090 machine's"],
|
|
[/\bthe PC\b/g, 'the RTX 5090 machine'],
|
|
[/\bPC (joins|start|period)\b/g, 'RTX 5090 $1'],
|
|
[/\(Mac side only;/g, '(Apple M5 Max side only;'],
|
|
[/\bthe Mac's\b/g, "the Apple M5 Max's"],
|
|
[/\bthe Mac\b/g, 'the Apple M5 Max'],
|
|
[/\bJosh's\b/g, "the maintainers'"],
|
|
[/\bJosh\b/g, 'the maintainers'],
|
|
[/ Not deployed to Vercel tonight\./g, ''],
|
|
// addresses, hosts, paths
|
|
[/192\.168\.[0-9]+\.[0-9]+/g, '<lan-ip>'],
|
|
[/\b100\.[0-9]+\.[0-9]+\.[0-9]+\b/g, '<overlay-ip>'],
|
|
[/DESKTOP-[A-Z0-9]{7}/g, '<pc-hostname>'],
|
|
[/igneum-seed-\d+/g, 'the seed node'],
|
|
[/\bHetzner\b/g, 'the cloud provider'],
|
|
[/\bhcloud\b/g, 'the cloud CLI'],
|
|
[/\/root\/[A-Za-z0-9_./-]*/g, '<server path>'],
|
|
[/\/opt\/igneum[A-Za-z0-9_./-]*/g, '<server path>'],
|
|
[/dl\.igneum\.network[^ )`]*/g, 'the downloads host'],
|
|
[/,? ?log intake id \d+/g, ''],
|
|
[/\bintake id \d+\b/g, 'intake'],
|
|
// the site audit's page-leak shapes (6 October 2026): process ids, listen addresses, config paths, the node's listen flag
|
|
[/\bpid \d+\b/g, 'pid <n>'],
|
|
[/0\.0\.0\.0:\d+/g, '<listen address>'],
|
|
[/--rpclisten=\S*/g, 'the RPC listen flag'],
|
|
[/~\/\.config\/[A-Za-z0-9_./-]*/g, '<config path>'],
|
|
[/~\/\.config/g, '<config path>'],
|
|
[/~\/Desktop\//g, '`'], [/``/g, '`'],
|
|
[/~\/\.cargo\/bin\/cargo/g, 'cargo'],
|
|
[/\/Users\/[A-Za-z0-9_.-]+/g, '~'],
|
|
[/C:\\Users\\[A-Za-z0-9_.-]+/g, '%USERPROFILE%'],
|
|
// unpublished documents
|
|
[/`docs\/fud-ledger\.md`/g, 'the break ledger (kept by the maintainers, not yet published)'],
|
|
[/\(CLAUDE\.md, /g, '(the design document, '],
|
|
[/\bCLAUDE\.md\b/g, 'the design document'],
|
|
// local times to UTC (the log is written in UTC+1)
|
|
[/2,193 blocks at 22:35;/g, '2,193 blocks at 21:35 UTC;'],
|
|
[/(\d{1,2}:\d{2}(?::\d{2})? UTC) = \d{1,2}:\d{2} B[S]T/g, '$1'],
|
|
[/(\d{1,2}):(\d{2})(:\d{2})? to (\d{1,2}):(\d{2})(:\d{2})? B[S]T/g, (_, h1, m1, s1, h2, m2, s2) => `${utc(h1, m1, s1).replace(' UTC', '')} to ${utc(h2, m2, s2)}`],
|
|
[/(\d{1,2}):(\d{2})(:\d{2})? B[S]T/g, (_, h, m, s) => utc(h, m, s)],
|
|
[/\(local time, UTC\+1\)/g, '(UTC)'],
|
|
[/\bB[S]T\b/g, 'UTC'],
|
|
];
|
|
export function scrubBench(text) {
|
|
let out = text;
|
|
for (const [re, rep] of RULES) out = out.replace(re, rep);
|
|
const pats = readFileSync(join(here, 'forbidden-strings.txt'), 'utf8').split('\n').map(l => l.trim()).filter(l => l && !l.startsWith('#'))
|
|
.map(l => (l.startsWith('b64:') ? new RegExp(Buffer.from(l.slice(4), 'base64').toString('utf8'), 'i') : new RegExp(l))); // a b64: line is an encoded, case-insensitive pattern
|
|
const hits = [];
|
|
out.split('\n').forEach((line, i) => { for (const p of pats) if (p.test(line)) { hits.push(`${i + 1}: ${p.source.startsWith('(?<!') || p.flags.includes('i') ? '(an encoded founder pattern)' : p.source}`); break; } });
|
|
if (hits.length) throw new Error(`scrub: forbidden strings remain on the bench page:\n${hits.slice(0, 20).join('\n')}`);
|
|
return out;
|
|
}
|