tradesenseAi / backend /security /error_handler.py
Niranjan-Murugarasu024
feat: TradeSense AI Chairman Edition production release ready for Hugging Face Spaces
0125724
Raw History Blame Contribute Delete
3.28 kB
"""
TradeSense AI — Production Error Sanitizer & Information Leakage Defense (Module 08)
Prevents internal stack traces, database schema details, file paths, and secrets
from leaking in production API error responses.
"""
import uuid
import logging
from datetime import datetime, timezone
from typing import Dict, Any, Optional
from fastapi import Request, HTTPException, status
from fastapi.responses import JSONResponse
logger = logging.getLogger("tradesense.security.errors")
class ProductionErrorSanitizer:
"""
Sanitizes unhandled exceptions and security errors into stable, opaque schemas.
"""
@staticmethod
def format_sanitized_error(
status_code: int,
error_code: str,
message: str,
request_id: Optional[str] = None,
) -> Dict[str, Any]:
return {
"error_code": error_code,
"message": message,
"request_id": request_id or str(uuid.uuid4()),
"timestamp": datetime.now(timezone.utc).isoformat(),
}
@classmethod
def sanitize_exception(cls, exc: Exception, request_id: Optional[str] = None) -> Dict[str, Any]:
req_id = request_id or str(uuid.uuid4())
return {
"error": {
"code": "INTERNAL_SERVER_ERROR",
"message": "An unexpected error occurred while processing your request. Please contact support with the request ID.",
"request_id": req_id,
}
}
@classmethod
async def unhandled_exception_handler(cls, request: Request, exc: Exception) -> JSONResponse:
request_id = str(uuid.uuid4())
# Log full internal diagnostics securely on server
logger.error(
f"Unhandled exception [req_id={request_id}] at {request.method} {request.url.path}: {exc}",
exc_info=True,
)
sanitized_payload = cls.format_sanitized_error(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
error_code="INTERNAL_SERVER_ERROR",
message="An unexpected error occurred while processing your request. Please contact support with the request ID.",
request_id=request_id,
)
return JSONResponse(status_code=500, content=sanitized_payload)
@classmethod
async def http_exception_handler(cls, request: Request, exc: HTTPException) -> JSONResponse:
request_id = str(uuid.uuid4())
# Preserve client-facing message but sanitize any internal substrings
raw_detail = str(exc.detail) if exc.detail else "Operation failed."
# Strip potential SQL or path leakage
if "sqlite" in raw_detail.lower() or "postgresql" in raw_detail.lower() or "traceback" in raw_detail.lower():
sanitized_detail = "Database error occurred. Please contact administrator."
else:
sanitized_detail = raw_detail
sanitized_payload = cls.format_sanitized_error(
status_code=exc.status_code,
error_code=f"HTTP_{exc.status_code}",
message=sanitized_detail,
request_id=request_id,
)
headers = dict(exc.headers) if exc.headers else {}
return JSONResponse(status_code=exc.status_code, content=sanitized_payload, headers=headers)