mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-09 03:18:44 +00:00
fix(ovalix): send the raw user identifier (empty when absent), not its hash, as the tracker actor
This commit is contained in:
parent
fa0d3ea14c
commit
8b7a8bf73b
2 changed files with 43 additions and 4 deletions
|
|
@ -196,12 +196,12 @@ class OvalixGuardrail(CustomGuardrail):
|
|||
return metadata["user_api_key_user_email"]
|
||||
if metadata.get("user_api_key_user_id"):
|
||||
return metadata["user_api_key_user_id"]
|
||||
return "unknown"
|
||||
return ""
|
||||
|
||||
def _get_tracker_actor_id(self, data: dict) -> str:
|
||||
"""Normalize the actor string into a short, stable id for Tracker API payloads."""
|
||||
# NOTE: this hash is purely for normalization — it collapses an arbitrary actor
|
||||
# string (email, user id, or "unknown") into a compact, fixed-length, consistent
|
||||
# string (email, user id, or empty) into a compact, fixed-length, consistent
|
||||
# key. It is not a privacy/security measure and the actor value is not sensitive,
|
||||
# so a plain SHA-256 (truncated) is sufficient; no salting/KDF is needed here.
|
||||
actor_id = self._get_actor(data).encode()
|
||||
|
|
@ -311,7 +311,7 @@ class OvalixGuardrail(CustomGuardrail):
|
|||
logging_obj: Optional[Any] = None,
|
||||
) -> GenericGuardrailAPIInputs:
|
||||
routing = await self._resolve_routing(request_data)
|
||||
actor = self._get_tracker_actor_id(request_data)
|
||||
actor = self._get_actor(request_data)
|
||||
session_id = self._get_session_id_for_application(request_data, routing.application_id)
|
||||
is_response = input_type == "response"
|
||||
|
||||
|
|
|
|||
|
|
@ -590,7 +590,7 @@ class TestOvalixGuardrail:
|
|||
assert guardrail._get_actor({"metadata": {"user_api_key_user_email": "a@b.com"}}) == "a@b.com"
|
||||
assert guardrail._get_actor({"metadata": {"user_api_key_user_id": "uid-1"}}) == "uid-1"
|
||||
assert guardrail._get_actor({"litellm_metadata": {"user_api_key_user_id": "uid-2"}}) == "uid-2"
|
||||
assert guardrail._get_actor({}) == "unknown"
|
||||
assert guardrail._get_actor({}) == ""
|
||||
finally:
|
||||
for k in _ovalix_env():
|
||||
if k in os.environ:
|
||||
|
|
@ -994,6 +994,45 @@ async def test_all_allow_passes_through():
|
|||
assert result["texts"] == ["hi"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_actor_sent_to_tracker_is_raw_identifier_not_hash():
|
||||
g = _static_guardrail()
|
||||
request_data = {"metadata": {"user_api_key_user_email": "user@example.com"}}
|
||||
inputs = GenericGuardrailAPIInputs(texts=["hi"])
|
||||
seen = {}
|
||||
|
||||
async def _post(url, headers=None, json=None):
|
||||
seen["last"] = json
|
||||
r = MagicMock()
|
||||
r.json.return_value = _ALLOW
|
||||
r.raise_for_status = MagicMock()
|
||||
return r
|
||||
|
||||
with patch.object(g._async_handler, "post", new=_post):
|
||||
await g.apply_guardrail(inputs=inputs, request_data=request_data, input_type="request", logging_obj=None)
|
||||
assert seen["last"]["actor"] == "user@example.com"
|
||||
assert seen["last"]["session_id"] != "user@example.com"
|
||||
assert g._get_tracker_actor_id(request_data) in seen["last"]["session_id"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_empty_user_sends_empty_actor_matching_reference():
|
||||
g = _static_guardrail()
|
||||
inputs = GenericGuardrailAPIInputs(texts=["hi"])
|
||||
seen = {}
|
||||
|
||||
async def _post(url, headers=None, json=None):
|
||||
seen["last"] = json
|
||||
r = MagicMock()
|
||||
r.json.return_value = _ALLOW
|
||||
r.raise_for_status = MagicMock()
|
||||
return r
|
||||
|
||||
with patch.object(g._async_handler, "post", new=_post):
|
||||
await g.apply_guardrail(inputs=inputs, request_data={}, input_type="request", logging_obj=None)
|
||||
assert seen["last"]["actor"] == ""
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_tool_result_content_skipped_on_text_path():
|
||||
g = _static_guardrail()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue