mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-02 07:13:02 +00:00
fix(proxy): retain the addressed comparison response id and authorize only the effective prompt_cache_options
The hook keeps the encrypted comparison id under _litellm_addressed_comparison_response_id, a registered LiteLLM-owned kwarg that never reaches a provider, so a repeated hook run re-checks ownership for the current caller. When extra_body carries prompt_cache_options it replaces the top-level value as a whole, so only that effective value is authorized and rewritten Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
1bbb32b697
commit
ad006b9542
3 changed files with 31 additions and 28 deletions
|
|
@ -24,7 +24,13 @@ from litellm.types.llms.openai import (
|
|||
BaseLiteLLMOpenAIResponseObject,
|
||||
ResponsesAPIResponse,
|
||||
)
|
||||
from litellm.types.utils import ADDRESSED_RESPONSE_ID_FIELD, CallTypesLiteral, LLMResponseTypes, SpecialEnums
|
||||
from litellm.types.utils import (
|
||||
ADDRESSED_COMPARISON_RESPONSE_ID_FIELD,
|
||||
ADDRESSED_RESPONSE_ID_FIELD,
|
||||
CallTypesLiteral,
|
||||
LLMResponseTypes,
|
||||
SpecialEnums,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from litellm.caching.caching import DualCache
|
||||
|
|
@ -155,37 +161,29 @@ class ResponsesIDSecurity(CustomLogger):
|
|||
data: Mapping[str, object],
|
||||
user_api_key_dict: "UserAPIKeyAuth",
|
||||
) -> Mapping[str, object]:
|
||||
options: Final = self._authorized_prompt_cache_options(data.get("prompt_cache_options"), user_api_key_dict)
|
||||
extra_body: Final = as_str_mapping(data.get("extra_body"))
|
||||
extra_body_options: Final = (
|
||||
None
|
||||
if extra_body is None
|
||||
else self._authorized_prompt_cache_options(extra_body.get("prompt_cache_options"), user_api_key_dict)
|
||||
overriding_extra_body: Final = (
|
||||
extra_body if extra_body is not None and "prompt_cache_options" in extra_body else None
|
||||
)
|
||||
options_field: Final[Mapping[str, object]] = {} if options is None else {"prompt_cache_options": options}
|
||||
extra_body_field: Final[Mapping[str, object]] = (
|
||||
{}
|
||||
if extra_body is None or extra_body_options is None
|
||||
else {"extra_body": {**extra_body, "prompt_cache_options": extra_body_options}}
|
||||
options: Final = as_str_mapping(
|
||||
data.get("prompt_cache_options")
|
||||
if overriding_extra_body is None
|
||||
else overriding_extra_body.get("prompt_cache_options")
|
||||
)
|
||||
return {**options_field, **extra_body_field}
|
||||
|
||||
def _authorized_prompt_cache_options(
|
||||
self,
|
||||
prompt_cache_options: object,
|
||||
user_api_key_dict: "UserAPIKeyAuth",
|
||||
) -> Mapping[str, object] | None:
|
||||
options: Final = as_str_mapping(prompt_cache_options)
|
||||
comparison_response_id: Final = None if options is None else options.get("comparison_response_id")
|
||||
if (
|
||||
options is None
|
||||
or not isinstance(comparison_response_id, str)
|
||||
or not self._is_encrypted_response_id(comparison_response_id)
|
||||
):
|
||||
return None
|
||||
original_response_id, user_id, team_id = self._decrypt_response_id(comparison_response_id)
|
||||
retained_id: Final = data.get(ADDRESSED_COMPARISON_RESPONSE_ID_FIELD)
|
||||
requested_id: Final = None if options is None else options.get("comparison_response_id")
|
||||
addressed_id: Final = retained_id if isinstance(retained_id, str) and retained_id else requested_id
|
||||
if options is None or not isinstance(addressed_id, str) or not self._is_encrypted_response_id(addressed_id):
|
||||
return {}
|
||||
original_response_id, user_id, team_id = self._decrypt_response_id(addressed_id)
|
||||
self.check_user_access_to_response_id(user_id, team_id, user_api_key_dict)
|
||||
return {**options, "comparison_response_id": original_response_id}
|
||||
authorized_options: Final = {**options, "comparison_response_id": original_response_id}
|
||||
authorized_field: Final[Mapping[str, object]] = (
|
||||
{"prompt_cache_options": authorized_options}
|
||||
if overriding_extra_body is None
|
||||
else {"extra_body": {**overriding_extra_body, "prompt_cache_options": authorized_options}}
|
||||
)
|
||||
return {**authorized_field, ADDRESSED_COMPARISON_RESPONSE_ID_FIELD: addressed_id}
|
||||
|
||||
def authorize_response_id(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ RoutingStrategyName: TypeAlias = Literal[
|
|||
|
||||
TRUSTED_CALLBACK_VARS_FIELD: Final = "litellm_trusted_callback_vars"
|
||||
ADDRESSED_RESPONSE_ID_FIELD: Final = "_litellm_addressed_response_id"
|
||||
ADDRESSED_COMPARISON_RESPONSE_ID_FIELD: Final = "_litellm_addressed_comparison_response_id"
|
||||
STREAM_USAGE_INJECTED_FIELD: Final = "_litellm_stream_usage_injected"
|
||||
|
||||
WIRE_NAME: Final = "wire_name"
|
||||
|
|
@ -406,6 +407,9 @@ class ProxyRequestState:
|
|||
secret_fields: "SecretFields | None" = None
|
||||
trusted_callback_vars: Mapping[str, str] | None = field(default=None, metadata=wire(TRUSTED_CALLBACK_VARS_FIELD))
|
||||
addressed_response_id: str | None = field(default=None, metadata=wire(ADDRESSED_RESPONSE_ID_FIELD))
|
||||
addressed_comparison_response_id: str | None = field(
|
||||
default=None, metadata=wire(ADDRESSED_COMPARISON_RESPONSE_ID_FIELD)
|
||||
)
|
||||
strip_stream_usage: bool | None = field(default=None, metadata=wire("_litellm_strip_stream_usage"))
|
||||
stream_usage_injected: bool | None = field(default=None, metadata=wire(STREAM_USAGE_INJECTED_FIELD))
|
||||
client_side_timeout: bool | None = None
|
||||
|
|
|
|||
|
|
@ -4334,6 +4334,7 @@ bedrock_batch_litellm_params: Final = BEDROCK_BATCH_KWARG_NAMES
|
|||
|
||||
TRUSTED_CALLBACK_VARS_FIELD: Final = _litellm_params.TRUSTED_CALLBACK_VARS_FIELD
|
||||
ADDRESSED_RESPONSE_ID_FIELD: Final = _litellm_params.ADDRESSED_RESPONSE_ID_FIELD
|
||||
ADDRESSED_COMPARISON_RESPONSE_ID_FIELD: Final = _litellm_params.ADDRESSED_COMPARISON_RESPONSE_ID_FIELD
|
||||
|
||||
anthropic_wif_litellm_params: Final = tuple(sorted(ANTHROPIC_WIF_KWARGS_KEYS))
|
||||
openai_wif_litellm_params: Final = tuple(sorted(OPENAI_WIF_KWARGS_KEYS))
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue