Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
b8e367d
🐛 fix(proxy_server): remove redundant decryption of already-decrypted…
danielaskdd Mar 25, 2026
9ef938a
✅ test(proxy_unit_tests): update decrypt_value_helper mock in callbac…
danielaskdd Mar 25, 2026
b8adffc
✨ feat(proxy): decrypt env vars in get_config for both DB and YAML modes
danielaskdd Mar 26, 2026
687b1c1
🐛 fix(health_endpoints): resolve TEST_EMAIL_ADDRESS not read from DB …
danielaskdd Mar 26, 2026
631942d
Merge branch 'main' into fix/redundant-decrption
danielaskdd Apr 1, 2026
9f87504
Modify docker-compose and license check for development mode
danielaskdd Nov 25, 2025
0aaa70f
Merge branch 'fix/redundant-decrption' into v1.83-stable-ydh
danielaskdd Apr 1, 2026
aa19b74
Merge branch 'main' into fix/redundant-decrption
danielaskdd Apr 1, 2026
8d4b8ce
✨ feat(health): add database-backed test email resolution for email h…
danielaskdd Apr 1, 2026
5396db6
Merge branch 'fix/redundant-decrption' into v1.83-stable-ydh
danielaskdd Apr 1, 2026
277e398
♻️ refactor(health_endpoints): eliminate proxy startup import cycles
danielaskdd Apr 1, 2026
70be621
Merge branch 'fix/redundant-decrption' into v1.83-stable-ydh
danielaskdd Apr 1, 2026
1096682
♻️ refactor(health_endpoints): eliminate proxy import cycles in healt…
danielaskdd Apr 1, 2026
e2a3ccc
♻️ refactor(health_endpoints): eliminate proxy import cycles in healt…
danielaskdd Apr 1, 2026
efa29a1
Merge branch 'fix/redundant-decrption' into v1.83-stable-ydh
danielaskdd Apr 1, 2026
d341828
♻️ refactor(health_endpoints): extract encryption utilities and updat…
danielaskdd Apr 1, 2026
c87f7c8
♻️ refactor(encrypt_decrypt): extract signing key logic to dedicated …
danielaskdd Apr 1, 2026
5f076ae
Merge branch 'fix/redundant-decrption' into v1.83-stable-ydh
danielaskdd Apr 1, 2026
11067f2
🔧 chore(docker): update container registry and disable prometheus
danielaskdd Apr 1, 2026
38ee440
🔧 chore(litellm_license): update default license limits
danielaskdd Apr 1, 2026
ff3d0a1
Merge branch 'main' into main-ydh
danielaskdd Apr 1, 2026
f5adcd1
Merge branch 'main' into v1.83-stable-ydh
danielaskdd Apr 1, 2026
379b457
Merge branch 'main' into main-ydh
danielaskdd Apr 3, 2026
6ac70a8
Merge branch 'main' into v1.83-stable-ydh
danielaskdd Apr 3, 2026
a7e997f
📦 build(Dockerfile): update base image and python development package
danielaskdd Apr 3, 2026
eb6e9ca
Merge branch 'main' into main-ydh
danielaskdd Apr 5, 2026
a0d5e12
Merge branch 'main-ydh' into v1.83-stable-ydh
danielaskdd Apr 5, 2026
eadf195
✨ feat(assets): add dashscope provider logo
danielaskdd Apr 6, 2026
674104c
Merge branch 'main' into v1.83-stable-ydh
danielaskdd Apr 9, 2026
8f7e03c
🔧 chore(docker): restructure compose configuration for environment se…
danielaskdd Apr 9, 2026
f4dbea5
Merge branch 'main' into v1.83-stable-ydh
danielaskdd Apr 9, 2026
8fe2a95
Merge branch 'main' into v1.83-stable-ydh
danielaskdd Apr 10, 2026
0f8dbae
Merge branch 'main' into v1.83-stable-ydh
danielaskdd Apr 10, 2026
f500b8a
Merge branch 'main' into v1.83-stable-ydh
danielaskdd Apr 10, 2026
5ad3987
Merge branch 'main' into v1.83-stable-ydh
danielaskdd Apr 11, 2026
1e458e9
Merge tag 'v1.83.7.rc.1' into v1.83-stable-ydh
danielaskdd Apr 13, 2026
b5de153
Merge branch 'main' into v1.83-stable-ydh
danielaskdd Apr 14, 2026
e313ad3
Merge branch 'main' into v1.83-stable-ydh
danielaskdd Apr 17, 2026
aa9cb5b
🔧 chore(docker): add restart policies to services
danielaskdd Apr 19, 2026
a5f8def
Merge branch 'main' into v1.83-stable-ydh
danielaskdd Apr 21, 2026
67e7753
Merge branch 'main' into v1.83-stable-ydh
danielaskdd Apr 23, 2026
741962b
🐛 fix(reset_budget_job): fix prisma json null filter compatibility
danielaskdd Apr 23, 2026
3eaf151
🐛 fix(reset_budget_job): fix prisma json null filter compatibility
danielaskdd Apr 23, 2026
822132b
♻️ refactor(reset_budget_job): use prisma json filter for budget_limi…
danielaskdd Apr 23, 2026
ca812fb
⚡ fix(reset_budget_job): use query_raw to filter budget_limits IS NOT…
danielaskdd Apr 23, 2026
1a16456
Merge branch 'fix-reset-bugget' into v1.83-stable-ydh
danielaskdd Apr 23, 2026
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
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Base image for building
ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:a5a619c1793039dcf92f02178f37c94bb3d6001403716da59d6092dfe8d9b502
ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:52e71f61c6afd1f8d2625cff4465d8ecee156668ca665f7e9c582d1cc914eb6a

