UNPKG

@ordojs/security

Version:

Security package for OrdoJS with XSS, CSRF, and injection protection

426 lines (405 loc) • 16.8 kB
#!/usr/bin/env node import { writeFileSync } from 'fs'; import { join } from 'path'; import { SecurityAuditor } from './security-auditor'; import { VulnerabilityScanner } from './vulnerability-scanner'; class SecurityAuditCLI { options; constructor(options) { this.options = { format: 'json', severity: 'low', enableDependencyCheck: true, enableCodeAnalysis: true, enableConfigurationCheck: true, generateReport: true, verbose: false, ...options, }; } async run() { try { if (this.options.verbose) { console.log('šŸ” Starting OrdoJS Security Audit...'); console.log(`šŸ“ Project path: ${this.options.projectPath}`); } // Run security audit const auditorOptions = { projectPath: this.options.projectPath, }; if (this.options.includePatterns) { auditorOptions.includePatterns = this.options.includePatterns; } if (this.options.excludePatterns) { auditorOptions.excludePatterns = this.options.excludePatterns; } if (this.options.enableDependencyCheck !== undefined) { auditorOptions.enableDependencyCheck = this.options.enableDependencyCheck; } if (this.options.enableCodeAnalysis !== undefined) { auditorOptions.enableCodeAnalysis = this.options.enableCodeAnalysis; } if (this.options.enableConfigurationCheck !== undefined) { auditorOptions.enableConfigurationCheck = this.options.enableConfigurationCheck; } const auditor = new SecurityAuditor(auditorOptions); const auditResult = await auditor.audit(); // Filter by severity if specified if (this.options.severity && this.options.severity !== 'low') { const severityLevels = ['low', 'medium', 'high', 'critical']; const minSeverityIndex = severityLevels.indexOf(this.options.severity); auditResult.vulnerabilities = auditResult.vulnerabilities.filter(vuln => { const vulnSeverityIndex = severityLevels.indexOf(vuln.severity); return vulnSeverityIndex >= minSeverityIndex; }); // Recalculate summary auditResult.summary = auditResult.vulnerabilities.reduce((acc, vuln) => { acc.total++; acc[vuln.severity]++; return acc; }, { total: 0, critical: 0, high: 0, medium: 0, low: 0 }); } // Generate dependency vulnerability report let dependencyReport; if (this.options.enableDependencyCheck) { const scanner = new VulnerabilityScanner({ projectPath: this.options.projectPath, }); dependencyReport = await scanner.scanDependencies(); } // Display results this.displayResults(auditResult, dependencyReport); // Generate output files if (this.options.output || this.options.generateReport) { await this.generateOutputFiles(auditResult, dependencyReport); } // Generate fix script if (this.options.generateFixScript && dependencyReport) { await this.generateFixScript(dependencyReport); } // Exit with appropriate code const hasHighSeverityIssues = auditResult.summary.critical > 0 || auditResult.summary.high > 0; process.exit(hasHighSeverityIssues ? 1 : 0); } catch (error) { console.error('āŒ Security audit failed:', error); process.exit(1); } } displayResults(auditResult, dependencyReport) { console.log('\nšŸ“Š Security Audit Results'); console.log('='.repeat(50)); // Summary console.log(`\nšŸ“ˆ Summary:`); console.log(` Total vulnerabilities: ${auditResult.summary.total}`); console.log(` šŸ”“ Critical: ${auditResult.summary.critical}`); console.log(` 🟠 High: ${auditResult.summary.high}`); console.log(` 🟔 Medium: ${auditResult.summary.medium}`); console.log(` 🟢 Low: ${auditResult.summary.low}`); // OWASP Compliance console.log(`\nšŸ›”ļø OWASP Compliance Score: ${auditResult.owaspCompliance.score}%`); // Dependency vulnerabilities if (dependencyReport) { console.log(`\nšŸ“¦ Dependency Vulnerabilities: ${dependencyReport.summary.total}`); console.log(` šŸ”“ Critical: ${dependencyReport.summary.critical}`); console.log(` 🟠 High: ${dependencyReport.summary.high}`); console.log(` 🟔 Medium: ${dependencyReport.summary.medium}`); console.log(` 🟢 Low: ${dependencyReport.summary.low}`); } // Top vulnerabilities if (auditResult.vulnerabilities.length > 0) { console.log('\n🚨 Top Vulnerabilities:'); auditResult.vulnerabilities .slice(0, 5) .forEach((vuln, index) => { const severityIcon = this.getSeverityIcon(vuln.severity); console.log(` ${index + 1}. ${severityIcon} ${vuln.description}`); if (vuln.file) { console.log(` šŸ“„ ${vuln.file}:${vuln.line || '?'}`); } console.log(` šŸ’” ${vuln.recommendation}`); console.log(''); }); } // Recommendations if (auditResult.summary.total > 0) { console.log('\nšŸ’” Recommendations:'); console.log(' 1. Fix critical and high severity vulnerabilities immediately'); console.log(' 2. Review and update dependencies regularly'); console.log(' 3. Implement security headers and HTTPS'); console.log(' 4. Use input validation and output encoding'); console.log(' 5. Enable runtime security monitoring'); } else { console.log('\nāœ… No security vulnerabilities found!'); } } async generateOutputFiles(auditResult, dependencyReport) { const outputPath = this.options.output || join(this.options.projectPath, 'security-audit-report'); const reportData = { audit: auditResult, dependencies: dependencyReport, generatedAt: new Date().toISOString(), options: this.options, }; switch (this.options.format) { case 'json': writeFileSync(`${outputPath}.json`, JSON.stringify(reportData, null, 2)); console.log(`\nšŸ“„ JSON report saved to: ${outputPath}.json`); break; case 'html': const htmlReport = this.generateHTMLReport(reportData); writeFileSync(`${outputPath}.html`, htmlReport); console.log(`\nšŸ“„ HTML report saved to: ${outputPath}.html`); break; case 'markdown': const markdownReport = this.generateMarkdownReport(reportData); writeFileSync(`${outputPath}.md`, markdownReport); console.log(`\nšŸ“„ Markdown report saved to: ${outputPath}.md`); break; case 'csv': const csvReport = this.generateCSVReport(reportData); writeFileSync(`${outputPath}.csv`, csvReport); console.log(`\nšŸ“„ CSV report saved to: ${outputPath}.csv`); break; } } async generateFixScript(dependencyReport) { const scanner = new VulnerabilityScanner({ projectPath: this.options.projectPath, }); const fixScript = await scanner.generateFixScript(); const scriptPath = join(this.options.projectPath, 'fix-vulnerabilities.sh'); writeFileSync(scriptPath, fixScript); console.log(`\nšŸ”§ Fix script saved to: ${scriptPath}`); console.log(' Run with: chmod +x fix-vulnerabilities.sh && ./fix-vulnerabilities.sh'); } generateHTMLReport(data) { return ` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>OrdoJS Security Audit Report</title> <style> body { font-family: Arial, sans-serif; margin: 20px; } .header { background: #f8f9fa; padding: 20px; border-radius: 8px; } .summary { display: flex; gap: 20px; margin: 20px 0; } .metric { background: #fff; border: 1px solid #ddd; padding: 15px; border-radius: 8px; } .vulnerability { border-left: 4px solid #dc3545; padding: 10px; margin: 10px 0; background: #f8f9fa; } .critical { border-left-color: #dc3545; } .high { border-left-color: #fd7e14; } .medium { border-left-color: #ffc107; } .low { border-left-color: #28a745; } .recommendation { background: #e7f3ff; padding: 10px; border-radius: 4px; margin: 5px 0; } </style> </head> <body> <div class="header"> <h1>šŸ›”ļø OrdoJS Security Audit Report</h1> <p>Generated on: ${data.generatedAt}</p> <p>Project: ${this.options.projectPath}</p> </div> <div class="summary"> <div class="metric"> <h3>Total Vulnerabilities</h3> <h2>${data.audit.summary.total}</h2> </div> <div class="metric"> <h3>OWASP Compliance</h3> <h2>${data.audit.owaspCompliance.score}%</h2> </div> ${data.dependencies ? ` <div class="metric"> <h3>Dependency Issues</h3> <h2>${data.dependencies.summary.total}</h2> </div> ` : ''} </div> <h2>🚨 Vulnerabilities</h2> ${data.audit.vulnerabilities.map((vuln) => ` <div class="vulnerability ${vuln.severity}"> <h4>${vuln.description}</h4> ${vuln.file ? `<p><strong>File:</strong> ${vuln.file}:${vuln.line || '?'}</p>` : ''} <p><strong>Severity:</strong> ${vuln.severity.toUpperCase()}</p> <p><strong>Type:</strong> ${vuln.type}</p> ${vuln.owaspCategory ? `<p><strong>OWASP:</strong> ${vuln.owaspCategory}</p>` : ''} <div class="recommendation"> <strong>Recommendation:</strong> ${vuln.recommendation} </div> </div> `).join('')} ${data.dependencies && data.dependencies.vulnerabilities.length > 0 ? ` <h2>šŸ“¦ Dependency Vulnerabilities</h2> ${data.dependencies.vulnerabilities.map((vuln) => ` <div class="vulnerability ${vuln.vulnerability.severity}"> <h4>${vuln.package}@${vuln.version}</h4> <p><strong>Issue:</strong> ${vuln.vulnerability.title}</p> <p><strong>Severity:</strong> ${vuln.vulnerability.severity.toUpperCase()}</p> ${vuln.vulnerability.cvss ? `<p><strong>CVSS Score:</strong> ${vuln.vulnerability.cvss.score}</p>` : ''} <div class="recommendation"> <strong>Fix:</strong> ${vuln.fixAvailable.available ? `Update to ${vuln.fixAvailable.version}` : 'No automatic fix available'} </div> </div> `).join('')} ` : ''} </body> </html> `.trim(); } generateMarkdownReport(data) { return ` # šŸ›”ļø OrdoJS Security Audit Report **Generated:** ${data.generatedAt} **Project:** ${this.options.projectPath} ## šŸ“Š Summary - **Total Vulnerabilities:** ${data.audit.summary.total} - **Critical:** ${data.audit.summary.critical} - **High:** ${data.audit.summary.high} - **Medium:** ${data.audit.summary.medium} - **Low:** ${data.audit.summary.low} - **OWASP Compliance Score:** ${data.audit.owaspCompliance.score}% ${data.dependencies ? ` ## šŸ“¦ Dependency Vulnerabilities - **Total:** ${data.dependencies.summary.total} - **Critical:** ${data.dependencies.summary.critical} - **High:** ${data.dependencies.summary.high} - **Medium:** ${data.dependencies.summary.medium} - **Low:** ${data.dependencies.summary.low} ` : ''} ## 🚨 Vulnerabilities ${data.audit.vulnerabilities.map((vuln) => ` ### ${vuln.description} - **Severity:** ${vuln.severity.toUpperCase()} - **Type:** ${vuln.type} ${vuln.file ? `- **File:** ${vuln.file}:${vuln.line || '?'}` : ''} ${vuln.owaspCategory ? `- **OWASP Category:** ${vuln.owaspCategory}` : ''} **Recommendation:** ${vuln.recommendation} --- `).join('')} ${data.dependencies && data.dependencies.vulnerabilities.length > 0 ? ` ## šŸ“¦ Dependency Issues ${data.dependencies.vulnerabilities.map((vuln) => ` ### ${vuln.package}@${vuln.version} - **Issue:** ${vuln.vulnerability.title} - **Severity:** ${vuln.vulnerability.severity.toUpperCase()} - **ID:** ${vuln.vulnerability.id} ${vuln.vulnerability.cvss ? `- **CVSS Score:** ${vuln.vulnerability.cvss.score}` : ''} **Fix:** ${vuln.fixAvailable.available ? `Update to ${vuln.fixAvailable.version}` : 'No automatic fix available'} --- `).join('')} ` : ''} `.trim(); } generateCSVReport(data) { const headers = ['Type', 'Severity', 'Description', 'File', 'Line', 'Recommendation', 'OWASP Category']; const rows = data.audit.vulnerabilities.map((vuln) => [ vuln.type, vuln.severity, vuln.description, vuln.file || '', vuln.line || '', vuln.recommendation, vuln.owaspCategory || '', ]); return [headers, ...rows] .map(row => row.map((cell) => `"${cell}"`).join(',')) .join('\n'); } getSeverityIcon(severity) { switch (severity) { case 'critical': return 'šŸ”“'; case 'high': return '🟠'; case 'medium': return '🟔'; case 'low': return '🟢'; default: return '⚪'; } } } // CLI argument parsing function parseArgs() { const args = process.argv.slice(2); const options = { projectPath: process.cwd(), }; for (let i = 0; i < args.length; i++) { const arg = args[i]; const nextArg = args[i + 1]; switch (arg) { case '--path': case '-p': if (nextArg) options.projectPath = nextArg; i++; break; case '--output': case '-o': if (nextArg) options.output = nextArg; i++; break; case '--format': case '-f': options.format = nextArg; i++; break; case '--severity': case '-s': options.severity = nextArg; i++; break; case '--no-deps': options.enableDependencyCheck = false; break; case '--no-code': options.enableCodeAnalysis = false; break; case '--no-config': options.enableConfigurationCheck = false; break; case '--fix': options.generateFixScript = true; break; case '--verbose': case '-v': options.verbose = true; break; case '--help': case '-h': console.log(` OrdoJS Security Audit CLI Usage: ordojs-security-audit [options] Options: -p, --path <path> Project path (default: current directory) -o, --output <file> Output file path -f, --format <format> Output format: json, html, markdown, csv (default: json) -s, --severity <level> Minimum severity: low, medium, high, critical (default: low) --no-deps Skip dependency vulnerability check --no-code Skip source code analysis --no-config Skip configuration audit --fix Generate vulnerability fix script -v, --verbose Verbose output -h, --help Show this help message Examples: ordojs-security-audit ordojs-security-audit --path ./my-project --format html --output report ordojs-security-audit --severity high --fix --verbose `); process.exit(0); } } return options; } // Run CLI if this file is executed directly if (require.main === module) { const options = parseArgs(); const cli = new SecurityAuditCLI(options); cli.run().catch(console.error); } export { SecurityAuditCLI }; //# sourceMappingURL=cli.js.map