"""Control-plane domain invariants.""" from __future__ import annotations from uuid import uuid4 import pytest from ragcore.domain.control import ( CrossWorkspaceRelationship, InvalidEntity, Role, Scope, Workspace, ) def test_workspace_creates_typed_control_plane_entities() -> None: workspace = Workspace(uuid4(), "Platform", "platform") application = workspace.create_application( id=uuid4(), name="Search client", scopes={Scope.SEARCH, Scope.DOCUMENTS_READ} ) space = workspace.create_knowledge_space( id=uuid4(), name="Runbooks", slug="runbooks", retention_days=30 ) service_account = application.create_service_account( id=uuid4(), name="worker", scopes={Scope.SEARCH} ) policy = workspace.create_policy( id=uuid4(), operation="search", knowledge_space=space, required_scopes={Scope.SEARCH} ) grant = workspace.grant( id=uuid4(), application=application, knowledge_space=space, role=Role.VIEWER ) assert application.workspace_id == workspace.id assert service_account.application_id == application.id assert service_account.workspace_id == workspace.id assert policy.knowledge_space_id == space.id assert grant.knowledge_space_id == space.id def test_service_account_cannot_escalate_application_scopes() -> None: workspace = Workspace(uuid4(), "Platform", "platform") application = workspace.create_application(id=uuid4(), name="Search", scopes={Scope.SEARCH}) with pytest.raises(InvalidEntity, match="scopes"): application.create_service_account( id=uuid4(), name="overreach", scopes={Scope.SEARCH, Scope.ANSWER} ) def test_cross_workspace_grant_is_rejected() -> None: first = Workspace(uuid4(), "First", "first") second = Workspace(uuid4(), "Second", "second") application = first.create_application(id=uuid4(), name="Client", scopes={Scope.SEARCH}) space = second.create_knowledge_space(id=uuid4(), name="Private", slug="private") with pytest.raises(CrossWorkspaceRelationship, match="same workspace"): first.grant(id=uuid4(), application=application, knowledge_space=space, role=Role.VIEWER) @pytest.mark.parametrize("slug", ["Upper", "with space", "-leading", "trailing-"]) def test_workspace_and_space_slugs_are_normalized_by_contract(slug: str) -> None: with pytest.raises(InvalidEntity, match="slug"): Workspace(uuid4(), "Invalid", slug) def test_retention_policy_must_be_positive() -> None: workspace = Workspace(uuid4(), "Platform", "platform") with pytest.raises(InvalidEntity, match="retention_days"): workspace.create_knowledge_space( id=uuid4(), name="Runbooks", slug="runbooks", retention_days=0 )