/**
 * Unit tests for agent-integrity module
 */
import { describe, it, expect } from "vitest";
import { analyzeConsensus, hashFinding, verifyFindingChain, detectCrossContamination, runIntegrityCheck, integrityToFindings, } from "./agent-integrity.js";
// Helper to create mock agent contribution
function createMockContribution(agent, findings, options) {
    return {
        agent,
        findings,
        severity: {
            critical: options?.severity?.critical ?? 0,
            high: options?.severity?.high ?? Math.floor(findings * 0.2),
            medium: options?.severity?.medium ?? Math.floor(findings * 0.3),
            low: options?.severity?.low ?? Math.floor(findings * 0.3),
            info: options?.severity?.info ?? Math.floor(findings * 0.2),
        },
        confidence: options?.confidence ?? 85,
        timestamp: options?.timestamp ?? new Date().toISOString(),
    };
}
// Helper to create mock finding
function createMockFinding(id, category, severity = "medium") {
    return {
        id,
        severity,
        category,
        description: `Mock finding: ${category}`,
        evidence: `File: src/test.ts:10`,
        confidence: 80,
        verifications: [],
        created_at: new Date().toISOString(),
        scanner_source: undefined,
    };
}
describe("analyzeConsensus", () => {
    it("returns ConsensusAnalysis structure", () => {
        const contributions = [
            createMockContribution("security", 10),
            createMockContribution("reliability", 8),
            createMockContribution("typesafety", 7),
        ];
        const result = analyzeConsensus(contributions);
        expect(result).toHaveProperty("totalAgents");
        expect(result).toHaveProperty("activeAgents");
        expect(result).toHaveProperty("findingsDistribution");
        expect(result).toHaveProperty("dominationScore");
        expect(result).toHaveProperty("entropyScore");
        expect(result).toHaveProperty("outlierAgents");
        expect(result).toHaveProperty("suspiciousPatterns");
        expect(result).toHaveProperty("isHealthy");
    });
    it("correctly counts total and active agents", () => {
        const contributions = [
            createMockContribution("security", 10),
            createMockContribution("reliability", 0),
            createMockContribution("typesafety", 5),
        ];
        const result = analyzeConsensus(contributions);
        expect(result.totalAgents).toBe(3);
        expect(result.activeAgents).toBe(2);
    });
    it("detects domination when single agent has >70% of findings", () => {
        const contributions = [
            createMockContribution("security", 80),
            createMockContribution("reliability", 10),
            createMockContribution("typesafety", 10),
        ];
        const result = analyzeConsensus(contributions);
        expect(result.dominationScore).toBe(80);
        expect(result.suspiciousPatterns.some((p) => p.type === "domination")).toBe(true);
        expect(result.isHealthy).toBe(false);
    });
    it("does not flag domination for balanced contributions", () => {
        const contributions = [
            createMockContribution("security", 10),
            createMockContribution("reliability", 12),
            createMockContribution("typesafety", 11),
        ];
        const result = analyzeConsensus(contributions);
        expect(result.dominationScore).toBeLessThan(70);
        expect(result.suspiciousPatterns.some((p) => p.type === "domination")).toBe(false);
    });
    it("detects low entropy when contributions are suspiciously uniform", () => {
        const contributions = [
            createMockContribution("security", 1),
            createMockContribution("reliability", 1),
            createMockContribution("typesafety", 1),
            createMockContribution("redteam", 1),
        ];
        const result = analyzeConsensus(contributions);
        // Perfect uniformity = 100% entropy, so this should pass
        expect(result.entropyScore).toBe(100);
        expect(result.suspiciousPatterns.some((p) => p.type === "low-entropy")).toBe(false);
    });
    it("detects outlier agents", () => {
        // Need more agents to dilute outlier's impact on stdDev calculation
        // With 6 agents where 5 have similar values, the outlier's deviation
        // will exceed 2*stdDev threshold
        const contributions = [
            createMockContribution("security", 10),
            createMockContribution("reliability", 12),
            createMockContribution("typesafety", 8),
            createMockContribution("quality", 11),
            createMockContribution("performance", 9),
            createMockContribution("redteam", 500), // Extreme outlier > 2*stdDev
        ];
        const result = analyzeConsensus(contributions);
        expect(result.outlierAgents).toContain("redteam");
        expect(result.suspiciousPatterns.some((p) => p.type === "outlier")).toBe(true);
    });
    it("handles empty contributions array", () => {
        const result = analyzeConsensus([]);
        expect(result.totalAgents).toBe(0);
        expect(result.activeAgents).toBe(0);
        expect(result.isHealthy).toBe(true);
    });
    it("handles single contribution without crashing", () => {
        const contributions = [createMockContribution("security", 10)];
        const result = analyzeConsensus(contributions);
        expect(result.totalAgents).toBe(1);
        expect(result.dominationScore).toBe(100);
    });
    it("detects timing anomalies for suspiciously fast completions", () => {
        const now = Date.now();
        const contributions = [
            createMockContribution("security", 10, { timestamp: new Date(now).toISOString() }),
            createMockContribution("reliability", 8, { timestamp: new Date(now + 10).toISOString() }),
            createMockContribution("typesafety", 7, { timestamp: new Date(now + 20).toISOString() }),
        ];
        const result = analyzeConsensus(contributions);
        expect(result.suspiciousPatterns.some((p) => p.type === "timing-anomaly")).toBe(true);
    });
});
describe("hashFinding", () => {
    it("returns consistent hash for same input", () => {
        const finding = {
            severity: "high",
            category: "injection",
            description: "SQL injection vulnerability",
            evidence: "Line 42: user input directly used in query",
        };
        const hash1 = hashFinding(finding);
        const hash2 = hashFinding(finding);
        expect(hash1).toBe(hash2);
        expect(hash1).toHaveLength(64); // SHA256 hex
    });
    it("returns different hash for different input", () => {
        const finding1 = {
            severity: "high",
            category: "injection",
            description: "SQL injection",
            evidence: "Line 42",
        };
        const finding2 = {
            severity: "high",
            category: "injection",
            description: "Different description",
            evidence: "Line 42",
        };
        expect(hashFinding(finding1)).not.toBe(hashFinding(finding2));
    });
});
describe("verifyFindingChain", () => {
    it("returns VerificationChain structure", () => {
        const finding = {
            severity: "high",
            category: "injection",
            description: "SQL injection",
            evidence: "Line 42",
        };
        const result = verifyFindingChain("f1", finding, []);
        expect(result).toHaveProperty("findingId");
        expect(result).toHaveProperty("originalHash");
        expect(result).toHaveProperty("verifications");
        expect(result).toHaveProperty("isValid");
    });
    it("marks empty verification chain as valid", () => {
        const finding = {
            severity: "high",
            category: "injection",
            description: "SQL injection",
            evidence: "Line 42",
        };
        const result = verifyFindingChain("f1", finding, []);
        expect(result.isValid).toBe(true);
        expect(result.verifications).toHaveLength(0);
    });
    it("builds verification chain from verifications", () => {
        const finding = {
            severity: "high",
            category: "injection",
            description: "SQL injection",
            evidence: "Line 42",
        };
        const verifications = [
            {
                verifying_agent: "reliability",
                verdict: "confirmed",
                evidence: "Confirmed via static analysis",
                created_at: new Date().toISOString(),
            },
            {
                verifying_agent: "typesafety",
                verdict: "confirmed",
                evidence: "Type coercion detected",
                created_at: new Date().toISOString(),
            },
        ];
        const result = verifyFindingChain("f1", finding, verifications);
        expect(result.verifications).toHaveLength(2);
        expect(result.verifications[0].agent).toBe("reliability");
        expect(result.verifications[1].agent).toBe("typesafety");
    });
});
describe("detectCrossContamination", () => {
    it("returns empty array when no duplicates exist", () => {
        const agentFindings = {
            security: [createMockFinding("f1", "injection")],
            reliability: [createMockFinding("f2", "error-handling")],
            typesafety: [createMockFinding("f3", "type-safety")],
        };
        const result = detectCrossContamination(agentFindings);
        expect(result).toHaveLength(0);
    });
    it("detects cross-contamination when >5 identical findings across agents", () => {
        const sharedFindings = Array.from({ length: 6 }, (_, i) => createMockFinding(`shared-${i}`, "injection"));
        // Make descriptions identical to produce same hash
        for (const f of sharedFindings) {
            f.description = "Identical vulnerability description";
            f.evidence = "Identical evidence";
        }
        const agentFindings = {
            security: sharedFindings.slice(0, 3),
            reliability: sharedFindings.slice(0, 3), // Same findings = contamination
        };
        // Need to create copies with same content
        const findings1 = [
            { ...createMockFinding("f1", "injection"), description: "Test", evidence: "E1" },
            { ...createMockFinding("f2", "injection"), description: "Test2", evidence: "E2" },
            { ...createMockFinding("f3", "injection"), description: "Test3", evidence: "E3" },
            { ...createMockFinding("f4", "injection"), description: "Test4", evidence: "E4" },
            { ...createMockFinding("f5", "injection"), description: "Test5", evidence: "E5" },
            { ...createMockFinding("f6", "injection"), description: "Test6", evidence: "E6" },
        ];
        const findings2 = findings1.map((f) => ({ ...f, id: f.id + "-copy" }));
        const contaminatedFindings = {
            security: findings1,
            reliability: findings2,
        };
        const result = detectCrossContamination(contaminatedFindings);
        expect(result.some((f) => f.type === "cross-contamination")).toBe(true);
    });
});
describe("runIntegrityCheck", () => {
    it("returns complete integrity check result", async () => {
        const contributions = [
            createMockContribution("security", 10),
            createMockContribution("reliability", 8),
        ];
        const agentFindings = {
            security: [createMockFinding("f1", "injection")],
            reliability: [createMockFinding("f2", "error-handling")],
        };
        const result = await runIntegrityCheck(contributions, agentFindings);
        expect(result).toHaveProperty("consensus");
        expect(result).toHaveProperty("crossContamination");
        expect(result).toHaveProperty("hashVerification");
        expect(result).toHaveProperty("overallHealth");
        expect(result).toHaveProperty("recommendations");
    });
    it("reports healthy status for good consensus", async () => {
        const contributions = [
            createMockContribution("security", 10),
            createMockContribution("reliability", 12),
            createMockContribution("typesafety", 11),
        ];
        const agentFindings = {};
        const result = await runIntegrityCheck(contributions, agentFindings);
        expect(result.overallHealth).toBe("healthy");
    });
    it("reports warning for domination issues", async () => {
        const contributions = [
            createMockContribution("security", 90),
            createMockContribution("reliability", 5),
            createMockContribution("typesafety", 5),
        ];
        const agentFindings = {};
        const result = await runIntegrityCheck(contributions, agentFindings);
        expect(result.overallHealth).toBe("warning");
    });
    it("checks cross-contamination when option enabled", async () => {
        const contributions = [
            createMockContribution("security", 10),
            createMockContribution("reliability", 10),
        ];
        const agentFindings = {
            security: [createMockFinding("f1", "injection")],
            reliability: [createMockFinding("f2", "error-handling")],
        };
        const result = await runIntegrityCheck(contributions, agentFindings, {
            checkCrossContamination: true,
        });
        expect(result.crossContamination).toBeDefined();
        expect(Array.isArray(result.crossContamination)).toBe(true);
    });
    it("verifies hashes when option enabled", async () => {
        const contributions = [createMockContribution("security", 1)];
        const agentFindings = {
            security: [createMockFinding("f1", "injection")],
        };
        const result = await runIntegrityCheck(contributions, agentFindings, {
            verifyHashes: true,
        });
        expect(result.hashVerification.verified).toBeGreaterThanOrEqual(0);
        expect(Array.isArray(result.hashVerification.chains)).toBe(true);
    });
});
describe("integrityToFindings", () => {
    it("converts integrity findings to certification findings", () => {
        const contributions = [
            createMockContribution("security", 90),
            createMockContribution("reliability", 5),
        ];
        const analysis = analyzeConsensus(contributions);
        const crossContamination = [];
        const result = integrityToFindings(analysis, crossContamination);
        expect(Array.isArray(result)).toBe(true);
        if (analysis.suspiciousPatterns.length > 0) {
            expect(result.length).toBeGreaterThan(0);
            expect(result[0]).toHaveProperty("id");
            expect(result[0]).toHaveProperty("severity");
            expect(result[0]).toHaveProperty("category");
            expect(result[0].category).toBe("consensus-manipulation");
        }
    });
    it("generates unique IDs for each finding", () => {
        const contributions = [
            createMockContribution("security", 100),
            createMockContribution("reliability", 1),
        ];
        const analysis = analyzeConsensus(contributions);
        // Add some findings to test
        analysis.suspiciousPatterns.push({
            type: "domination",
            severity: "high",
            description: "Test",
            evidence: "Test",
            recommendation: "Test",
        });
        analysis.suspiciousPatterns.push({
            type: "outlier",
            severity: "medium",
            description: "Test2",
            evidence: "Test2",
            recommendation: "Test2",
        });
        const result = integrityToFindings(analysis, []);
        const ids = result.map((f) => f.id);
        const uniqueIds = new Set(ids);
        expect(uniqueIds.size).toBe(ids.length);
    });
});
//# sourceMappingURL=agent-integrity.test.js.map