From 19dd0aa74f7e3d11cccbaab425ec5164f7a8a033 Mon Sep 17 00:00:00 2001 From: Agent Zero Date: Mon, 3 Aug 2026 16:20:27 +0200 Subject: [PATCH] Phase 7.2: WebSocket Plugin-Gate fuer kommunikation und ai_ui_control - Beide WebSocket Endpoints pruefen jetzt Plugin-Aktivierung (global + tenant) - Fail-closed bei Fehlern - Pruefung direkt im WebSocket-Endpunkt (Router-Dependency greift bei WS nicht) --- app/plugins/builtins/ai_ui_control/routes.py | 23 ++++++++++++++++++++ app/plugins/builtins/kommunikation/routes.py | 23 ++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/app/plugins/builtins/ai_ui_control/routes.py b/app/plugins/builtins/ai_ui_control/routes.py index 94ee491..0cd01b2 100644 --- a/app/plugins/builtins/ai_ui_control/routes.py +++ b/app/plugins/builtins/ai_ui_control/routes.py @@ -227,6 +227,29 @@ async def ai_ui_control_ws(websocket: WebSocket): user_id = session_data["user_id"] tenant_id = session_data["tenant_id"] + # Plugin-Gate: check if ai_ui_control plugin is active (global + tenant) + from app.core.permission_registry import get_permission_registry + from sqlalchemy import text as sa_text + from app.core.db import async_session_maker + import uuid as _uuid + try: + registry = get_permission_registry() + if not registry.is_plugin_active("ai_ui_control"): + await websocket.close(code=4003, reason="Plugin not active") + return + async with async_session_maker() as db: + result = await db.execute( + sa_text("SELECT is_active FROM tenant_plugin_activation WHERE plugin_name = :name AND tenant_id = :tid"), + {"name": "ai_ui_control", "tid": _uuid.UUID(tenant_id)}, + ) + row = result.first() + if row is not None and not row[0]: + await websocket.close(code=4003, reason="Plugin not active for tenant") + return + except Exception: + await websocket.close(code=4003, reason="Plugin check failed") + return + container = get_container() if not container.has("ai_ui_control_ws"): await websocket.close(code=4003, reason="AI UI Control not available") diff --git a/app/plugins/builtins/kommunikation/routes.py b/app/plugins/builtins/kommunikation/routes.py index d8d3182..a195dab 100644 --- a/app/plugins/builtins/kommunikation/routes.py +++ b/app/plugins/builtins/kommunikation/routes.py @@ -494,6 +494,29 @@ async def websocket_endpoint( user_id = session_data["user_id"] tenant_id = session_data["tenant_id"] + # Plugin-Gate: check if kommunikation plugin is active (global + tenant) + from app.core.permission_registry import get_permission_registry + from sqlalchemy import text as sa_text + from app.core.db import async_session_maker + import uuid as _uuid + try: + registry = get_permission_registry() + if not registry.is_plugin_active("kommunikation"): + await websocket.close(code=4003, reason="Plugin not active") + return + async with async_session_maker() as db: + result = await db.execute( + sa_text("SELECT is_active FROM tenant_plugin_activation WHERE plugin_name = :name AND tenant_id = :tid"), + {"name": "kommunikation", "tid": _uuid.UUID(tenant_id)}, + ) + row = result.first() + if row is not None and not row[0]: + await websocket.close(code=4003, reason="Plugin not active for tenant") + return + except Exception: + await websocket.close(code=4003, reason="Plugin check failed") + return + # Get WebSocket manager from service container from app.core.service_container import get_container container = get_container()