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
JavaScript
/**
* @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
};