diff --git a/apps/api/src/api/terminal.py b/apps/api/src/api/terminal.py index a283444..2edace2 100644 --- a/apps/api/src/api/terminal.py +++ b/apps/api/src/api/terminal.py @@ -1,5 +1,6 @@ """WebSocket terminal endpoint for tool instances.""" +import logging import uuid from fastapi import APIRouter, Depends, HTTPException, WebSocket, WebSocketDisconnect, status @@ -10,6 +11,7 @@ from src.models.tool_instance import ToolInstance from src.services.terminal_manager import terminal_manager router = APIRouter() +logger = logging.getLogger(__name__) @router.websocket( @@ -32,35 +34,42 @@ async def terminal_websocket( Returns: None. Communicates via WebSocket messages. """ + logger.info("Terminal WebSocket connection attempt for instance %s", instance_id) await websocket.accept() try: # Parse instance_id instance_uuid = uuid.UUID(instance_id) except ValueError: + logger.error("Invalid instance ID: %s", instance_id) await websocket.close(code=4001, reason="Invalid instance ID") return # Authenticate user from session cookie user_id = await _get_user_from_websocket(websocket, db_session) if user_id is None: + logger.warning("Unauthorized terminal access attempt for instance %s", instance_id) await websocket.close(code=4003, reason="Unauthorized") return # Get instance and verify ownership instance = await db_session.get(ToolInstance, instance_uuid) if instance is None: + logger.warning("Instance %s not found", instance_id) await websocket.close(code=4004, reason="Instance not found") return if instance.owner_id != user_id: + logger.warning("Forbidden terminal access for instance %s by user %s", instance_id, user_id) await websocket.close(code=4003, reason="Forbidden") return if instance.status != "running" or not instance.container_id: + logger.warning("Instance %s not running (status=%s, container_id=%s)", instance_id, instance.status, instance.container_id) await websocket.close(code=4004, reason="Instance not running") return + logger.info("Creating terminal session for instance %s (container_id=%s)", instance_id, instance.container_id) # Create terminal session try: session = await terminal_manager.create_session( @@ -68,6 +77,7 @@ async def terminal_websocket( instance.container_id, websocket, ) + logger.info("Terminal session created successfully for instance %s", instance_id) # Send connected status await websocket.send_json({"type": "status", "status": "connected"}) @@ -84,6 +94,7 @@ async def terminal_websocket( break except Exception as exc: + logger.error("Terminal session error for instance %s: %s", instance_id, str(exc), exc_info=True) await websocket.close(code=4000, reason=f"Error: {exc}") finally: # Cleanup will be handled by the session manager