1919from __future__ import annotations
2020
2121import csv
22+ import hmac
2223import io
2324import json
2425import logging
2829from datetime import datetime , timezone
2930from typing import Any
3031
31- from fastapi import APIRouter , Depends , HTTPException , Query
32+ from fastapi import APIRouter , Depends , HTTPException , Query , Response
3233from fastapi .responses import StreamingResponse
3334from fastapi .security import HTTPAuthorizationCredentials , HTTPBearer
3435
@@ -60,7 +61,7 @@ def _require_admin(
6061 "environment variable to enable it."
6162 ),
6263 )
63- if credentials is None or credentials .credentials != admin_key :
64+ if credentials is None or not hmac . compare_digest ( credentials .credentials , admin_key ) :
6465 raise HTTPException (
6566 status_code = 401 ,
6667 detail = "Invalid or missing Bearer token." ,
@@ -298,32 +299,21 @@ def get_session_risk(
298299 finally :
299300 conn .close ()
300301
301- from humane_proxy .risk .trajectory import analyze
302+ from humane_proxy .risk .trajectory import snapshot
302303
303- # Build trajectory by replaying each escalation.
304- trajectory = None
305- for row in rows :
306- rec = _row_to_dict (row )
307- trajectory = analyze (
308- session_id + "_admin_replay" , # isolated session key
309- rec ["risk_score" ],
310- rec .get ("category" , "safe" ),
311- )
304+ trajectory = snapshot (session_id )
312305
313306 return {
314307 "session_id" : session_id ,
315308 "escalation_count" : len (rows ),
316309 "history" : [_row_to_dict (r ) for r in rows ],
317- "trajectory" : (
318- {
319- "spike_detected" : trajectory .spike_detected ,
320- "trend" : trajectory .trend ,
321- "window_scores" : trajectory .window_scores ,
322- "category_counts" : trajectory .category_counts ,
323- }
324- if trajectory
325- else None
326- ),
310+ "trajectory" : {
311+ "spike_detected" : trajectory .spike_detected ,
312+ "trend" : trajectory .trend ,
313+ "window_scores" : trajectory .window_scores ,
314+ "category_counts" : trajectory .category_counts ,
315+ "message_count" : trajectory .message_count ,
316+ },
327317 }
328318
329319
@@ -381,11 +371,11 @@ def get_stats(_: str = Depends(_require_admin)) -> dict:
381371 }
382372
383373
384- @router .delete ("/sessions/{session_id}" , status_code = 204 )
374+ @router .delete ("/sessions/{session_id}" , status_code = 204 , response_class = Response )
385375def delete_session_data (
386376 session_id : str ,
387377 _ : str = Depends (_require_admin ),
388- ) -> None :
378+ ) -> Response :
389379 """Delete all escalation records for a session (privacy right to erasure)."""
390380 conn = _get_conn ()
391381 try :
@@ -397,3 +387,4 @@ def delete_session_data(
397387 conn .close ()
398388
399389 logger .info ("Deleted %d records for session %s (admin request)" , deleted , session_id )
390+ return Response (status_code = 204 )
0 commit comments