UNPKG

tops-bmad

Version:

CLI tool to install BMAD workflow files into any project with integrated Shai-Hulud 2.0 security scanning

204 lines (166 loc) 6.01 kB
#!/usr/bin/env node /** * TOPS BMAD Security Scanner - Security Dashboard Generator * * Generates a security dashboard report from scan results * * Usage: * node security-dashboard.js [--output <file>] */ import { readFileSync, writeFileSync, existsSync, statSync } from 'fs'; import { join, dirname, resolve } from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const workspaceRoot = resolve(__dirname, '..', '..'); const configPath = join(__dirname, '..', 'config', 'organization-config.json'); // Load organization config let orgConfig = { projects: [] }; if (existsSync(configPath)) { try { orgConfig = JSON.parse(readFileSync(configPath, 'utf8')); } catch (error) { console.warn('⚠️ Could not load organization config:', error.message); } } function findScanResults() { const results = []; const projects = orgConfig.projects || []; // Search for SARIF files for (const project of projects) { const projectPath = resolve(workspaceRoot, project.path || project); const sarifPath = join(projectPath, 'shai-hulud-results.sarif'); if (existsSync(sarifPath)) { try { const sarifData = JSON.parse(readFileSync(sarifPath, 'utf8')); const stats = statSync(sarifPath); results.push({ project: project.name || project.path || project, path: projectPath, sarifPath, timestamp: stats.mtime, results: sarifData.runs?.[0]?.results || [], rules: sarifData.runs?.[0]?.tool?.driver?.rules || [] }); } catch (error) { console.warn(`⚠️ Could not read SARIF file: ${sarifPath}`); } } } return results; } function generateDashboard(scanResults, outputPath) { const lines = []; lines.push('# TOPS BMAD Security Dashboard'); lines.push(''); lines.push(`Generated: ${new Date().toISOString()}`); lines.push(''); lines.push('---'); lines.push(''); if (scanResults.length === 0) { lines.push('## No Scan Results Found'); lines.push(''); lines.push('Run security scans to generate results:'); lines.push('```bash'); lines.push('npm run security:scan:all'); lines.push('```'); lines.push(''); return lines.join('\n'); } lines.push('## Summary'); lines.push(''); let totalIssues = 0; let totalCritical = 0; let totalHigh = 0; for (const result of scanResults) { const critical = result.results.filter(r => r.level === 'error').length; const high = result.results.filter(r => r.level === 'warning').length; const total = result.results.length; totalIssues += total; totalCritical += critical; totalHigh += high; } lines.push(`- **Total Projects Scanned:** ${scanResults.length}`); lines.push(`- **Total Issues Found:** ${totalIssues}`); lines.push(`- **Critical Issues:** ${totalCritical}`); lines.push(`- **High Issues:** ${totalHigh}`); lines.push(''); lines.push('---'); lines.push(''); lines.push('## Project Details'); lines.push(''); for (const result of scanResults) { const critical = result.results.filter(r => r.level === 'error').length; const high = result.results.filter(r => r.level === 'warning').length; const total = result.results.length; lines.push(`### ${result.project}`); lines.push(''); lines.push(`- **Path:** \`${result.path}\``); lines.push(`- **Last Scanned:** ${result.timestamp.toISOString()}`); lines.push(`- **Total Issues:** ${total}`); lines.push(` - Critical: ${critical}`); lines.push(` - High: ${high}`); lines.push(''); if (total > 0) { lines.push('#### Issues:'); lines.push(''); for (const issue of result.results.slice(0, 10)) { // Show first 10 const level = issue.level === 'error' ? '🔴' : issue.level === 'warning' ? '🟡' : '🔵'; lines.push(`- ${level} **${issue.level.toUpperCase()}**: ${issue.message.text.substring(0, 100)}${issue.message.text.length > 100 ? '...' : ''}`); } if (total > 10) { lines.push(`- ... and ${total - 10} more issues`); } lines.push(''); } else { lines.push('✅ No issues found'); lines.push(''); } lines.push('---'); lines.push(''); } lines.push('## Recommendations'); lines.push(''); if (totalCritical > 0) { lines.push('🔴 **CRITICAL**: Immediate action required'); lines.push(''); lines.push('1. Review all critical findings'); lines.push('2. Rotate all credentials'); lines.push('3. Update compromised packages'); lines.push('4. Review CI/CD configurations'); lines.push(''); } else if (totalHigh > 0) { lines.push('🟡 **HIGH**: Review and address high-priority issues'); lines.push(''); lines.push('1. Review high-severity findings'); lines.push('2. Update packages as needed'); lines.push('3. Review security configurations'); lines.push(''); } else { lines.push('✅ **CLEAN**: No critical or high-severity issues found'); lines.push(''); lines.push('Continue regular security scans to maintain security posture.'); lines.push(''); } return lines.join('\n'); } function main() { const args = process.argv.slice(2); let outputPath = null; for (let i = 0; i < args.length; i++) { if (args[i] === '--output' && i + 1 < args.length) { outputPath = resolve(args[++i]); } } console.log('📊 Generating security dashboard...\n'); const scanResults = findScanResults(); console.log(`📦 Found scan results for ${scanResults.length} project(s)\n`); const dashboard = generateDashboard(scanResults, outputPath); if (outputPath) { writeFileSync(outputPath, dashboard, 'utf8'); console.log(`✅ Dashboard written to: ${outputPath}`); } else { console.log(dashboard); } } main();