/**
 * The OWASP-Agentic scanner must recognize REAL-WORLD tool names, not just
 * Claude-native ids. Customer manifests declare tools like `shell_exec`,
 * `network_request`, `file_write` (snake_case) — the capability matchers were
 * exact-set, so these were invisible and EVERY agent scored identically
 * (Thomas 2026-06-05: "all agents are the same … I do not understand why they
 * are not getting different scores"). Token-aware matching fixes it.
 *
 * RED before: snake_case dangerous tools produced no trifecta / no shell/fs/net
 * findings, so a high-risk agent and a read-only agent got the same findings.
 */
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { scanAgent, OWASP_AGENTIC_RISK } from './owasp-agentic-scanner.js';
const base = {
    hooks: { preToolUse: false, postToolUse: false, postResponse: false },
    llmProvider: 'anthropic',
    killSwitchCapable: true,
};
// A high-risk agent declared with snake_case tool names (real customer manifest).
const HEALTHCARE = ['lookup_patient_record', 'write_triage_note', 'shell_exec', 'network_request', 'file_write'];
// A read-only agent.
const DOCSEARCH = ['vector_search', 'fetch_document'];
describe('OWASP scanner recognizes custom snake_case tool names', () => {
    it('snake_case shell+network+file_write triggers the Lethal Trifecta (CRIT)', () => {
        const r = scanAgent({ agentId: 'hc', name: 'hc', tools: HEALTHCARE, ...base });
        const trifecta = r.findings.find((f) => f.risk === OWASP_AGENTIC_RISK.A01_PROMPT_INJECTION && /Lethal Trifecta/i.test(f.title));
        assert.ok(trifecta, 'shell_exec + network_request + file_write must be detected as the trifecta');
        assert.equal(trifecta.severity, 'CRIT');
    });
    it('a read-only agent does NOT trigger the trifecta', () => {
        const r = scanAgent({ agentId: 'ds', name: 'ds', tools: DOCSEARCH, ...base });
        assert.ok(!r.findings.some((f) => /Lethal Trifecta/i.test(f.title)));
    });
    it('snake_case dangerous tools surface ungated-capability (A08) findings', () => {
        const r = scanAgent({ agentId: 'hc', name: 'hc', tools: HEALTHCARE, ...base });
        const a08 = r.findings.filter((f) => f.risk === OWASP_AGENTIC_RISK.A08_EXCESSIVE_AGENCY);
        assert.ok(a08.length > 0, 'shell_exec / file_write must produce ungated-capability findings');
    });
    it('a high-risk agent scores strictly lower than a read-only agent (differentiation)', () => {
        const hc = scanAgent({ agentId: 'hc', name: 'hc', tools: HEALTHCARE, ...base });
        const ds = scanAgent({ agentId: 'ds', name: 'ds', tools: DOCSEARCH, ...base });
        // The trifecta + ungated caps must make healthcare produce MORE / WORSE
        // findings than the read-only agent — the input to a differentiated build axis.
        const crit = (r) => r.findings.filter((f) => f.severity === 'CRIT').length;
        assert.ok(crit(hc) > crit(ds), 'high-risk agent must have more CRIT findings');
        assert.ok(hc.findings.length > ds.findings.length, 'high-risk agent must have more findings overall');
    });
    // Semantic egress channels (Thomas 2026-06-05): `send_email`, `upload_file`,
    // webhook posts, etc. are real data-exfiltration vectors but were invisible to
    // NETWORK_EGRESS_TOOLS, so a customer-support agent that can email data out
    // scored identically to a pure read-only PDF analyzer. Recognize them.
    const isEgressFinding = (f) => /Pattern-only injection detection/i.test(f.title);
    it('send_email is recognized as a network-egress (exfiltration) capability', () => {
        const r = scanAgent({ agentId: 'cs', name: 'cs', tools: ['lookup_order', 'send_email', 'create_ticket'], ...base });
        assert.ok(r.findings.some(isEgressFinding), 'send_email must be treated as untrusted-content egress');
    });
    it('upload_file is recognized as a network-egress capability', () => {
        const r = scanAgent({ agentId: 'up', name: 'up', tools: ['upload_file'], ...base });
        assert.ok(r.findings.some(isEgressFinding), 'upload_file must be treated as egress');
    });
    it('a genuinely benign read-only agent has NO egress finding (no false positive)', () => {
        const r = scanAgent({ agentId: 'fin', name: 'fin', tools: ['extract_pdf_text', 'compute_metrics'], ...base });
        assert.ok(!r.findings.some(isEgressFinding), 'benign compute tools must NOT be flagged as egress');
    });
    it('an email-capable agent has strictly more findings than a benign compute agent', () => {
        const cs = scanAgent({ agentId: 'cs', name: 'cs', tools: ['lookup_order', 'send_email', 'create_ticket'], ...base });
        const fin = scanAgent({ agentId: 'fin', name: 'fin', tools: ['extract_pdf_text', 'compute_metrics'], ...base });
        assert.ok(cs.findings.length > fin.findings.length, 'exfil-capable agent must differentiate above a benign one');
    });
});
//# sourceMappingURL=owasp-scanner-custom-tool-names.test.js.map