mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
fix(jwt): surface DB-fallback membership lookup failures at warning level
A transient get_team_membership failure on the DB team fallback path is recoverable: the team is still resolved and the request proceeds, just without per-team membership budget enforcement for that request. Logging that at debug hid a silent budget-enforcement gap from operators, so it now logs at warning and states that enforcement was skipped. Behavior is otherwise unchanged: the resolved team is returned with a None membership rather than failing the request, covered by test_resolve_db_team_fallback_survives_membership_lookup_error.
This commit is contained in:
parent
9911998e62
commit
4a2b0c0696
2 changed files with 53 additions and 2 deletions
|
|
@ -2038,8 +2038,9 @@ class JWTAuthManager:
|
|||
),
|
||||
)
|
||||
except Exception:
|
||||
verbose_proxy_logger.debug(
|
||||
"JWT DB team fallback: membership lookup failed for team_id=%s",
|
||||
verbose_proxy_logger.warning(
|
||||
"JWT DB team fallback: membership lookup failed for team_id=%s; "
|
||||
"proceeding without per-team membership budget enforcement",
|
||||
candidate_team_id,
|
||||
exc_info=True,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4827,6 +4827,56 @@ async def test_resolve_db_team_fallback_loads_team_membership():
|
|||
assert team_membership.budget_id == "budget_xyz"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_resolve_db_team_fallback_survives_membership_lookup_error():
|
||||
"""A transient membership-lookup failure must not deny an otherwise-authorized
|
||||
request: the resolved team is still returned with a None membership (budget
|
||||
enforcement degrades gracefully) instead of the error propagating as a 403."""
|
||||
user_object = LiteLLM_UserTable(
|
||||
user_id="u_flaky",
|
||||
user_role=LitellmUserRoles.INTERNAL_USER,
|
||||
teams=["team_flaky"],
|
||||
)
|
||||
|
||||
async def fake_get_team(team_id, **kwargs):
|
||||
return LiteLLM_TeamTable(team_id=team_id)
|
||||
|
||||
async def boom_get_membership(user_id, team_id, **kwargs):
|
||||
raise Exception("transient DB error")
|
||||
|
||||
with (
|
||||
patch(
|
||||
"litellm.proxy.auth.handle_jwt.get_team_object",
|
||||
new_callable=AsyncMock,
|
||||
side_effect=fake_get_team,
|
||||
),
|
||||
patch(
|
||||
"litellm.proxy.auth.handle_jwt.get_team_membership",
|
||||
new_callable=AsyncMock,
|
||||
side_effect=boom_get_membership,
|
||||
),
|
||||
):
|
||||
(
|
||||
team_id,
|
||||
team_object,
|
||||
team_membership,
|
||||
) = await JWTAuthManager._resolve_db_team_fallback(
|
||||
user_object=user_object,
|
||||
user_id="u_flaky",
|
||||
requested_model=None,
|
||||
enforce_team_based_model_access=True,
|
||||
team_id_upsert=False,
|
||||
prisma_client=None,
|
||||
user_api_key_cache=MagicMock(),
|
||||
parent_otel_span=None,
|
||||
proxy_logging_obj=MagicMock(),
|
||||
)
|
||||
|
||||
assert team_id == "team_flaky"
|
||||
assert team_object is not None
|
||||
assert team_membership is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_auth_builder_db_fallback_does_not_validate_rbac_team_against_db_membership():
|
||||
"""When fallback_to_db_teams is on and the JWT carries an RBAC team role but no
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue