// tests/kb-update/test-adversarial-scan.test.mjs // Layer B (G6 §8 / R6 punkt d) — the PURE disposition core of the ingestion // security gate. `classifyFindings` takes already-detected raw findings + the file // content and decides, per provenance tier, whether each finding BLOCKS (hard-fail, // never written), WARNs (flag → human review), or passes. It is orthogonal to the // correctness judge: a factually-correct file with a payload is still blocked. // // These tests feed SYNTHETIC raw findings — they never touch disk nor llm-security, // so they isolate the ms-ai-architect-specific brain (tiering + matrix) from the // shared llm-security detector (integration-tested separately). import { test } from 'node:test'; import assert from 'node:assert/strict'; import { findFencedCodeRanges, lineInCode, localeFromSource, provenanceTier, disposition, classifyFindings, } from '../../scripts/kb-update/lib/adversarial-scan.mjs'; // A KB-style doc: header (authored prose) + a fenced code block. // Line map (1-indexed): // 1 # Title // 2 (blank) // 3 **Source:** https://learn.microsoft.com/azure/x // 4 (blank) // 5 Authored prose line. // 6 (blank) // 7 ```json // 8 { "payload": "..." } // 9 ``` // 10 More prose. const DOC = '# Title\n\n**Source:** https://learn.microsoft.com/azure/x\n\n' + 'Authored prose line.\n\n```json\n{ "payload": "..." }\n```\nMore prose.\n'; test('findFencedCodeRanges — locates the ``` fenced block line span', () => { const ranges = findFencedCodeRanges(DOC); assert.equal(ranges.length, 1); assert.deepEqual(ranges[0], [7, 9]); // opening fence line 7 .. closing fence line 9 }); test('findFencedCodeRanges — unterminated fence treats the rest as code', () => { const ranges = findFencedCodeRanges('a\n```\nb\nc'); assert.equal(ranges.length, 1); assert.deepEqual(ranges[0], [2, 4]); }); test('lineInCode — inside vs outside the fence', () => { const ranges = findFencedCodeRanges(DOC); assert.equal(lineInCode(8, ranges), true); // inside the code block assert.equal(lineInCode(5, ranges), false); // authored prose }); test('localeFromSource — extracts a Microsoft Learn locale segment', () => { assert.equal(localeFromSource('https://learn.microsoft.com/nb-no/azure/x'), 'nb-no'); assert.equal(localeFromSource('https://learn.microsoft.com/en-us/azure/x'), 'en-us'); assert.equal(localeFromSource('https://learn.microsoft.com/azure/x'), null); // no locale segment assert.equal(localeFromSource(null), null); }); test('provenanceTier — code line is code-sample (low trust)', () => { const ranges = findFencedCodeRanges(DOC); assert.equal(provenanceTier({ line: 8, ranges, sourceUrl: 'https://learn.microsoft.com/azure/x' }), 'code-sample'); }); test('provenanceTier — prose in an en-us/no-locale doc is authored-doc (high trust)', () => { const ranges = findFencedCodeRanges(DOC); assert.equal(provenanceTier({ line: 5, ranges, sourceUrl: 'https://learn.microsoft.com/azure/x' }), 'authored-doc'); }); test('provenanceTier — prose in a localized (non-en) doc is localized (low trust)', () => { const ranges = findFencedCodeRanges(DOC); assert.equal(provenanceTier({ line: 5, ranges, sourceUrl: 'https://learn.microsoft.com/nb-no/azure/x' }), 'localized'); }); // --- Disposition matrix ----------------------------------------------------- test('disposition — invisible unicode carriers BLOCK in any tier (never legitimate)', () => { for (const subtype of ['zero-width', 'bidi', 'unicode-tag']) { const f = { class: 'unicode', subtype, severity: 'high' }; assert.equal(disposition(f, 'authored-doc'), 'block', `${subtype} in prose`); assert.equal(disposition(f, 'code-sample'), 'block', `${subtype} in code`); } }); test('disposition — unicode homoglyph WARNs (may be legitimate multilingual text)', () => { const f = { class: 'unicode', subtype: 'homoglyph', severity: 'medium' }; assert.equal(disposition(f, 'authored-doc'), 'warn'); assert.equal(disposition(f, 'code-sample'), 'warn'); }); test('disposition — encoded blob BLOCKs in low-trust (code/localized), WARNs in authored prose', () => { const f = { class: 'encoded', severity: 'high' }; assert.equal(disposition(f, 'code-sample'), 'block'); assert.equal(disposition(f, 'localized'), 'block'); assert.equal(disposition(f, 'authored-doc'), 'warn'); }); test('disposition — critical injection BLOCKs regardless of tier', () => { const f = { class: 'injection', severity: 'critical' }; assert.equal(disposition(f, 'authored-doc'), 'block'); assert.equal(disposition(f, 'code-sample'), 'block'); }); test('disposition — provenance tiering, both directions (brief §8): high injection blocks in code, warns in prose', () => { const f = { class: 'injection', severity: 'high' }; assert.equal(disposition(f, 'code-sample'), 'block'); // low-trust surface → hard-fail assert.equal(disposition(f, 'authored-doc'), 'warn'); // high-trust surface → flag, not silent block }); test('disposition — medium/low injection WARNs (flag for human)', () => { assert.equal(disposition({ class: 'injection', severity: 'medium' }, 'code-sample'), 'warn'); assert.equal(disposition({ class: 'injection', severity: 'low' }, 'authored-doc'), 'warn'); }); // --- Overall verdict -------------------------------------------------------- test('classifyFindings — clean content (no findings) → clean, findings empty', () => { const r = classifyFindings(DOC, [], {}); assert.equal(r.disposition, 'clean'); assert.deepEqual(r.findings, []); }); test('classifyFindings — a critical injection anywhere → block verdict', () => { const raw = [{ class: 'injection', severity: 'critical', line: 5, evidence: 'spoofed tag: ' }]; const r = classifyFindings(DOC, raw, {}); assert.equal(r.disposition, 'block'); assert.equal(r.findings[0].disposition, 'block'); assert.equal(r.findings[0].tier, 'authored-doc'); }); test('classifyFindings — base64 on a code-block line → block (uses in-file Source header for tier)', () => { const raw = [{ class: 'encoded', severity: 'high', line: 8, evidence: 'base64 blob' }]; const r = classifyFindings(DOC, raw, {}); assert.equal(r.disposition, 'block'); assert.equal(r.findings[0].tier, 'code-sample'); }); test('classifyFindings — a high injection only in authored prose → warn verdict (not block)', () => { const raw = [{ class: 'injection', severity: 'high', line: 5, evidence: 'imperative to reader' }]; const r = classifyFindings(DOC, raw, {}); assert.equal(r.disposition, 'warn'); }); test('classifyFindings — block wins over warn when both present', () => { const raw = [ { class: 'injection', severity: 'high', line: 5, evidence: 'warn-level in prose' }, { class: 'unicode', subtype: 'zero-width', severity: 'high', line: 10, evidence: 'U+200B' }, ]; const r = classifyFindings(DOC, raw, {}); assert.equal(r.disposition, 'block'); }); test('classifyFindings — explicit sourceUrl opt overrides the in-file header for tiering', () => { // Same prose finding, but caller declares a localized source → low trust → high injection blocks. const raw = [{ class: 'injection', severity: 'high', line: 5, evidence: 'x' }]; const r = classifyFindings(DOC, raw, { sourceUrl: 'https://learn.microsoft.com/nb-no/azure/x' }); assert.equal(r.disposition, 'block'); assert.equal(r.findings[0].tier, 'localized'); });