Files
cve-dashboard/backend/helpers/excelProcessor.js

94 lines
2.9 KiB
JavaScript
Raw Normal View History

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 };