""" Webhook Action für Alerts Agent. Sendet HTTP-Webhooks für Alerts. """ import logging from typing import Dict, Any, List import httpx from .base import ActionHandler, ActionResult, ActionType, AlertContext logger = logging.getLogger(__name__) class WebhookAction(ActionHandler): """ Webhook-Benachrichtigungen für Alerts. Konfiguration: - url: Webhook-URL - method: HTTP-Methode (default: POST) - headers: Zusätzliche Headers - include_full_context: Vollen Alert-Kontext senden (default: true) """ @property def action_type(self) -> ActionType: return ActionType.WEBHOOK def get_required_config_fields(self) -> List[str]: return ["url"] def validate_config(self, config: Dict[str, Any]) -> bool: url = config.get("url", "") return url.startswith("http://") or url.startswith("https://") async def execute( self, context: AlertContext, config: Dict[str, Any], ) -> ActionResult: """ Sendet einen Webhook. Args: context: Alert-Kontext config: Webhook-Konfiguration (url, method, headers) Returns: ActionResult """ try: url = config.get("url") method = config.get("method", "POST").upper() headers = config.get("headers", {}) timeout = config.get("timeout", 30) # Payload erstellen payload = self._build_payload(context, config) # Standard-Headers headers.setdefault("Content-Type", "application/json") headers.setdefault("User-Agent", "BreakPilot-AlertsAgent/1.0") # Request senden async with httpx.AsyncClient(timeout=timeout) as client: if method == "POST": response = await client.post(url, json=payload, headers=headers) elif method == "PUT": response = await client.put(url, json=payload, headers=headers) else: response = await client.get(url, params=payload, headers=headers) # Erfolg prüfen success = 200 <= response.status_code < 300 return ActionResult( success=success, action_type=self.action_type, message=f"Webhook {method} {url} - Status {response.status_code}", details={ "url": url, "method": method, "status_code": response.status_code, "response_length": len(response.text), }, error=None if success else f"HTTP {response.status_code}", ) except httpx.TimeoutException: logger.error(f"Webhook timeout: {config.get('url')}") return ActionResult( success=False, action_type=self.action_type, message="Webhook Timeout", error="Request timed out", ) except Exception as e: logger.error(f"Webhook error: {e}") return ActionResult( success=False, action_type=self.action_type, message="Webhook-Fehler", error=str(e), ) def _build_payload( self, context: AlertContext, config: Dict[str, Any], ) -> Dict[str, Any]: """Erstellt den Webhook-Payload.""" if config.get("include_full_context", True): # Voller Kontext return { "event": "alert.matched", "alert": context.to_dict(), "timestamp": self._get_timestamp(), } else: # Minimal-Payload return { "event": "alert.matched", "alert_id": context.alert_id, "title": context.title, "url": context.url, "timestamp": self._get_timestamp(), } def _get_timestamp(self) -> str: """Gibt aktuellen ISO-Timestamp zurück.""" from datetime import datetime return datetime.utcnow().isoformat() + "Z"