Skip to content

Commit fe35a42

Browse files
committed
fix(readiness): resolve F-06 validate Foundry configuration
1 parent 9747234 commit fe35a42

4 files changed

Lines changed: 45 additions & 5 deletions

File tree

src/cas_reference_product/config.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from functools import lru_cache
2+
import re
23
from typing import Literal
34

45
from 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
2738
def get_settings() -> Settings:

src/cas_reference_product/workflow.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff 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,

tests/test_api.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff 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+
4459
def test_workflow_api_sanitizes_external_service_failures(envelope) -> None:
4560
with patch(
4661
"cas_reference_product.app.build_workflow_agent_service",

tests/test_service_factory.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff 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+
3042
def test_foundry_service_uses_next_gen_agent_reference(envelope) -> None:
3143
settings = Settings(
3244
environment="prod",

0 commit comments

Comments
 (0)