Skip to content

Commit 74ba6ae

Browse files
desioracclaude
andcommitted
feat(stats): add server-side scan counter to /v1/stats + scan_events.jsonl
- /v1/stats now returns assessments_completed alongside proofs_generated - POST /v1/assess logs each scan to data/scan_events.jsonl for persistent analytics - Enables measuring real API scan volume independently from local CLI scans Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5c517ae commit 74ba6ae

2 files changed

Lines changed: 26 additions & 4 deletions

File tree

trust_layer/app.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1918,15 +1918,19 @@ async def get_agent_json():
19181918

19191919
@app.get("/v1/stats")
19201920
async def get_stats():
1921-
"""Public proof count — no auth required. Cached 60s."""
1922-
from .config import PROOFS_DIR
1921+
"""Public proof + assess counts — no auth required. Cached 60s."""
1922+
from .config import PROOFS_DIR, ASSESSMENTS_DIR
19231923
import time
19241924
cache = getattr(get_stats, "_cache", None)
19251925
now = time.monotonic()
19261926
if cache and now - cache["ts"] < 60:
19271927
return cache["data"]
1928-
count = sum(1 for f in PROOFS_DIR.iterdir() if f.suffix == ".json") if PROOFS_DIR.exists() else 0
1929-
data = {"proofs_generated": count}
1928+
proof_count = sum(1 for f in PROOFS_DIR.iterdir() if f.suffix == ".json") if PROOFS_DIR.exists() else 0
1929+
assess_count = sum(1 for f in ASSESSMENTS_DIR.iterdir() if f.suffix == ".json") if ASSESSMENTS_DIR.exists() else 0
1930+
data = {
1931+
"proofs_generated": proof_count,
1932+
"assessments_completed": assess_count,
1933+
}
19301934
get_stats._cache = {"ts": now, "data": data}
19311935
return data
19321936

trust_layer/routers/assess.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,21 @@
55
"""
66

77
import hashlib
8+
import json
89
import logging
910
from datetime import datetime, timezone
1011
from typing import Optional
1112

1213
from fastapi import APIRouter, Header, Request
1314
from fastapi.responses import JSONResponse
1415

16+
from ..config import DATA_DIR
1517
from ..keys import validate_api_key
1618
from ..mcp_assess import build_assessment, ASSESS_DAILY_LIMIT
1719
from ..redis_client import get_redis
1820

21+
SCAN_EVENTS_LOG = DATA_DIR / "scan_events.jsonl"
22+
1923
logger = logging.getLogger("trust_layer.routers.assess")
2024

2125
router = APIRouter()
@@ -138,4 +142,18 @@ async def assess_endpoint(
138142
logger.error("Assessment failed for server_id=%s: %s", server_id, e)
139143
return _error("assessment_error", "Assessment failed. Please retry.", 500)
140144

145+
# --- Log scan event for server-side analytics ---
146+
try:
147+
with open(SCAN_EVENTS_LOG, "a") as f:
148+
f.write(json.dumps({
149+
"ts": datetime.now(timezone.utc).isoformat(),
150+
"event": "assess",
151+
"server_id": server_id,
152+
"tools_count": len(tools),
153+
"risk_score": assessment.get("risk_score"),
154+
"key_hash": fp[:8],
155+
}) + "\n")
156+
except Exception:
157+
pass # non-critical
158+
141159
return JSONResponse(status_code=200, content=assessment)

0 commit comments

Comments
 (0)