mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-06 06:24:16 +00:00
Allow deleting key expiry
This commit is contained in:
@@ -507,7 +507,11 @@ async def _common_key_generation_helper( # noqa: PLR0915
|
||||
upperbound_duration = duration_in_seconds(
|
||||
duration=upperbound_value
|
||||
)
|
||||
user_duration = duration_in_seconds(duration=value)
|
||||
# Handle special case where duration is "-1" (never expires)
|
||||
if value == "-1":
|
||||
user_duration = float('inf') # Infinite duration
|
||||
else:
|
||||
user_duration = duration_in_seconds(duration=value)
|
||||
if user_duration > upperbound_duration:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
@@ -1339,7 +1343,10 @@ async def prepare_key_update_data(
|
||||
|
||||
if "duration" in non_default_values:
|
||||
duration = non_default_values.pop("duration")
|
||||
if duration and (isinstance(duration, str)) and len(duration) > 0:
|
||||
if duration == "-1":
|
||||
# Set expires to None to indicate the key never expires
|
||||
non_default_values["expires"] = None
|
||||
elif duration and (isinstance(duration, str)) and len(duration) > 0:
|
||||
duration_s = duration_in_seconds(duration=duration)
|
||||
expires = datetime.now(timezone.utc) + timedelta(seconds=duration_s)
|
||||
non_default_values["expires"] = expires
|
||||
@@ -1452,7 +1459,7 @@ async def update_key_fn(
|
||||
- tpm_limit_type: Optional[str] - TPM rate limit type - "best_effort_throughput", "guaranteed_throughput", or "dynamic"
|
||||
- rpm_limit_type: Optional[str] - RPM rate limit type - "best_effort_throughput", "guaranteed_throughput", or "dynamic"
|
||||
- allowed_cache_controls: Optional[list] - List of allowed cache control values
|
||||
- duration: Optional[str] - Key validity duration ("30d", "1h", etc.)
|
||||
- duration: Optional[str] - Key validity duration ("30d", "1h", etc.) or "-1" to never expire
|
||||
- permissions: Optional[dict] - Key-specific permissions
|
||||
- send_invite_email: Optional[bool] - Send invite email to user_id
|
||||
- guardrails: Optional[List[str]] - List of active guardrails for the key
|
||||
|
||||
@@ -678,6 +678,11 @@ async def test_prepare_key_update_data():
|
||||
updated_data = await prepare_key_update_data(data, existing_key_row)
|
||||
assert updated_data["metadata"] is None
|
||||
|
||||
# Test duration "-1" sets expires to None (never expires)
|
||||
data = UpdateKeyRequest(key="test_key", duration="-1")
|
||||
updated_data = await prepare_key_update_data(data, existing_key_row)
|
||||
assert updated_data["expires"] is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"env_vars, expected_url",
|
||||
|
||||
@@ -815,6 +815,37 @@ async def test_update_service_account_works_with_team_id():
|
||||
await prepare_key_update_data(data=data, existing_key_row=existing_key)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_prepare_key_update_data_duration_never_expires():
|
||||
"""Test that duration="-1" sets expires to None (never expires)."""
|
||||
from litellm.proxy._types import UpdateKeyRequest
|
||||
from litellm.proxy.management_endpoints.key_management_endpoints import (
|
||||
prepare_key_update_data,
|
||||
)
|
||||
|
||||
# Mock existing key
|
||||
existing_key = LiteLLM_VerificationToken(
|
||||
token="test-token",
|
||||
key_alias="test-key",
|
||||
models=["gpt-3.5-turbo"],
|
||||
user_id="test-user",
|
||||
team_id=None,
|
||||
auto_rotate=False,
|
||||
rotation_interval=None,
|
||||
metadata={},
|
||||
)
|
||||
|
||||
# Test setting duration to "-1" (never expires)
|
||||
update_request = UpdateKeyRequest(key="test-token", duration="-1")
|
||||
|
||||
result = await prepare_key_update_data(
|
||||
data=update_request, existing_key_row=existing_key
|
||||
)
|
||||
|
||||
# Verify that expires is set to None
|
||||
assert result["expires"] is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_validate_team_id_used_in_service_account_request_requires_team_id():
|
||||
"""
|
||||
|
||||
@@ -64,13 +64,13 @@ const KeyLifecycleSettings: React.FC<KeyLifecycleSettingsProps> = ({
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-gray-700 flex items-center space-x-1">
|
||||
<span>Expire Key</span>
|
||||
<Tooltip title="Set when this key should expire. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days)">
|
||||
<Tooltip title="Set when this key should expire. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days). Use -1 to never expire.">
|
||||
<InfoCircleOutlined className="text-gray-400 cursor-help text-xs" />
|
||||
</Tooltip>
|
||||
</label>
|
||||
<TextInput
|
||||
name="duration"
|
||||
placeholder="e.g., 30d"
|
||||
placeholder="e.g., 30d or -1 to never expire"
|
||||
className="w-full"
|
||||
value={durationValue}
|
||||
onValueChange={handleDurationChange}
|
||||
|
||||
Reference in New Issue
Block a user