source-guards.test.ts
Language TypeScript6.3 KB154 lines
/*** Two whole-tree guards against rot that compiles, passes, and looks fine.** The first is the credentials decision, which is a security decision and the* kind that erodes by accident. The second is source searchability; see its own* note further down.** Credentials come from the process environment only, exported from the shell* profile. There is no `.env` reader in this repo and there must not be one: a* credentials file in the working tree is readable by every tool and agent that* touches the repo, and a secret that has been read has to be rotated.** The failure this catches is social, not technical: a README line or an error* message telling people to create a credentials file, shown at the moment they* are stuck and most likely to comply. Nothing is broken and the advice is* wrong, which is the hardest combination to notice. A single helpful error* message is all it takes to put the file back.** It also pins the template to empty values, because a template is exactly where* a real secret gets pasted "just for a minute".*/import { readdir, readFile, stat } from 'node:fs/promises'import { join, relative } from 'node:path'import { fileURLToPath } from 'node:url'import { describe, expect, it } from 'vitest'const ROOT = fileURLToPath(new URL('../../../', import.meta.url))const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'coverage', '.wrangler', '__pycache__'])/*** This file is skipped because it necessarily contains every pattern it looks* for.*/const SKIP_FILES = new Set(['apps/dashboard/test/source-guards.test.ts',])// A file type the walk does not know about is a file type both guards below silently stop// covering, which is this test's own failure mode.const EXTS = ['.ts', '.py', '.md', '.sh', '.json', '.jsonc', '.sql']async function sources(): Promise<{ path: string; text: string }[]> {const out: { path: string; text: string }[] = []async function walk(dir: string): Promise<void> {for (const entry of await readdir(dir)) {if (SKIP_DIRS.has(entry)) continueconst full = join(dir, entry)const rel = relative(ROOT, full)if ((await stat(full)).isDirectory()) {await walk(full)continue}if (!EXTS.some((e) => entry.endsWith(e))) continueif (SKIP_FILES.has(rel) || entry === 'pnpm-lock.yaml') continueout.push({ path: rel, text: await readFile(full, 'utf8') })}}await walk(ROOT)return out}/*** Only unambiguous instructions and mechanisms. Deliberately does not match the* many correct sentences saying there is no such file; the point is to catch* something telling a person or a build to use one.*/const FORBIDDEN: { pattern: RegExp; why: string }[] = [{ pattern: /\bdotenv\b/i, why: 'a dotenv dependency reintroduces the file' },{ pattern: /--env-file/, why: 'a script loading an env file' },{ pattern: /\.env\.example/, why: 'the deleted template; credentials.example.sh replaced it' },{ pattern: /\b(cp|copy|mv|touch)\s+\.env/i, why: 'an instruction to create the file' },{ pattern: /source\s+\.env/, why: 'an instruction to source the file' },{ pattern: /load_dotenv/, why: 'a Python dotenv loader' },]describe('nothing tells anyone to create a .env', () => {it('has no instruction or loader anywhere in the tree', async () => {const hits: string[] = []for (const { path, text } of await sources()) {for (const { pattern, why } of FORBIDDEN) {const lines = text.split('\n')lines.forEach((line, i) => {if (pattern.test(line)) hits.push(`${path}:${i + 1}: ${why}\n ${line.trim()}`)})}}expect(hits, `\n${hits.join('\n')}\n`).toEqual([])})it('scanned a believable number of files, so a broken walk cannot pass silently', async () => {// An empty scan would satisfy the test above without checking anything.const files = await sources()expect(files.length).toBeGreaterThan(40)expect(files.map((f) => f.path)).toContain('README.md')})})describe('the credentials template carries no secrets', () => {const template = () => readFile(join(ROOT, 'credentials.example.sh'), 'utf8')it('exists, because it is what the docs now point at', async () => {expect((await template()).length).toBeGreaterThan(0)})it('leaves every secret empty', async () => {// A model name and the public API URL are not secrets and may carry a value.const NOT_SECRET = new Set(['ANTHROPIC_MODEL', 'ANTHROPIC_BASE_URL'])for (const line of (await template()).split('\n')) {const m = /^export\s+([A-Z0-9_]+)=(.*)$/.exec(line.trim())if (!m || NOT_SECRET.has(m[1]!)) continueexpect(m[2]!.replace(/["']/g, ''), `${m[1]} has a value in the template`).toBe('')}})it('names every credential the code actually reads', async () => {const text = await template()for (const key of ['NINETY_TOKEN', 'BITRIX_WEBHOOK_URL', 'PLINTH_API_KEY', 'ANTHROPIC_API_KEY']) {expect(text, `${key} is missing from the template`).toContain(key)}})})/*** A literal 0x00 byte in a source file (say, a separator in a composite Map key)* compiles happily, but `file` then classifies the source as binary and grep* prints nothing for it: no error, no "binary file matches", just silence. That* is a silent false negative on every search of that file, for a person or an* agent. Write the character as an escape; this keeps every source file that* way.*/describe('source files stay searchable', () => {it('has no raw control byte anywhere in source', async () => {// Tabs, newlines and carriage returns are ordinary whitespace. Everything// else below 0x20, plus DEL, makes grep treat the whole file as binary.const hits: string[] = []for (const { path, text } of await sources()) {for (let i = 0; i < text.length; i++) {const c = text.charCodeAt(i)const ok = c === 0x09 || c === 0x0a || c === 0x0dif ((c < 0x20 && !ok) || c === 0x7f) {const line = text.slice(0, i).split('\n').lengthhits.push(`${path}:${line}: raw 0x${c.toString(16).padStart(2, '0')}. ` +`Write it as an escape; a raw one makes grep silently skip the file.`,)break}}}expect(hits, `\n${hits.join('\n')}\n`).toEqual([])})})