/**
 * Trivy Scanner Integration
 *
 * Comprehensive vulnerability scanner for containers, filesystems, and IaC.
 *
 * @module scanners/trivy
 */
import { exec } from "child_process";
import { promisify } from "util";
import { SEVERITY_MAPPINGS } from "./types.js";
const execAsync = promisify(exec);
/**
 * Check if Trivy is available
 */
export async function checkTrivyAvailable() {
    try {
        const { stdout } = await execAsync("trivy --version", { timeout: 5000 });
        const match = stdout.match(/Version: ([\d.]+)/);
        const version = match ? match[1] : stdout.trim().split("\n")[0];
        return {
            scanner: "trivy",
            available: true,
            version,
        };
    }
    catch (error) {
        return {
            scanner: "trivy",
            available: false,
            error: error instanceof Error ? error.message : "Trivy not found",
        };
    }
}
/**
 * Convert Trivy severity to vaspera severity
 */
function mapSeverity(severity) {
    return SEVERITY_MAPPINGS.trivy[severity];
}
/**
 * Run Trivy filesystem scan
 */
export async function runTrivy(projectPath, options) {
    const startTime = Date.now();
    try {
        // Check if Trivy is available
        const availability = await checkTrivyAvailable();
        if (!availability.available) {
            return {
                scanner: "trivy",
                findings: [],
                duration: Date.now() - startTime,
                success: false,
                error: "Trivy is not installed. Install from: https://aquasecurity.github.io/trivy/",
            };
        }
        // Build command
        const scanType = options?.scanType || "fs";
        let command = `trivy ${scanType} --format json`;
        if (options?.ignoreUnfixed) {
            command += " --ignore-unfixed";
        }
        if (options?.severity && options.severity.length > 0) {
            command += ` --severity ${options.severity.join(",")}`;
        }
        command += ` "${projectPath}"`;
        // Run Trivy
        const { stdout, stderr } = await execAsync(command, {
            timeout: options?.timeout || 300000, // 5 minutes for Trivy
            maxBuffer: 50 * 1024 * 1024, // 50MB
        }).catch((error) => {
            if (error.stdout) {
                return { stdout: error.stdout, stderr: error.stderr || "" };
            }
            throw error;
        });
        // Parse JSON output
        const output = JSON.parse(stdout);
        // Convert to DeterministicFindings
        const findings = [];
        for (const result of output.Results) {
            // Process vulnerabilities
            if (result.Vulnerabilities) {
                for (const vuln of result.Vulnerabilities) {
                    findings.push({
                        scanner: "trivy",
                        ruleId: `trivy:${vuln.VulnerabilityID}`,
                        file: result.Target,
                        line: 1,
                        message: `${vuln.PkgName}@${vuln.InstalledVersion}: ${vuln.Title || vuln.VulnerabilityID}${vuln.FixedVersion ? ` (fixed in ${vuln.FixedVersion})` : ""}`,
                        severity: mapSeverity(vuln.Severity),
                        confidence: 100,
                        cweIds: vuln.CweIDs,
                        cveIds: [vuln.VulnerabilityID],
                        fixAvailable: !!vuln.FixedVersion,
                        fix: vuln.FixedVersion ? `Upgrade to ${vuln.FixedVersion}` : undefined,
                        metadata: {
                            pkgName: vuln.PkgName,
                            installedVersion: vuln.InstalledVersion,
                            fixedVersion: vuln.FixedVersion,
                            primaryURL: vuln.PrimaryURL,
                        },
                    });
                }
            }
            // Process misconfigurations
            if (result.Misconfigurations) {
                for (const misconfig of result.Misconfigurations) {
                    const startLine = misconfig.CauseMetadata?.StartLine || 1;
                    findings.push({
                        scanner: "trivy",
                        ruleId: `trivy:${misconfig.ID}`,
                        file: result.Target,
                        line: startLine,
                        endLine: misconfig.CauseMetadata?.EndLine,
                        message: `${misconfig.Title}: ${misconfig.Message}`,
                        severity: mapSeverity(misconfig.Severity),
                        confidence: 100,
                        fix: misconfig.Resolution,
                        evidence: misconfig.CauseMetadata?.Code?.Lines
                            ?.map((l) => l.Content)
                            .join("\n"),
                        metadata: {
                            type: misconfig.Type,
                            namespace: misconfig.Namespace,
                            resource: misconfig.CauseMetadata?.Resource,
                            provider: misconfig.CauseMetadata?.Provider,
                            service: misconfig.CauseMetadata?.Service,
                            primaryURL: misconfig.PrimaryURL,
                        },
                    });
                }
            }
            // Process secrets
            if (result.Secrets) {
                for (const secret of result.Secrets) {
                    findings.push({
                        scanner: "trivy",
                        ruleId: `trivy:${secret.RuleID}`,
                        file: result.Target,
                        line: secret.StartLine,
                        endLine: secret.EndLine,
                        message: `${secret.Title}: ${secret.Category}`,
                        severity: mapSeverity(secret.Severity),
                        confidence: 100,
                        evidence: secret.Code?.Lines
                            ?.map((l) => l.Content)
                            .join("\n"),
                        metadata: {
                            category: secret.Category,
                            match: secret.Match,
                        },
                    });
                }
            }
        }
        return {
            scanner: "trivy",
            findings,
            duration: Date.now() - startTime,
            success: true,
            version: availability.version,
        };
    }
    catch (error) {
        return {
            scanner: "trivy",
            findings: [],
            duration: Date.now() - startTime,
            success: false,
            error: error instanceof Error ? error.message : "Unknown error",
        };
    }
}
/**
 * Check if a project has Dockerfiles or IaC files
 */
export async function detectIaC(projectPath) {
    try {
        const { stdout } = await execAsync(`find "${projectPath}" -maxdepth 3 \\( -name "Dockerfile*" -o -name "*.tf" -o -name "*.yaml" -name "*compose*.yml" -o -name "kubernetes*.yaml" \\) | head -1`, { timeout: 5000 });
        return stdout.trim().length > 0;
    }
    catch {
        return false;
    }
}
//# sourceMappingURL=trivy.js.map