import json import unittest from fastapi.testclient import TestClient from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.pool import StaticPool from app.api.model_settings import require_current_user from app.db import Base, get_db_session from app.main import app OPENAI_TOML = ''' model_provider = "OpenAI" model = "gpt-5.5" review_model = "gpt-5.5" model_reasoning_effort = "xhigh" disable_response_storage = true network_access = "enabled" windows_wsl_setup_acknowledged = true [model_providers.OpenAI] name = "OpenAI" base_url = "https://sub2api.example.test" wire_api = "responses" requires_openai_auth = true [shared_ai_platform] base_url = "http://shared-ai.example.test" api_key = "shared-platform-key" api_prefix = "/api/v0.2" app_id = "ai-contract-platform-test" timeout_seconds = 45 provider = "openai" legal_review_enabled = true legal_review_fallback_to_local = true document_extraction_enabled = true [features] goals = true ''' ANTHROPIC_JSON = { "env": { "ANTHROPIC_BASE_URL": "https://sub2api.example.test", "ANTHROPIC_AUTH_TOKEN": "sk-test-anthropic", "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", "CLAUDE_CODE_ATTRIBUTION_HEADER": "0", }, "shared_ai_platform": { "base_url": "http://shared-ai-anthropic.example.test", "api_key": "shared-platform-anthropic-key", "api_prefix": "/api/v0.2", "app_id": "ai-contract-platform-test", "timeout_seconds": 50, "provider": "anthropic", "legal_review_enabled": True, "legal_review_fallback_to_local": False, "document_extraction_enabled": True, }, } class ModelSettingsApiTestCase(unittest.TestCase): def setUp(self): self.engine = create_engine( "sqlite:///:memory:", future=True, connect_args={"check_same_thread": False}, poolclass=StaticPool, ) Base.metadata.create_all(self.engine) self.SessionLocal = sessionmaker(bind=self.engine, future=True) def override_db(): session = self.SessionLocal() try: yield session finally: session.close() app.dependency_overrides[get_db_session] = override_db self.client = TestClient(app) def tearDown(self): app.dependency_overrides.clear() self.engine.dispose() def _as_admin(self): app.dependency_overrides[require_current_user] = lambda: { "id": "user-admin", "tenant_id": "tenant-demo-001", "role": "admin", } def _as_member(self): app.dependency_overrides[require_current_user] = lambda: { "id": "user-member", "tenant_id": "tenant-demo-001", "role": "member", } def test_admin_can_save_openai_toml_and_export_runtime_env(self): self._as_admin() response = self.client.put( "/api/v1/model-settings", json={ "config_format": "openai_toml", "raw_config": OPENAI_TOML, "display_name": "Primary OpenAI compatible", "auth_token": "sk-test-openai", }, ) self.assertEqual(response.status_code, 200) body = response.json()["data"] self.assertEqual(body["provider_type"], "openai") self.assertEqual(body["model_provider"], "OpenAI") self.assertEqual(body["model"], "gpt-5.5") self.assertEqual(body["review_model"], "gpt-5.5") self.assertEqual(body["base_url"], "https://sub2api.example.test") self.assertEqual(body["wire_api"], "responses") self.assertEqual(body["reasoning_effort"], "xhigh") self.assertTrue(body["has_auth_token"]) self.assertTrue(body["shared_ai_platform"]["configured"]) self.assertEqual(body["shared_ai_platform"]["base_url"], "http://shared-ai.example.test") self.assertEqual(body["shared_ai_platform"]["api_prefix"], "/api/v0.2") self.assertEqual(body["shared_ai_platform"]["app_id"], "ai-contract-platform-test") self.assertEqual(body["shared_ai_platform"]["provider"], "openai") self.assertTrue(body["shared_ai_platform"]["legal_review_fallback_to_local"]) self.assertNotIn("shared-platform-key", json.dumps(body["config_json"], ensure_ascii=False)) self.assertNotIn("sk-test-openai", body["raw_config"]) self.assertNotIn("shared-platform-key", body["raw_config"]) export_response = self.client.get("/api/v1/model-settings/runtime-export") self.assertEqual(export_response.status_code, 200) exported = export_response.json()["data"] self.assertTrue(exported["configured"]) self.assertEqual(exported["env"]["SHARED_AI_OPENAI_BASE_URL"], "https://sub2api.example.test") self.assertEqual(exported["env"]["SHARED_AI_OPENAI_API_KEY"], "sk-test-openai") self.assertEqual(exported["env"]["SHARED_AI_OPENAI_MODEL"], "gpt-5.5") self.assertEqual(exported["env"]["SHARED_AI_PLATFORM_BASE_URL"], "http://shared-ai.example.test") self.assertEqual(exported["env"]["SHARED_AI_PLATFORM_API_KEY"], "shared-platform-key") self.assertEqual(exported["env"]["SHARED_AI_PLATFORM_APP_ID"], "ai-contract-platform-test") self.assertEqual(exported["env"]["SHARED_AI_PLATFORM_API_PREFIX"], "/api/v0.2") self.assertEqual(exported["shared_ai_platform"]["api_key"], "shared-platform-key") self.assertEqual(exported["config"]["model_providers"]["OpenAI"]["wire_api"], "responses") updated_toml = OPENAI_TOML.replace("gpt-5.5", "gpt-5.6").replace( 'api_key = "shared-platform-key"', 'api_key = ""', ) update_response = self.client.put( "/api/v1/model-settings", json={ "config_format": "openai_toml", "raw_config": updated_toml, "display_name": "Primary OpenAI compatible", "auth_token": "", }, ) self.assertEqual(update_response.status_code, 200) preserved_export_response = self.client.get("/api/v1/model-settings/runtime-export") preserved_exported = preserved_export_response.json()["data"] self.assertEqual(preserved_exported["env"]["SHARED_AI_OPENAI_API_KEY"], "sk-test-openai") self.assertEqual(preserved_exported["env"]["SHARED_AI_OPENAI_MODEL"], "gpt-5.6") self.assertEqual(preserved_exported["env"]["SHARED_AI_PLATFORM_API_KEY"], "shared-platform-key") def test_admin_can_save_anthropic_env_json(self): self._as_admin() response = self.client.put( "/api/v1/model-settings", json={ "config_format": "anthropic_env_json", "raw_config": json.dumps(ANTHROPIC_JSON), "display_name": "Claude compatible", }, ) self.assertEqual(response.status_code, 200) body = response.json()["data"] self.assertEqual(body["provider_type"], "anthropic") self.assertEqual(body["base_url"], "https://sub2api.example.test") self.assertTrue(body["has_auth_token"]) self.assertTrue(body["shared_ai_platform"]["configured"]) self.assertEqual(body["shared_ai_platform"]["base_url"], "http://shared-ai-anthropic.example.test") self.assertEqual(body["shared_ai_platform"]["provider"], "anthropic") self.assertEqual(body["config_json"]["env"]["ANTHROPIC_AUTH_TOKEN"], "***") self.assertEqual(body["config_json"]["shared_ai_platform"]["api_key_encrypted"], "***") self.assertNotIn("sk-test-anthropic", body["raw_config"]) self.assertNotIn("shared-platform-anthropic-key", body["raw_config"]) export_response = self.client.get("/api/v1/model-settings/runtime-export") self.assertEqual(export_response.status_code, 200) exported = export_response.json()["data"] self.assertEqual(exported["provider_type"], "anthropic") self.assertEqual(exported["env"]["ANTHROPIC_BASE_URL"], "https://sub2api.example.test") self.assertEqual(exported["env"]["ANTHROPIC_AUTH_TOKEN"], "sk-test-anthropic") self.assertEqual(exported["env"]["SHARED_AI_PLATFORM_API_KEY"], "shared-platform-anthropic-key") self.assertEqual(exported["env"]["CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC"], "1") def test_member_cannot_access_model_settings(self): self._as_member() get_response = self.client.get("/api/v1/model-settings") put_response = self.client.put( "/api/v1/model-settings", json={"config_format": "openai_toml", "raw_config": OPENAI_TOML}, ) self.assertEqual(get_response.status_code, 403) self.assertEqual(put_response.status_code, 403) if __name__ == "__main__": unittest.main()