mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-21 05:15:06 +00:00
fix(proxy): return actionable 500 on invalid Relay settings schema and stop leaking file path
Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
This commit is contained in:
parent
926727fa4c
commit
3d44fdcf73
3 changed files with 30 additions and 13 deletions
|
|
@ -3,6 +3,7 @@ from pathlib import Path
|
|||
|
||||
import yaml
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import ValidationError
|
||||
|
||||
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
|
||||
from litellm.types.proxy.relay_endpoints import RelayManagedConfigResponse
|
||||
|
|
@ -26,7 +27,7 @@ def _load_managed_config(path: Path) -> RelayManagedConfigResponse:
|
|||
except yaml.YAMLError as e:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail={"error": f"Failed to parse Relay settings at {path}: {e}"},
|
||||
detail={"error": f"Failed to parse Relay settings ({RELAY_SETTINGS_PATH_ENV}): {e}"},
|
||||
)
|
||||
|
||||
if parsed is None:
|
||||
|
|
@ -34,9 +35,17 @@ def _load_managed_config(path: Path) -> RelayManagedConfigResponse:
|
|||
if not isinstance(parsed, dict):
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail={"error": f"Relay settings at {path} must be a YAML mapping, got {type(parsed).__name__}"},
|
||||
detail={
|
||||
"error": f"Relay settings ({RELAY_SETTINGS_PATH_ENV}) must be a YAML mapping, got {type(parsed).__name__}"
|
||||
},
|
||||
)
|
||||
try:
|
||||
return RelayManagedConfigResponse.model_validate(parsed)
|
||||
except ValidationError as e:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail={"error": f"Relay settings ({RELAY_SETTINGS_PATH_ENV}) failed schema validation: {e}"},
|
||||
)
|
||||
return RelayManagedConfigResponse.model_validate(parsed)
|
||||
|
||||
|
||||
@router.get(
|
||||
|
|
|
|||
|
|
@ -1,28 +1,26 @@
|
|||
from typing import Dict, Optional
|
||||
|
||||
from pydantic import BaseModel, Field, JsonValue
|
||||
|
||||
|
||||
class RelayClaudeCodeConfig(BaseModel):
|
||||
channel: str = Field(default="pinned")
|
||||
version: Optional[str] = Field(default=None)
|
||||
version: str | None = Field(default=None)
|
||||
registry: str = Field(default="npm")
|
||||
package: str = Field(default="@anthropic-ai/claude-code")
|
||||
model: Optional[str] = Field(default=None)
|
||||
managed_settings: Dict[str, JsonValue] = Field(default_factory=dict)
|
||||
model: str | None = Field(default=None)
|
||||
managed_settings: dict[str, JsonValue] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class RelayCodexConfig(BaseModel):
|
||||
channel: str = Field(default="pinned")
|
||||
version: Optional[str] = Field(default=None)
|
||||
version: str | None = Field(default=None)
|
||||
registry: str = Field(default="npm")
|
||||
package: str = Field(default="@openai/codex")
|
||||
model: Optional[str] = Field(default=None)
|
||||
model: str | None = Field(default=None)
|
||||
|
||||
|
||||
class RelayManagedConfigResponse(BaseModel):
|
||||
claude_code: RelayClaudeCodeConfig = Field(default_factory=RelayClaudeCodeConfig)
|
||||
codex: RelayCodexConfig = Field(default_factory=RelayCodexConfig)
|
||||
policy_version: Optional[int] = Field(default=None)
|
||||
updated_by: Optional[str] = Field(default=None)
|
||||
updated_at: Optional[str] = Field(default=None)
|
||||
policy_version: int | None = Field(default=None)
|
||||
updated_by: str | None = Field(default=None)
|
||||
updated_at: str | None = Field(default=None)
|
||||
|
|
|
|||
|
|
@ -109,6 +109,16 @@ def test_load_managed_config_rejects_invalid_yaml(tmp_path: Path) -> None:
|
|||
assert exc_info.value.status_code == 500
|
||||
|
||||
|
||||
def test_load_managed_config_rejects_wrong_field_type(tmp_path: Path) -> None:
|
||||
path = tmp_path / "relay_settings.yaml"
|
||||
path.write_text("policy_version: not-an-integer\n")
|
||||
|
||||
with pytest.raises(HTTPException) as exc_info:
|
||||
_load_managed_config(path)
|
||||
|
||||
assert exc_info.value.status_code == 500
|
||||
|
||||
|
||||
def test_load_managed_config_preserves_nested_managed_settings(tmp_path: Path) -> None:
|
||||
path = tmp_path / "relay_settings.yaml"
|
||||
path.write_text(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue