From 29807cf94979b56e82b5bb263df4d9995ec38d3b Mon Sep 17 00:00:00 2001 From: AxelRay <110029405+axelray-dev@users.noreply.github.com> Date: Thu, 8 Oct 2026 06:55:18 +0800 Subject: [PATCH] test(proxy): cover empty user key scopes --- .../test_common_daily_activity.py | 22 ++++++++++ .../test_internal_user_endpoints.py | 41 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/tests/unit/proxy/management_endpoints/test_common_daily_activity.py b/tests/unit/proxy/management_endpoints/test_common_daily_activity.py index d99b4abcb88..35655020149 100644 --- a/tests/unit/proxy/management_endpoints/test_common_daily_activity.py +++ b/tests/unit/proxy/management_endpoints/test_common_daily_activity.py @@ -2559,6 +2559,28 @@ async def test_get_user_api_key_filter_scopes_to_active_and_deleted_user_keys(): assert await get_user_api_key_filter(mock_prisma, "target-user", "unrelated-key") == [] +@pytest.mark.asyncio +async def test_get_user_api_key_filter_ignores_malformed_and_duplicate_rows(): + mock_prisma = MagicMock() + mock_prisma.db.litellm_verificationtoken.find_many = AsyncMock( + return_value=[ + SimpleNamespace(token="active-key", user_id="target-user"), + SimpleNamespace(token="active-key", user_id="target-user"), + SimpleNamespace(token="other-user-key", user_id="other-user"), + SimpleNamespace(token=None, user_id="target-user"), + ] + ) + mock_prisma.db.litellm_deletedverificationtoken.find_many = AsyncMock( + return_value=[ + SimpleNamespace(token="deleted-key", user_id="target-user"), + SimpleNamespace(token="active-key", user_id="target-user"), + SimpleNamespace(token="orphaned-key", user_id=None), + ] + ) + + assert await get_user_api_key_filter(mock_prisma, "target-user", None) == ["active-key", "deleted-key"] + + @pytest.mark.asyncio async def test_get_user_api_key_filter_fails_closed_when_deleted_lookup_fails(): mock_prisma = MagicMock() diff --git a/tests/unit/proxy/management_endpoints/test_internal_user_endpoints.py b/tests/unit/proxy/management_endpoints/test_internal_user_endpoints.py index 4a952c4356a..24ad3dc7a01 100644 --- a/tests/unit/proxy/management_endpoints/test_internal_user_endpoints.py +++ b/tests/unit/proxy/management_endpoints/test_internal_user_endpoints.py @@ -2645,6 +2645,47 @@ async def test_get_user_daily_activity_aggregated_admin_keeps_requested_key(monk assert captured_scope.api_keys == ("admin-digest",) +@pytest.mark.asyncio +async def test_get_user_daily_activity_aggregated_admin_does_not_widen_empty_user_key_filter(monkeypatch): + import litellm.proxy.management_endpoints.internal_user_endpoints as endpoints + + prisma_client = MagicMock() + repository = object() + expected = SimpleNamespace(result="empty-user-scope") + calls = {} + + monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", prisma_client) + + async def empty_key_filter(client, user_id, api_key): + calls["filter"] = (client, user_id, api_key) + return [] + + monkeypatch.setattr(endpoints, "get_user_api_key_filter", empty_key_filter) + monkeypatch.setattr(endpoints, "daily_activity_repository", lambda client: repository) + + async def capture_scope(repository_arg, scope): + calls["scope"] = (repository_arg, scope) + return expected + + monkeypatch.setattr(endpoints, "get_daily_activity_aggregated", capture_scope) + + result = await endpoints.get_user_daily_activity_aggregated( + start_date="2026-01-01", + end_date="2026-01-01", + model=None, + api_key="not-owned-by-selected-user", + user_id="selected-user", + timezone=None, + include_current_utc_day=False, + user_api_key_dict=UserAPIKeyAuth(user_id="admin", user_role=LitellmUserRoles.PROXY_ADMIN), + ) + + assert result is expected + assert calls["filter"] == (prisma_client, "selected-user", "not-owned-by-selected-user") + assert calls["scope"][0] is repository + assert calls["scope"][1].api_keys == () + + @pytest.mark.asyncio async def test_get_user_daily_activity_aggregated_rejects_other_non_admin(monkeypatch): from litellm.proxy.management_endpoints.internal_user_endpoints import (