From 0a03f3d0c83e243f79cf474f6e10069462877472 Mon Sep 17 00:00:00 2001 From: Joshua Valluru <326636767+joshua-berri@users.noreply.github.com> Date: Sat, 26 Sep 2026 13:05:53 -0700 Subject: [PATCH] fix(agents): honor explicitly empty delegated scope requirements at registration --- .../proxy/agent_endpoints/managed_identity.py | 2 -- .../agent_endpoints/test_managed_identity.py | 24 +++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/litellm/proxy/agent_endpoints/managed_identity.py b/litellm/proxy/agent_endpoints/managed_identity.py index 9a0b202d92f..260b74fcbd1 100644 --- a/litellm/proxy/agent_endpoints/managed_identity.py +++ b/litellm/proxy/agent_endpoints/managed_identity.py @@ -87,8 +87,6 @@ def _configuration_failure( return AgentIdentityFailure( message="Autonomous mode requires the Enterprise application service-principal object ID" ) - if identity is not None and mode != "autonomous" and not identity.required_scopes: - return AgentIdentityFailure(message="Delegated mode requires at least one delegated scope") if enabling_without_binding and ( identity is None or isinstance(identity, AgentIdentityBinding) and not identity.active ): diff --git a/tests/test_litellm/proxy/agent_endpoints/test_managed_identity.py b/tests/test_litellm/proxy/agent_endpoints/test_managed_identity.py index f0a02163342..45fe4b0655f 100644 --- a/tests/test_litellm/proxy/agent_endpoints/test_managed_identity.py +++ b/tests/test_litellm/proxy/agent_endpoints/test_managed_identity.py @@ -185,11 +185,26 @@ def test_enabling_unbound_or_inactive_identity_requires_rebinding(identity: Agen assert "Bind an identity" in result.message -def test_delegated_identity_requires_a_scope() -> None: +@pytest.mark.parametrize("mode", ["delegated", "both"]) +def test_explicit_empty_scope_requirements_can_be_registered_and_preserved(mode: str) -> None: + from litellm.types.proxy.agent_identity import EntraIdentityConfig + + configuration: Final = EntraIdentityConfig( + provider="microsoft_entra", + tenant_id=TENANT, + client_id=CLIENT, + service_principal_id=PRINCIPAL, + required_scopes=(), + ) + created: Final = managed_write_fields( + {"identity": configuration.model_dump(), "execution_mode": mode}, None, "admin" + ) + assert not isinstance(created, AgentIdentityFailure) + assert created["identity"]["create"]["required_scopes"] == () agent: Final = managed_agent().model_copy(update={"identity": BINDING.model_copy(update={"required_scopes": ()})}) - result: Final = managed_write_fields({"execution_mode": "delegated"}, agent, "admin") - assert isinstance(result, AgentIdentityFailure) - assert "delegated scope" in result.message + updated: Final = managed_write_fields({"execution_mode": mode}, agent, "admin") + assert not isinstance(updated, AgentIdentityFailure) + assert updated["execution_mode"] == mode @pytest.mark.parametrize( @@ -215,6 +230,7 @@ def test_malformed_application_roles_are_rejected(roles: object) -> None: def test_entra_binding_normalizes_identifiers_and_rejects_invalid_configuration() -> None: from pydantic import ValidationError + from litellm.types.proxy.agent_identity import EntraIdentityConfig identifier = "ABCDEF00-1234-4234-9234-123456789ABC"