mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-15 23:31:29 +00:00
fix(guardrails): expand os.environ/ references in every litellm_params field
initialize_guardrail only expanded os.environ/ for api_key and api_base, so every other field kept the literal reference string. A guardrail registered with aws_region_name="os.environ/AWS_REGION" handed boto3 the string "os.environ/AWS_REGION", which failed the request with "Invalid AWS region format: 'os.environ/AWS_REGION'. Region names must contain only lowercase letters, digits, and hyphens." The same silently broke aws_access_key_id, aws_secret_access_key, the presidio analyzer/anonymizer bases, and the rest of the credential fields, none of which are reachable through api_key/api_base. Resolve every string field that starts with os.environ/ instead of two named ones. A reference that resolves to nothing now becomes None rather than the string "None", so the downstream client falls back to its own credential chain (pod identity, for example) instead of authenticating with a literal "None". Reproduced against the live stage proxy before the fix: registering a bedrock guardrail with the three os.environ/ AWS params returned 500 with the invalid region message, while the same guardrail without them blocked correctly.
This commit is contained in:
parent
2ef64acf6c
commit
de74191acb
2 changed files with 52 additions and 5 deletions
|
|
@ -384,6 +384,23 @@ class GuardrailRegistry:
|
|||
raise Exception(f"Error getting guardrail from DB: {str(e)}")
|
||||
|
||||
|
||||
def _resolve_env_references(litellm_params: LitellmParams) -> LitellmParams:
|
||||
"""Expand every ``os.environ/NAME`` reference in a guardrail's litellm_params.
|
||||
|
||||
Only ``api_key`` and ``api_base`` used to be expanded, so a guardrail
|
||||
configured with e.g. ``aws_region_name: os.environ/AWS_REGION`` handed boto3
|
||||
the literal string and failed with "Invalid AWS region format". A name that
|
||||
resolves to nothing becomes None rather than the string "None", so the
|
||||
downstream client falls back to its own credential chain.
|
||||
"""
|
||||
resolved = {
|
||||
name: get_secret(value)
|
||||
for name, value in litellm_params.model_dump().items()
|
||||
if isinstance(value, str) and value.startswith("os.environ/")
|
||||
}
|
||||
return litellm_params.model_copy(update=resolved) if resolved else litellm_params
|
||||
|
||||
|
||||
class InMemoryGuardrailHandler:
|
||||
"""
|
||||
Class that handles initializing guardrails and adding them to the CallbackManager
|
||||
|
|
@ -442,11 +459,7 @@ class InMemoryGuardrailHandler:
|
|||
lakera_category_thresholds = LakeraCategoryThresholds(**litellm_params_data["category_thresholds"])
|
||||
litellm_params.category_thresholds = lakera_category_thresholds
|
||||
|
||||
if litellm_params.api_key and litellm_params.api_key.startswith("os.environ/"):
|
||||
litellm_params.api_key = str(get_secret(litellm_params.api_key))
|
||||
|
||||
if litellm_params.api_base and litellm_params.api_base.startswith("os.environ/"):
|
||||
litellm_params.api_base = str(get_secret(litellm_params.api_base))
|
||||
litellm_params = _resolve_env_references(litellm_params)
|
||||
|
||||
guardrail_type = litellm_params.guardrail
|
||||
|
||||
|
|
|
|||
|
|
@ -367,3 +367,37 @@ def test_repeated_db_sync_does_not_accumulate_runner_instances():
|
|||
finally:
|
||||
for cb_list, snapshot in zip(lists, snapshots):
|
||||
cb_list[:] = snapshot
|
||||
|
||||
|
||||
def test_resolve_env_references_expands_every_string_field(monkeypatch):
|
||||
"""Regression: only api_key/api_base used to be expanded, so a guardrail set up
|
||||
with aws_region_name="os.environ/AWS_REGION" handed boto3 the literal string and
|
||||
failed with "Invalid AWS region format"."""
|
||||
from litellm.proxy.guardrails.guardrail_registry import _resolve_env_references
|
||||
|
||||
monkeypatch.setenv("TEST_GUARDRAIL_REGION", "us-east-1")
|
||||
monkeypatch.setenv("TEST_GUARDRAIL_KEY", "sk-guardrail")
|
||||
monkeypatch.setenv("TEST_GUARDRAIL_ANALYZER", "https://analyzer.example")
|
||||
monkeypatch.delenv("TEST_GUARDRAIL_ABSENT", raising=False)
|
||||
|
||||
resolved = _resolve_env_references(
|
||||
LitellmParams(
|
||||
guardrail="bedrock",
|
||||
mode="pre_call",
|
||||
api_key="os.environ/TEST_GUARDRAIL_KEY",
|
||||
aws_region_name="os.environ/TEST_GUARDRAIL_REGION",
|
||||
presidio_analyzer_api_base="os.environ/TEST_GUARDRAIL_ANALYZER",
|
||||
aws_secret_access_key="os.environ/TEST_GUARDRAIL_ABSENT",
|
||||
aws_access_key_id="AKIA_LITERAL_VALUE",
|
||||
)
|
||||
)
|
||||
|
||||
assert resolved.aws_region_name == "us-east-1"
|
||||
assert resolved.presidio_analyzer_api_base == "https://analyzer.example"
|
||||
assert resolved.api_key == "sk-guardrail"
|
||||
# An unset name must not become the string "None", which boto3 would treat as a credential.
|
||||
assert resolved.aws_secret_access_key is None
|
||||
# Literal values are left alone, and unrelated fields survive the copy.
|
||||
assert resolved.aws_access_key_id == "AKIA_LITERAL_VALUE"
|
||||
assert resolved.guardrail == "bedrock"
|
||||
assert resolved.mode == "pre_call"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue