const { spawn } = require('child_process'); const path = require('path'); const fs = require('fs'); /** * Process vulnerability report Excel file by splitting CVE IDs into separate rows * @param {string} inputPath - Path to original Excel file * @param {string} outputPath - Path for processed Excel file * @returns {Promise<{original_rows: number, processed_rows: number, output_path: string}>} */ function processVulnerabilityReport(inputPath, outputPath) { return new Promise((resolve, reject) => { const scriptPath = path.join(__dirname, '..', 'scripts', 'split_cve_report.py'); // Verify script exists if (!fs.existsSync(scriptPath)) { return reject(new Error(`Python script not found: ${scriptPath}`)); } // Verify input file exists if (!fs.existsSync(inputPath)) { return reject(new Error(`Input file not found: ${inputPath}`)); } const python = spawn('python3', [scriptPath, inputPath, outputPath]); let stdout = ''; let stderr = ''; let timedOut = false; // 30 second timeout const timeout = setTimeout(() => { timedOut = true; python.kill(); reject(new Error('Processing timed out. File may be too large or corrupted.')); }, 30000); python.stdout.on('data', (data) => { stdout += data.toString(); }); python.stderr.on('data', (data) => { stderr += data.toString(); }); python.on('close', (code) => { clearTimeout(timeout); if (timedOut) return; if (code !== 0) { // Parse Python error messages if (stderr.includes('Sheet') && stderr.includes('not found')) { return reject(new Error('Invalid Excel file. Expected "Vulnerabilities" sheet with "CVE ID" column.')); } if (stderr.includes('pandas') || stderr.includes('openpyxl')) { return reject(new Error('Python dependencies missing. Run: pip3 install pandas openpyxl')); } return reject(new Error(`Python script failed: ${stderr || 'Unknown error'}`)); } // Parse output for row counts const originalMatch = stdout.match(/Original rows:\s*(\d+)/); const newMatch = stdout.match(/New rows:\s*(\d+)/); if (!originalMatch || !newMatch) { return reject(new Error('Failed to parse row counts from Python output')); } // Verify output file was created if (!fs.existsSync(outputPath)) { return reject(new Error('Processed file was not created')); } resolve({ original_rows: parseInt(originalMatch[1]), processed_rows: parseInt(newMatch[1]), output_path: outputPath }); }); python.on('error', (err) => { clearTimeout(timeout); if (err.code === 'ENOENT') { reject(new Error('Python 3 is required but not found. Please install Python.')); } else { reject(err); } }); }); } module.exports = { processVulnerabilityReport };