/**
 * SARIF Export Module
 *
 * Exports certification findings to SARIF (Static Analysis Results Interchange Format)
 * for integration with GitHub Security, SonarQube, and other analysis tools.
 *
 * SARIF Spec: https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
 *
 * @module certification/sarif
 */
import { writeFile } from "fs/promises";
import { join } from "path";
import { logger } from "../logger.js";
/**
 * Map vaspera severity to SARIF level
 */
const SEVERITY_TO_SARIF = {
    critical: "error",
    high: "error",
    medium: "warning",
    low: "note",
    info: "none",
};
/**
 * Generate a SARIF report from certification data
 */
export function generateSarifReport(certification) {
    const rules = [];
    const results = [];
    const seenRules = new Set();
    // Collect all findings from all agents
    for (const [agent, agentData] of Object.entries(certification.agents)) {
        if (!agentData)
            continue;
        for (const finding of agentData.findings) {
            // Add rule if not seen
            if (!seenRules.has(finding.id)) {
                seenRules.add(finding.id);
                rules.push(createRule(finding, agent));
            }
            // Add result
            results.push(createResult(finding, agent));
            // Add results for instances
            if (finding.instances) {
                for (const instance of finding.instances) {
                    results.push(createInstanceResult(finding, instance, agent));
                }
            }
        }
    }
    const report = {
        $schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
        version: "2.1.0",
        runs: [
            {
                tool: {
                    driver: {
                        name: "vaspera-hardening",
                        version: "1.0.0",
                        informationUri: "https://github.com/RCOLKITT/hardening-mcp",
                        rules,
                    },
                },
                results,
                invocations: [
                    {
                        executionSuccessful: true,
                        startTimeUtc: certification.metadata.started_at,
                        endTimeUtc: certification.metadata.completed_at,
                    },
                ],
            },
        ],
    };
    return report;
}
function createRule(finding, agent) {
    const securitySeverity = {
        critical: "9.0",
        high: "7.0",
        medium: "4.0",
        low: "2.0",
        info: "0.0",
    };
    return {
        id: finding.id,
        name: `${finding.category}/${finding.id}`,
        shortDescription: { text: finding.description.slice(0, 200) },
        fullDescription: { text: finding.description },
        help: { text: finding.evidence },
        defaultConfiguration: {
            level: SEVERITY_TO_SARIF[finding.severity],
        },
        properties: {
            tags: [agent, finding.category, finding.severity],
            "security-severity": securitySeverity[finding.severity],
        },
    };
}
function createResult(finding, agent) {
    const locations = [];
    if (finding.file) {
        locations.push({
            physicalLocation: {
                artifactLocation: {
                    uri: finding.file,
                    uriBaseId: "%SRCROOT%",
                },
                region: finding.line
                    ? {
                        startLine: finding.line,
                    }
                    : undefined,
            },
        });
    }
    const result = {
        ruleId: finding.id,
        level: SEVERITY_TO_SARIF[finding.severity],
        message: { text: finding.description },
        locations,
        properties: {
            confidence: finding.confidence,
            agent,
            category: finding.category,
            instances: finding.instances ? finding.instances.length + 1 : 1,
        },
    };
    if (finding.file) {
        result.partialFingerprints = {
            primaryLocationLineHash: Buffer.from(`${finding.file}:${finding.line || 0}`).toString("base64"),
        };
    }
    return result;
}
function createInstanceResult(finding, instance, agent) {
    return {
        ruleId: finding.id,
        level: SEVERITY_TO_SARIF[finding.severity],
        message: { text: instance.evidence || finding.description },
        locations: [
            {
                physicalLocation: {
                    artifactLocation: {
                        uri: instance.file,
                        uriBaseId: "%SRCROOT%",
                    },
                    region: instance.line
                        ? {
                            startLine: instance.line,
                        }
                        : undefined,
                },
            },
        ],
        properties: {
            confidence: finding.confidence,
            agent,
            category: finding.category,
        },
    };
}
/**
 * Export certification to SARIF file
 */
export async function exportToSarif(projectPath, certification, outputFilename = "vaspera-findings.sarif") {
    const report = generateSarifReport(certification);
    const outputPath = join(projectPath, outputFilename);
    await writeFile(outputPath, JSON.stringify(report, null, 2), "utf-8");
    logger.info("sarif.exported", {
        certId: certification.metadata.id,
        outputPath,
        resultCount: report.runs[0].results.length,
        ruleCount: report.runs[0].tool.driver.rules.length,
    });
    return outputPath;
}
/**
 * Export to GitHub Code Scanning format (compatible with SARIF upload action)
 */
export async function exportForGitHub(projectPath, certification) {
    return exportToSarif(projectPath, certification, "github-code-scanning.sarif");
}
/**
 * Export to SonarQube format (subset of SARIF)
 */
export async function exportForSonarQube(projectPath, certification) {
    // SonarQube uses a similar SARIF format
    return exportToSarif(projectPath, certification, "sonarqube-issues.sarif");
}
//# sourceMappingURL=sarif.js.map