# Runtime image
ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:a5a619c1793039dcf92f02178f37c94bb3d6001403716da59d6092dfe8d9b502
Expand Down
17 changes: 17 additions & 0 deletions docker-compose.override.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
services:
litellm:
image: ghcr.io/danielaskdd/litellm/litellm:main-stable
volumes:
- ./config.yaml:/app/config.yaml
command:
- "--config=/app/config.yaml"
extra_hosts:
- "host.docker.internal:host-gateway"
restart: unless-stopped

db:
restart: unless-stopped

prometheus:
deploy:
replicas: 0
38 changes: 38 additions & 0 deletions litellm/proxy/_experimental/out/assets/logos/dashscope.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
51 changes: 17 additions & 34 deletions litellm/proxy/auth/litellm_license.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,18 @@ def __init__(self) -> None:
self._premium_check_logged = False
self.public_key = None
self.read_public_key()
self.airgapped_license_data: Optional["EnterpriseLicenseData"] = None

# 🔧 Modified for development: Permanent enterprise license data
from datetime import datetime, timedelta
from litellm.proxy._types import EnterpriseLicenseData

self.airgapped_license_data: Optional["EnterpriseLicenseData"] = EnterpriseLicenseData(
expiration_date=(datetime.now() + timedelta(days=36500)).strftime("%Y-%m-%d"), # 100 years
user_id="dev_enterprise_user",
allowed_features=["all"],
max_users=100, # User limit
max_teams=200 # Team limit
)

def read_public_key(self):
try:
Expand Down Expand Up @@ -96,42 +107,14 @@ def _verify(self, license_str: str) -> bool:

def is_premium(self) -> bool:
"""
🔧 Modified for development: Always returns True to enable enterprise features

Original behavior:
1. verify_license_without_api_request: checks if license was generate using private / public key pair
2. _verify: checks if license is valid calling litellm API. This is the old way we were generating/validating license
"""
try:
if not self._premium_check_logged:
verbose_proxy_logger.debug(
"litellm.proxy.auth.litellm_license.py::is_premium() - ENTERING 'IS_PREMIUM' - LiteLLM License={}".format(
self.license_str
)
)

if self.license_str is None:
self.license_str = os.getenv("LITELLM_LICENSE", None)

if not self._premium_check_logged:
verbose_proxy_logger.debug(
"litellm.proxy.auth.litellm_license.py::is_premium() - Updated 'self.license_str' - {}".format(
self.license_str
)
)
self._premium_check_logged = True

if self.license_str is None:
return False
elif (
self.verify_license_without_api_request(
public_key=self.public_key, license_key=self.license_str
)
is True
):
return True
elif self._verify(license_str=self.license_str) is True:
return True
return False
except Exception:
return False
# 🔧 Development mode: Always return True
return True

