mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-01 02:02:20 +00:00
fix(policy): reject empty specific attachments
This commit is contained in:
parent
73e9071311
commit
e777ebeefe
2 changed files with 46 additions and 1 deletions
|
|
@ -8,7 +8,7 @@ the final guardrails list.
|
|||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||
|
||||
|
||||
class PolicyMatchContext(BaseModel):
|
||||
|
|
@ -326,6 +326,19 @@ class PolicyAttachmentCreateRequest(BaseModel):
|
|||
description="Tag patterns this attachment applies to. Supports wildcards (e.g., health-*).",
|
||||
)
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_scope_has_selector(self) -> "PolicyAttachmentCreateRequest":
|
||||
if self.scope == "*":
|
||||
return self
|
||||
|
||||
if any((self.teams, self.keys, self.models, self.tags)):
|
||||
return self
|
||||
|
||||
raise ValueError(
|
||||
"Specific policy attachments must include at least one non-empty selector "
|
||||
"(teams, keys, models, or tags). Use scope='*' for global attachments."
|
||||
)
|
||||
|
||||
|
||||
class PolicyAttachmentDBResponse(BaseModel):
|
||||
"""Response for a policy attachment from the database."""
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ Tests for pipeline field on policy CRUD types (resolver_types.py).
|
|||
"""
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from litellm.types.proxy.policy_engine.resolver_types import (
|
||||
PolicyAttachmentCreateRequest,
|
||||
PolicyCreateRequest,
|
||||
PolicyDBResponse,
|
||||
PolicyUpdateRequest,
|
||||
|
|
@ -100,3 +102,33 @@ def test_policy_create_request_roundtrip():
|
|||
dumped = req.model_dump()
|
||||
restored = PolicyCreateRequest(**dumped)
|
||||
assert restored.pipeline == pipeline_data
|
||||
|
||||
|
||||
def test_policy_attachment_create_request_rejects_empty_specific_scope():
|
||||
with pytest.raises(ValidationError, match="at least one non-empty selector"):
|
||||
PolicyAttachmentCreateRequest(policy_name="pii-policy")
|
||||
|
||||
|
||||
def test_policy_attachment_create_request_rejects_empty_selector_list():
|
||||
with pytest.raises(ValidationError, match="at least one non-empty selector"):
|
||||
PolicyAttachmentCreateRequest(policy_name="pii-policy", teams=[])
|
||||
|
||||
|
||||
def test_policy_attachment_create_request_allows_explicit_global_scope():
|
||||
request = PolicyAttachmentCreateRequest(
|
||||
policy_name="pii-policy",
|
||||
scope="*",
|
||||
)
|
||||
|
||||
assert request.scope == "*"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("selector_field", ["teams", "keys", "models", "tags"])
|
||||
def test_policy_attachment_create_request_allows_selector_scope(selector_field):
|
||||
selector_value = f"{selector_field}-a"
|
||||
request = PolicyAttachmentCreateRequest(
|
||||
policy_name="pii-policy",
|
||||
**{selector_field: [selector_value]},
|
||||
)
|
||||
|
||||
assert getattr(request, selector_field) == [selector_value]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue