UNPKG

agentsqripts

Version:

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

339 lines (290 loc) • 10.6 kB
/** * @file Enhanced security output formatter * @description Provides detailed, actionable output with code context */ const { promises: fsPromises } = require('fs'); const path = require('path'); /** * Gets code context around a vulnerability (async version for better scalability) * @param {string} filePath - Path to the file * @param {number} lineNumber - Line number of vulnerability * @param {number} contextLines - Number of lines before/after to show * @returns {Promise<Object>} Code context with highlighted line */ async function getCodeContext(filePath, lineNumber, contextLines = 3) { try { const content = await fsPromises.readFile(filePath, 'utf8'); const lines = content.split('\n'); const startLine = Math.max(0, lineNumber - contextLines - 1); const endLine = Math.min(lines.length, lineNumber + contextLines); const context = []; for (let i = startLine; i < endLine; i++) { const lineNum = i + 1; const isVulnLine = lineNum === lineNumber; context.push({ number: lineNum, content: lines[i], isVulnerability: isVulnLine }); } return { file: filePath, line: lineNumber, context: context }; } catch (error) { return null; } } /** * Formats a single vulnerability with full context (async version for better scalability) * @param {Object} vuln - Vulnerability object * @param {string} filePath - Full file path * @returns {Promise<string>} Formatted vulnerability output */ async function formatVulnerability(vuln, filePath) { const output = []; // Header with severity badge const severityColors = { 'CRITICAL': 'šŸ”“', 'HIGH': '🟠', 'MEDIUM': '🟔', 'LOW': 'šŸ”µ', 'INFO': '🟢' }; output.push(`\n${severityColors[vuln.severity] || '⚪'} [${vuln.severity}] ${vuln.name || vuln.type}`); output.push(`šŸ“ File: ${filePath}:${vuln.line}`); output.push(`šŸ“ ${vuln.description}`); // Add code context const codeContext = await getCodeContext(filePath, vuln.line); if (codeContext) { output.push('\nšŸ“„ Code Context:'); output.push('```javascript'); codeContext.context.forEach(line => { const prefix = line.isVulnerability ? '>>> ' : ' '; const lineNumStr = String(line.number).padStart(4, ' '); output.push(`${lineNumStr} ${prefix}${line.content}`); }); output.push('```'); } // Add remediation suggestions if (vuln.remediation) { output.push('\nšŸ’” Remediation:'); output.push(vuln.remediation); } else { output.push('\nšŸ’” Suggested Fix:'); output.push(getRemediationSuggestion(vuln)); } // Add confidence level if available if (vuln.confidence) { output.push(`\nšŸŽÆ Confidence: ${vuln.confidence}`); } return output.join('\n'); } /** * Gets remediation suggestions based on vulnerability type * @param {Object} vuln - Vulnerability object * @returns {string} Remediation suggestion */ function getRemediationSuggestion(vuln) { const suggestions = { 'SQL_INJECTION': 'Use parameterized queries or prepared statements:\n' + '```javascript\n' + '// Instead of: query = "SELECT * FROM users WHERE id = " + userId\n' + '// Use: query = "SELECT * FROM users WHERE id = ?"\n' + '// db.query(query, [userId])\n' + '```', 'XSS': 'Sanitize user input and use safe rendering methods:\n' + '```javascript\n' + '// Instead of: element.innerHTML = userInput\n' + '// Use: element.textContent = userInput\n' + '// Or use a sanitization library like DOMPurify\n' + '```', 'EVAL_USAGE': 'Avoid eval() and use safer alternatives:\n' + '```javascript\n' + '// Instead of: eval(userCode)\n' + '// Use: JSON.parse() for JSON data\n' + '// Or use Function constructor with strict validation\n' + '```', 'PROTOTYPE_POLLUTION': 'Validate object keys and use Object.create(null):\n' + '```javascript\n' + '// Create objects without prototype\n' + 'const obj = Object.create(null);\n' + '// Or validate keys: if (key === "__proto__") return;\n' + '```', 'REDOS': 'Simplify regex or use alternative parsing methods:\n' + '```javascript\n' + '// Avoid nested quantifiers like (a+)+\n' + '// Use atomic groups or possessive quantifiers\n' + '// Consider using a parser library instead\n' + '```', 'SSRF': 'Validate and whitelist URLs:\n' + '```javascript\n' + '// Validate URL protocol and domain\n' + 'const url = new URL(userInput);\n' + 'if (!allowedDomains.includes(url.hostname)) {\n' + ' throw new Error("Invalid domain");\n' + '}\n' + '```', 'INSECURE_DESERIALIZATION': 'Use JSON.parse with validation:\n' + '```javascript\n' + '// Never use eval() or Function() with user input\n' + '// Use JSON.parse and validate the structure\n' + 'const data = JSON.parse(userInput);\n' + 'validateSchema(data);\n' + '```', 'JWT_NONE_ALGORITHM': 'Explicitly specify allowed algorithms:\n' + '```javascript\n' + '// Specify algorithms explicitly\n' + 'jwt.verify(token, secret, { algorithms: ["HS256"] });\n' + '// Never allow "none" algorithm\n' + '```', 'JWT_NO_VERIFICATION': 'Always verify JWT tokens:\n' + '```javascript\n' + '// Instead of: jwt.decode(token)\n' + '// Use: jwt.verify(token, secret)\n' + '```' }; return suggestions[vuln.type] || 'Review this code for security implications and apply appropriate validation/sanitization.'; } /** * Formats framework security findings * @param {Array} frameworks - Array of framework security objects * @returns {string} Formatted framework findings */ function formatFrameworkFindings(frameworks) { if (!frameworks || frameworks.length === 0) return ''; const output = ['\nšŸ›”ļø Framework Security Analysis:\n']; frameworks.forEach(fw => { output.push(`šŸ“¦ ${fw.framework} Security:`); // Show positive findings const positiveRecs = fw.recommendations.filter(r => r.positive); if (positiveRecs.length > 0) { output.push(' āœ… Good practices found:'); positiveRecs.forEach(rec => { output.push(` • ${rec.message}`); }); } // Show security configurations if (fw.framework === 'Express.js') { output.push(` ${fw.helmet ? 'āœ…' : 'āŒ'} Helmet middleware`); output.push(` ${fw.cors ? 'āœ…' : 'āŒ'} CORS configured`); output.push(` ${fw.rateLimit ? 'āœ…' : 'āŒ'} Rate limiting`); } // Show issues const issues = fw.recommendations.filter(r => !r.positive); if (issues.length > 0) { output.push(' āš ļø Security recommendations:'); issues.forEach(rec => { const icon = rec.severity === 'HIGH' || rec.severity === 'CRITICAL' ? 'šŸ”“' : '🟔'; output.push(` ${icon} ${rec.message}`); }); } output.push(''); }); return output.join('\n'); } /** * Generates an enhanced security report * @param {Object} analysis - Complete analysis results * @returns {string} Enhanced formatted report */ function generateEnhancedReport(analysis) { const output = []; // Summary section output.push('šŸ”’ ENHANCED SECURITY ANALYSIS REPORT'); output.push('=' .repeat(50)); if (analysis.projectAnalysis) { const proj = analysis.projectAnalysis; output.push(`\nšŸ“Š Summary:`); output.push(` Files analyzed: ${proj.filesAnalyzed}`); output.push(` Total vulnerabilities: ${proj.totalVulnerabilities}`); output.push(` Risk level: ${proj.overallRisk}`); output.push(` Security score: ${proj.overallScore}/100`); } // Detailed vulnerabilities if (analysis.vulnerabilities && analysis.vulnerabilities.length > 0) { output.push('\n🚨 Vulnerabilities Found:'); output.push('=' .repeat(50)); // Group by severity const bySeverity = {}; analysis.vulnerabilities.forEach(vuln => { const sev = vuln.severity || 'UNKNOWN'; if (!bySeverity[sev]) bySeverity[sev] = []; bySeverity[sev].push(vuln); }); // Output in severity order ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'INFO'].forEach(severity => { if (bySeverity[severity]) { bySeverity[severity].forEach(vuln => { output.push(formatVulnerability(vuln, vuln.file)); }); } }); } // Framework findings if (analysis.frameworkFindings) { output.push(formatFrameworkFindings(analysis.frameworkFindings)); } // Recommendations summary output.push('\nšŸ“‹ Priority Actions:'); output.push('=' .repeat(50)); output.push(generatePriorityActions(analysis)); return output.join('\n'); } /** * Generates priority actions based on findings * @param {Object} analysis - Analysis results * @returns {string} Priority actions */ function generatePriorityActions(analysis) { const actions = []; let priority = 1; // Check for critical vulnerabilities if (analysis.vulnerabilities) { const critical = analysis.vulnerabilities.filter(v => v.severity === 'CRITICAL'); if (critical.length > 0) { actions.push(`${priority++}. šŸ”“ Fix ${critical.length} CRITICAL vulnerabilities immediately`); critical.slice(0, 3).forEach(v => { actions.push(` - ${v.type} in ${path.basename(v.file)}:${v.line}`); }); } const high = analysis.vulnerabilities.filter(v => v.severity === 'HIGH'); if (high.length > 0) { actions.push(`${priority++}. 🟠 Address ${high.length} HIGH severity issues`); } } // Framework recommendations if (analysis.frameworkFindings) { analysis.frameworkFindings.forEach(fw => { const criticalRecs = fw.recommendations.filter(r => r.severity === 'HIGH' || r.severity === 'CRITICAL' && !r.positive ); if (criticalRecs.length > 0) { actions.push(`${priority++}. šŸ›”ļø Fix ${fw.framework} security configurations`); } }); } if (actions.length === 0) { actions.push('āœ… No critical security issues found!'); actions.push(' Continue following security best practices'); } return actions.join('\n'); } module.exports = { formatVulnerability, formatFrameworkFindings, generateEnhancedReport, getCodeContext, getRemediationSuggestion };