feat: sécurité HIGH — token Bearer, validation, rate limiting, headers

- Token Bearer auth sur le streaming server (auto-généré ou env var)
- Validation actions replay (types, longueurs, coordonnées 0-1)
- Rate limiting in-memory (10 replays/min, 200 images/min)
- Security headers Flask (nosniff, SAMEORIGIN, XSS)
- Validation uploads (50MB max, MIME type)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dom
2026-03-19 00:29:54 +01:00
parent 24a947b51d
commit fe5e0ba83d
6 changed files with 96 additions and 12 deletions

View File

@@ -475,25 +475,27 @@ class TestAPIEndpoints:
)
client = TestClient(api_stream.app, raise_server_exceptions=False)
yield client, test_processor
# Récupérer le token API pour les requêtes authentifiées
token = api_stream.API_TOKEN
yield client, test_processor, token
# Restaurer
api_stream.processor = original_processor
api_stream.worker = original_worker
def test_get_sessions_empty(self, client):
c, _ = client
resp = c.get("/api/v1/traces/stream/sessions")
c, _, token = client
resp = c.get("/api/v1/traces/stream/sessions", headers={"Authorization": f"Bearer {token}"})
assert resp.status_code == 200
data = resp.json()
assert data["sessions"] == []
def test_get_sessions_with_data(self, client):
c, proc = client
c, proc, token = client
proc.session_manager.register_session("api_sess_1")
proc.session_manager.add_event("api_sess_1", {"type": "click"})
resp = c.get("/api/v1/traces/stream/sessions")
resp = c.get("/api/v1/traces/stream/sessions", headers={"Authorization": f"Bearer {token}"})
assert resp.status_code == 200
sessions = resp.json()["sessions"]
assert len(sessions) == 1
@@ -501,14 +503,14 @@ class TestAPIEndpoints:
assert sessions[0]["events_count"] == 1
def test_get_workflows_empty(self, client):
c, _ = client
resp = c.get("/api/v1/traces/stream/workflows")
c, _, token = client
resp = c.get("/api/v1/traces/stream/workflows", headers={"Authorization": f"Bearer {token}"})
assert resp.status_code == 200
data = resp.json()
assert data["workflows"] == []
def test_get_workflows_with_data(self, client):
c, proc = client
c, proc, token = client
mock_wf = MagicMock()
mock_wf.nodes = [1, 2]
mock_wf.edges = [1]
@@ -516,7 +518,7 @@ class TestAPIEndpoints:
with proc._data_lock:
proc._workflows["wf_api_001"] = mock_wf
resp = c.get("/api/v1/traces/stream/workflows")
resp = c.get("/api/v1/traces/stream/workflows", headers={"Authorization": f"Bearer {token}"})
assert resp.status_code == 200
workflows = resp.json()["workflows"]
assert len(workflows) == 1