from __future__ import annotations import asyncio import json from pathlib import Path from aiohttp.test_utils import TestClient, TestServer from observatory_read_adapter.app import create_app from observatory_read_adapter.config import EXPECTED_CONNECTION_NAME, Settings from observatory_read_adapter.db import CloudSqlClaimReader CLAIM_ID = "d0000000-0000-0000-0000-000000000005" API_KEY = "observatory-test-api-key-000000000000000000000000" ROOT = Path(__file__).resolve().parents[1] def settings(**overrides: object) -> Settings: values = { "project_id": "teleo-501523", "instance_connection_name": EXPECTED_CONNECTION_NAME, "database": "teleo_canonical", "iam_database_user": "sa-observatory-read-adapter@teleo-501523.iam", "authorization_role": "kb_observatory_read", "api_key": API_KEY, "service_revision": "test-revision", } values.update(overrides) return Settings(**values) class FakeReader: def __init__(self) -> None: self.closed = False def check_ready(self) -> dict[str, object]: return { "ready": True, "database": "teleo_canonical", "authorization_role": "kb_observatory_read", "transaction_read_only": True, } def read_claim(self, claim_id: str | None = None) -> dict[str, object] | None: if claim_id not in (None, CLAIM_ID): return None return { "schema": "livingip.observatory-canonical-claim.v1", "read_only": True, "provenance": { "database": "teleo_canonical", "database_principal": "sa-observatory-read-adapter@teleo-501523.iam", "authorization_role": "kb_observatory_read", "transaction_read_only": True, "write_privileges_denied": True, }, "canonical": { "claim": {"id": CLAIM_ID, "status": "open", "text": "Canonical claim"}, "evidence": [{"source_id": "e0000000-0000-0000-0000-000000000006"}], }, "proposal_ledger": { "distinct_from_canonical": True, "status_counts": {"pending_review": 2, "approved": 1, "applied": 1}, "related": [{"status": "approved", "applied_at": None}], }, } def close(self) -> None: self.closed = True class FakeCursor: def __init__(self) -> None: self.description: list[tuple[str]] = [] self.result: list[tuple[object, ...]] = [] self.executed: list[tuple[str, tuple[object, ...]]] = [] def execute(self, sql: str, parameters: tuple[object, ...] = ()) -> None: normalized = " ".join(sql.split()).lower() self.executed.append((normalized, parameters)) self.description = [] self.result = [] if "current_database() as database" in normalized: self.description = [ ("database",), ("database_principal",), ("transaction_read_only",), ("has_authorization_role",), ("has_required_reads",), ("required_writes_denied",), ] self.result = [ ( "teleo_canonical", "sa-observatory-read-adapter@teleo-501523.iam", "on", True, True, True, ) ] elif "from public.claims c" in normalized: self.description = [ ("id",), ("type",), ("text",), ("status",), ("confidence",), ("tags",), ("superseded_by",), ("created_at",), ("updated_at",), ] self.result = [ ( CLAIM_ID, "strategy", "Canonical claim", "open", 0.8, ["test"], None, "2026-07-15T00:00:00+00:00", "2026-07-15T00:00:00+00:00", ) ] elif "from public.claim_evidence ce" in normalized: self.description = [ ("evidence_id",), ("role",), ("weight",), ("linked_at",), ("source_id",), ("source_type",), ("url",), ("storage_path",), ("excerpt",), ("content_hash",), ("captured_at",), ("source_created_at",), ] self.result = [ ( "e0000000-0000-0000-0000-000000000006", "grounds", 1.0, "2026-07-15T00:00:00+00:00", "f0000000-0000-0000-0000-000000000007", "document", "https://example.test/source", None, "Source excerpt", "sha256:test", "2026-07-15T00:00:00+00:00", "2026-07-15T00:00:00+00:00", ) ] elif "from public.claim_edges e" in normalized: self.description = [ ("edge_id",), ("direction",), ("edge_type",), ("weight",), ("connected_claim_id",), ("created_at",), ] self.result = [] elif "group by status" in normalized: self.description = [("status",), ("count",)] self.result = [("approved", 1), ("applied", 1), ("pending_review", 2)] elif "where p.payload::text like" in normalized: self.description = [ ("id",), ("proposal_type",), ("status",), ("source_ref",), ("reviewed_at",), ("applied_at",), ("updated_at",), ] self.result = [ ( "a0000000-0000-0000-0000-000000000001", "revise_claim", "approved", "source:test", "2026-07-15T00:00:00+00:00", None, "2026-07-15T00:00:00+00:00", ) ] elif "from kb_stage.kb_proposals p" in normalized: self.description = [ ("id",), ("proposal_type",), ("status",), ("source_ref",), ("reviewed_at",), ("applied_at",), ("updated_at",), ] self.result = [] def fetchone(self) -> tuple[object, ...] | None: return self.result.pop(0) if self.result else None def fetchall(self) -> list[tuple[object, ...]]: result, self.result = self.result, [] return result class FakeConnection: def __init__(self) -> None: self.cursor_value = FakeCursor() self.rolled_back = False self.closed = False def cursor(self) -> FakeCursor: return self.cursor_value def rollback(self) -> None: self.rolled_back = True def close(self) -> None: self.closed = True def test_settings_fail_closed_on_wrong_database_role_or_short_key() -> None: for overrides in ( {"database": "teleo"}, {"authorization_role": "leoclean_kb_runtime"}, {"api_key": "too-short"}, {"instance_connection_name": "other:region:instance"}, ): candidate = settings(**overrides) try: candidate.validate() except ValueError: pass else: raise AssertionError(f"unsafe settings accepted: {overrides}") def test_authenticated_claim_response_and_negative_http_paths() -> None: async def exercise() -> None: reader = FakeReader() client = TestClient(TestServer(create_app(settings(), reader=reader))) await client.start_server() try: anonymous = await client.get("/v1/claims/sample") assert anonymous.status == 401 assert await anonymous.json() == {"error": "unauthorized"} response = await client.get( f"/v1/claims/{CLAIM_ID}", headers={"X-Api-Key": API_KEY}, ) assert response.status == 200 assert response.headers["Cache-Control"] == "private, no-store, max-age=0" payload = await response.json() assert payload["schema"] == "livingip.observatory-canonical-claim.v1" assert payload["provenance"]["database"] == "teleo_canonical" assert payload["provenance"]["write_privileges_denied"] is True assert payload["canonical"]["evidence"] assert payload["proposal_ledger"]["distinct_from_canonical"] is True assert payload["proposal_ledger"]["related"][0]["applied_at"] is None assert API_KEY not in json.dumps(payload) write_attempt = await client.post( f"/v1/claims/{CLAIM_ID}", headers={"X-Api-Key": API_KEY}, json={"status": "applied"}, ) assert write_attempt.status == 405 invalid = await client.get( "/v1/claims/not-a-uuid", headers={"X-Api-Key": API_KEY}, ) assert invalid.status == 400 finally: await client.close() assert reader.closed is True asyncio.run(exercise()) def test_readiness_checks_database_contract_without_exposing_claims() -> None: async def exercise() -> None: client = TestClient(TestServer(create_app(settings(), reader=FakeReader()))) await client.start_server() try: response = await client.get("/readyz") payload = await response.json() assert response.status == 200 assert payload == {"status": "ready"} finally: await client.close() asyncio.run(exercise()) def test_database_reader_returns_provenance_and_keeps_proposals_distinct() -> None: connection = FakeConnection() reader = CloudSqlClaimReader(settings(), connection_factory=lambda: connection) payload = reader.read_claim(CLAIM_ID) assert payload is not None assert payload["provenance"]["database"] == "teleo_canonical" assert payload["provenance"]["database_principal"] == settings().iam_database_user assert payload["provenance"]["write_privileges_denied"] is True assert payload["canonical"]["claim"]["id"] == CLAIM_ID assert payload["canonical"]["evidence"][0]["content_hash"] == "sha256:test" assert payload["proposal_ledger"]["distinct_from_canonical"] is True assert payload["proposal_ledger"]["related"][0]["status"] == "approved" assert payload["proposal_ledger"]["related"][0]["applied_at"] is None assert connection.rolled_back is True assert connection.closed is True assert any("set transaction read only" in sql for sql, _parameters in connection.cursor_value.executed) def test_database_role_contract_is_select_only_and_iam_scoped() -> None: sql = (ROOT / "ops" / "observatory_read_role.sql").read_text(encoding="utf-8") lowered = sql.lower() assert "kb_observatory_read nologin" in lowered assert "default_transaction_read_only = on" in lowered assert "public.claims" in lowered assert "public.sources" in lowered assert "public.claim_evidence" in lowered assert "public.claim_edges" in lowered assert "kb_stage.kb_proposals" in lowered assert "grant select on" in lowered assert "grant insert" not in lowered assert "grant update" not in lowered assert "grant delete" not in lowered assert "effective_table_writes_denied" in lowered def test_container_runs_as_non_root_and_contains_no_password_contract() -> None: dockerfile = (ROOT / "Dockerfile.observatory-read-adapter").read_text(encoding="utf-8") assert "USER 10001:10001" in dockerfile assert "PGPASSWORD" not in dockerfile assert "DB_PASS" not in dockerfile