mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-18 04:44:37 +00:00
address review: validate defaulted models against org limits, preserve explicit empty models
Apply default_team_params before _check_org_team_limits so inherited defaults (including models) are validated against the organization's allowlist, and use model_fields_set to distinguish an omitted models field (apply default) from an explicit 'models: []' (unrestricted — preserved). Adds a regression test for the explicit-empty-list case.
This commit is contained in:
parent
301459adf7
commit
27ed550e47
2 changed files with 51 additions and 22 deletions
|
|
@ -1010,6 +1010,31 @@ async def new_team( # noqa: PLR0915
|
|||
},
|
||||
)
|
||||
|
||||
# Apply defaults from litellm.default_team_params for any fields
|
||||
# not explicitly provided in the request. This runs before the org
|
||||
# limit checks below so inherited defaults (e.g. models) are validated
|
||||
# against the organization's allowlist like explicit values.
|
||||
for field in (
|
||||
"max_budget",
|
||||
"budget_duration",
|
||||
"tpm_limit",
|
||||
"rpm_limit",
|
||||
"team_member_permissions",
|
||||
):
|
||||
if getattr(data, field, None) is None:
|
||||
default_value = _get_default_team_param(field)
|
||||
if default_value is not None:
|
||||
setattr(data, field, default_value)
|
||||
|
||||
# `models` defaults to an empty list rather than None on the request, so
|
||||
# use model_fields_set to distinguish "field omitted" (apply the default,
|
||||
# matching SSO-provisioned team behavior) from an explicit `models: []`
|
||||
# (meaning unrestricted access, which must be preserved).
|
||||
if "models" not in data.model_fields_set:
|
||||
default_models = _get_default_team_param("models")
|
||||
if default_models is not None:
|
||||
data.models = default_models
|
||||
|
||||
# check org key limits - done here to handle inheriting org id from team
|
||||
if data.organization_id is not None and prisma_client is not None:
|
||||
org_table = await get_org_object(
|
||||
|
|
@ -1029,28 +1054,6 @@ async def new_team( # noqa: PLR0915
|
|||
prisma_client=prisma_client,
|
||||
)
|
||||
|
||||
# Apply defaults from litellm.default_team_params for any fields
|
||||
# not explicitly provided in the request.
|
||||
for field in (
|
||||
"max_budget",
|
||||
"budget_duration",
|
||||
"tpm_limit",
|
||||
"rpm_limit",
|
||||
"team_member_permissions",
|
||||
):
|
||||
if getattr(data, field, None) is None:
|
||||
default_value = _get_default_team_param(field)
|
||||
if default_value is not None:
|
||||
setattr(data, field, default_value)
|
||||
|
||||
# `models` defaults to an empty list rather than None on the request, so it
|
||||
# needs its own check: apply the configured default when the request did not
|
||||
# specify any models (matches SSO-provisioned team behavior).
|
||||
if not getattr(data, "models", None):
|
||||
default_models = _get_default_team_param("models")
|
||||
if default_models is not None:
|
||||
data.models = default_models
|
||||
|
||||
# Legacy fallback: apply max_budget from default_team_settings (YAML config)
|
||||
# if still not set after checking default_team_params.
|
||||
if data.max_budget is None:
|
||||
|
|
|
|||
|
|
@ -342,6 +342,32 @@ class TestNewTeamDefaultParamsApplied:
|
|||
|
||||
assert data.models == ["claude-3-5-sonnet"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_models_explicit_empty_list_not_overridden(self, monkeypatch):
|
||||
"""An explicit `models: []` means unrestricted access and must be preserved,
|
||||
distinguished from an omitted field via model_fields_set."""
|
||||
from litellm.proxy.management_endpoints.team_endpoints import new_team
|
||||
|
||||
monkeypatch.setattr(
|
||||
litellm,
|
||||
"default_team_params",
|
||||
{"models": ["gpt-4"]},
|
||||
)
|
||||
|
||||
data = NewTeamRequest(team_alias="my-team", models=[])
|
||||
auth = self._make_admin_auth()
|
||||
|
||||
try:
|
||||
await new_team(
|
||||
data=data,
|
||||
user_api_key_dict=auth,
|
||||
http_request=MagicMock(),
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
assert data.models == []
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_no_defaults_when_config_is_none(self, monkeypatch):
|
||||
"""When default_team_params is None, no defaults applied."""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue