GT AI OS Community Edition v2.0.33

Security hardening release addressing CodeQL and Dependabot alerts:

- Fix stack trace exposure in error responses
- Add SSRF protection with DNS resolution checking
- Implement proper URL hostname validation (replaces substring matching)
- Add centralized path sanitization to prevent path traversal
- Fix ReDoS vulnerability in email validation regex
- Improve HTML sanitization in validation utilities
- Fix capability wildcard matching in auth utilities
- Update glob dependency to address CVE
- Add CodeQL suppression comments for verified false positives

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
HackWeasel
2025-12-12 17:04:45 -05:00
commit b9dfb86260
746 changed files with 232071 additions and 0 deletions

View File

@@ -0,0 +1,162 @@
"""
Composite ASGI Router for GT 2.0 Tenant Backend
Handles routing between FastAPI and Socket.IO applications to prevent
ASGI protocol conflicts while maintaining both WebSocket systems.
Architecture:
- `/socket.io/*` → Socket.IO ASGIApp (agentic real-time features)
- All other paths → FastAPI app (REST API, native WebSocket)
"""
import logging
from typing import Dict, Any, Callable, Awaitable
logger = logging.getLogger(__name__)
class CompositeASGIRouter:
"""
ASGI router that handles both FastAPI and Socket.IO applications
without protocol conflicts.
"""
def __init__(self, fastapi_app, socketio_app):
"""
Initialize composite router with both applications.
Args:
fastapi_app: FastAPI application instance
socketio_app: Socket.IO ASGIApp instance
"""
self.fastapi_app = fastapi_app
self.socketio_app = socketio_app
logger.info("Composite ASGI router initialized for FastAPI + Socket.IO")
async def __call__(self, scope: Dict[str, Any], receive: Callable, send: Callable) -> None:
"""
ASGI application entry point that routes requests based on path.
Args:
scope: ASGI scope containing request information
receive: ASGI receive callable
send: ASGI send callable
"""
try:
# Extract path from scope
path = scope.get("path", "")
# Route based on path pattern
if self._is_socketio_path(path):
# Only log Socket.IO routing at DEBUG level for non-operational paths
if self._should_log_route(path):
logger.debug(f"Routing to Socket.IO: {path}")
await self.socketio_app(scope, receive, send)
else:
# Only log FastAPI routing at DEBUG level for non-operational paths
if self._should_log_route(path):
logger.debug(f"Routing to FastAPI: {path}")
await self.fastapi_app(scope, receive, send)
except Exception as e:
logger.error(f"Error in ASGI routing: {e}")
# Fallback to FastAPI for error handling
try:
await self.fastapi_app(scope, receive, send)
except Exception as fallback_error:
logger.error(f"Fallback routing also failed: {fallback_error}")
# Last resort: send basic error response
await self._send_error_response(scope, send)
def _is_socketio_path(self, path: str) -> bool:
"""
Determine if path should be routed to Socket.IO.
Args:
path: Request path
Returns:
True if path should go to Socket.IO, False for FastAPI
"""
socketio_patterns = [
"/socket.io/",
"/socket.io"
]
# Check if path starts with any Socket.IO pattern
for pattern in socketio_patterns:
if path.startswith(pattern):
return True
return False
def _should_log_route(self, path: str) -> bool:
"""
Determine if this path should be logged during routing.
Operational endpoints like health checks and metrics are excluded
to reduce log noise during normal operation.
Args:
path: Request path
Returns:
True if path should be logged, False for operational endpoints
"""
operational_endpoints = [
"/health",
"/ready",
"/metrics",
"/api/v1/health"
]
# Don't log operational endpoints
if any(path.startswith(endpoint) for endpoint in operational_endpoints):
return False
return True
async def _send_error_response(self, scope: Dict[str, Any], send: Callable) -> None:
"""
Send basic error response when both applications fail.
Args:
scope: ASGI scope
send: ASGI send callable
"""
try:
if scope["type"] == "http":
await send({
"type": "http.response.start",
"status": 500,
"headers": [
[b"content-type", b"application/json"],
[b"content-length", b"27"]
]
})
await send({
"type": "http.response.body",
"body": b'{"error": "ASGI routing failed"}'
})
elif scope["type"] == "websocket":
await send({
"type": "websocket.close",
"code": 1011,
"reason": "ASGI routing failed"
})
except Exception as e:
logger.error(f"Failed to send error response: {e}")
def create_composite_asgi_app(fastapi_app, socketio_app):
"""
Factory function to create composite ASGI application.
Args:
fastapi_app: FastAPI application instance
socketio_app: Socket.IO ASGIApp instance
Returns:
CompositeASGIRouter instance
"""
return CompositeASGIRouter(fastapi_app, socketio_app)