File tree Expand file tree Collapse file tree
src/cas_reference_product Expand file tree Collapse file tree Original file line number Diff line number Diff line change 11from functools import lru_cache
2+ import re
23from typing import Literal
34
45from pydantic import Field
@@ -17,11 +18,21 @@ class Settings(BaseSettings):
1718 applicationinsights_connection_string : str | None = Field (default = None , repr = False )
1819
1920 @property
20- def ready (self ) -> bool :
21- return self .workflow_backend == "local" or bool (
22- self .foundry_project_endpoint and self .foundry_agent_name
21+ def foundry_ready (self ) -> bool :
22+ return bool (
23+ self .foundry_project_endpoint
24+ and re .fullmatch (
25+ r"https://[A-Za-z0-9.-]+\.services\.ai\.azure\.com/api/projects/[A-Za-z0-9_.-]+/?" ,
26+ self .foundry_project_endpoint ,
27+ )
28+ and self .foundry_agent_name
29+ and self .foundry_agent_name .strip ()
2330 )
2431
32+ @property
33+ def ready (self ) -> bool :
34+ return self .workflow_backend == "local" or self .foundry_ready
35+
2536
2637@lru_cache
2738def get_settings () -> Settings :
Original file line number Diff line number Diff line change @@ -36,8 +36,10 @@ class FoundryWorkflowAgentService:
3636 """Invoke a Foundry Next Gen agent reference through the project Responses client."""
3737
3838 def __init__ (self , settings : Settings ) -> None :
39- if not settings .foundry_project_endpoint or not settings .foundry_agent_name :
40- raise ValueError ("Foundry backend requires project endpoint and agent name" )
39+ if not settings .foundry_ready :
40+ raise ValueError ("Foundry backend requires a valid project endpoint and agent name" )
41+ assert settings .foundry_project_endpoint is not None
42+ assert settings .foundry_agent_name is not None
4143 self ._agent_name = settings .foundry_agent_name
4244 self ._client = AIProjectClient (
4345 endpoint = settings .foundry_project_endpoint ,
Original file line number Diff line number Diff line change @@ -41,6 +41,21 @@ def test_incomplete_foundry_configuration_is_not_ready() -> None:
4141 assert client .post ("/api/v1/workflows" , json = {}).status_code == 422
4242
4343
44+ def test_invalid_foundry_endpoint_is_not_ready () -> None :
45+ client = TestClient (
46+ create_app (
47+ Settings (
48+ workflow_backend = "foundry" ,
49+ foundry_project_endpoint = "https://example.invalid/project" ,
50+ foundry_agent_name = "cas-reference-agent" ,
51+ )
52+ )
53+ )
54+
55+ assert client .get ("/health/live" ).status_code == 200
56+ assert client .get ("/health/ready" ).status_code == 503
57+
58+
4459def test_workflow_api_sanitizes_external_service_failures (envelope ) -> None :
4560 with patch (
4661 "cas_reference_product.app.build_workflow_agent_service" ,
Original file line number Diff line number Diff line change @@ -27,6 +27,18 @@ def test_factory_builds_foundry_service_when_configured() -> None:
2727 service .assert_called_once_with (settings )
2828
2929
30+ def test_foundry_service_rejects_invalid_project_endpoint () -> None :
31+ settings = Settings (
32+ environment = "prod" ,
33+ workflow_backend = "foundry" ,
34+ foundry_project_endpoint = "https://example.invalid/project" ,
35+ foundry_agent_name = "cas-reference-agent" ,
36+ )
37+
38+ with pytest .raises (ValueError , match = "valid project endpoint" ):
39+ FoundryWorkflowAgentService (settings )
40+
41+
3042def test_foundry_service_uses_next_gen_agent_reference (envelope ) -> None :
3143 settings = Settings (
3244 environment = "prod" ,
You can’t perform that action at this time.
0 commit comments