mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
fix(proxy): cap /key/list user_email lookup at 1000 users
A broad substring like @ matches every user, and the unbounded lookup materialized the full user table in proxy memory before building the key filter. Bound it with take so the resolved id list and the IN clause stay a fixed size
This commit is contained in:
parent
139dc60e5b
commit
74cb382932
3 changed files with 8 additions and 3 deletions
|
|
@ -5176,6 +5176,7 @@ async def get_member_team_ids(
|
|||
|
||||
|
||||
VALID_EXPIRES_FILTER_VALUES = frozenset({"active", "expired"})
|
||||
USER_EMAIL_KEY_FILTER_MAX_USERS = 1000
|
||||
|
||||
|
||||
@router.get(
|
||||
|
|
@ -5195,7 +5196,7 @@ async def list_keys(
|
|||
),
|
||||
user_email: str | None = Query(
|
||||
None,
|
||||
description="Filter keys by the owning user's email. Case-insensitive substring match against the user table; only keys whose user_id belongs to a matching user are returned.",
|
||||
description="Filter keys by the owning user's email. Case-insensitive substring match against the user table, capped at the first 1000 matching users; only keys whose user_id belongs to a matching user are returned.",
|
||||
),
|
||||
team_id: Optional[str] = Query(None, description="Filter keys by team ID"),
|
||||
organization_id: Optional[str] = Query(None, description="Filter keys by organization ID"),
|
||||
|
|
@ -5329,7 +5330,8 @@ async def list_keys(
|
|||
[
|
||||
user.user_id
|
||||
for user in await UserRepository(prisma_client).table.find_many(
|
||||
where={"user_email": {"contains": user_email, "mode": "insensitive"}}
|
||||
where={"user_email": {"contains": user_email, "mode": "insensitive"}},
|
||||
take=USER_EMAIL_KEY_FILTER_MAX_USERS,
|
||||
)
|
||||
]
|
||||
if user_email and isinstance(user_email, str)
|
||||
|
|
|
|||
|
|
@ -6354,6 +6354,9 @@ async def test_list_keys_user_email_resolves_to_user_ids():
|
|||
assert mock_find_many.call_args.kwargs["where"] == {
|
||||
"user_email": {"contains": "alias@example.com", "mode": "insensitive"}
|
||||
}
|
||||
assert mock_find_many.call_args.kwargs["take"] == 1000, (
|
||||
"user lookup must be bounded; a broad substring like '@' matches every user"
|
||||
)
|
||||
assert mock_list_key_helper.call_args.kwargs["user_ids_for_email"] == ["user-1", "user-2"]
|
||||
|
||||
mock_find_many.return_value = []
|
||||
|
|
|
|||
2
ui/litellm-dashboard/src/lib/http/schema.d.ts
generated
vendored
2
ui/litellm-dashboard/src/lib/http/schema.d.ts
generated
vendored
|
|
@ -42813,7 +42813,7 @@ export interface operations {
|
|||
size?: number;
|
||||
/** @description Filter keys by user ID. Exact match by default; set substring_matching=true (admin only) for case-insensitive substring matching. */
|
||||
user_id?: string | null;
|
||||
/** @description Filter keys by the owning user's email. Case-insensitive substring match against the user table; only keys whose user_id belongs to a matching user are returned. */
|
||||
/** @description Filter keys by the owning user's email. Case-insensitive substring match against the user table, capped at the first 1000 matching users; only keys whose user_id belongs to a matching user are returned. */
|
||||
user_email?: string | null;
|
||||
/** @description Filter keys by team ID */
|
||||
team_id?: string | null;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue