UNPKG

ctrlshiftleft

Version:

AI-powered toolkit for embedding QA and security testing into development workflows

221 lines (185 loc) 6.81 kB
#!/usr/bin/env node /** * Ctrl+Shift+Left Security Analyzer * A direct command-line tool for analyzing security risks in code */ const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); // Configuration const TARGET_FILE = process.argv[2] || '/Users/johngaspar/CascadeProjects/ctrlshiftleft/demo/src/components/PaymentForm.tsx'; const OUTPUT_FILE = '/Users/johngaspar/CascadeProjects/ctrlshiftleft/vscode-ext-test/security-report.md'; const REPORTS_DIR = '/Users/johngaspar/CascadeProjects/ctrlshiftleft/security-reports'; // Ensure all required directories exist function ensureDirectoriesExist() { // Ensure output directory for the main report exists const outputDir = path.dirname(OUTPUT_FILE); if (!fs.existsSync(outputDir)) { console.log(`Creating output directory: ${outputDir}`); fs.mkdirSync(outputDir, { recursive: true }); } // Ensure security-reports directory exists if (!fs.existsSync(REPORTS_DIR)) { console.log(`Creating reports directory: ${REPORTS_DIR}`); fs.mkdirSync(REPORTS_DIR, { recursive: true }); } // Create other potential directories that might be needed const dirs = [ './security-reports', path.join(path.dirname(TARGET_FILE), 'security-reports'), '/Users/johngaspar/CascadeProjects/ctrlshiftleft/reports', '/Users/johngaspar/CascadeProjects/ctrlshiftleft/tests' ]; dirs.forEach(dir => { if (!fs.existsSync(dir)) { console.log(`Creating directory: ${dir}`); fs.mkdirSync(dir, { recursive: true }); } }); } // Security patterns to scan for const SECURITY_PATTERNS = [ { pattern: /password/i, severity: 'HIGH', title: 'Unprotected Password Field', description: 'Password fields should be properly secured with encryption or hashing', remediation: 'Ensure passwords are never stored in plaintext and are properly hashed before storage' }, { pattern: /innerHTML|dangerouslySetInnerHTML/, severity: 'CRITICAL', title: 'Potential XSS Vulnerability', description: 'Using innerHTML or dangerouslySetInnerHTML can lead to cross-site scripting attacks', remediation: 'Use safer alternatives like textContent or sanitize input before using' }, { pattern: /localStorage|sessionStorage/, severity: 'MEDIUM', title: 'Client-side Storage of Sensitive Data', description: 'Storing sensitive information in localStorage or sessionStorage is insecure', remediation: 'Use secure storage mechanisms or encrypted tokens for sensitive data' }, { pattern: /fetch\s*\(/, severity: 'INFO', title: 'Network Request', description: 'Network requests should be properly secured and validated', remediation: 'Ensure proper CORS settings and validate all input and output' } ]; // Function to analyze a file for security issues function analyzeFile(filePath) { console.log(`Analyzing file: ${filePath}`); // Check if file exists if (!fs.existsSync(filePath)) { console.error(`File not found: ${filePath}`); return []; } // Read file content const content = fs.readFileSync(filePath, 'utf8'); const lines = content.split('\n'); // Find security issues const issues = []; lines.forEach((line, index) => { SECURITY_PATTERNS.forEach(pattern => { if (pattern.pattern.test(line)) { issues.push({ lineNumber: index + 1, line: line.trim(), severity: pattern.severity, title: pattern.title, description: pattern.description, remediation: pattern.remediation }); } }); }); return issues; } // Generate a markdown report function generateReport(filePath, issues) { const fileName = path.basename(filePath); let report = `# Security Analysis for ${fileName}\n\n`; report += `*Generated by Ctrl+Shift+Left on ${new Date().toLocaleString()}*\n\n`; if (issues.length === 0) { report += '✅ No security issues found!\n'; return report; } // Group by severity const severityGroups = { 'CRITICAL': [], 'HIGH': [], 'MEDIUM': [], 'LOW': [], 'INFO': [] }; issues.forEach(issue => { if (severityGroups[issue.severity]) { severityGroups[issue.severity].push(issue); } else { severityGroups.INFO.push(issue); } }); // Summary report += '## Summary\n\n'; const criticalCount = severityGroups.CRITICAL.length; const highCount = severityGroups.HIGH.length; const mediumCount = severityGroups.MEDIUM.length; const lowCount = severityGroups.LOW.length; const infoCount = severityGroups.INFO.length; report += `- 🚨 Critical: ${criticalCount}\n`; report += `- ⚠️ High: ${highCount}\n`; report += `- ⚠️ Medium: ${mediumCount}\n`; report += `- ℹ️ Low: ${lowCount}\n`; report += `- ℹ️ Info: ${infoCount}\n\n`; // Detailed issues report += '## Detailed Issues\n\n'; ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'INFO'].forEach(severity => { if (severityGroups[severity].length > 0) { report += `### ${severity} Severity\n\n`; severityGroups[severity].forEach(issue => { report += `#### ${issue.title}\n\n`; report += `- **Line ${issue.lineNumber}**: \`${issue.line}\`\n`; report += `- **Description**: ${issue.description}\n`; report += `- **Remediation**: ${issue.remediation}\n\n`; }); } }); // Add test generation recommendation report += '## Next Steps\n\n'; report += '1. Review and fix the identified security issues\n'; report += '2. Generate tests to verify fixes using `npx ctrlshiftleft gen <file> --output tests`\n'; report += '3. Run the generated tests to validate your changes\n'; return report; } // Main function function main() { console.log('Ctrl+Shift+Left Security Analyzer'); console.log('================================='); // Ensure all directories exist first ensureDirectoriesExist(); // Analyze file const issues = analyzeFile(TARGET_FILE); // Generate report const report = generateReport(TARGET_FILE, issues); // Write report to file fs.writeFileSync(OUTPUT_FILE, report); // Print summary console.log(`Analysis complete. Found ${issues.length} potential security issues.`); console.log(`Report written to: ${OUTPUT_FILE}`); // Try to open the report in the default browser try { if (process.platform === 'darwin') { // macOS execSync(`open "${OUTPUT_FILE}"`); } else if (process.platform === 'win32') { // Windows execSync(`start "" "${OUTPUT_FILE}"`); } else { // Linux execSync(`xdg-open "${OUTPUT_FILE}"`); } } catch (error) { console.log('Could not automatically open the report.'); } } // Run the analyzer main();