From 38c09a8d7feb93e4a5c8f30871caaf0ded57a36b Mon Sep 17 00:00:00 2001 From: Joshua Valluru <326636767+joshua-berri@users.noreply.github.com> Date: Sat, 26 Sep 2026 14:26:44 -0700 Subject: [PATCH] fix(agents): restrict identity configuration to administrators --- litellm/proxy/agent_endpoints/endpoints.py | 1 + .../proxy/agent_endpoints/test_endpoints.py | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/litellm/proxy/agent_endpoints/endpoints.py b/litellm/proxy/agent_endpoints/endpoints.py index 28c82a715e0..763d9cfa640 100644 --- a/litellm/proxy/agent_endpoints/endpoints.py +++ b/litellm/proxy/agent_endpoints/endpoints.py @@ -186,6 +186,7 @@ def _redact_sensitive_agent_fields( copy.extra_headers = None copy.keys = None copy.kill_switch = None + copy.identity = None if copy.litellm_params: copy.litellm_params = _redact_agent_litellm_params_dict(copy.litellm_params) copy.kill_switch = redact_kill_switch(copy.kill_switch) diff --git a/tests/test_litellm/proxy/agent_endpoints/test_endpoints.py b/tests/test_litellm/proxy/agent_endpoints/test_endpoints.py index 526f24c5221..fc1eab89899 100644 --- a/tests/test_litellm/proxy/agent_endpoints/test_endpoints.py +++ b/tests/test_litellm/proxy/agent_endpoints/test_endpoints.py @@ -22,6 +22,7 @@ from litellm.proxy.agent_endpoints.endpoints import ( user_api_key_auth, ) from litellm.types.agents import AgentResponse +from litellm.types.proxy.agent_identity import AgentIdentityBinding def _sample_agent_card_params() -> dict: @@ -1357,3 +1358,34 @@ def test_get_agent_redacts_kill_switch_secret_for_admins_and_hides_it_from_other assert internal.status_code == 200, internal.text assert internal.json()["kill_switch"] is None assert "tok-real" not in internal.text + + +@pytest.mark.parametrize("role", [LitellmUserRoles.PROXY_ADMIN, LitellmUserRoles.INTERNAL_USER, LitellmUserRoles.PROXY_ADMIN_VIEW_ONLY]) +@pytest.mark.parametrize("path", ["/v1/agents", "/v1/agents/agent-123"]) +def test_agent_identity_configuration_is_only_returned_to_admins(role, path, monkeypatch): + from litellm.proxy.agent_endpoints import agent_registry + + binding = AgentIdentityBinding( + agent_id="agent-123", provider="microsoft_entra", tenant_id="tenant", client_id="client", + issuer="https://login.microsoftonline.com/tenant/v2.0", revision="revision", + ) + agent = _sample_agent_response().model_copy(update={"identity": binding}) + registry = MagicMock() + registry.get_agent_by_id.return_value = agent + registry.get_agent_list.return_value = [agent] + registry.ids_for_agent.return_value = frozenset({agent.agent_id}) + monkeypatch.setattr(agent_endpoints, "AGENT_REGISTRY", registry) + monkeypatch.setattr(agent_registry, "global_agent_registry", registry) + monkeypatch.setattr( + "litellm.proxy.agent_endpoints.auth.agent_permission_handler.AgentRequestHandler.resolve_agent_access", + AsyncMock(return_value=RestrictedAgentAccess(frozenset({agent.agent_id}))), + ) + with patch("litellm.proxy.proxy_server.prisma_client") as prisma: + prisma.db.litellm_agentstable.find_unique = AsyncMock(return_value=None) + prisma.db.litellm_agentstable.find_many = AsyncMock(return_value=[]) + prisma.db.litellm_verificationtoken.find_many = AsyncMock(return_value=[]) + response = _make_app_with_role(role).get(path, headers={"Authorization": "Bearer k"}) + assert response.status_code == 200 + payload = response.json()[0] if path == "/v1/agents" else response.json() + assert payload["identity"] == (binding.model_dump(mode="json") if role == LitellmUserRoles.PROXY_ADMIN else None) + assert agent.identity == binding