security: critical auth fixes, test migration to SQLite+FK, 44 test fixes
CRITICAL (CVE-class): - C-4: Remove DEV_MODE fallback with hardcoded postgres:postgres credentials - C-3: WebSocket endpoints now require JWT or API key token (?token=) auth - C-1: Superset environment passwords encrypted via Fernet at rest in DB - H-4: SESSION_SECRET_KEY separated from JWT AUTH_SECRET_KEY - H-1: Log injection via %s-formatting instead of f-strings - H-5: X-Trace-ID header validated as UUID4 to prevent trace poisoning INFRASTRUCTURE: - New src/core/encryption.py — EncryptionManager extracted from llm_provider - Test DB: per-module sqlite:///:memory: with PRAGMA foreign_keys=ON - testcontainers PostgreSQL via TEST_DB=postgres env var - conftest temp-file global engine (no 10GB shared-cache leak) TEST FIXES (44 pre-existing → 0): - test_smoke_plugins: module-level sys.modules mock isolated to per-test fixture - test_migration_engine: EXT:Python:uuid → uuid syntax fix - test_dashboards_api: mock env attributes + correct patch target - test_constants_audit_fixes: sync expected constant names with actual - test_defensive_guards: patch.object instead of module-level Repo mock - test_clean_release_cli: removed empty config.json directory - FK violations: TaskRecord parents in log_persistence, Environment in mapping_service, ReleaseCandidate in candidate_manifest_services ORTHOGONAL TESTS (18 new): - test_security_orthogonal.py: bcrypt 72-byte limit, unicode, API key format invariants, Fernet robustness, encryption key lifecycle, log injection protection, JWT edge cases MODEL FIXES: - MetricSnapshot.job_id: nullable with SET NULL (was broken FK for aggregate prune snapshots, hidden by SQLite) CLEANUP: - Removed stale :memory:test_main/test_auth/test_tasks file databases - Removed duplicate #endregion in encryption_key.py
This commit is contained in:
@@ -4,11 +4,14 @@
|
||||
# @LAYER Core
|
||||
# @RELATION DEPENDS_ON -> [CotLoggerModule]
|
||||
# @RELATION CALLED_BY -> [AppModule]
|
||||
# @INVARIANT X-Trace-ID header is validated as UUID4 format to prevent log injection / trace poisoning.
|
||||
# @PRE FastAPI app instance with Starlette middleware support.
|
||||
# @POST Every request gets a trace_id via seed_trace_id(). Existing X-Trace-ID header is
|
||||
# preserved and used as the trace_id when present.
|
||||
# preserved and used as the trace_id when present and valid.
|
||||
# @SIDE_EFFECT Sets ContextVar _trace_id for the duration of the request.
|
||||
|
||||
import uuid
|
||||
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import Response
|
||||
@@ -23,8 +26,9 @@ class TraceContextMiddleware(BaseHTTPMiddleware):
|
||||
"""FastAPI/Starlette middleware that seeds a trace_id for every request.
|
||||
|
||||
If the incoming request carries an ``X-Trace-ID`` header, that value is
|
||||
used as the trace_id (enabling cross-service trace chaining). Otherwise a
|
||||
new UUID4 is generated.
|
||||
validated as UUID4 and used as the trace_id (enabling cross-service trace
|
||||
chaining). Invalid or non-UUID values are ignored and a new UUID4 is
|
||||
generated instead.
|
||||
|
||||
Usage::
|
||||
|
||||
@@ -46,8 +50,10 @@ class TraceContextMiddleware(BaseHTTPMiddleware):
|
||||
) -> Response:
|
||||
"""Intercept every request, seed the trace_id, and forward.
|
||||
|
||||
If the client sent an ``X-Trace-ID`` header, use it; otherwise
|
||||
``seed_trace_id()`` generates a new UUID4.
|
||||
If the client sent an ``X-Trace-ID`` header with a valid UUID4 value,
|
||||
use it; otherwise ``seed_trace_id()`` generates a new UUID4.
|
||||
Invalid X-Trace-ID values are silently ignored to prevent log
|
||||
injection / trace poisoning (see [SEC:H-5]).
|
||||
|
||||
Args:
|
||||
request: The incoming Starlette Request.
|
||||
@@ -58,7 +64,11 @@ class TraceContextMiddleware(BaseHTTPMiddleware):
|
||||
"""
|
||||
incoming_trace_id = request.headers.get("X-Trace-ID")
|
||||
if incoming_trace_id:
|
||||
set_trace_id(incoming_trace_id)
|
||||
try:
|
||||
uuid.UUID(hex=incoming_trace_id, version=4)
|
||||
set_trace_id(incoming_trace_id)
|
||||
except (ValueError, AttributeError):
|
||||
seed_trace_id()
|
||||
else:
|
||||
seed_trace_id()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user