fix(alerts): honor explicit parent route grants

This commit is contained in:
moe-berri 2026-11-08 15:04:34 +08:00
parent d8d98d0133
commit a363f68c3c
3 changed files with 19 additions and 3 deletions

View file

@ -49,6 +49,8 @@ ScopeId: TypeAlias = Annotated[str | None, Query(min_length=1, max_length=1024)]
def _allows_write(grant: str, route: str) -> bool:
if grant == "info_routes":
return False
if route == grant or route.startswith(grant + "/"):
return True
paths: Final = (
TypeAdapter(tuple[str, ...]).validate_python(LiteLLMRoutes[grant].value)
if grant in LiteLLMRoutes.__members__

View file

@ -39,12 +39,13 @@ async def test_alert_resource_labels_bound_legacy_display_values(db: ManagementD
await repository.database.query_raw('DELETE FROM "LiteLLM_UserTable" WHERE user_id=$1', identity)
def test_scoped_rules_use_real_management_auth_and_preserve_read_only_roles(gateway: Gateway) -> None:
@pytest.mark.parametrize("grant", ["management_routes", "/usage", "/usage/alert-rules"])
def test_scoped_rules_use_real_management_auth_and_preserve_read_only_roles(gateway: Gateway, grant: str) -> None:
with gateway.scenario() as scenario:
owner: Final = scenario.user(user_role="internal_user")
outsider: Final = scenario.user(user_role="internal_user")
viewer: Final = scenario.user(user_role="proxy_admin_viewer")
owner_key: Final = scenario.key(user_id=owner, key_type="management")
owner_key: Final = scenario.key(user_id=owner, key_type="default", allowed_routes=[grant])
outsider_key: Final = scenario.key(user_id=outsider, key_type="management")
viewer_key: Final = scenario.key(user_id=viewer, key_type="read_only")
inference_key: Final = scenario.key(user_id=owner, key_type="llm_api")

View file

@ -6,7 +6,7 @@ import pytest
from fastapi import HTTPException
from litellm.proxy._types import UserAPIKeyAuth
from litellm.proxy.alerting_endpoints.usage_alerts import require_scope, require_write_access
from litellm.proxy.alerting_endpoints.usage_alerts import _allows_write, require_scope, require_write_access
from litellm.repositories.usage_alerts import UsageAlertsRepository, activity_path
from litellm.types.proxy.auth.user_roles import LitellmUserRoles
@ -25,6 +25,19 @@ def test_info_grants_do_not_authorize_mutations(role: LitellmUserRoles, key_type
assert error.value.status_code == 403
@pytest.mark.parametrize("grant", ["management_routes", "/usage", "/usage/alert-rules", "/usage/*"])
def test_explicit_route_grants_authorize_alert_mutations(grant: str) -> None:
assert _allows_write(grant, "/usage/alert-rules/example") is True
@pytest.mark.parametrize("grant", ["/usag", "/usage/alert-rule", "/usage/alerts"])
def test_route_grants_require_a_complete_path_segment(grant: str) -> None:
user: Final = UserAPIKeyAuth(user_role=LitellmUserRoles.INTERNAL_USER, allowed_routes=[grant])
with pytest.raises(HTTPException) as error:
require_write_access(user, "/usage/alert-rules/example")
assert error.value.status_code == 403
@pytest.mark.asyncio
@pytest.mark.parametrize(
"role,key_type,write",