"""Tests for the request access-log middleware (token-label attribution). The middleware emits one structured ``http_request`` line per request, tagged with the friendly label of the API token used (from ``auth.api_keys``) so traffic can be attributed to a specific client. These tests capture the ``main.logger`` calls to assert the label is recorded and that no-auth endpoints fall back to ``"unauthenticated"``. """ import pytest @pytest.fixture def client_and_logs(authenticated_client, monkeypatch): """authenticated_client plus a captured list of (event, kwargs) log calls.""" import ledgrab.main as main_mod calls: list[tuple[str, dict]] = [] class _FakeLogger: def info(self, event, **kw): calls.append((event, kw)) # main.logger is shared; keep other levels as harmless no-ops. def debug(self, *a, **k): pass def warning(self, *a, **k): pass def error(self, *a, **k): pass monkeypatch.setattr(main_mod, "logger", _FakeLogger()) return authenticated_client, calls def _http_request_logs(calls): return [kw for event, kw in calls if event == "http_request"] def test_access_log_records_token_label_for_authed_request(client_and_logs): client, calls = client_and_logs # /openapi.json requires auth but needs no initialized store, so it returns # 200 even without app lifespan — and exercises the auth → label path. resp = client.get("/openapi.json") assert resp.status_code == 200 logs = _http_request_logs(calls) assert logs, "no http_request access log emitted" entry = logs[-1] assert entry["method"] == "GET" assert entry["path"] == "/openapi.json" assert entry["status"] == 200 assert entry["token"] == "test" # label of the configured test API key assert "duration_ms" in entry def test_access_log_marks_unauthenticated_for_no_auth_endpoint(client_and_logs): client, calls = client_and_logs # /health has no auth dependency, so no label is set on request.state. resp = client.get("/health") assert resp.status_code == 200 logs = _http_request_logs(calls) assert logs assert logs[-1]["token"] == "unauthenticated" def test_access_log_never_contains_the_token_secret(client_and_logs): client, calls = client_and_logs client.get("/openapi.json") for _event, kw in calls: assert "test-api-key-12345" not in repr(kw), "token secret leaked into logs"