/**
 * Checkmarx Exporter
 *
 * Exports findings to Checkmarx XML format.
 *
 * @module exporters/checkmarx
 */
import { writeFile } from "fs/promises";
import { createHash } from "crypto";
/**
 * Map Vaspera severity to Checkmarx severity
 */
const SEVERITY_MAP = {
    critical: "High",
    high: "High",
    medium: "Medium",
    low: "Low",
    info: "Information",
};
/**
 * Map confidence to Checkmarx state
 */
function confidenceToState(confidence) {
    if (confidence >= 90)
        return "Confirmed";
    if (confidence >= 70)
        return "Urgent";
    return "To Verify";
}
/**
 * Generate a result hash
 */
function generateHash(finding) {
    const hashInput = `${finding.file || "unknown"}:${finding.line || 0}:${finding.category}:${finding.description.slice(0, 100)}`;
    return createHash("md5").update(hashInput).digest("hex").slice(0, 16);
}
/**
 * Convert a finding to Checkmarx result
 */
function findingToResult(finding, projectRoot) {
    let sourceFile = finding.file || "unknown";
    if (projectRoot && sourceFile.startsWith(projectRoot)) {
        sourceFile = sourceFile.slice(projectRoot.length).replace(/^\//, "");
    }
    return {
        queryId: finding.scanner_rule_id || `vaspera-${finding.category}`,
        queryName: finding.category.charAt(0).toUpperCase() + finding.category.slice(1).replace(/-/g, " "),
        queryGroup: getCategoryGroup(finding.category),
        cweId: finding.cwe_ids?.[0],
        severity: SEVERITY_MAP[finding.severity],
        state: confidenceToState(finding.confidence),
        sourceFile,
        sourceLine: finding.line || 1,
        sourceObject: extractObjectName(finding.evidence || finding.description),
        resultHash: generateHash(finding),
        detectionDate: finding.created_at || new Date().toISOString(),
        comment: finding.evidence,
    };
}
/**
 * Get category group for Checkmarx
 */
function getCategoryGroup(category) {
    const groups = {
        injection: "Input Validation",
        xss: "Input Validation",
        authentication: "Authentication",
        authorization: "Authorization",
        cryptography: "Cryptography",
        secrets: "Sensitive Data",
        "api-security": "API Security",
        "error-handling": "Error Handling",
        "type-safety": "Type Safety",
        "null-safety": "Null Safety",
        logging: "Logging",
        performance: "Performance",
        "code-quality": "Code Quality",
    };
    for (const [key, group] of Object.entries(groups)) {
        if (category.toLowerCase().includes(key)) {
            return group;
        }
    }
    return "General";
}
/**
 * Extract object name from code snippet or description
 */
function extractObjectName(text) {
    // Try to find function name
    const funcMatch = text.match(/function\s+(\w+)/);
    if (funcMatch)
        return funcMatch[1];
    // Try to find variable name
    const varMatch = text.match(/(?:const|let|var)\s+(\w+)/);
    if (varMatch)
        return varMatch[1];
    // Try to find class/method
    const classMatch = text.match(/(?:class|interface)\s+(\w+)/);
    if (classMatch)
        return classMatch[1];
    return "unknown";
}
/**
 * Convert report to XML string
 */
function toXml(report) {
    const escapeXml = (str) => str
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&apos;");
    const lines = [
        '<?xml version="1.0" encoding="UTF-8"?>',
        "<CxXMLResults>",
        `  <ProjectName>${escapeXml(report.projectName)}</ProjectName>`,
        `  <ProjectId>${escapeXml(report.projectId)}</ProjectId>`,
        `  <ScanId>${escapeXml(report.scanId)}</ScanId>`,
        `  <ScanDate>${escapeXml(report.scanDate)}</ScanDate>`,
        `  <ScanStatus>${escapeXml(report.scanStatus)}</ScanStatus>`,
        `  <ResultsCount>${report.resultsCount}</ResultsCount>`,
        "  <Results>",
    ];
    for (const result of report.results) {
        lines.push("    <Result>");
        lines.push(`      <QueryId>${escapeXml(result.queryId)}</QueryId>`);
        lines.push(`      <QueryName>${escapeXml(result.queryName)}</QueryName>`);
        lines.push(`      <QueryGroup>${escapeXml(result.queryGroup)}</QueryGroup>`);
        if (result.cweId) {
            lines.push(`      <CweId>${escapeXml(result.cweId)}</CweId>`);
        }
        lines.push(`      <Severity>${escapeXml(result.severity)}</Severity>`);
        lines.push(`      <State>${escapeXml(result.state)}</State>`);
        lines.push(`      <SourceFile>${escapeXml(result.sourceFile)}</SourceFile>`);
        lines.push(`      <SourceLine>${result.sourceLine}</SourceLine>`);
        lines.push(`      <SourceObject>${escapeXml(result.sourceObject)}</SourceObject>`);
        if (result.destFile) {
            lines.push(`      <DestFile>${escapeXml(result.destFile)}</DestFile>`);
            lines.push(`      <DestLine>${result.destLine || 0}</DestLine>`);
            lines.push(`      <DestObject>${escapeXml(result.destObject || "")}</DestObject>`);
        }
        lines.push(`      <ResultHash>${escapeXml(result.resultHash)}</ResultHash>`);
        lines.push(`      <DetectionDate>${escapeXml(result.detectionDate)}</DetectionDate>`);
        if (result.comment) {
            lines.push(`      <Comment>${escapeXml(result.comment)}</Comment>`);
        }
        lines.push("    </Result>");
    }
    lines.push("  </Results>");
    lines.push("</CxXMLResults>");
    return lines.join("\n");
}
/**
 * Export certification to Checkmarx format
 */
export async function exportToCheckmarx(certification, options = {}) {
    const { outputPath, minSeverity = "info", projectRoot, includeResolved = false } = options;
    const severityOrder = ["critical", "high", "medium", "low", "info"];
    const minIndex = severityOrder.indexOf(minSeverity);
    // Collect all findings
    const allFindings = [];
    for (const [, agentData] of Object.entries(certification.agents)) {
        if (agentData?.findings) {
            allFindings.push(...agentData.findings);
        }
    }
    // Filter by severity
    const filteredFindings = allFindings.filter((f) => {
        const sevIndex = severityOrder.indexOf(f.severity);
        return sevIndex <= minIndex;
    });
    // Convert to Checkmarx format
    const results = filteredFindings.map((f) => findingToResult(f, projectRoot));
    const report = {
        projectName: certification.metadata.project_name,
        projectId: certification.metadata.id,
        scanId: certification.metadata.id,
        scanDate: certification.metadata.started_at,
        scanStatus: certification.metadata.status === "completed" ? "Finished" : "In Progress",
        resultsCount: results.length,
        results,
    };
    const content = toXml(report);
    // Write to file if path provided
    if (outputPath) {
        await writeFile(outputPath, content, "utf-8");
    }
    return {
        format: "checkmarx",
        outputPath,
        findingsExported: results.length,
        content,
    };
}
/**
 * Checkmarx exporter instance
 */
export const checkmarxExporter = {
    format: "checkmarx",
    export: exportToCheckmarx,
};
//# sourceMappingURL=checkmarx.js.map