litellm/tests/test_litellm/proxy/utils
joshua-berri 79756cbb9b
feat(agents): enforce authoritative agent permissions (#43721)
* feat(agents): authoritative permissions

* fix: enforce authoritative managed agent permissions

* fix(agents): only consult the identity store for managed targets

is_agent_allowed entered the identity-store path whenever a prisma client
was configured, so an ordinary agent paired with an internal user returned
503 instead of 200. Classify the target from the registry first and fall
back to the store only when the registry has no entry, so an unmanaged
target never depends on the store being reachable.

* fix(agents): gate the managed path on an admitted policy object

Ten call sites branched on `managed_agent_policy is not None`, which any
MagicMock attribute satisfies, so the managed path fired on unmanaged
subjects and died in Pydantic validation as a 503. Route every check
through a shared helper that requires a real AgentResponse.

* test(mcp): stub the writer replica the fresh-policy reads use

reload_admitted_user now passes check_db_only through to get_user_object,
so the user row is read from writer_db. Point the mocks at the replica the
code actually reads and give each parametrized case its own user id.

* fix(agents): cap a managed agent at the invoking team's agents

resolve_agent_access returned the managed policy's grants before the
agent_caller ceiling was applied, so a managed agent acting on behalf of a
user reached agents that user's team was never granted. Intersect with the
caller ceiling the unmanaged path already honours.

* fix(agents): restore token narrowing and scope the private-access suppressions

The managed-model check lost its valid_token narrowing when it moved to the
shared helper. Make the caller-access resolver public rather than reaching
into it from module scope, and give each remaining private access a reason.

* docs(agents): drop the comment claiming admins skip the A2A permission check

The check has never had an admin bypass on this path, so the comment
described behaviour the code does not implement.

* test(proxy): stub the writer reads and restore the MCP manager singleton

Fresh-policy user lookups read writer_db, so the team and rest-endpoint
mocks stubbed a replica the code no longer reads, and the dashboard
session fake still had the pre-kwarg signature. The manager reload also
rebound global_mcp_server_manager in every MCP module without restoring
it, leaking an empty manager into later files.

* style: sort imports under the litellm package ruff config

* fix(mcp): cap a managed agent's servers and tools at the invoking caller

managed_agent_servers and managed_agent_tools returned the agent's own
grants without the agent_caller ceiling the unmanaged resolvers apply, so
a managed agent reached MCP servers and tools the echoed caller could not.
Call the existing ceiling helpers on both axes.

* refactor(mcp): return the caller-capped tools without an interim list

The ceiling helper already returns a sequence, so materializing it into a
list added a mutable collection for nothing. Sort at the return sites
instead, which also makes the tool order stable across both branches.

* fix(agents): preserve actor ceilings during managed target checks

* fix(agents): keep managed permission ceilings authoritative

* fix(mcp): fail closed on authoritative caller team outages

---------

Co-authored-by: Joshua Valluru <326636767+joshua-berri@users.noreply.github.com>
2026-09-30 11:11:37 -07:00
..
helpers fix(agents): evict the cached agent access groups on every agent write and cap the model listing 2026-09-17 20:31:03 +00:00
prisma_and_spend feat(agents): enforce authoritative agent permissions (#43721) 2026-09-30 11:11:37 -07:00
proxy_logging feat(mcp): scan and pin upstream tool descriptions (#43283) 2026-09-28 18:38:49 -07:00
__init__.py test(proxy/utils): pin bottom-of-file helper behavior (#29509) 2026-06-02 17:45:19 -07:00