Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3096,8 +3096,8 @@ async def _rotate_master_key( # noqa: PLR0915
)
if new_model:
_dumped = new_model.model_dump(exclude_none=True)
_dumped["litellm_params"] = prisma.Json(_dumped["litellm_params"]) # type: ignore[attr-defined]
_dumped["model_info"] = prisma.Json(_dumped["model_info"]) # type: ignore[attr-defined]
_dumped["litellm_params"] = safe_dumps(_dumped["litellm_params"])
_dumped["model_info"] = safe_dumps(_dumped["model_info"])
Comment on lines +3099 to +3100
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaking existing test and likely runtime behavior

Replacing prisma.Json(...) with safe_dumps(...) changes the type from a prisma.Json wrapper (which wraps a Python dict) to a JSON string. The existing test test_rotate_master_key_model_data_valid_for_prisma in tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py at lines 5716-5724 explicitly asserts that these fields must be prisma.Json instances, not JSON strings:

assert isinstance(model_data["litellm_params"], prisma.Json), (
    f"litellm_params should be prisma.Json for create_many(), got {type(model_data['litellm_params'])}"
)

This change will cause that test to fail. Additionally, Prisma's create_many() for Json fields may not accept raw JSON strings the same way create() does — the original code used prisma.Json() specifically for create_many() compatibility.

If the intent is to remove the prisma import dependency here, the existing test also needs to be updated, and you should verify that create_many() actually accepts JSON strings for Json fields (or use json.loads(safe_dumps(...)) to get back a dict).

Context Used: Rule from dashboard - What: Ensure that any PR claiming to fix an issue includes evidence that the issue is resolved, such... (source)

new_models.append(_dumped)
verbose_proxy_logger.debug("Resetting proxy model table")
async with prisma_client.db.tx() as tx:
Expand Down
24 changes: 24 additions & 0 deletions tests/test_litellm/proxy/auth/test_object_permission_loading.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,21 @@ async def test_get_key_object_loads_object_permission():
vector_stores=["store1"],
)

# Mock proxy_logging_obj to handle async service hooks
mock_proxy_logging_obj = MagicMock()
mock_proxy_logging_obj.service_logging_obj.async_service_success_hook = AsyncMock()
mock_proxy_logging_obj.service_logging_obj.async_service_failure_hook = AsyncMock()

# Mock get_object_permission to return the permission
with patch(
"litellm.proxy.auth.auth_checks.get_object_permission",
AsyncMock(return_value=mock_object_permission)
), patch(
"litellm.proxy.auth.auth_checks._cache_key_object",
AsyncMock()
), patch(
"litellm.proxy.proxy_server.proxy_logging_obj",
mock_proxy_logging_obj
):
result = await get_key_object(
hashed_token="test_token_hash",
Expand Down Expand Up @@ -84,9 +92,17 @@ async def test_get_key_object_no_permission_id():
}
mock_prisma_client.get_data = AsyncMock(return_value=mock_token_data)

# Mock proxy_logging_obj to handle async service hooks
mock_proxy_logging_obj = MagicMock()
mock_proxy_logging_obj.service_logging_obj.async_service_success_hook = AsyncMock()
mock_proxy_logging_obj.service_logging_obj.async_service_failure_hook = AsyncMock()

with patch(
"litellm.proxy.auth.auth_checks._cache_key_object",
AsyncMock()
), patch(
"litellm.proxy.proxy_server.proxy_logging_obj",
mock_proxy_logging_obj
):
result = await get_key_object(
hashed_token="test_token_hash",
Expand Down Expand Up @@ -124,6 +140,11 @@ async def test_get_team_object_loads_object_permission():
vector_stores=["team_store1"],
)

# Mock proxy_logging_obj to handle async service hooks
mock_proxy_logging_obj = MagicMock()
mock_proxy_logging_obj.service_logging_obj.async_service_success_hook = AsyncMock()
mock_proxy_logging_obj.service_logging_obj.async_service_failure_hook = AsyncMock()

with patch(
"litellm.proxy.auth.auth_checks._get_team_db_check",
AsyncMock(return_value=mock_team)
Expand All @@ -138,6 +159,9 @@ async def test_get_team_object_loads_object_permission():
return_value=True
), patch(
"litellm.proxy.auth.auth_checks._update_last_db_access_time"
), patch(
"litellm.proxy.proxy_server.proxy_logging_obj",
mock_proxy_logging_obj
):
result = await get_team_object(
team_id="test_team",
Expand Down
Loading