/**
 * Gosec Scanner Integration
 *
 * Go security scanner that inspects source code for security vulnerabilities.
 *
 * @module scanners/gosec
 */
import { exec, spawn } from "child_process";
import { promisify } from "util";
import { SEVERITY_MAPPINGS } from "./types.js";
const execAsync = promisify(exec);
/**
 * Run a command with spawn and return stdout/stderr
 */
function runSpawn(command, args, options) {
    return new Promise((resolve, reject) => {
        const child = spawn(command, args, {
            cwd: options.cwd,
            timeout: options.timeout,
        });
        let stdout = "";
        let stderr = "";
        child.stdout.on("data", (data) => {
            stdout += data.toString();
        });
        child.stderr.on("data", (data) => {
            stderr += data.toString();
        });
        child.on("close", (code) => {
            // gosec exits with code 1 if issues are found, which is expected
            if (code === 0 || (code === 1 && stdout)) {
                resolve({ stdout, stderr });
            }
            else {
                const error = new Error(`gosec exited with code ${code}`);
                error.stdout = stdout;
                error.stderr = stderr;
                reject(error);
            }
        });
        child.on("error", (err) => {
            reject(err);
        });
    });
}
/**
 * Check if gosec is available
 */
export async function checkGosecAvailable() {
    try {
        const { stdout } = await execAsync("gosec --version", { timeout: 5000 });
        const version = stdout.trim();
        return {
            scanner: "gosec",
            available: true,
            version,
        };
    }
    catch (error) {
        return {
            scanner: "gosec",
            available: false,
            error: error instanceof Error ? error.message : "gosec not found",
        };
    }
}
/**
 * Convert gosec severity to vaspera severity
 */
function mapSeverity(severity) {
    return SEVERITY_MAPPINGS.gosec[severity];
}
/**
 * Run gosec on a Go project
 */
export async function runGosec(projectPath, options) {
    const startTime = Date.now();
    try {
        // Check if gosec is available
        const availability = await checkGosecAvailable();
        if (!availability.available) {
            return {
                scanner: "gosec",
                findings: [],
                duration: Date.now() - startTime,
                success: false,
                error: "gosec is not installed. Install with: go install github.com/securego/gosec/v2/cmd/gosec@latest",
            };
        }
        // Build command args (array to prevent command injection)
        const args = ["-fmt=json"];
        if (options?.exclude && options.exclude.length > 0) {
            args.push(`-exclude=${options.exclude.join(",")}`);
        }
        if (options?.configFile) {
            args.push(`-conf=${options.configFile}`);
        }
        // Add the target path (./... scans all packages)
        args.push("./...");
        // Run gosec with spawn (safer than exec with string)
        const { stdout, stderr } = await runSpawn("gosec", args, {
            timeout: options?.timeout || 120000,
            cwd: projectPath,
        }).catch((error) => {
            // gosec exits with code 1 if issues are found
            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 = output.Issues.map((issue) => ({
            scanner: "gosec",
            ruleId: `gosec:${issue.rule_id}`,
            file: issue.file.replace(projectPath + "/", ""),
            line: parseInt(issue.line, 10),
            column: parseInt(issue.column, 10),
            message: issue.details,
            severity: mapSeverity(issue.severity),
            confidence: 100,
            cweIds: issue.cwe ? [`CWE-${issue.cwe.id}`] : undefined,
            evidence: issue.code,
            metadata: {
                ruleId: issue.rule_id,
                confidence: issue.confidence,
                cweUrl: issue.cwe?.url,
            },
        }));
        return {
            scanner: "gosec",
            findings,
            duration: Date.now() - startTime,
            success: true,
            version: availability.version,
            filesScanned: output.Stats?.files,
        };
    }
    catch (error) {
        return {
            scanner: "gosec",
            findings: [],
            duration: Date.now() - startTime,
            success: false,
            error: error instanceof Error ? error.message : "Unknown error",
        };
    }
}
/**
 * Check if a project contains Go files
 */
export async function detectGo(projectPath) {
    try {
        // Check for common Go files
        const { stdout } = await execAsync(`find "${projectPath}" -maxdepth 3 -name "*.go" -o -name "go.mod" | head -1`, { timeout: 5000 });
        return stdout.trim().length > 0;
    }
    catch {
        return false;
    }
}
//# sourceMappingURL=gosec.js.map