mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-07 08:24:52 +00:00
fix: merge admin metadata from both metadata and litellm_metadata
Greptile P2: _get_admin_metadata used 'litellm_metadata or metadata', meaning a caller sending a non-empty litellm_metadata would shadow admin config the proxy had injected into data['metadata']. Admin exemptions would be silently ignored. Check both keys and prefer whichever contains admin fields. Add regression test covering the shadowing scenario.
This commit is contained in:
@@ -257,11 +257,20 @@ class CustomGuardrail(CustomLogger):
|
||||
|
||||
@staticmethod
|
||||
def _get_admin_metadata(data: dict) -> dict:
|
||||
"""Return merged admin-configured key and team metadata from the request data."""
|
||||
metadata = data.get("litellm_metadata") or data.get("metadata", {})
|
||||
team_meta = metadata.get("user_api_key_team_metadata") or {}
|
||||
key_meta = metadata.get("user_api_key_metadata") or {}
|
||||
# Key-level settings override team-level
|
||||
"""Return merged admin-configured key and team metadata from the request data.
|
||||
|
||||
The proxy may inject admin metadata (user_api_key_metadata,
|
||||
user_api_key_team_metadata) into either ``metadata`` or
|
||||
``litellm_metadata`` depending on endpoint. Check both so a caller
|
||||
cannot shadow admin config by pre-populating the other key.
|
||||
Key-level settings override team-level.
|
||||
"""
|
||||
team_meta: dict = {}
|
||||
key_meta: dict = {}
|
||||
for key in ("metadata", "litellm_metadata"):
|
||||
meta = data.get(key) or {}
|
||||
team_meta = meta.get("user_api_key_team_metadata") or team_meta
|
||||
key_meta = meta.get("user_api_key_metadata") or key_meta
|
||||
return {**team_meta, **key_meta}
|
||||
|
||||
def get_disable_global_guardrail(self, data: dict) -> Optional[bool]:
|
||||
|
||||
@@ -227,6 +227,20 @@ class TestCustomGuardrailShouldRunGuardrail:
|
||||
)
|
||||
assert result is False, "Admin-configured disable should be respected"
|
||||
|
||||
# Test 5: Admin config in metadata isn't shadowed by user-supplied litellm_metadata
|
||||
data_cross_key = {
|
||||
"model": "gpt-3.5-turbo",
|
||||
"messages": [{"role": "user", "content": "test"}],
|
||||
"metadata": {"user_api_key_metadata": {"disable_global_guardrails": True}},
|
||||
"litellm_metadata": {"request_tags": ["user-supplied"]},
|
||||
}
|
||||
result = custom_guardrail.should_run_guardrail(
|
||||
data=data_cross_key, event_type=GuardrailEventHooks.pre_call
|
||||
)
|
||||
assert (
|
||||
result is False
|
||||
), "Admin config in metadata must not be shadowed by user-supplied litellm_metadata"
|
||||
|
||||
def test_should_run_guardrail_with_opted_out_global_guardrails(self):
|
||||
"""Test that per-guardrail opt-out only works from admin metadata"""
|
||||
from litellm.types.guardrails import GuardrailEventHooks
|
||||
|
||||
Reference in New Issue
Block a user