""" Rule Engine für Alerts Agent. Evaluiert Regeln gegen Alert-Items und führt Aktionen aus. Batch-Verarbeitung und Action-Anwendung. """ import logging from typing import List, Dict, Any, Optional from alerts_agent.db.models import AlertItemDB, AlertRuleDB, RuleActionEnum from .rule_models import ( ConditionOperator, RuleCondition, RuleMatch, get_field_value, evaluate_condition, evaluate_rule, evaluate_rules_for_alert, create_keyword_rule, create_exclusion_rule, create_score_threshold_rule, ) logger = logging.getLogger(__name__) # Re-export for backward compatibility __all__ = [ "ConditionOperator", "RuleCondition", "RuleMatch", "get_field_value", "evaluate_condition", "evaluate_rule", "evaluate_rules_for_alert", "RuleEngine", "create_keyword_rule", "create_exclusion_rule", "create_score_threshold_rule", ] class RuleEngine: """Rule Engine für Batch-Verarbeitung von Alerts.""" def __init__(self, db_session): self.db = db_session self._rules_cache: Optional[List[AlertRuleDB]] = None def _get_active_rules(self) -> List[AlertRuleDB]: """Lädt aktive Regeln aus der Datenbank (cached).""" if self._rules_cache is None: from alerts_agent.db.repository import RuleRepository repo = RuleRepository(self.db) self._rules_cache = repo.get_active() return self._rules_cache def clear_cache(self) -> None: """Leert den Regel-Cache.""" self._rules_cache = None def process_alert(self, alert: AlertItemDB) -> Optional[RuleMatch]: """Verarbeitet einen Alert mit allen aktiven Regeln.""" rules = self._get_active_rules() return evaluate_rules_for_alert(alert, rules) def process_alerts(self, alerts: List[AlertItemDB]) -> Dict[str, RuleMatch]: """Verarbeitet mehrere Alerts mit allen aktiven Regeln.""" rules = self._get_active_rules() results = {} for alert in alerts: match = evaluate_rules_for_alert(alert, rules) if match: results[alert.id] = match return results def apply_rule_actions(self, alert: AlertItemDB, match: RuleMatch) -> Dict[str, Any]: """Wendet die Regel-Aktion auf einen Alert an.""" from alerts_agent.db.repository import AlertItemRepository, RuleRepository alert_repo = AlertItemRepository(self.db) rule_repo = RuleRepository(self.db) action = match.action config = match.action_config result = {"action": action.value, "success": False} try: if action == RuleActionEnum.KEEP: alert_repo.update_scoring( alert_id=alert.id, score=1.0, decision="KEEP", reasons=["rule_match"], summary=f"Matched rule: {match.rule_name}", model="rule_engine", ) result["success"] = True elif action == RuleActionEnum.DROP: alert_repo.update_scoring( alert_id=alert.id, score=0.0, decision="DROP", reasons=["rule_match"], summary=f"Dropped by rule: {match.rule_name}", model="rule_engine", ) result["success"] = True elif action == RuleActionEnum.TAG: tags = config.get("tags", []) if tags: existing_tags = alert.user_tags or [] new_tags = list(set(existing_tags + tags)) alert_repo.update(alert.id, user_tags=new_tags) result["tags_added"] = tags result["success"] = True elif action == RuleActionEnum.EMAIL: result["email_config"] = config result["success"] = True result["deferred"] = True elif action == RuleActionEnum.WEBHOOK: result["webhook_config"] = config result["success"] = True result["deferred"] = True elif action == RuleActionEnum.SLACK: result["slack_config"] = config result["success"] = True result["deferred"] = True rule_repo.increment_match_count(match.rule_id) except Exception as e: logger.error(f"Error applying rule action: {e}") result["error"] = str(e) return result