diff --git a/litellm/proxy/guardrails/guardrail_hooks/agent_365/agent_365.py b/litellm/proxy/guardrails/guardrail_hooks/agent_365/agent_365.py index ff06f09114d..56cc5763e30 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/agent_365/agent_365.py +++ b/litellm/proxy/guardrails/guardrail_hooks/agent_365/agent_365.py @@ -500,22 +500,15 @@ class Agent365Guardrail(CustomGuardrail): if isinstance(exchange_result, Ok): return SignedIn() error: Final = exchange_result.error - match error.tag: - case "unauthorized": - return Rejected(detail=error.unauthorized.detail, claims=error.unauthorized.claims) - case "misconfigured": - return Unavailable( - detail=( - f"Entra rejected the gateway's own Agent 365 credentials ({error.misconfigured}); " - "check the guardrail's client_id and client_secret" - ), - fail_open=self.unreachable_fallback == "fail_open", - ) - case _: - return Unavailable( - detail=f"the Entra token exchange failed ({error.summary})", - fail_open=self.unreachable_fallback == "fail_open", - ) + if error.tag == "unauthorized": + return Rejected(detail=error.unauthorized.detail, claims=error.unauthorized.claims) + detail: Final = ( + f"Entra rejected the gateway's own Agent 365 credentials ({error.misconfigured}); " + "check the guardrail's client_id and client_secret" + if error.tag == "misconfigured" + else f"the Entra token exchange failed ({error.summary})" + ) + return Unavailable(detail=detail, fail_open=self.unreachable_fallback == "fail_open") async def _post_allowing_error_status( self, diff --git a/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_agent_365.py b/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_agent_365.py index fd2f14471ce..ba90460d573 100644 --- a/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_agent_365.py +++ b/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_agent_365.py @@ -1284,6 +1284,17 @@ class TestPreflightCallerSignIn: "the field was removed from the config; do not tell admins to check it" ) + @pytest.mark.asyncio + async def test_token_endpoint_failure_is_unavailable_under_the_fallback_policy(self): + exchanger: Final = StubTokenExchanger([Error(CredError.of_upstream_unavailable("token endpoint 503"))]) + guardrail: Final = _make_guardrail(FakeHandler([]), exchanger=exchanger, unreachable_fallback="fail_open") + + verdict: Final = await guardrail.preflight_caller_sign_in(_server(), _user(), FAKE_ASSERTION) + + assert verdict == Unavailable( + detail="the Entra token exchange failed (upstream unavailable: token endpoint 503)", fail_open=True + ) + @pytest.mark.asyncio async def test_endpoint_unreachable_fail_open_is_unavailable(self): exchanger: Final = StubTokenExchanger(