mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-06 08:16:43 +00:00
fix: keep body tags visible to _tag_max_budget_check pre-auth
Stripping body-supplied tags in apply_client_tag_policy_pre_auth silently disabled per-tag budget enforcement for non-opted-in keys — pre-PR behavior was that those tags reached _tag_max_budget_check inside common_checks. The post-auth strip in add_litellm_data_to_request continues to remove unauthorized tags before they leave the proxy. Also moves the LiteLLMProxyRequestSetup import to module-level (no circular dep with auth/user_api_key_auth.py). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
36caeb013b
commit
4fc0f1d8f6
3 changed files with 22 additions and 20 deletions
|
|
@ -67,6 +67,7 @@ from litellm.proxy.common_utils.http_parsing_utils import (
|
|||
populate_request_with_path_params,
|
||||
)
|
||||
from litellm.proxy.common_utils.realtime_utils import _realtime_request_body
|
||||
from litellm.proxy.litellm_pre_call_utils import LiteLLMProxyRequestSetup
|
||||
from litellm.proxy.utils import (
|
||||
PrismaClient,
|
||||
ProxyLogging,
|
||||
|
|
@ -1939,13 +1940,10 @@ async def _run_centralized_common_checks(
|
|||
llm_router=llm_router,
|
||||
)
|
||||
|
||||
# Merge x-litellm-tags (or strip body tags when the key/team has not
|
||||
# opted in via allow_client_tags) into request_data BEFORE common_checks
|
||||
# runs. _tag_max_budget_check inside common_checks only inspects
|
||||
# request_data; without this pre-merge, header-supplied tags bypass
|
||||
# tag-budget enforcement.
|
||||
from litellm.proxy.litellm_pre_call_utils import LiteLLMProxyRequestSetup
|
||||
|
||||
# Merge x-litellm-tags into request_data BEFORE common_checks runs.
|
||||
# _tag_max_budget_check inside common_checks only inspects request_data;
|
||||
# without this pre-merge, header-supplied tags bypass tag-budget
|
||||
# enforcement.
|
||||
LiteLLMProxyRequestSetup.apply_client_tag_policy_pre_auth(
|
||||
request=request,
|
||||
request_data=request_data,
|
||||
|
|
|
|||
|
|
@ -1217,15 +1217,12 @@ class LiteLLMProxyRequestSetup:
|
|||
break
|
||||
|
||||
if not _admin_allow_client_tags:
|
||||
# Strip any caller-supplied tags so the budget gate doesn't act
|
||||
# on tags this key/team isn't authorized to set. Matches the
|
||||
# post-auth strip in add_litellm_data_to_request.
|
||||
for _meta_key in ("metadata", "litellm_metadata"):
|
||||
_user_meta = request_data.get(_meta_key)
|
||||
if isinstance(_user_meta, dict) and "tags" in _user_meta:
|
||||
_user_meta.pop("tags", None)
|
||||
if "tags" in request_data:
|
||||
request_data.pop("tags", None)
|
||||
# Don't strip body-supplied tags here — pre-PR behavior was that
|
||||
# _tag_max_budget_check (inside common_checks) saw and enforced
|
||||
# per-tag budgets on body tags regardless of allow_client_tags.
|
||||
# Stripping pre-auth would silently disable that enforcement.
|
||||
# The post-auth strip in add_litellm_data_to_request still
|
||||
# removes unauthorized tags before they leave the proxy.
|
||||
return
|
||||
|
||||
headers = _safe_get_request_headers(request=request)
|
||||
|
|
|
|||
|
|
@ -4110,7 +4110,14 @@ class TestApplyClientTagPolicyPreAuth:
|
|||
# Existing tags first, dedupe header tags
|
||||
assert data["metadata"]["tags"] == ["env:prod", "team:platform", "tenant:acme"]
|
||||
|
||||
def test_strips_body_tags_when_not_opted_in(self):
|
||||
def test_preserves_body_tags_when_not_opted_in(self):
|
||||
# Pre-auth must NOT strip body-supplied tags for non-opted-in keys.
|
||||
# _tag_max_budget_check (inside common_checks) enforces per-tag
|
||||
# budgets on whatever tags it sees in request_data, and pre-PR
|
||||
# behavior was that body tags hit that check regardless of
|
||||
# allow_client_tags. The post-auth strip in add_litellm_data_to_request
|
||||
# cleans them up before they leave the proxy — that's covered by a
|
||||
# separate regression test.
|
||||
request_mock = _build_request_mock_with_headers(
|
||||
{"x-litellm-tags": "tenant:acme"}
|
||||
)
|
||||
|
|
@ -4132,9 +4139,9 @@ class TestApplyClientTagPolicyPreAuth:
|
|||
user_api_key_dict=user_api_key_dict,
|
||||
)
|
||||
|
||||
assert "tags" not in data
|
||||
assert "tags" not in data["metadata"]
|
||||
assert "tags" not in data["litellm_metadata"]
|
||||
assert data["tags"] == ["root-tag"]
|
||||
assert data["metadata"]["tags"] == ["meta-tag"]
|
||||
assert data["litellm_metadata"]["tags"] == ["litellm-meta-tag"]
|
||||
|
||||
def test_does_not_merge_header_tags_when_not_opted_in(self):
|
||||
# Even with the header set, no opt-in means the header is ignored
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue