mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-30 01:52:18 +00:00
fix(a2a): scrub upstream url from /public/agent_hub cards
Some checks are pending
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / schema-migration (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests: Security / security (push) Waiting to run
Some checks are pending
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / schema-migration (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests: Security / security (push) Waiting to run
Public agent_hub returned agent_card_params verbatim, exposing the
retained upstream backend url to unauthenticated callers. Rewrite the
url to the proxy /a2a/{agent_id} entrypoint on response, matching the
behavior of the authenticated well-known agent-card endpoint, so the
backend cannot be reached outside LiteLLM's auth, budget, and logging
path.
This commit is contained in:
parent
65484a831c
commit
70fe8e58de
2 changed files with 73 additions and 5 deletions
|
|
@ -5,7 +5,7 @@ from importlib.resources import files
|
|||
from typing import Any, Dict, List, Optional
|
||||
|
||||
import litellm
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from fastapi import APIRouter, HTTPException, Request
|
||||
|
||||
from litellm._logging import verbose_logger
|
||||
from litellm.litellm_core_utils.get_blog_posts import (
|
||||
|
|
@ -211,7 +211,7 @@ async def public_model_hub():
|
|||
tags=["[beta] Agents", "public"],
|
||||
response_model=List[AgentCard],
|
||||
)
|
||||
async def get_agents():
|
||||
async def get_agents(request: Request):
|
||||
import litellm
|
||||
from litellm.proxy.agent_endpoints.agent_registry import global_agent_registry
|
||||
|
||||
|
|
@ -219,12 +219,16 @@ async def get_agents():
|
|||
|
||||
if litellm.public_agent_groups is None:
|
||||
return []
|
||||
agent_card_list = [
|
||||
agent.agent_card_params
|
||||
|
||||
proxy_base = str(request.base_url).rstrip("/")
|
||||
return [
|
||||
{
|
||||
**(agent.agent_card_params or {}),
|
||||
"url": f"{proxy_base}/a2a/{agent.agent_id}",
|
||||
}
|
||||
for agent in agents
|
||||
if agent.agent_id in litellm.public_agent_groups
|
||||
]
|
||||
return agent_card_list
|
||||
|
||||
|
||||
@router.get(
|
||||
|
|
|
|||
|
|
@ -463,6 +463,70 @@ def test_public_model_hub_mixed_health_statuses():
|
|||
app.dependency_overrides.clear()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# /public/agent_hub
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_public_agent_hub_rewrites_upstream_url_to_proxy():
|
||||
"""Public agent hub must not leak the upstream backend URL retained on the
|
||||
stored card. The ``url`` field has to be overwritten with the proxy
|
||||
``/a2a/{agent_id}`` entrypoint, matching the well-known card endpoint, so
|
||||
an unauthenticated client cannot call the backend directly."""
|
||||
from litellm.types.agents import AgentResponse
|
||||
|
||||
upstream_url = "https://upstream.internal.example.com/a2a"
|
||||
agent = AgentResponse(
|
||||
agent_id="agent-123",
|
||||
agent_name="public-agent",
|
||||
agent_card_params={"name": "public-agent", "url": upstream_url},
|
||||
)
|
||||
|
||||
app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
mock_registry = MagicMock()
|
||||
mock_registry.get_public_agent_list.return_value = [agent]
|
||||
|
||||
with (
|
||||
patch("litellm.public_agent_groups", ["agent-123"]),
|
||||
patch(
|
||||
"litellm.proxy.agent_endpoints.agent_registry.global_agent_registry",
|
||||
mock_registry,
|
||||
),
|
||||
):
|
||||
response = client.get("/public/agent_hub")
|
||||
|
||||
assert response.status_code == 200, response.text
|
||||
payload = response.json()
|
||||
assert len(payload) == 1
|
||||
card = payload[0]
|
||||
assert upstream_url not in card.get("url", "")
|
||||
assert card["url"].endswith("/a2a/agent-123")
|
||||
|
||||
|
||||
def test_public_agent_hub_returns_empty_when_no_public_groups():
|
||||
app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
mock_registry = MagicMock()
|
||||
mock_registry.get_public_agent_list.return_value = []
|
||||
|
||||
with (
|
||||
patch("litellm.public_agent_groups", None),
|
||||
patch(
|
||||
"litellm.proxy.agent_endpoints.agent_registry.global_agent_registry",
|
||||
mock_registry,
|
||||
),
|
||||
):
|
||||
response = client.get("/public/agent_hub")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == []
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# /public/endpoints
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue