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 mcp.waf_intelligence.analyzer import AnalysisResult, RuleViolation, WAFRuleAnalyzer from mcp.waf_intelligence.compliance import ComplianceMapper, FrameworkMapping from mcp.waf_intelligence.generator import GeneratedRule, WAFRuleGenerator # Optional advanced modules (Phase 7) try: from mcp.waf_intelligence.threat_intel import ( ThreatIntelCollector, ThreatIntelReport, ThreatIndicator, ) _HAS_THREAT_INTEL = True except ImportError: _HAS_THREAT_INTEL = False ThreatIntelCollector = None try: from mcp.waf_intelligence.classifier import ( ThreatClassifier, ClassificationResult, ) _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, }