mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-09 22:31:41 +00:00
fix(proxy): extend banned-params + admin-clear lists for NVIDIA Riva (VERIA-493) (#31742)
Two NVIDIA-Riva-specific fields consumed by the audio-transcription handler via the provider's `optional_params` passthrough were not covered by the proxy's existing banned-request-body list or the admin-config clearing list applied on `api_base` BYOK override: * `nvcf_function_id` * `use_ssl` Add both to `_BANNED_REQUEST_BODY_PARAMS` in `litellm/proxy/auth/auth_utils.py` and to the kwargs-only list in `_admin_config_fields_to_clear_on_base_override()` in `litellm/router_utils/clientside_credential_handler.py`, next to the analogous provider-specific entries already there (`aws_bedrock_*`, OCI provider fields, etc.). Same admin opt-ins as every other entry on those lists (`general_settings.allow_client_side_credentials` proxy-wide, or `configurable_clientside_auth_params` per deployment). Regression tests in `tests/test_litellm/proxy/auth/test_auth_utils.py` cover root-level rejection, the historical `api_key` bypass, both admin opt-in paths (proxy-wide and per-deployment), nested-container smuggling via the existing recursive walk, and clearing on `api_base` override. Mutation check verified. Resolves VERIA-493
This commit is contained in:
parent
a7d8c6f467
commit
41f9d8de7b
3 changed files with 186 additions and 0 deletions
|
|
@ -278,6 +278,12 @@ _BANNED_REQUEST_BODY_PARAMS: Tuple[str, ...] = (
|
|||
"s3_endpoint_url",
|
||||
"sagemaker_base_url",
|
||||
"deployment_url",
|
||||
# NVIDIA Riva fields consumed by the audio-transcription handler
|
||||
# via ``optional_params``. Banned for the same reason as the
|
||||
# provider-specific entries above: a caller-supplied value retargets
|
||||
# the request away from the admin's pinned configuration.
|
||||
"nvcf_function_id",
|
||||
"use_ssl",
|
||||
# SDK-only field; also rejected outright in is_request_body_safe.
|
||||
"model_list",
|
||||
# Observability credentials, hosts, and project identifiers: derived
|
||||
|
|
|
|||
|
|
@ -52,6 +52,13 @@ def _admin_config_fields_to_clear_on_base_override() -> List[str]:
|
|||
"oci_tenancy",
|
||||
"oci_key",
|
||||
"oci_key_file",
|
||||
# NVIDIA Riva fields — consumed by
|
||||
# ``litellm/llms/nvidia_riva/audio_transcription/handler.py`` via
|
||||
# optional_params and not declared on CredentialLiteLLMParams.
|
||||
# Admin-pinned values must not flow through on a caller-redirected
|
||||
# ``api_base`` for the same reason as the OCI entries above.
|
||||
"nvcf_function_id",
|
||||
"use_ssl",
|
||||
]
|
||||
return typed_fields + kwargs_only_fields
|
||||
|
||||
|
|
|
|||
|
|
@ -1520,6 +1520,42 @@ class TestGetDynamicLitellmParamsClearsAdminConfigOnBaseOverride:
|
|||
assert "vertex_credentials" not in out
|
||||
assert "vertex_project" not in out
|
||||
|
||||
def test_clears_nvcf_function_id_on_base_override(self):
|
||||
from litellm.router_utils.clientside_credential_handler import (
|
||||
get_dynamic_litellm_params,
|
||||
)
|
||||
|
||||
admin_params = {
|
||||
"model": "nvidia_riva/parakeet",
|
||||
"api_base": "grpc.nvcf.nvidia.com:443",
|
||||
"api_key": "nvapi-admin",
|
||||
"nvcf_function_id": "admin-pinned-function",
|
||||
}
|
||||
out = get_dynamic_litellm_params(
|
||||
litellm_params=dict(admin_params),
|
||||
request_kwargs={"api_base": "self-hosted.example.com:50051"},
|
||||
)
|
||||
assert out["api_base"] == "self-hosted.example.com:50051"
|
||||
assert "nvcf_function_id" not in out
|
||||
|
||||
def test_clears_use_ssl_on_base_override(self):
|
||||
from litellm.router_utils.clientside_credential_handler import (
|
||||
get_dynamic_litellm_params,
|
||||
)
|
||||
|
||||
admin_params = {
|
||||
"model": "nvidia_riva/parakeet",
|
||||
"api_base": "grpc.nvcf.nvidia.com:443",
|
||||
"api_key": "nvapi-admin",
|
||||
"use_ssl": True,
|
||||
}
|
||||
out = get_dynamic_litellm_params(
|
||||
litellm_params=dict(admin_params),
|
||||
request_kwargs={"api_base": "self-hosted.example.com:50051"},
|
||||
)
|
||||
assert out["api_base"] == "self-hosted.example.com:50051"
|
||||
assert "use_ssl" not in out
|
||||
|
||||
def test_caller_resupplied_value_overrides_admin_value_on_base_override(self):
|
||||
# When the caller redirects ``api_base`` and *also* supplies their
|
||||
# own value for one of the admin fields (e.g. ``organization``),
|
||||
|
|
@ -1712,6 +1748,127 @@ class TestIsRequestBodySafeBlocksBedrockProjectOverride:
|
|||
)
|
||||
|
||||
|
||||
class TestIsRequestBodySafeBlocksNVCFFunctionOverride:
|
||||
"""``nvcf_function_id`` is rejected as a request-body param unless the
|
||||
admin opted in proxy-wide or per-deployment."""
|
||||
|
||||
def test_nvcf_function_id_in_request_body_is_rejected(self):
|
||||
with pytest.raises(ValueError, match="nvcf_function_id"):
|
||||
is_request_body_safe(
|
||||
request_body={
|
||||
"model": "nvidia_riva/parakeet",
|
||||
"nvcf_function_id": "caller-supplied",
|
||||
},
|
||||
general_settings={},
|
||||
llm_router=None,
|
||||
model="nvidia_riva/parakeet",
|
||||
)
|
||||
|
||||
def test_nvcf_function_id_with_api_key_still_rejected(self):
|
||||
with pytest.raises(ValueError, match="nvcf_function_id"):
|
||||
is_request_body_safe(
|
||||
request_body={
|
||||
"model": "nvidia_riva/parakeet",
|
||||
"api_key": "sk-anything",
|
||||
"nvcf_function_id": "caller-supplied",
|
||||
},
|
||||
general_settings={},
|
||||
llm_router=None,
|
||||
model="nvidia_riva/parakeet",
|
||||
)
|
||||
|
||||
def test_admin_opt_in_proxy_wide_allows_nvcf_function_id(self):
|
||||
assert (
|
||||
is_request_body_safe(
|
||||
request_body={
|
||||
"model": "nvidia_riva/parakeet",
|
||||
"nvcf_function_id": "byok-function-id",
|
||||
},
|
||||
general_settings={"allow_client_side_credentials": True},
|
||||
llm_router=None,
|
||||
model="nvidia_riva/parakeet",
|
||||
)
|
||||
is True
|
||||
)
|
||||
|
||||
def test_admin_opt_in_per_deployment_allows_nvcf_function_id(self, monkeypatch):
|
||||
"""The error message lists per-deployment ``configurable_clientside_auth_params``
|
||||
as a second opt-in. Cover that path too so it can't silently regress."""
|
||||
from litellm.proxy.auth import auth_utils
|
||||
|
||||
monkeypatch.setattr(
|
||||
auth_utils,
|
||||
"_allow_model_level_clientside_configurable_parameters",
|
||||
lambda model, param, request_body_value, llm_router: param == "nvcf_function_id",
|
||||
)
|
||||
|
||||
assert (
|
||||
is_request_body_safe(
|
||||
request_body={
|
||||
"model": "nvidia_riva/parakeet",
|
||||
"nvcf_function_id": "byok-function-id",
|
||||
},
|
||||
general_settings={},
|
||||
llm_router=None,
|
||||
model="nvidia_riva/parakeet",
|
||||
)
|
||||
is True
|
||||
)
|
||||
|
||||
|
||||
class TestIsRequestBodySafeBlocksRivaUseSsl:
|
||||
"""``use_ssl`` is rejected as a request-body param unless the admin
|
||||
opted in proxy-wide or per-deployment."""
|
||||
|
||||
def test_use_ssl_in_request_body_is_rejected(self):
|
||||
with pytest.raises(ValueError, match="use_ssl"):
|
||||
is_request_body_safe(
|
||||
request_body={
|
||||
"model": "nvidia_riva/parakeet",
|
||||
"use_ssl": False,
|
||||
},
|
||||
general_settings={},
|
||||
llm_router=None,
|
||||
model="nvidia_riva/parakeet",
|
||||
)
|
||||
|
||||
def test_admin_opt_in_proxy_wide_allows_use_ssl(self):
|
||||
assert (
|
||||
is_request_body_safe(
|
||||
request_body={
|
||||
"model": "nvidia_riva/parakeet",
|
||||
"use_ssl": True,
|
||||
},
|
||||
general_settings={"allow_client_side_credentials": True},
|
||||
llm_router=None,
|
||||
model="nvidia_riva/parakeet",
|
||||
)
|
||||
is True
|
||||
)
|
||||
|
||||
def test_admin_opt_in_per_deployment_allows_use_ssl(self, monkeypatch):
|
||||
from litellm.proxy.auth import auth_utils
|
||||
|
||||
monkeypatch.setattr(
|
||||
auth_utils,
|
||||
"_allow_model_level_clientside_configurable_parameters",
|
||||
lambda model, param, request_body_value, llm_router: param == "use_ssl",
|
||||
)
|
||||
|
||||
assert (
|
||||
is_request_body_safe(
|
||||
request_body={
|
||||
"model": "nvidia_riva/parakeet",
|
||||
"use_ssl": True,
|
||||
},
|
||||
general_settings={},
|
||||
llm_router=None,
|
||||
model="nvidia_riva/parakeet",
|
||||
)
|
||||
is True
|
||||
)
|
||||
|
||||
|
||||
# ── is_request_body_safe nested-config recursion (VERIA-6) ────────────────────
|
||||
|
||||
|
||||
|
|
@ -1748,6 +1905,22 @@ class TestIsRequestBodySafeNestedConfig:
|
|||
model="milvus-store",
|
||||
)
|
||||
|
||||
def test_nested_nvcf_function_id_in_metadata_blocked(self):
|
||||
"""Smuggling ``nvcf_function_id`` via ``metadata`` / ``extra_body``
|
||||
is the same shape as the VERIA-6 ``api_base`` bypass — must be
|
||||
rejected by the recursive walk so the NVCF override gate cannot
|
||||
be sidestepped with nesting."""
|
||||
with pytest.raises(ValueError, match="nvcf_function_id"):
|
||||
is_request_body_safe(
|
||||
request_body={
|
||||
"model": "nvidia_riva/parakeet",
|
||||
"litellm_metadata": {"nvcf_function_id": "attacker-via-metadata"},
|
||||
},
|
||||
general_settings={},
|
||||
llm_router=None,
|
||||
model="nvidia_riva/parakeet",
|
||||
)
|
||||
|
||||
def test_nested_langfuse_host_in_embedding_config_blocked(self):
|
||||
"""The recursion uses the *full* banned-param list, not a special
|
||||
subset — so any flag that's banned at the root is also banned
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue