from __future__ import annotations import os from dataclasses import dataclass, field from datetime import datetime from pathlib import Path from typing import Any, Dict, List, Optional from .analyzer import AnalysisResult, RuleViolation, WAFRuleAnalyzer from .compliance import ComplianceMapper, FrameworkMapping from .generator import GeneratedRule, WAFRuleGenerator # Optional advanced modules (Phase 7) try: from .threat_intel import ( ThreatIntelCollector, ThreatIntelReport, ThreatIndicator, ) _HAS_THREAT_INTEL = True except ImportError: _HAS_THREAT_INTEL = False ThreatIntelCollector = None try: from .classifier import ThreatClassifier _HAS_CLASSIFIER = True except ImportError: _HAS_CLASSIFIER = False ThreatClassifier = None @dataclass class WAFInsight: """Single high-quality insight across analysis + generation + compliance.""" violation: RuleViolation | None suggested_rule: GeneratedRule | None mappings: List[FrameworkMapping] @dataclass class ThreatAssessment: """Phase 7: Comprehensive threat assessment result.""" analysis_result: Optional[AnalysisResult] = None threat_report: Optional[Any] = None # ThreatIntelReport when available classification_summary: Dict[str, int] = field(default_factory=dict) risk_score: float = 0.0 recommended_actions: List[str] = field(default_factory=list) generated_at: datetime = field(default_factory=datetime.utcnow) @property def risk_level(self) -> str: if self.risk_score >= 0.8: return "critical" elif self.risk_score >= 0.6: return "high" elif self.risk_score >= 0.4: return "medium" else: return "low" class WAFIntelligence: """ Quality-first orchestration layer: - analyze WAF config - propose a few rules - attach compliance mappings - Phase 7: integrate threat intel and ML classification """ def __init__( self, workspace_path: Optional[str] = None, enable_threat_intel: bool = True, enable_ml_classifier: bool = True, ) -> None: self.workspace = Path(workspace_path) if workspace_path else Path.cwd() # Core components self.analyzer = WAFRuleAnalyzer() self.generator = WAFRuleGenerator() self.mapper = ComplianceMapper() # Phase 7 components (optional) self.threat_intel: Optional[Any] = None self.classifier: Optional[Any] = None if enable_threat_intel and _HAS_THREAT_INTEL: try: self.threat_intel = ThreatIntelCollector() except Exception: pass if enable_ml_classifier and _HAS_CLASSIFIER: try: self.classifier = ThreatClassifier() except Exception: pass def analyze_and_recommend( self, path: str, *, limit: int = 3, min_severity: str = "warning", ) -> List[WAFInsight]: analysis: AnalysisResult = self.analyzer.analyze_file( path, min_severity=min_severity, ) top_violations = analysis.top_violations( min_severity=min_severity, limit=limit, ) insights: List[WAFInsight] = [] for violation in top_violations: mappings = self.mapper.best_effort_from_violation(violation.message) scenario = violation.message rules = self.generator.generate_from_scenario(scenario, limit=1) suggested = rules[0] if rules else None insights.append( WAFInsight( violation=violation, suggested_rule=suggested, mappings=mappings, ) ) return insights # ───────────────────────────────────────────────────────────────────────── # Phase 7: Advanced threat intelligence methods # ───────────────────────────────────────────────────────────────────────── def collect_threat_intel( self, log_paths: Optional[List[str]] = None, max_indicators: int = 100, ) -> Optional[Any]: """ Collect threat intelligence from logs and external feeds. Args: log_paths: Paths to Cloudflare log files max_indicators: Maximum indicators to collect Returns: ThreatIntelReport or None if unavailable """ if not self.threat_intel: return None # Default log paths if log_paths is None: log_paths = [ str(self.workspace / "logs"), "/var/log/cloudflare", ] return self.threat_intel.collect( log_paths=log_paths, max_indicators=max_indicators, ) def classify_threat(self, payload: str) -> Optional[Any]: """ Classify a payload using ML classifier. Args: payload: Request payload to classify Returns: ClassificationResult or None """ if not self.classifier: return None return self.classifier.classify(payload) def full_assessment( self, waf_config_path: Optional[str] = None, log_paths: Optional[List[str]] = None, include_threat_intel: bool = True, ) -> ThreatAssessment: """ Phase 7: Perform comprehensive threat assessment. Combines: - WAF configuration analysis - Threat intelligence collection - ML classification summary - Risk scoring Args: waf_config_path: Path to WAF Terraform file log_paths: Paths to log files include_threat_intel: Whether to collect threat intel Returns: ThreatAssessment with full analysis results """ assessment = ThreatAssessment() risk_factors: List[float] = [] recommendations: List[str] = [] # 1. Analyze WAF configuration if waf_config_path is None: waf_config_path = str(self.workspace / "terraform" / "waf.tf") if Path(waf_config_path).exists(): assessment.analysis_result = self.analyzer.analyze_file( waf_config_path, min_severity="info", ) # Calculate risk from violations severity_weights = {"error": 0.8, "warning": 0.5, "info": 0.2} for violation in assessment.analysis_result.violations: weight = severity_weights.get(violation.severity, 0.3) risk_factors.append(weight) # Generate recommendations critical_count = sum( 1 for v in assessment.analysis_result.violations if v.severity == "error" ) if critical_count > 0: recommendations.append( f"🔴 Fix {critical_count} critical WAF configuration issues" ) # 2. Collect threat intelligence if include_threat_intel and self.threat_intel: try: assessment.threat_report = self.collect_threat_intel( log_paths=log_paths, max_indicators=50, ) if assessment.threat_report: indicators = assessment.threat_report.indicators # Count by severity severity_counts = {"critical": 0, "high": 0, "medium": 0, "low": 0} for ind in indicators: sev = getattr(ind, "severity", "low") severity_counts[sev] = severity_counts.get(sev, 0) + 1 # Add to classification summary assessment.classification_summary["threat_indicators"] = len( indicators ) assessment.classification_summary.update(severity_counts) # Calculate threat intel risk if indicators: critical_ratio = severity_counts["critical"] / len(indicators) high_ratio = severity_counts["high"] / len(indicators) risk_factors.append(critical_ratio * 0.9 + high_ratio * 0.7) if severity_counts["critical"] > 0: recommendations.append( f"🚨 Block {severity_counts['critical']} critical threat IPs immediately" ) except Exception: pass # 3. ML classification summary (from any collected data) if self.classifier and assessment.threat_report: try: attack_types = {"sqli": 0, "xss": 0, "rce": 0, "clean": 0, "unknown": 0} indicators = assessment.threat_report.indicators pattern_indicators = [ i for i in indicators if getattr(i, "indicator_type", "") == "pattern" ] for ind in pattern_indicators[:20]: # Sample first 20 result = self.classifier.classify(ind.value) if result: label = result.label attack_types[label] = attack_types.get(label, 0) + 1 assessment.classification_summary["ml_classifications"] = attack_types # Add ML risk factor dangerous = attack_types.get("sqli", 0) + attack_types.get("rce", 0) if dangerous > 5: risk_factors.append(0.8) recommendations.append( f"⚠️ ML detected {dangerous} dangerous attack patterns" ) except Exception: pass # 4. Calculate final risk score if risk_factors: assessment.risk_score = min( 1.0, sum(risk_factors) / max(len(risk_factors), 1) ) else: assessment.risk_score = 0.3 # Baseline risk assessment.recommended_actions = recommendations return assessment def generate_gitops_proposals( self, threat_report: Optional[Any] = None, max_proposals: int = 5, ) -> List[Dict[str, Any]]: """ Generate GitOps-ready rule proposals. Args: threat_report: ThreatIntelReport to use max_proposals: Maximum proposals to generate Returns: List of proposal dicts ready for MR creation """ proposals: List[Dict[str, Any]] = [] if not threat_report: return proposals try: # Import proposer dynamically from gitops.waf_rule_proposer import WAFRuleProposer proposer = WAFRuleProposer(workspace_path=str(self.workspace)) batch = proposer.generate_proposals( threat_report=threat_report, max_proposals=max_proposals, ) for proposal in batch.proposals: proposals.append( { "name": proposal.rule_name, "type": proposal.rule_type, "severity": proposal.severity, "confidence": proposal.confidence, "terraform": proposal.terraform_code, "justification": proposal.justification, "auto_deploy": proposal.auto_deploy_eligible, } ) except ImportError: pass return proposals @property def capabilities(self) -> Dict[str, bool]: """Report available capabilities.""" return { "core_analysis": True, "rule_generation": True, "compliance_mapping": True, "threat_intel": self.threat_intel is not None, "ml_classification": self.classifier is not None, }