/**
 * Unit tests for Enterprise Certification Store
 */
import { describe, it, expect, beforeEach, afterEach, afterAll } from "vitest";
import { mkdir, rm, readFile } from "fs/promises";
import { join } from "path";
import { tmpdir } from "os";
import { generateCertificationId, initializeCertification, getCertificationMetadata, updateCertificationMetadata, startAgent, getAgentFindings, submitFinding, completeAgent, addCrossVerification, getCrossVerifications, addRedTeamChallenge, getRedTeamChallenges, getCertification, saveConsensus, listCertifications, getLatestCertification, isCertificationValid, finalizeCertification, } from "./store.js";
// Use a unique temp directory for each test run
const TEST_BASE = join(tmpdir(), "vaspera-test-" + Date.now() + "-" + Math.random().toString(36).slice(2));
let testProjectPath;
let testCertId;
beforeEach(async () => {
    testProjectPath = join(TEST_BASE, "test-project-" + Math.random().toString(36).slice(2));
    await mkdir(testProjectPath, { recursive: true });
    testCertId = `cert-test-${Date.now()}`;
});
afterEach(async () => {
    // Clean up only the individual test project directory
    try {
        await rm(testProjectPath, { recursive: true, force: true });
    }
    catch {
        // Ignore cleanup errors
    }
});
afterAll(async () => {
    // Clean up the base directory after all tests complete
    try {
        await rm(TEST_BASE, { recursive: true, force: true });
    }
    catch {
        // Ignore cleanup errors
    }
});
describe("generateCertificationId", () => {
    it("generates valid certification ID from project path", () => {
        const id = generateCertificationId("/path/to/MyProject");
        expect(id).toMatch(/^cert-myproject-\d+$/);
    });
    it("sanitizes special characters", () => {
        const id = generateCertificationId("/path/to/My-Project_123");
        expect(id).toMatch(/^cert-my-project-123-\d+$/);
    });
    it("generates unique IDs for different projects", () => {
        const id1 = generateCertificationId("/path/to/projectA");
        const id2 = generateCertificationId("/path/to/projectB");
        // IDs should differ due to different project names
        expect(id1).not.toBe(id2);
        expect(id1).toContain("projecta");
        expect(id2).toContain("projectb");
    });
});
describe("initializeCertification", () => {
    it("creates certification with metadata", async () => {
        const agents = ["security", "reliability"];
        const metadata = await initializeCertification(testProjectPath, testCertId, agents);
        expect(metadata.id).toBe(testCertId);
        expect(metadata.project_path).toBe(testProjectPath);
        expect(metadata.status).toBe("in_progress");
        expect(metadata.agents_requested).toEqual(agents);
        expect(metadata.agents_completed).toEqual([]);
    });
    it("creates required directories", async () => {
        await initializeCertification(testProjectPath, testCertId, ["security"]);
        // Check metadata file exists
        const metadataPath = join(testProjectPath, ".vaspera/certifications", testCertId, "metadata.json");
        const content = await readFile(metadataPath, "utf-8");
        expect(JSON.parse(content).id).toBe(testCertId);
    });
});
describe("getCertificationMetadata", () => {
    it("returns metadata for existing certification", async () => {
        await initializeCertification(testProjectPath, testCertId, ["security"]);
        const metadata = await getCertificationMetadata(testProjectPath, testCertId);
        expect(metadata).not.toBeNull();
        expect(metadata.id).toBe(testCertId);
    });
    it("returns null for non-existent certification", async () => {
        const metadata = await getCertificationMetadata(testProjectPath, "cert-nonexistent-123");
        expect(metadata).toBeNull();
    });
});
describe("updateCertificationMetadata", () => {
    it("updates metadata fields", async () => {
        await initializeCertification(testProjectPath, testCertId, ["security"]);
        const updated = await updateCertificationMetadata(testProjectPath, testCertId, {
            status: "completed",
            agents_completed: ["security"],
        });
        expect(updated.status).toBe("completed");
        expect(updated.agents_completed).toContain("security");
    });
    it("preserves existing fields", async () => {
        await initializeCertification(testProjectPath, testCertId, ["security", "reliability"]);
        await updateCertificationMetadata(testProjectPath, testCertId, {
            status: "completed",
        });
        const metadata = await getCertificationMetadata(testProjectPath, testCertId);
        expect(metadata.agents_requested).toEqual(["security", "reliability"]);
    });
});
describe("Agent operations", () => {
    beforeEach(async () => {
        await initializeCertification(testProjectPath, testCertId, ["security"]);
    });
    it("starts an agent run", async () => {
        const agentFindings = await startAgent(testProjectPath, testCertId, "security");
        expect(agentFindings.agent).toBe("security");
        expect(agentFindings.status).toBe("running");
        expect(agentFindings.findings).toEqual([]);
    });
    it("gets agent findings", async () => {
        await startAgent(testProjectPath, testCertId, "security");
        const findings = await getAgentFindings(testProjectPath, testCertId, "security");
        expect(findings).not.toBeNull();
        expect(findings.agent).toBe("security");
    });
    it("submits a finding", async () => {
        await startAgent(testProjectPath, testCertId, "security");
        const finding = await submitFinding(testProjectPath, testCertId, "security", {
            id: "sec-001",
            severity: "high",
            category: "authentication",
            description: "Missing auth check",
            evidence: "File lacks auth middleware",
            confidence: 90,
        });
        expect(finding.id).toBe("sec-001");
        expect(finding.verifications).toEqual([]);
        expect(finding.created_at).toBeDefined();
        // Check it's persisted
        const agentFindings = await getAgentFindings(testProjectPath, testCertId, "security");
        expect(agentFindings.findings).toHaveLength(1);
        expect(agentFindings.findings[0].id).toBe("sec-001");
    });
    it("throws when submitting to non-started agent", async () => {
        await expect(submitFinding(testProjectPath, testCertId, "reliability", {
            id: "rel-001",
            severity: "medium",
            category: "error-handling",
            description: "Missing try/catch",
            evidence: "Function lacks error handling",
            confidence: 80,
        })).rejects.toThrow("Agent reliability not started");
    });
    it("completes an agent run", async () => {
        await startAgent(testProjectPath, testCertId, "security");
        await submitFinding(testProjectPath, testCertId, "security", {
            id: "sec-001",
            severity: "high",
            category: "auth",
            description: "Test",
            evidence: "Test evidence - deterministic scanner finding",
            confidence: 100, // Deterministic findings skip validation
        });
        const completed = await completeAgent(testProjectPath, testCertId, "security", {
            total_findings: 1,
            by_severity: { critical: 0, high: 1, medium: 0, low: 0, info: 0 },
            confidence_score: 90,
            coverage_areas: ["authentication"],
        });
        expect(completed.status).toBe("completed");
        expect(completed.completed_at).toBeDefined();
        expect(completed.summary).toBeDefined();
        // Check metadata updated
        const metadata = await getCertificationMetadata(testProjectPath, testCertId);
        expect(metadata.agents_completed).toContain("security");
    });
});
describe("Cross-verification", () => {
    beforeEach(async () => {
        await initializeCertification(testProjectPath, testCertId, ["security", "reliability"]);
        await startAgent(testProjectPath, testCertId, "security");
        await submitFinding(testProjectPath, testCertId, "security", {
            id: "sec-001",
            severity: "high",
            category: "auth",
            description: "Test finding",
            evidence: "Test evidence - deterministic scanner finding for cross-verification testing",
            confidence: 100, // Deterministic findings skip validation
        });
    });
    it("adds cross-verification", async () => {
        const verification = await addCrossVerification(testProjectPath, testCertId, {
            finding_id: "sec-001",
            verifying_agent: "reliability",
            verdict: "confirmed",
            evidence: "Verified via testing",
            adjusted_confidence: 95,
        });
        expect(verification.finding_id).toBe("sec-001");
        expect(verification.verdict).toBe("confirmed");
        expect(verification.created_at).toBeDefined();
    });
    it("updates finding with verification", async () => {
        await addCrossVerification(testProjectPath, testCertId, {
            finding_id: "sec-001",
            verifying_agent: "reliability",
            verdict: "confirmed",
            evidence: "Verified",
        });
        const findings = await getAgentFindings(testProjectPath, testCertId, "security");
        expect(findings.findings[0].verifications).toHaveLength(1);
        expect(findings.findings[0].verifications[0].verdict).toBe("confirmed");
    });
    it("gets all cross-verifications", async () => {
        await addCrossVerification(testProjectPath, testCertId, {
            finding_id: "sec-001",
            verifying_agent: "reliability",
            verdict: "confirmed",
            evidence: "Test 1",
        });
        await addCrossVerification(testProjectPath, testCertId, {
            finding_id: "sec-001",
            verifying_agent: "typesafety",
            verdict: "disputed",
            evidence: "Test 2",
        });
        const verifications = await getCrossVerifications(testProjectPath, testCertId);
        expect(verifications).toHaveLength(2);
    });
});
describe("Red team challenges", () => {
    beforeEach(async () => {
        await initializeCertification(testProjectPath, testCertId, ["security", "redteam"]);
    });
    it("adds red team challenge with crypto ID", async () => {
        const challenge = await addRedTeamChallenge(testProjectPath, testCertId, {
            target_agent: "security",
            area: "authentication",
            challenge_type: "missed_issue",
            evidence: "Found bypass method",
            severity_if_valid: "critical",
        });
        expect(challenge.id).toMatch(/^rtc-[a-f0-9-]+$/);
        expect(challenge.target_agent).toBe("security");
        expect(challenge.created_at).toBeDefined();
    });
    it("gets all challenges", async () => {
        await addRedTeamChallenge(testProjectPath, testCertId, {
            target_agent: "security",
            area: "auth",
            challenge_type: "missed_issue",
            evidence: "Test",
            severity_if_valid: "high",
        });
        await addRedTeamChallenge(testProjectPath, testCertId, {
            target_agent: "reliability",
            area: "errors",
            challenge_type: "edge_case",
            evidence: "Test",
            severity_if_valid: "medium",
        });
        const challenges = await getRedTeamChallenges(testProjectPath, testCertId);
        expect(challenges).toHaveLength(2);
    });
});
describe("Full certification operations", () => {
    it("gets complete certification data", async () => {
        await initializeCertification(testProjectPath, testCertId, ["security"]);
        await startAgent(testProjectPath, testCertId, "security");
        await submitFinding(testProjectPath, testCertId, "security", {
            id: "sec-001",
            severity: "medium",
            category: "test",
            description: "Test finding for full certification",
            evidence: "Test evidence - deterministic scanner finding for full certification operations",
            confidence: 100, // Deterministic findings skip validation
        });
        await completeAgent(testProjectPath, testCertId, "security", {
            total_findings: 1,
            by_severity: { critical: 0, high: 0, medium: 1, low: 0, info: 0 },
            confidence_score: 80,
            coverage_areas: ["test"],
        });
        const cert = await getCertification(testProjectPath, testCertId);
        expect(cert).not.toBeNull();
        expect(cert.metadata.id).toBe(testCertId);
        expect(cert.agents.security).toBeDefined();
        expect(cert.agents.security.findings).toHaveLength(1);
    });
    it("saves consensus result", async () => {
        await initializeCertification(testProjectPath, testCertId, ["security"]);
        const consensus = {
            overall_score: 85,
            certification_level: "APPROVED",
            agent_scores: { security: 85 },
            agent_confidences: { security: 90 },
            total_findings: 5,
            by_severity: { critical: 0, high: 1, medium: 2, low: 1, info: 1 },
            cross_verification_rate: 0.8,
            red_team_challenges_accepted: 1,
            red_team_challenges_total: 2,
            calculated_at: new Date().toISOString(),
        };
        await saveConsensus(testProjectPath, testCertId, consensus);
        const cert = await getCertification(testProjectPath, testCertId);
        expect(cert.consensus).toEqual(consensus);
    });
    it("lists certifications sorted by date", async () => {
        const certId1 = `cert-first-${Date.now()}`;
        await initializeCertification(testProjectPath, certId1, ["security"]);
        // Small delay to ensure different timestamps
        await new Promise((resolve) => setTimeout(resolve, 10));
        const certId2 = `cert-second-${Date.now()}`;
        await initializeCertification(testProjectPath, certId2, ["security"]);
        const certs = await listCertifications(testProjectPath);
        expect(certs).toHaveLength(2);
        // Most recent first (certId2 was created later)
        expect(certs[0].id).toBe(certId2);
        expect(certs[1].id).toBe(certId1);
    });
    it("gets latest certification", async () => {
        const certId1 = `cert-test-${Date.now()}`;
        const certId2 = `cert-test-${Date.now() + 1}`;
        await initializeCertification(testProjectPath, certId1, ["security"]);
        await startAgent(testProjectPath, certId1, "security");
        await completeAgent(testProjectPath, certId1, "security", {
            total_findings: 0,
            by_severity: { critical: 0, high: 0, medium: 0, low: 0, info: 0 },
            confidence_score: 100,
            coverage_areas: [],
        });
        await initializeCertification(testProjectPath, certId2, ["security"]);
        const latest = await getLatestCertification(testProjectPath);
        expect(latest).not.toBeNull();
        expect(latest.metadata.id).toBe(certId2);
    });
    it("returns null for empty project", async () => {
        const latest = await getLatestCertification(testProjectPath);
        expect(latest).toBeNull();
    });
});
describe("Certification validity", () => {
    it("returns not_completed for in-progress certification", async () => {
        const metadata = {
            id: "cert-test-123",
            project_name: "test",
            project_path: testProjectPath,
            started_at: new Date().toISOString(),
            status: "in_progress",
            agents_requested: ["security"],
            agents_completed: [],
        };
        const result = await isCertificationValid(testProjectPath, metadata);
        expect(result.valid).toBe(false);
        expect(result.reason).toBe("not_completed");
    });
    it("returns no_expiry for completed without expiry", async () => {
        const metadata = {
            id: "cert-test-123",
            project_name: "test",
            project_path: testProjectPath,
            started_at: new Date().toISOString(),
            status: "completed",
            agents_requested: ["security"],
            agents_completed: ["security"],
        };
        const result = await isCertificationValid(testProjectPath, metadata);
        expect(result.valid).toBe(false);
        expect(result.reason).toBe("no_expiry");
    });
    it("returns valid for non-expired certification without project_hash", async () => {
        const future = new Date();
        future.setDate(future.getDate() + 15);
        const metadata = {
            id: "cert-test-123",
            project_name: "test",
            project_path: testProjectPath,
            started_at: new Date().toISOString(),
            status: "completed",
            agents_requested: ["security"],
            agents_completed: ["security"],
            expires_at: future.toISOString(),
        };
        const result = await isCertificationValid(testProjectPath, metadata);
        expect(result.valid).toBe(true);
        expect(result.reason).toBeUndefined();
    });
    it("returns expired for expired certification", async () => {
        const past = new Date();
        past.setDate(past.getDate() - 1);
        const metadata = {
            id: "cert-test-123",
            project_name: "test",
            project_path: testProjectPath,
            started_at: new Date().toISOString(),
            status: "completed",
            agents_requested: ["security"],
            agents_completed: ["security"],
            expires_at: past.toISOString(),
        };
        const result = await isCertificationValid(testProjectPath, metadata);
        expect(result.valid).toBe(false);
        expect(result.reason).toBe("expired");
    });
    it("returns code_changed when project files changed", async () => {
        const future = new Date();
        future.setDate(future.getDate() + 15);
        const metadata = {
            id: "cert-test-123",
            project_name: "test",
            project_path: testProjectPath,
            started_at: new Date().toISOString(),
            status: "completed",
            agents_requested: ["security"],
            agents_completed: ["security"],
            expires_at: future.toISOString(),
            project_hash: "old-hash-that-no-longer-matches",
        };
        const result = await isCertificationValid(testProjectPath, metadata);
        expect(result.valid).toBe(false);
        expect(result.reason).toBe("code_changed");
    });
});
describe("finalizeCertification", () => {
    it("finalizes with correct data and project hash", async () => {
        await initializeCertification(testProjectPath, testCertId, ["security"]);
        const result = await finalizeCertification(testProjectPath, testCertId, "APPROVED", 85);
        expect(result.status).toBe("completed");
        expect(result.certification_level).toBe("APPROVED");
        expect(result.final_score).toBe(85);
        expect(result.completed_at).toBeDefined();
        expect(result.expires_at).toBeDefined();
        expect(result.project_hash).toBeDefined();
        expect(result.project_hash).toMatch(/^[a-f0-9]{64}$/); // SHA-256 hex
        // Check expiry is 30 days in the future
        const expiry = new Date(result.expires_at);
        const now = new Date();
        const daysDiff = Math.round((expiry.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
        expect(daysDiff).toBeGreaterThanOrEqual(29);
        expect(daysDiff).toBeLessThanOrEqual(30);
    });
    it("certification becomes invalid when files change", async () => {
        // Create a test file to hash
        const { writeFile } = await import("fs/promises");
        const testFile = join(testProjectPath, "test.ts");
        await writeFile(testFile, "const x = 1;", "utf-8");
        await initializeCertification(testProjectPath, testCertId, ["security"]);
        const result = await finalizeCertification(testProjectPath, testCertId, "CERTIFIED", 95);
        // Initially valid
        const validBefore = await isCertificationValid(testProjectPath, result);
        expect(validBefore.valid).toBe(true);
        // Modify the file
        await writeFile(testFile, "const x = 2; // changed", "utf-8");
        // Now invalid due to code change
        const validAfter = await isCertificationValid(testProjectPath, result);
        expect(validAfter.valid).toBe(false);
        expect(validAfter.reason).toBe("code_changed");
    });
});
describe("Path validation", () => {
    it("rejects relative project paths", async () => {
        await expect(initializeCertification("./relative/path", testCertId, ["security"])).rejects.toThrow("Project path must be absolute");
    });
    it("rejects invalid certification IDs", async () => {
        await expect(initializeCertification(testProjectPath, "invalid-id", ["security"])).rejects.toThrow("Invalid certification ID format");
    });
    it("rejects path traversal in cert ID", async () => {
        await expect(initializeCertification(testProjectPath, "cert-../../../etc-123", ["security"])).rejects.toThrow("Invalid certification ID format");
    });
    it("rejects too long cert ID", async () => {
        const longId = "cert-" + "a".repeat(100) + "-123";
        await expect(initializeCertification(testProjectPath, longId, ["security"])).rejects.toThrow("Certification ID too long");
    });
});
//# sourceMappingURL=store.test.js.map