from __future__ import annotations from datetime import datetime, timezone import pytest from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker from api.models.agent_message import AgentMessage from api.models.fabric_graph import FabricGraphImport, FabricGraphNode from api.models.interface_change import InterfaceChange from api.models.managed_repo import ManagedRepo from api.models.repository_rename import RepositorySlug from tests.conftest import ( create_test_domain, create_test_repo, create_test_workplan, ) async def _rename_in_state_hub(test_engine, repo_id: str) -> None: factory = async_sessionmaker(test_engine, class_=AsyncSession, expire_on_commit=False) async with factory() as session: repo = await session.get(ManagedRepo, repo_id) old = ( await session.execute( select(RepositorySlug).where(RepositorySlug.slug == "flex-auth") ) ).scalar_one() old.kind = "alias" old.protected = True repo.slug = "access-engine" repo.name = "Access Engine" session.add( RepositorySlug( repo_id=repo.id, slug="access-engine", kind="canonical", protected=True, ) ) await session.commit() @pytest.mark.asyncio async def test_alias_lookup_dispatch_bindings_and_external_staleness( client, test_engine ): domain = await create_test_domain(client) repo = await create_test_repo(client, domain_slug=domain["slug"], slug="flex-auth") workplan = await create_test_workplan( client, repo_id=repo["id"], slug="FLEX-WP-0001", title="Security stack migration", ) task = await client.post( "/tasks/", json={ "workplan_id": workplan["id"], "title": "Preserve identity", "status": "todo", "priority": "high", }, ) assert task.status_code == 201, task.text await _rename_in_state_hub(test_engine, repo["id"]) factory = async_sessionmaker(test_engine, class_=AsyncSession, expire_on_commit=False) async with factory() as session: change = InterfaceChange( repo_id=repo["id"], interface_type="rest_api", change_type="breaking", title="Historical consumer notice", description="Recorded before cutover", affected_paths=["/authorize"], affected_repo_slugs=["flex-auth"], status="published", published_at=datetime.now(timezone.utc), author="pytest", ) import_run = FabricGraphImport( source_repo_slug="railiance-fabric", content_hash="a" * 64, graph_json={}, validation_status="valid", is_latest=True, ) session.add_all([change, import_run]) await session.flush() session.add( FabricGraphNode( import_id=import_run.id, source_repo_slug="railiance-fabric", graph_id="repo:flex-auth", kind="repository", name="Flex Auth", repo_slug="flex-auth", domain_slug="infotech", lifecycle="active", ) ) await session.commit() old_lookup = await client.get("/repos/flex-auth") new_lookup = await client.get("/repos/access-engine") assert old_lookup.status_code == new_lookup.status_code == 200 assert old_lookup.json()["id"] == new_lookup.json()["id"] == repo["id"] assert old_lookup.json()["requested_slug"] == "flex-auth" assert old_lookup.json()["canonical_slug"] == "access-engine" assert old_lookup.json()["slug_status"] == "alias" assert old_lookup.json()["aliases"] == ["flex-auth"] assert new_lookup.json()["slug_status"] == "canonical" assert old_lookup.json()["stale_external_references"] == [ { "owner": "railiance-fabric", "surface": "fabric_graph_nodes", "field": "repo_slug", "value": "flex-auth", "count": 1, "status": "stale", "handoff": "owner update or re-ingest required", } ] dispatch = await client.get("/repos/access-engine/dispatch") assert dispatch.status_code == 200, dispatch.text assert dispatch.json()["repo_slug"] == "access-engine" assert dispatch.json()["pending_interface_changes"][0]["title"] == change.title bound = await client.get(f"/workplans/{workplan['id']}") assert bound.status_code == 200 assert bound.json()["id"] == workplan["id"] assert bound.json()["repo_id"] == repo["id"] bound_task = await client.get(f"/tasks/{task.json()['id']}") assert bound_task.status_code == 200 assert bound_task.json()["id"] == task.json()["id"] @pytest.mark.asyncio async def test_message_history_is_immutable_and_old_slug_write_replays_once( client, test_engine ): domain = await create_test_domain(client) repo = await create_test_repo(client, domain_slug=domain["slug"], slug="flex-auth") await _rename_in_state_hub(test_engine, repo["id"]) factory = async_sessionmaker(test_engine, class_=AsyncSession, expire_on_commit=False) async with factory() as session: historical = AgentMessage( from_agent="security-review", to_agent="flex-auth", subject="Before cutover", body="Historical recipient must not be rewritten", ) session.add(historical) await session.commit() historical_id = historical.id history = await client.get("/messages/", params={"to_agent": "access-engine"}) assert history.status_code == 200 assert [item["id"] for item in history.json()] == [str(historical_id)] assert history.json()[0]["to_agent"] == "flex-auth" payload = { "from_agent": "flex-auth", "to_agent": "flex-auth", "subject": "Queued during cutover", "body": "Replay exactly once", } headers = {"Idempotency-Key": "repo-rename-old-slug-message"} first = await client.post("/messages/", json=payload, headers=headers) replay = await client.post("/messages/", json=payload, headers=headers) assert first.status_code == replay.status_code == 201 assert first.json()["id"] == replay.json()["id"] assert first.json()["from_agent"] == "access-engine" assert first.json()["to_agent"] == "access-engine" async with factory() as session: assert await session.scalar( select(func.count()) .select_from(AgentMessage) .where(AgentMessage.subject == "Queued during cutover") ) == 1 unchanged = await session.get(AgentMessage, historical_id) assert unchanged.to_agent == "flex-auth" @pytest.mark.asyncio async def test_alias_aware_interface_catalog_sbom_and_telemetry_reads( client, test_engine ): domain = await create_test_domain(client) repo = await create_test_repo(client, domain_slug=domain["slug"], slug="flex-auth") await _rename_in_state_hub(test_engine, repo["id"]) interface = await client.post( "/interface-changes/", json={ "repo_slug": "flex-auth", "interface_type": "rest_api", "change_type": "additive", "title": "Canonical write", "description": "New references use the current slug", "affected_repo_slugs": ["flex-auth"], }, ) assert interface.status_code == 201, interface.text assert interface.json()["repo_slug"] == "access-engine" assert interface.json()["affected_repo_slugs"] == ["access-engine"] affected = await client.get( "/interface-changes/", params={"affected_repo": "flex-auth"} ) assert [item["id"] for item in affected.json()] == [interface.json()["id"]] goal = await client.post( "/repo-goals/", json={ "repo_id": repo["id"], "title": "Preserve authorization continuity", "description": "Keep Net Kingdom consumers online", }, ) assert goal.status_code == 201, goal.text goals = await client.get("/repo-goals/", params={"repo_slug": "flex-auth"}) assert [item["id"] for item in goals.json()] == [goal.json()["id"]] assert goals.json()[0]["repo_slug"] == "access-engine" capability = await client.post( "/capability-catalog/", json={ "domain": "infotech", "repo_slug": "flex-auth", "capability_type": "authorization", "title": "Policy decisions", "description": "Net Kingdom authorization", "keywords": ["authorize"], }, ) assert capability.status_code == 201, capability.text catalog = await client.get( "/capability-catalog/", params={"repo_slug": "access-engine"} ) assert [item["id"] for item in catalog.json()] == [capability.json()["id"]] assert catalog.json()[0]["repo_slug"] == "access-engine" service = await client.post( "/services/catalog", json={ "slug": "access-engine-api", "name": "Access Engine API", "hosting_type": "self_hosted", "development_type": "first_party", "first_party": {"repo_slug": "flex-auth", "owning_domain": "infotech"}, "self_hosted": {}, }, ) assert service.status_code == 201, service.text services = await client.get("/services/catalog", params={"repo_slug": "flex-auth"}) assert [item["id"] for item in services.json()] == [service.json()["id"]] ingested = await client.post( "/sbom/ingest/", json={ "repo_slug": "flex-auth", "entries": [ { "package_name": "opa", "package_version": "1.0", "ecosystem": "go", } ], }, ) assert ingested.status_code == 200, ingested.text assert ingested.json()["repo_slug"] == "access-engine" sbom = await client.get("/sbom/flex-auth") assert sbom.status_code == 200 assert sbom.json()["repo_slug"] == "access-engine" event = await client.post( "/token-events/", json={"repo_id": repo["id"], "tokens_in": 12, "tokens_out": 3}, ) assert event.status_code == 201, event.text summary = await client.get( "/token-events/by-repo/", params={"repo_slug": "flex-auth"} ) assert summary.status_code == 200 assert len(summary.json()) == 1 assert summary.json()[0]["repo_slug"] == "access-engine" assert summary.json()[0]["tokens_total"] == 15