mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-13 23:11:40 +00:00
fix(proxy): make auth_v2 import-safe and lock its deps so CI/startup don't break
Importing proxy_server registers the auth_v2 router, which pulled casbin in at module load via enforcer.py - so the proxy failed to even start in any env without casbin (CI, minimal installs), regardless of whether auth_v2 was enabled. An opt-in feature must not be a hard import. - enforcer.py imports casbin lazily inside CasbinEnforcer.__init__; authlib in jwt_verifier.py is imported lazily inside the verify/JWKS functions. The package (and the startup router) now import with both deps absent; they are required only when auth_v2 actually builds an enforcer or verifies a JWT. - casbin and authlib were declared in pyproject but missing from uv.lock, so `uv sync --frozen` never installed them. Regenerated the lock (adds casbin, authlib, joserfc, simpleeval) so the deps install where the feature runs. Verified: the v2 package imports with casbin+authlib blocked, and building an enforcer raises a clear ImportError only when casbin is genuinely absent.
This commit is contained in:
parent
fd638b484a
commit
6f9d906abe
3 changed files with 60 additions and 6 deletions
|
|
@ -1,8 +1,6 @@
|
|||
import os
|
||||
from typing import List, Optional, Sequence
|
||||
|
||||
import casbin
|
||||
|
||||
_MODEL_PATH = os.path.join(os.path.dirname(__file__), "model.conf")
|
||||
|
||||
Rule = Sequence[str]
|
||||
|
|
@ -24,6 +22,11 @@ class CasbinEnforcer:
|
|||
resource_groupings: Optional[List[Rule]] = None,
|
||||
domain_groupings: Optional[List[Rule]] = None,
|
||||
):
|
||||
# Imported lazily so merely importing the proxy (or this package, e.g. to
|
||||
# register the policy-admin router) never requires casbin. The dependency
|
||||
# is only needed once auth_v2 is actually enabled and builds an enforcer.
|
||||
import casbin
|
||||
|
||||
self._enforcer = casbin.Enforcer(_MODEL_PATH)
|
||||
self._enforcer.enable_auto_save(False)
|
||||
for rule in policies:
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import time
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from authlib.jose import JsonWebKey, JsonWebToken
|
||||
from authlib.jose.errors import JoseError
|
||||
|
||||
|
||||
class JWTVerificationError(Exception):
|
||||
"""Raised when a token fails signature or standard-claim validation."""
|
||||
|
|
@ -55,6 +52,9 @@ def verify(
|
|||
network). Raises :class:`JWTVerificationError` on any failure so callers
|
||||
never branch on authlib's internal exception types.
|
||||
"""
|
||||
from authlib.jose import JsonWebToken
|
||||
from authlib.jose.errors import JoseError
|
||||
|
||||
decoder = JsonWebToken(algorithms or _DEFAULT_ALGORITHMS)
|
||||
try:
|
||||
claims = decoder.decode(
|
||||
|
|
@ -83,6 +83,7 @@ class JWKSProvider:
|
|||
return self._key_set
|
||||
|
||||
import httpx
|
||||
from authlib.jose import JsonWebKey
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.get(self.jwks_uri)
|
||||
|
|
|
|||
52
uv.lock
generated
52
uv.lock
generated
|
|
@ -9,7 +9,7 @@ resolution-markers = [
|
|||
]
|
||||
|
||||
[options]
|
||||
exclude-newer = "2026-05-28T03:32:27.927695Z"
|
||||
exclude-newer = "0001-01-01T00:00:00Z" # This has no effect and is included for backwards compatibility when using relative exclude-newer values.
|
||||
exclude-newer-span = "P3D"
|
||||
|
||||
[manifest]
|
||||
|
|
@ -423,6 +423,19 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/a2/1f/aa74b23b6eea4cf9b79ace914df59123c4c8e7e4bd32dd22d09c126422d9/aurelio_sdk-0.0.19-py3-none-any.whl", hash = "sha256:390c0212b59ce99116df8722d3badced88c5ef0bb742a6222d479ceed0ed3948", size = 17322, upload-time = "2025-03-24T14:37:31.305Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "authlib"
|
||||
version = "1.7.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cryptography" },
|
||||
{ name = "joserfc" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/36/98/7d93f30d029643c0275dbc0bd6d5a6f670661ee6c9a94d93af7ab4887600/authlib-1.7.2.tar.gz", hash = "sha256:2cea25fefcd4e7173bdf1372c0afc265c8034b23a8cd5dcb6a9164b826c64231", size = 176511, upload-time = "2026-05-06T08:10:23.116Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/95/adcb68e20c34162e9135f370d6e31737719c2b6f94bc953fe7ed1f10fe21/authlib-1.7.2-py2.py3-none-any.whl", hash = "sha256:3e1faedc9d87e7d56a164eca3ccb6ace0d61b94abe83e92242f8dc8bba9b4a9f", size = 259548, upload-time = "2026-05-06T08:10:21.436Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "azure-ai-contentsafety"
|
||||
version = "1.0.0"
|
||||
|
|
@ -655,6 +668,18 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/bf/0f/f897abe4ea0a8c408ae65c8c83bffab4936ad65d6032d4fb4cd35bbdc3ee/cachetools-7.1.1-py3-none-any.whl", hash = "sha256:0335cd7a0952d2b22327441fb0628139e234c565559eeb91a8a4ac7551c5353d", size = 16775, upload-time = "2026-05-03T20:00:27.857Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "casbin"
|
||||
version = "1.43.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "simpleeval" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ad/df/ff2aa55cf0d7c14622ce4f9252cdc34c828c81d4213965d73207ac5434ae/casbin-1.43.0.tar.gz", hash = "sha256:d2e90ce8e72f912877851e94d37999f32c558c6ba7aba0437d483275262e86e0", size = 425727, upload-time = "2025-05-10T06:57:18.902Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/08/07/facef6abd81378e6153b757dc1848621675d971fbc88ebb5d182ebc1c37f/casbin-1.43.0-py3-none-any.whl", hash = "sha256:63a3d1228870250e859ccd94133fe478821093f71dd37f05e0baa0c6fea26623", size = 475059, upload-time = "2025-05-10T06:57:16.89Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2026.4.22"
|
||||
|
|
@ -2735,6 +2760,18 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "joserfc"
|
||||
version = "1.7.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cryptography" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d3/c3/2f590052b55cbdd0ace470ee7ee1f685f6882051be93a9374891005623e2/joserfc-1.7.0.tar.gz", hash = "sha256:4aced6ab0c47846f0a531402aec2419a874b91e918df9c4c9da8a82fb559d6c4", size = 232967, upload-time = "2026-06-02T09:59:34.506Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5b/83/b6b62a66a06ce872d9429a5eb5ee20b2002fd9c331b953c94381c1f7c9f9/joserfc-1.7.0-py3-none-any.whl", hash = "sha256:17e5d7a5a35e65442b05efc435a3d5d46696ffa2c8a2ed0eea6f63fc268e3224", size = 70387, upload-time = "2026-06-02T09:59:33.264Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonlines"
|
||||
version = "4.0.0"
|
||||
|
|
@ -3318,10 +3355,12 @@ mlflow = [
|
|||
]
|
||||
proxy = [
|
||||
{ name = "apscheduler" },
|
||||
{ name = "authlib" },
|
||||
{ name = "azure-identity" },
|
||||
{ name = "azure-storage-blob" },
|
||||
{ name = "backoff" },
|
||||
{ name = "boto3" },
|
||||
{ name = "casbin" },
|
||||
{ name = "cryptography" },
|
||||
{ name = "fastapi" },
|
||||
{ name = "fastapi-sso" },
|
||||
|
|
@ -3472,6 +3511,7 @@ requires-dist = [
|
|||
{ name = "apscheduler", marker = "extra == 'proxy'", specifier = ">=3.11.2,<4.0" },
|
||||
{ name = "audioread", marker = "extra == 'stt-nvidia-riva'", specifier = ">=3.0.1" },
|
||||
{ name = "aurelio-sdk", marker = "python_full_version < '3.14' and extra == 'semantic-router'", specifier = ">=0.0.19,<1.0" },
|
||||
{ name = "authlib", marker = "extra == 'proxy'", specifier = ">=1.6.5,<2.0" },
|
||||
{ name = "azure-ai-contentsafety", marker = "extra == 'proxy-runtime'", specifier = ">=1.0.0,<2.0" },
|
||||
{ name = "azure-identity", marker = "extra == 'extra-proxy'", specifier = ">=1.25.2,<2.0" },
|
||||
{ name = "azure-identity", marker = "extra == 'proxy'", specifier = ">=1.25.2,<2.0" },
|
||||
|
|
@ -3480,6 +3520,7 @@ requires-dist = [
|
|||
{ name = "azure-storage-file-datalake", marker = "extra == 'proxy-runtime'", specifier = ">=12.20.0,<13.0" },
|
||||
{ name = "backoff", marker = "extra == 'proxy'", specifier = ">=2.2.1,<3.0" },
|
||||
{ name = "boto3", marker = "extra == 'proxy'", specifier = ">=1.43.1,<2.0" },
|
||||
{ name = "casbin", marker = "extra == 'proxy'", specifier = ">=1.43.0,<2.0" },
|
||||
{ name = "click", specifier = ">=8.0.0,<9.0" },
|
||||
{ name = "cryptography", marker = "extra == 'proxy'", specifier = ">=46.0.7,<47.0" },
|
||||
{ name = "ddtrace", marker = "extra == 'proxy-runtime'", specifier = ">=2.19.0,<3.0" },
|
||||
|
|
@ -7055,6 +7096,15 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simpleeval"
|
||||
version = "1.0.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b4/9d/e7c9309940794dd3073cba2e5101df5874d84243595ce63b1e1c8f9b9c76/simpleeval-1.0.7.tar.gz", hash = "sha256:1e10e5f9fec597814444e20c0892ed15162fa214c8a88f434b5b077cf2fef85b", size = 30250, upload-time = "2026-03-16T10:53:03.464Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/2f/f32aa85591882378bb43caa09363f3ed97df399369a5144c7f19f2275bc0/simpleeval-1.0.7-py3-none-any.whl", hash = "sha256:97ac271bfd8f2af9e7b9a36ceea67617f26fa873f9d5ae1922f64d4c1442534b", size = 18792, upload-time = "2026-03-16T10:53:02.103Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.17.0"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue