This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
BreakPilot Dev 19855efacc
Some checks failed
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
ci/woodpecker/manual/build-ci-image Pipeline was successful
ci/woodpecker/manual/main Pipeline failed
feat: BreakPilot PWA - Full codebase (clean push without large binaries)
All services: admin-v2, studio-v2, website, ai-compliance-sdk,
consent-service, klausur-service, voice-service, and infrastructure.
Large PDFs and compiled binaries excluded via .gitignore.
2026-02-11 13:25:58 +01:00

233 lines
6.4 KiB
Python

"""
Action Dispatcher für Alerts Agent.
Verteilt Aktionen an die entsprechenden Handler.
"""
import logging
from typing import Dict, Any, List, Optional
from datetime import datetime
from .base import ActionHandler, ActionResult, ActionType, AlertContext
from .email_action import EmailAction
from .webhook_action import WebhookAction
from .slack_action import SlackAction
logger = logging.getLogger(__name__)
class ActionDispatcher:
"""
Zentrale Verteilung von Aktionen an Handler.
Registriert Handler für verschiedene Aktionstypen und
führt Aktionen basierend auf Regel-Konfigurationen aus.
"""
def __init__(self):
"""Initialisiert den Dispatcher mit Standard-Handlern."""
self._handlers: Dict[ActionType, ActionHandler] = {}
# Standard-Handler registrieren
self.register_handler(EmailAction())
self.register_handler(WebhookAction())
self.register_handler(SlackAction())
def register_handler(self, handler: ActionHandler) -> None:
"""
Registriert einen Action-Handler.
Args:
handler: Handler-Instanz
"""
self._handlers[handler.action_type] = handler
logger.debug(f"Registered action handler: {handler.action_type.value}")
def get_handler(self, action_type: ActionType) -> Optional[ActionHandler]:
"""
Gibt den Handler für einen Aktionstyp zurück.
Args:
action_type: Aktionstyp
Returns:
Handler oder None
"""
return self._handlers.get(action_type)
def list_handlers(self) -> List[str]:
"""Gibt Liste der registrierten Handler zurück."""
return [at.value for at in self._handlers.keys()]
async def dispatch(
self,
action_type: str,
context: AlertContext,
config: Dict[str, Any],
) -> ActionResult:
"""
Führt eine Aktion aus.
Args:
action_type: Aktionstyp als String (email, webhook, slack)
context: Alert-Kontext
config: Aktionsspezifische Konfiguration
Returns:
ActionResult
"""
try:
# ActionType aus String
at = ActionType(action_type.lower())
except ValueError:
return ActionResult(
success=False,
action_type=ActionType.WEBHOOK, # Fallback
message=f"Unbekannter Aktionstyp: {action_type}",
error="Unknown action type",
)
handler = self.get_handler(at)
if not handler:
return ActionResult(
success=False,
action_type=at,
message=f"Kein Handler für {action_type} registriert",
error="No handler registered",
)
# Konfiguration validieren
if not handler.validate_config(config):
required = handler.get_required_config_fields()
return ActionResult(
success=False,
action_type=at,
message=f"Ungültige Konfiguration für {action_type}",
error=f"Required fields: {required}",
)
# Aktion ausführen
logger.info(f"Dispatching {action_type} action for alert {context.alert_id[:8]}")
result = await handler.execute(context, config)
return result
async def dispatch_multiple(
self,
actions: List[Dict[str, Any]],
context: AlertContext,
) -> List[ActionResult]:
"""
Führt mehrere Aktionen aus.
Args:
actions: Liste von Aktionen [{type, config}, ...]
context: Alert-Kontext
Returns:
Liste von ActionResults
"""
results = []
for action in actions:
action_type = action.get("type", action.get("action_type", ""))
config = action.get("config", action.get("action_config", {}))
result = await self.dispatch(action_type, context, config)
results.append(result)
return results
# Singleton-Instanz
_dispatcher: Optional[ActionDispatcher] = None
def get_dispatcher() -> ActionDispatcher:
"""Gibt den globalen ActionDispatcher zurück."""
global _dispatcher
if _dispatcher is None:
_dispatcher = ActionDispatcher()
return _dispatcher
async def execute_action(
action_type: str,
alert_id: str,
title: str,
url: str,
snippet: str,
topic_name: str,
config: Dict[str, Any],
relevance_score: Optional[float] = None,
relevance_decision: Optional[str] = None,
matched_rule: Optional[str] = None,
tags: Optional[List[str]] = None,
) -> ActionResult:
"""
Convenience-Funktion zum Ausführen einer Aktion.
Erstellt den Kontext und ruft den Dispatcher auf.
"""
context = AlertContext(
alert_id=alert_id,
title=title,
url=url,
snippet=snippet,
topic_name=topic_name,
relevance_score=relevance_score,
relevance_decision=relevance_decision,
matched_rule=matched_rule,
tags=tags or [],
)
dispatcher = get_dispatcher()
return await dispatcher.dispatch(action_type, context, config)
async def execute_rule_actions(
alert_id: str,
title: str,
url: str,
snippet: str,
topic_name: str,
rule_action: str,
rule_config: Dict[str, Any],
rule_name: str,
) -> ActionResult:
"""
Führt die Aktion einer gematschten Regel aus.
Args:
alert_id: Alert-ID
title: Alert-Titel
url: Alert-URL
snippet: Alert-Snippet
topic_name: Topic-Name
rule_action: Aktionstyp der Regel
rule_config: Aktions-Konfiguration
rule_name: Name der Regel
Returns:
ActionResult
"""
# Nur externe Aktionen (email, webhook, slack) hier behandeln
# keep/drop/tag werden direkt von der Rule Engine behandelt
if rule_action not in ["email", "webhook", "slack"]:
return ActionResult(
success=True,
action_type=ActionType.TAG, # Dummy
message=f"Interne Aktion {rule_action} von Rule Engine behandelt",
)
return await execute_action(
action_type=rule_action,
alert_id=alert_id,
title=title,
url=url,
snippet=snippet,
topic_name=topic_name,
config=rule_config,
matched_rule=rule_name,
)