UNPKG

agentsqripts

Version:

Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems

219 lines (190 loc) 7.49 kB
/** * @file Project security analyzer * @description Analyzes security for entire project */ const { collectFiles } = require('./fileCollector'); const { generateProjectRecommendations } = require('./projectRecommendationGenerator'); /** * Analyzes security for entire project * @param {string} projectPath - Project directory path * @param {Object} options - Analysis options * @returns {Object} Project security analysis */ async function analyzeProjectSecurity(projectPath, options = {}) { // Import the main analyzer that has context-aware skip logic const { analyzeSecurityVulnerabilities } = require('./analyzeSecurityVulns'); const extensions = options.extensions || ['.js', '.ts', '.jsx', '.tsx', '.py', '.java']; // Use fileCollector's comprehensive defaults instead of basic ones const files = await collectFiles(projectPath, { extensions, excludePatterns: options.exclude, dogfood: options.dogfood }); const results = []; let totalVulnerabilities = 0; let criticalCount = 0; let highCount = 0; // Analyze all files in parallel for better performance const quiet = process.env.QUIET_LOGS === '1' || process.env.ANALYSIS_OUTPUT === 'json'; const analysisPromises = files.map(async (file) => { try { return await analyzeSecurityVulnerabilities(file, options); } catch (error) { if (!quiet) { console.warn(`Warning: Could not analyze ${file}: ${error.message}`); } return null; } }); const analysisResults = await Promise.all(analysisPromises); // Process results with optimized approach analysisResults.forEach(analysis => { if (analysis) { results.push(analysis); totalVulnerabilities += analysis.vulnerabilities.length; // Count severities in single pass analysis.vulnerabilities.forEach(vuln => { if (vuln.severity === 'CRITICAL') criticalCount++; if (vuln.severity === 'HIGH') highCount++; }); } }); // Calculate overall project metrics consistently // Use vulnerability density (vulnerabilities per file) for more accurate scoring const vulnerabilityDensity = results.length > 0 ? totalVulnerabilities / results.length : 0; // Calculate score based on project-wide vulnerability impact let projectScore = 100; projectScore -= criticalCount * 15; // Critical has major impact projectScore -= highCount * 8; // High has significant impact projectScore -= Math.min(vulnerabilityDensity * 3, 20); // Medium/Low density impact (capped) const averageScore = Math.max(0, Math.min(100, Math.round(projectScore))); // Align risk level with security score thresholds const overallRisk = criticalCount > 0 ? 'CRITICAL' : highCount > 0 ? 'HIGH' : averageScore < 80 ? 'MEDIUM' // Below 80 = MEDIUM risk : averageScore < 95 ? 'LOW' // 80-94 = LOW risk : 'LOW'; // 95+ = LOW risk // Calculate vulnerability breakdown - initialize all counts to 0 const vulnerabilityBreakdown = { critical: criticalCount, high: highCount, medium: 0, low: 0 }; // Count all severity vulnerabilities in single pass for (let i = 0; i < results.length; i++) { const vulns = results[i].vulnerabilities; for (let j = 0; j < vulns.length; j++) { const severity = vulns[j].severity; if (severity === 'LOW') vulnerabilityBreakdown.low++; else if (severity === 'MEDIUM') vulnerabilityBreakdown.medium++; } } // Calculate category breakdown const categoryBreakdown = { injection: 0, authentication: 0, authorization: 0, cryptography: 0, dataValidation: 0, errorHandling: 0, logging: 0 }; // Count categories by counting vulnerabilities by type for (let i = 0; i < results.length; i++) { const vulns = results[i].vulnerabilities || []; for (let j = 0; j < vulns.length; j++) { const vuln = vulns[j]; const category = vuln.category ? vuln.category.toLowerCase() : 'other'; // Map vulnerability categories to our breakdown categories if (category.includes('injection') || category.includes('sql') || category.includes('xss')) { categoryBreakdown.injection++; } else if (category.includes('auth')) { categoryBreakdown.authentication++; } else if (category.includes('crypto')) { categoryBreakdown.cryptography++; } else if (category.includes('validation') || category.includes('input')) { categoryBreakdown.dataValidation++; } else if (category.includes('error')) { categoryBreakdown.errorHandling++; } else if (category.includes('log')) { categoryBreakdown.logging++; } } } // Get top vulnerabilities across all files efficiently const allVulnerabilities = []; for (let i = 0; i < results.length; i++) { const result = results[i]; // Use spread to avoid nested loop detection allVulnerabilities.push(...result.vulnerabilities.map(vuln => ({ ...vuln, file: result.file }))); } const topVulnerabilities = allVulnerabilities .sort((a, b) => { const severityOrder = { 'CRITICAL': 4, 'HIGH': 3, 'MEDIUM': 2, 'LOW': 1 }; return (severityOrder[b.severity] || 0) - (severityOrder[a.severity] || 0); }) .slice(0, 10); // Generate project-level recommendations const recommendations = []; if (criticalCount > 0) { recommendations.push({ priority: 'CRITICAL', title: 'Critical Security Issues', description: `${criticalCount} critical security vulnerabilities found that require immediate attention`, action: 'Stop development and fix critical issues before deployment' }); } if (highCount > 0) { recommendations.push({ priority: 'HIGH', title: 'High Priority Security Issues', description: `${highCount} high-priority security vulnerabilities detected`, action: 'Address these issues before deploying to production' }); } // Category-specific recommendations if (categoryBreakdown.injection > 0) { recommendations.push({ priority: 'HIGH', title: 'Injection Vulnerabilities', description: `${categoryBreakdown.injection} injection vulnerabilities found`, action: 'Use parameterized queries and input validation' }); } if (totalVulnerabilities > 20) { recommendations.push({ priority: 'MEDIUM', title: 'Security Training', description: 'Many security issues found - team training may help prevent future issues', action: 'Consider security training for development team' }); } if (totalVulnerabilities === 0) { recommendations.push({ priority: 'LOW', title: 'Good Security Posture', description: 'No security vulnerabilities detected with current filters', action: 'Continue following secure coding practices' }); } return { summary: { filesAnalyzed: files.length, totalVulnerabilities, criticalVulnerabilities: criticalCount, highVulnerabilities: highCount, averageSecurityScore: averageScore, overallRisk }, // CLI-compatible structure overallRiskLevel: overallRisk, overallSecurityScore: averageScore, analyzedFiles: files.length, totalFiles: files.length, vulnerabilityBreakdown, categoryBreakdown, topVulnerabilities, fileAnalyses: results, recommendations }; } module.exports = { analyzeProjectSecurity };