UNPKG

@sun-asterisk/sunlint

Version:

☀️ SunLint - Multi-language static analysis tool for code quality and security | Sun* Engineering Standards

243 lines (209 loc) 7.54 kB
/** * S044 Main Analyzer - Re-authentication Required for Sensitive Operations * Primary: Symbol-based analysis (when available) * Fallback: Regex-based for all other cases * Command: node cli.js --rule=S044 --input=examples/rule-test-fixtures/rules/S044_re_authentication_required --engine=heuristic */ const S044SymbolBasedAnalyzer = require("./symbol-based-analyzer.js"); const S044RegexBasedAnalyzer = require("./regex-based-analyzer.js"); class S044Analyzer { constructor(options = {}) { if (process.env.SUNLINT_DEBUG) { console.log(`🔧 [S044] Constructor called with options:`, !!options); console.log( `🔧 [S044] Options type:`, typeof options, Object.keys(options || {}) ); } this.ruleId = "S044"; this.ruleName = "Re-authentication Required for Sensitive Operations"; this.description = "Require re-authentication before performing sensitive operations such as password changes, email changes, profile updates, and other critical account modifications. This prevents unauthorized access to sensitive account functions even if a session is compromised."; this.semanticEngine = options.semanticEngine || null; this.verbose = options.verbose || false; // Configuration this.config = { useSymbolBased: true, // Primary approach fallbackToRegex: true, // Secondary approach regexBasedOnly: false, // Can be set to true for pure mode }; // Initialize analyzers try { this.symbolAnalyzer = new S044SymbolBasedAnalyzer(this.semanticEngine); if (process.env.SUNLINT_DEBUG) { console.log(`🔧 [S044] Symbol analyzer created successfully`); } } catch (error) { console.error(`🔧 [S044] Error creating symbol analyzer:`, error); } try { this.regexAnalyzer = new S044RegexBasedAnalyzer(this.semanticEngine); if (process.env.SUNLINT_DEBUG) { console.log(`🔧 [S044] Regex analyzer created successfully`); } } catch (error) { console.error(`🔧 [S044] Error creating regex analyzer:`, error); } } /** * Initialize analyzer with semantic engine */ async initialize(semanticEngine) { this.semanticEngine = semanticEngine; if (process.env.SUNLINT_DEBUG) { console.log(`🔧 [S044] Main analyzer initializing...`); } // Initialize both analyzers if (this.symbolAnalyzer) { await this.symbolAnalyzer.initialize?.(semanticEngine); } if (this.regexAnalyzer) { await this.regexAnalyzer.initialize?.(semanticEngine); } // Clean up if needed if (this.regexAnalyzer) { this.regexAnalyzer.cleanup?.(); } if (process.env.SUNLINT_DEBUG) { console.log(`🔧 [S044] Main analyzer initialized successfully`); } } /** * Single file analysis method for testing */ analyzeSingle(filePath, options = {}) { if (process.env.SUNLINT_DEBUG) { console.log(`📊 [S044] analyzeSingle() called for: ${filePath}`); } // Return result using same format as analyze method return this.analyze([filePath], "typescript", options); } async analyze(files, language, options = {}) { if (process.env.SUNLINT_DEBUG) { console.log( `🔧 [S044] analyze() method called with ${files.length} files, language: ${language}` ); } const violations = []; for (const filePath of files) { try { if (process.env.SUNLINT_DEBUG) { console.log(`🔧 [S044] Processing file: ${filePath}`); } const fileViolations = await this.analyzeFile(filePath, options); violations.push(...fileViolations); if (process.env.SUNLINT_DEBUG) { console.log( `🔧 [S044] File ${filePath}: Found ${fileViolations.length} violations` ); } } catch (error) { console.warn( `⚠ [S044] Analysis failed for ${filePath}:`, error.message ); } } if (process.env.SUNLINT_DEBUG) { console.log(`🔧 [S044] Total violations found: ${violations.length}`); } return violations; } async analyzeFile(filePath, options = {}) { if (process.env.SUNLINT_DEBUG) { console.log(`🔍 [S044] analyzeFile() called for: ${filePath}`); } // Create a Map to track unique violations and prevent duplicates const violationMap = new Map(); // 1. Try Symbol-based analysis first (primary) if ( this.config.useSymbolBased && this.semanticEngine?.project && this.semanticEngine?.initialized ) { try { if (process.env.SUNLINT_DEBUG) { console.log(`🔧 [S044] Trying symbol-based analysis...`); } const sourceFile = this.semanticEngine.project.getSourceFile(filePath); if (sourceFile) { if (process.env.SUNLINT_DEBUG) { console.log(`🔧 [S044] Source file found, analyzing...`); } const symbolViolations = await this.symbolAnalyzer.analyze( sourceFile, filePath ); // Add to violation map with deduplication symbolViolations.forEach((violation) => { const key = `${violation.line}:${violation.column}:${violation.message}`; if (!violationMap.has(key)) { violationMap.set(key, violation); } }); if (process.env.SUNLINT_DEBUG) { console.log( `🔧 [S044] Symbol analysis completed: ${symbolViolations.length} violations` ); } } else { if (process.env.SUNLINT_DEBUG) { console.log(`🔧 [S044] Source file not found, falling back...`); } } } catch (error) { console.warn(`⚠ [S044] Symbol analysis failed:`, error.message); } } // 2. Try Regex-based analysis (fallback or additional) if (this.config.fallbackToRegex || this.config.regexBasedOnly) { try { if (process.env.SUNLINT_DEBUG) { console.log(`🔧 [S044] Trying regex-based analysis...`); } const regexViolations = await this.regexAnalyzer.analyze(filePath); // Add to violation map with deduplication regexViolations.forEach((violation) => { const key = `${violation.line}:${violation.column}:${violation.message}`; if (!violationMap.has(key)) { violationMap.set(key, violation); } }); if (process.env.SUNLINT_DEBUG) { console.log( `🔧 [S044] Regex analysis completed: ${regexViolations.length} violations` ); } } catch (error) { console.warn(`⚠ [S044] Regex analysis failed:`, error.message); } } // Convert Map values to array and add filePath to each violation const finalViolations = Array.from(violationMap.values()).map( (violation) => ({ ...violation, filePath: filePath, file: filePath, // Also add 'file' for compatibility }) ); if (process.env.SUNLINT_DEBUG) { console.log( `🔧 [S044] File analysis completed: ${finalViolations.length} unique violations` ); } return finalViolations; } /** * Clean up resources */ cleanup() { if (this.symbolAnalyzer?.cleanup) { this.symbolAnalyzer.cleanup(); } if (this.regexAnalyzer?.cleanup) { this.regexAnalyzer.cleanup(); } } } module.exports = S044Analyzer;