def is_over_limit(self, total_users: int) -> bool:
"""
Expand Down
11 changes: 2 additions & 9 deletions litellm/proxy/common_utils/encrypt_decrypt_utils.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
import base64
import os
from typing import Literal, Optional

from litellm._logging import verbose_proxy_logger
from litellm.proxy.common_utils.signing_key_utils import get_proxy_signing_key


def _get_salt_key():
from litellm.proxy.proxy_server import master_key

salt_key = os.getenv("LITELLM_SALT_KEY", None)

if salt_key is None:
salt_key = master_key

return salt_key
return get_proxy_signing_key()


def encrypt_value_helper(value: str, new_encryption_key: Optional[str] = None):
Expand Down
32 changes: 20 additions & 12 deletions litellm/proxy/common_utils/reset_budget_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -632,28 +632,35 @@ async def reset_budget_windows(self) -> None:

now = datetime.utcnow()

# Use query_raw to push the "budget_limits IS NOT NULL" filter to the DB
# and project only the two columns we need. The ORM path is blocked here:
# prisma-client-py rejects {"not": None} on Json? fields and has no
# select= kwarg, so a plain find_many() would scan both wide tables in
# full on every tick. Updates still go through the ORM below.

# --- Keys ---
try:
all_keys = await self.prisma_client.db.litellm_verificationtoken.find_many(
where={"budget_limits": {"not": None}} # type: ignore[arg-type]
key_rows = await self.prisma_client.db.query_raw(
'SELECT token, budget_limits FROM "LiteLLM_VerificationToken" '
"WHERE budget_limits IS NOT NULL"
)
for key in all_keys:
raw = key.budget_limits # type: ignore[attr-defined]
for key in key_rows or []:
raw = key["budget_limits"]
if not raw:
continue
windows: list = raw if isinstance(raw, list) else json.loads(raw)
changed = False
for window in windows:
counter_key = (
f"spend:key:{key.token}:window:{window['budget_duration']}"
f"spend:key:{key['token']}:window:{window['budget_duration']}"
)
if await ResetBudgetJob._reset_expired_window(
window, counter_key, spend_counter_cache, now
):
changed = True
if changed:
await self.prisma_client.db.litellm_verificationtoken.update(
where={"token": key.token},
where={"token": key["token"]},
data={"budget_limits": json.dumps(windows)}, # type: ignore[arg-type]
)
except Exception as e:
Expand All @@ -663,26 +670,27 @@ async def reset_budget_windows(self) -> None:

# --- Teams ---
try:
all_teams = await self.prisma_client.db.litellm_teamtable.find_many(
where={"budget_limits": {"not": None}} # type: ignore[arg-type]
team_rows = await self.prisma_client.db.query_raw(
'SELECT team_id, budget_limits FROM "LiteLLM_TeamTable" '
"WHERE budget_limits IS NOT NULL"
)
for team in all_teams:
raw = team.budget_limits # type: ignore[attr-defined]
for team in team_rows or []:
raw = team["budget_limits"]
if not raw:
continue
windows = raw if isinstance(raw, list) else json.loads(raw)
changed = False
for window in windows:
counter_key = (
f"spend:team:{team.team_id}:window:{window['budget_duration']}"
f"spend:team:{team['team_id']}:window:{window['budget_duration']}"
)
if await ResetBudgetJob._reset_expired_window(
window, counter_key, spend_counter_cache, now
):
changed = True
if changed:
await self.prisma_client.db.litellm_teamtable.update(
where={"team_id": team.team_id},
where={"team_id": team["team_id"]},
data={"budget_limits": json.dumps(windows)}, # type: ignore[arg-type]
)
except Exception as e:
Expand Down
17 changes: 17 additions & 0 deletions litellm/proxy/common_utils/signing_key_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import os
import sys
from typing import Optional


def get_proxy_signing_key() -> Optional[str]:
salt_key = os.getenv("LITELLM_SALT_KEY")
if salt_key is not None:
return salt_key

proxy_server_module = sys.modules.get("litellm.proxy.proxy_server")
if proxy_server_module is not None:
proxy_master_key = getattr(proxy_server_module, "master_key", None)
if isinstance(proxy_master_key, str):
return proxy_master_key

return os.getenv("LITELLM_MASTER_KEY")
Loading