mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-12 08:42:18 +00:00
fix(proxy): reject expires on key requests
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
8884f461af
commit
073df7b8f5
2 changed files with 43 additions and 7 deletions
|
|
@ -54,6 +54,16 @@ class LiteLLMKeyType(str, enum.Enum):
|
|||
DEFAULT = "default" # Uses default allowed routes
|
||||
|
||||
|
||||
def _is_mapping(value: object) -> TypeIs[Mapping[object, object]]: # guard-ok: raw before-validator payload
|
||||
return isinstance(value, Mapping)
|
||||
|
||||
|
||||
def _reject_expires(values: object) -> object:
|
||||
if _is_mapping(values) and "expires" in values:
|
||||
raise ValueError('expires is not supported on key requests. Set duration instead, e.g. "3600s" or "30d"')
|
||||
return values
|
||||
|
||||
|
||||
class GenerateKeyRequest(KeyRequestBase):
|
||||
soft_budget: float | None = None
|
||||
send_invite_email: bool | None = None
|
||||
|
|
@ -69,6 +79,11 @@ class GenerateKeyRequest(KeyRequestBase):
|
|||
organization_id: str | None = None
|
||||
project_id: str | None = None
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def reject_expires(cls, values: object) -> object:
|
||||
return _reject_expires(values)
|
||||
|
||||
@field_validator("team_id", "organization_id", "project_id", mode="before")
|
||||
@classmethod
|
||||
def treat_cleared_id_as_unset(cls, v: object) -> object:
|
||||
|
|
@ -77,10 +92,6 @@ class GenerateKeyRequest(KeyRequestBase):
|
|||
return v
|
||||
|
||||
|
||||
def _is_mapping(value: object) -> TypeIs[Mapping[object, object]]: # guard-ok: raw before-validator payload
|
||||
return isinstance(value, Mapping)
|
||||
|
||||
|
||||
class UpdateKeyRequest(KeyRequestBase):
|
||||
# Note: the defaults of all Params here MUST BE NONE
|
||||
# else they will get overwritten
|
||||
|
|
@ -99,6 +110,11 @@ class UpdateKeyRequest(KeyRequestBase):
|
|||
description="Omit to retain the project, or send null to detach. Assigning a different project is not supported.",
|
||||
)
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def reject_expires(cls, values: object) -> object:
|
||||
return _reject_expires(values)
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def drop_blank_team_id(cls, values: object) -> object:
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ from fastapi.testclient import TestClient
|
|||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from fastapi import HTTPException
|
||||
from pydantic import JsonValue
|
||||
from pydantic import JsonValue, ValidationError
|
||||
|
||||
import inspect
|
||||
|
||||
|
|
@ -108,6 +108,28 @@ from litellm.types.proxy.management_endpoints.key_management_endpoints import (
|
|||
client = TestClient(app)
|
||||
|
||||
|
||||
def test_key_request_models_reject_expires() -> None:
|
||||
for request_model, request_values in (
|
||||
(GenerateKeyRequest, {"expires": "2026-01-01T00:00:00Z"}),
|
||||
(UpdateKeyRequest, {"key": "sk-x", "expires": "2026-01-01T00:00:00Z"}),
|
||||
(RegenerateKeyRequest, {"expires": "2026-01-01T00:00:00Z"}),
|
||||
(GenerateKeyRequest, {"expires": None}),
|
||||
):
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
request_model.model_validate(request_values)
|
||||
assert "duration" in str(exc_info.value)
|
||||
|
||||
|
||||
def test_generate_key_response_preserves_expires() -> None:
|
||||
expires: Final = datetime(2026, 1, 1, tzinfo=timezone.utc)
|
||||
|
||||
assert GenerateKeyResponse(key="sk-x", expires=expires).expires == expires
|
||||
|
||||
|
||||
def test_generate_key_request_accepts_duration_without_expires() -> None:
|
||||
assert GenerateKeyRequest.model_validate({"duration": "1h"}).duration == "1h"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_keys():
|
||||
mock_prisma_client = AsyncMock()
|
||||
|
|
@ -23305,5 +23327,3 @@ def test_key_info_database_not_connected_sanitized_500(
|
|||
finally:
|
||||
proxy_server.app.dependency_overrides.pop(user_api_key_auth, None)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue