"""Per-tree AI model policy: owner-only, validated against configured providers.""" from app.core.config import get_settings from tests.conftest import auth, register async def test_ai_policy_is_owner_only(client): owner = auth(await register(client, "ai-o@ex.com")) editor = auth(await register(client, "ai-x@ex.com")) tid = (await client.post("/api/v1/trees", json={"name": "T"}, headers=owner)).json()["id"] await client.post( f"/api/v1/trees/{tid}/members", json={"email": "ai-x@ex.com", "role": "editor"}, headers=owner ) g = await client.get(f"/api/v1/trees/{tid}/ai", headers=owner) assert g.status_code == 200 assert g.json()["member_provider"] is None assert g.json()["configured_providers"] == [] # nothing configured in tests # An editor (not owner) can neither view nor change the policy. assert (await client.get(f"/api/v1/trees/{tid}/ai", headers=editor)).status_code == 403 assert ( await client.patch( f"/api/v1/trees/{tid}/ai", json={"member_provider": None, "recommender_provider": None}, headers=editor, ) ).status_code == 403 async def test_ai_policy_set_and_validate(client, monkeypatch): monkeypatch.setattr(get_settings(), "anthropic_api_key", "sk-ant-test") owner = auth(await register(client, "ai-set@ex.com")) tid = (await client.post("/api/v1/trees", json={"name": "T"}, headers=owner)).json()["id"] g = (await client.get(f"/api/v1/trees/{tid}/ai", headers=owner)).json() assert {p["name"] for p in g["configured_providers"]} == {"anthropic"} # Assign the member + recommender model. p = await client.patch( f"/api/v1/trees/{tid}/ai", json={"member_provider": "anthropic", "recommender_provider": "anthropic"}, headers=owner, ) assert p.status_code == 200 and p.json()["member_provider"] == "anthropic" # A provider that isn't configured is rejected. assert ( await client.patch( f"/api/v1/trees/{tid}/ai", json={"member_provider": "openai", "recommender_provider": None}, headers=owner, ) ).status_code == 403 # Clearing is allowed. c = await client.patch( f"/api/v1/trees/{tid}/ai", json={"member_provider": None, "recommender_provider": None}, headers=owner, ) assert c.status_code == 200 and c.json()["member_provider"] is None