mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-21 00:21:49 +00:00
fix(proxy): carry project_id through key metadata enrichment and drop docstrings
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
b00cd15bd7
commit
b20f1422eb
8 changed files with 5 additions and 19 deletions
|
|
@ -307,12 +307,10 @@ def model_access_group_spend_counter_key(access_group_name: str) -> str:
|
|||
|
||||
|
||||
def project_cache_key(project_id: str) -> str:
|
||||
"""Cache key one project row is stored under; shared by auth, spend tracking and the spend writer."""
|
||||
return f"project_id:{project_id}"
|
||||
|
||||
|
||||
def project_spend_counter_key(project_id: str) -> str:
|
||||
"""Spend counter key for one project; the reservation, cost callback, auth and reseed paths all read it."""
|
||||
return f"spend:project:{project_id}"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -504,6 +504,8 @@ class _ProxyDBLogger(CustomLogger):
|
|||
metadata["user_api_key_team_id"] = key_obj.team_id
|
||||
if metadata.get("user_api_key_org_id") is None:
|
||||
metadata["user_api_key_org_id"] = key_obj.org_id
|
||||
if metadata.get("user_api_key_project_id") is None:
|
||||
metadata["user_api_key_project_id"] = key_obj.project_id
|
||||
except Exception:
|
||||
verbose_proxy_logger.debug(
|
||||
"Failed to enrich failure metadata with key info for api_key=%s",
|
||||
|
|
|
|||
|
|
@ -7161,9 +7161,6 @@ def _project_with_budget(spend: float, max_budget: float):
|
|||
],
|
||||
)
|
||||
async def test_project_max_budget_check_reads_live_spend_counter(counter_spend, db_spend, blocks):
|
||||
"""LIT-3269: project budget enforcement must read the cross-pod
|
||||
``spend:project:{id}`` counter first and only fall back to the cached row's
|
||||
spend, matching key/team/org checks. The boundary is inclusive (>=)."""
|
||||
from litellm.caching.dual_cache import DualCache
|
||||
from litellm.proxy.auth.auth_checks import _project_max_budget_check
|
||||
|
||||
|
|
|
|||
|
|
@ -1666,7 +1666,6 @@ def test_budget_table_reset_invalidates_every_access_group_not_just_the_first(
|
|||
|
||||
|
||||
def test_project_reset_zeroes_spend_on_due_tiers(reset_budget_job, mock_prisma_client, monkeypatch):
|
||||
"""A project linked to an expiring budget tier has its spend zeroed in the same cascade transaction."""
|
||||
_make_counter_invalidation_job(monkeypatch)
|
||||
mock_prisma_client.data["budget"] = [_budget_row(budget_id="budget-due", budget_duration="7d")]
|
||||
mock_prisma_client.db.litellm_projecttable.set_find_many_results(
|
||||
|
|
|
|||
|
|
@ -1062,10 +1062,6 @@ async def test_batch_database_updates_queues_org_member_spend_for_the_request_us
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_project_spend_is_persisted_to_project_table_and_project_cache_is_evicted():
|
||||
"""Regression for LIT-3269: a request made with a project-scoped key must
|
||||
increment LiteLLM_ProjectTable.spend, otherwise /project/info stays at 0
|
||||
and the project budget never blocks. The cached project row is evicted so
|
||||
the next auth check reads the fresh spend."""
|
||||
db_writer: Final = DBSpendUpdateWriter()
|
||||
await db_writer._batch_database_updates(
|
||||
response_cost=0.25,
|
||||
|
|
|
|||
|
|
@ -432,8 +432,6 @@ async def test_from_db_bounds_in_flight_prisma_requests_across_counter_keys():
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_from_db_reseeds_project_counter_from_the_project_row():
|
||||
"""LIT-3269: a cold ``spend:project:{id}`` counter seeds from LiteLLM_ProjectTable.spend,
|
||||
so a fresh pod enforces the project budget against persisted spend rather than 0."""
|
||||
prisma: Final = _FakePrismaClient(project_row=SimpleNamespace(project_id="proj-1", spend=7.25))
|
||||
|
||||
assert await SpendCounterReseed.from_db(prisma_client=prisma, counter_key="spend:project:proj-1") == 7.25
|
||||
|
|
|
|||
|
|
@ -1372,6 +1372,7 @@ async def test_enrich_failure_metadata_with_full_key_lookup():
|
|||
mock_key_obj.user_id = "fetched-user-id"
|
||||
mock_key_obj.team_id = "fetched-team-id"
|
||||
mock_key_obj.org_id = "fetched-org-id"
|
||||
mock_key_obj.project_id = "fetched-project-id"
|
||||
|
||||
mock_team_obj = MagicMock()
|
||||
mock_team_obj.team_alias = "fetched-team-alias"
|
||||
|
|
@ -1395,12 +1396,14 @@ async def test_enrich_failure_metadata_with_full_key_lookup():
|
|||
"user_api_key_team_id": None,
|
||||
"user_api_key_team_alias": None,
|
||||
"user_api_key_org_id": None,
|
||||
"user_api_key_project_id": None,
|
||||
}
|
||||
result = await _ProxyDBLogger._enrich_failure_metadata_with_key_info(metadata)
|
||||
assert result["user_api_key_alias"] == "fetched-key-alias"
|
||||
assert result["user_api_key_user_id"] == "fetched-user-id"
|
||||
assert result["user_api_key_team_id"] == "fetched-team-id"
|
||||
assert result["user_api_key_org_id"] == "fetched-org-id"
|
||||
assert result["user_api_key_project_id"] == "fetched-project-id"
|
||||
assert result["user_api_key_team_alias"] == "fetched-team-alias"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -672,10 +672,6 @@ async def _seed_project_scoped_budgets(
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_should_reserve_project_and_team_member_counters_for_project_scoped_key(spend_counter_state):
|
||||
"""LIT-3269: a key carrying user_id, team_id and project_id reserves against
|
||||
both the team member counter and the project counter; neither replaces the
|
||||
other. After the call the project counter reflects the real cost once, not
|
||||
the reservation plus the post-call increment."""
|
||||
counter_cache, key_cache = spend_counter_state
|
||||
proxy_logging_obj = ProxyLogging(user_api_key_cache=key_cache)
|
||||
await _seed_project_scoped_budgets(
|
||||
|
|
@ -724,8 +720,6 @@ async def test_should_reserve_project_and_team_member_counters_for_project_scope
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_exhausted_team_member_budget_still_blocks_project_scoped_key(spend_counter_state):
|
||||
"""LIT-3269: the project budget is additive. A project with plenty of
|
||||
headroom must not let a key through once its team member budget is spent."""
|
||||
counter_cache, key_cache = spend_counter_state
|
||||
proxy_logging_obj = ProxyLogging(user_api_key_cache=key_cache)
|
||||
await _seed_project_scoped_budgets(
|
||||
|
|
@ -755,7 +749,6 @@ async def test_exhausted_team_member_budget_still_blocks_project_scoped_key(spen
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_exhausted_project_budget_blocks_project_scoped_key(spend_counter_state):
|
||||
"""LIT-3269: with team member headroom left, the project budget alone blocks the key."""
|
||||
counter_cache, key_cache = spend_counter_state
|
||||
proxy_logging_obj = ProxyLogging(user_api_key_cache=key_cache)
|
||||
await _seed_project_scoped_budgets(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue