/**
 * Bandit Scanner Integration
 *
 * Python security linter that finds common security issues.
 *
 * @module scanners/bandit
 */
import { exec } from "child_process";
import { promisify } from "util";
import { SEVERITY_MAPPINGS } from "./types.js";
const execAsync = promisify(exec);
/**
 * Check if Bandit is available
 */
export async function checkBanditAvailable() {
    try {
        const { stdout } = await execAsync("bandit --version", { timeout: 5000 });
        const version = stdout.trim().split("\n")[0];
        return {
            scanner: "bandit",
            available: true,
            version,
        };
    }
    catch (error) {
        return {
            scanner: "bandit",
            available: false,
            error: error instanceof Error ? error.message : "Bandit not found",
        };
    }
}
/**
 * Convert Bandit severity to vaspera severity
 */
function mapSeverity(severity) {
    return SEVERITY_MAPPINGS.bandit[severity];
}
/**
 * Run Bandit on a Python project
 */
export async function runBandit(projectPath, options) {
    const startTime = Date.now();
    try {
        // Check if Bandit is available
        const availability = await checkBanditAvailable();
        if (!availability.available) {
            return {
                scanner: "bandit",
                findings: [],
                duration: Date.now() - startTime,
                success: false,
                error: "Bandit is not installed. Install with: pip install bandit",
            };
        }
        // Build command
        let command = `bandit -r "${projectPath}" -f json`;
        if (options?.exclude && options.exclude.length > 0) {
            command += ` --exclude ${options.exclude.join(",")}`;
        }
        if (options?.configFile) {
            command += ` -c "${options.configFile}"`;
        }
        // Run Bandit
        const { stdout, stderr } = await execAsync(command, {
            timeout: options?.timeout || 120000,
            maxBuffer: 10 * 1024 * 1024, // 10MB
        }).catch((error) => {
            // Bandit 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.results.map((result) => ({
            scanner: "bandit",
            ruleId: `bandit:${result.test_id}`,
            file: result.filename.replace(projectPath + "/", ""),
            line: result.line_number,
            column: result.col_offset,
            endLine: result.line_range[result.line_range.length - 1],
            message: `${result.test_name}: ${result.issue_text}`,
            severity: mapSeverity(result.issue_severity),
            confidence: 100,
            cweIds: result.issue_cwe ? [`CWE-${result.issue_cwe.id}`] : undefined,
            evidence: result.code,
            metadata: {
                testId: result.test_id,
                testName: result.test_name,
                issueConfidence: result.issue_confidence,
                moreInfo: result.more_info,
            },
        }));
        return {
            scanner: "bandit",
            findings,
            duration: Date.now() - startTime,
            success: true,
            version: availability.version,
            filesScanned: output.metrics._totals.loc,
        };
    }
    catch (error) {
        return {
            scanner: "bandit",
            findings: [],
            duration: Date.now() - startTime,
            success: false,
            error: error instanceof Error ? error.message : "Unknown error",
        };
    }
}
/**
 * Check if a project contains Python files
 */
export async function detectPython(projectPath) {
    try {
        // Check for common Python files
        const { stdout } = await execAsync(`find "${projectPath}" -maxdepth 3 -name "*.py" -o -name "requirements.txt" -o -name "setup.py" -o -name "pyproject.toml" | head -1`, { timeout: 5000 });
        return stdout.trim().length > 0;
    }
    catch {
        return false;
    }
}
//# sourceMappingURL=bandit.js.map