feat(errors): incident-key safe error envelopes (v1.7.2)

This commit is contained in:
2026-04-27 16:56:17 -07:00
parent 9589141521
commit 12188f3ad2
4 changed files with 164 additions and 7 deletions

View File

@@ -0,0 +1,72 @@
import os
from pathlib import Path
from fastapi.testclient import TestClient
import app as app_module
def make_client(tmp_path: Path) -> TestClient:
os.environ["JARVISCHAT_ADMIN_PIN"] = "1234"
app_module.DB_PATH = tmp_path / "jarvischat-errors.db"
app_module.SESSIONS.clear()
app_module.PIN_ATTEMPTS.clear()
app_module.RATE_EVENTS.clear()
app_module.init_db()
return TestClient(app_module.app, raise_server_exceptions=False)
def test_unhandled_api_exception_returns_friendly_error_with_incident_key(
tmp_path: Path, monkeypatch
):
with make_client(tmp_path) as client:
sid = client.post("/api/auth/guest", headers={"Origin": "http://testserver"}).json()[
"session_id"
]
headers = {"X-Session-ID": sid}
def boom(_topic=None):
raise RuntimeError("super secret db internals")
monkeypatch.setattr(app_module, "get_all_memories", boom)
resp = client.get("/api/memories", headers=headers)
assert resp.status_code == 500
payload = resp.json()
assert payload.get("error_key", "").startswith("INC-")
assert "support lookup" in payload.get("detail", "").lower()
assert "super secret db internals" not in resp.text
def test_chat_stream_error_hides_internal_exception_and_emits_incident_key(
tmp_path: Path, monkeypatch
):
with make_client(tmp_path) as client:
sid = client.post("/api/auth/guest", headers={"Origin": "http://testserver"}).json()[
"session_id"
]
headers = {"X-Session-ID": sid, "Origin": "http://testserver"}
class BrokenStreamContext:
async def __aenter__(self):
raise RuntimeError("ultra secret model transport failure")
async def __aexit__(self, exc_type, exc, tb):
return False
def broken_stream(*args, **kwargs):
return BrokenStreamContext()
monkeypatch.setattr(app_module.httpx.AsyncClient, "stream", broken_stream)
resp = client.post(
"/api/chat",
json={"message": "hello", "model": app_module.DEFAULT_MODEL},
headers=headers,
)
assert resp.status_code == 200
body = resp.text
assert "ultra secret model transport failure" not in body
assert "error_key" in body
assert "support lookup" in body.lower()