fix(spend-tracking): take each unresolved key's newest spend row and drop docstrings

This commit is contained in:
mateo-berri 2026-09-08 12:40:28 -07:00
parent 8c878f3686
commit cf0488316e
4 changed files with 16 additions and 40 deletions

View file

@ -462,9 +462,7 @@ async def get_api_key_metadata(
This ensures that key_alias and team_id are preserved in historical activity logs
even after a key is deleted or regenerated. Also recovers aliases for api_key
values that were double-hashed by the v1.99 spend-log provenance gate, and, when
spend_logs_window is given, for keys never written to either token table (CLI
session tokens) from the spend-log rows those requests wrote in that window.
values that were double-hashed by the v1.99 spend-log provenance gate.
"""
key_records: Sequence[PrismaVerificationToken] = await VerificationTokenRepository(prisma_client).table.find_many(
where={"token": {"in": list(api_keys)}}

View file

@ -29,16 +29,21 @@ ORDER BY token, deleted_at DESC
"""
_SPEND_LOG_ALIAS_SQL: Final = """
SELECT DISTINCT ON (api_key)
api_key AS digest,
metadata->>'user_api_key_alias' AS key_alias,
COALESCE(NULLIF(team_id, ''), metadata->>'user_api_key_team_id') AS team_id,
COALESCE(NULLIF("user", ''), metadata->>'user_api_key_user_id') AS user_id
FROM "LiteLLM_SpendLogs"
WHERE api_key = ANY($1::text[])
AND "startTime" >= $2::timestamp
AND "startTime" < $3::timestamp
ORDER BY api_key, (metadata->>'user_api_key_alias') IS NULL, "startTime" DESC
SELECT newest.digest, newest.key_alias, newest.team_id, newest.user_id
FROM unnest($1::text[]) AS missing(digest)
CROSS JOIN LATERAL (
SELECT
api_key AS digest,
metadata->>'user_api_key_alias' AS key_alias,
COALESCE(NULLIF(team_id, ''), metadata->>'user_api_key_team_id') AS team_id,
COALESCE(NULLIF("user", ''), metadata->>'user_api_key_user_id') AS user_id
FROM "LiteLLM_SpendLogs"
WHERE api_key = missing.digest
AND "startTime" >= $2::timestamp
AND "startTime" < $3::timestamp
ORDER BY "startTime" DESC
LIMIT 1
) AS newest
"""
@ -152,14 +157,6 @@ async def recover_double_hashed_key_metadata(
prisma_client: PrismaClient,
missing_keys: AbstractSet[str],
) -> Mapping[str, KeyMetadataDict]:
"""
Recover key_alias/team_id/user_id for DailyUserSpend.api_key values that
were double-hashed by the v1.99 spend-log provenance gate.
Those rows store hash(VerificationToken.token) instead of the token, so the
exact join misses. Postgres hashes the token column itself, one pass over
active keys and one over deleted keys, so no key row crosses the wire.
"""
sha_missing: Final = frozenset(key for key in missing_keys if is_valid_sha256_hash(key))
if not sha_missing:
return _EMPTY_KEY_METADATA
@ -187,15 +184,6 @@ async def recover_key_metadata_from_spend_logs(
missing_keys: AbstractSet[str],
window: tuple[datetime, datetime],
) -> Mapping[str, KeyMetadataDict]:
"""
Recover key_alias/team_id/user_id for hashed api_key values absent from both
verification-token tables, e.g. in-memory CLI session tokens that never get a
token row. Their owner is written to LiteLLM_SpendLogs metadata at request
time under the same hashed api_key, so it is the only surviving source. Only
sha256 digests are looked up, matching the reverse-hash recovery gate, since
every current api_key value in spend logs is a token hash. The [start, end)
bound keeps the lookup on the startTime index instead of scanning the table.
"""
sha_missing: Final = frozenset(key for key in missing_keys if is_valid_sha256_hash(key))
if not sha_missing:
return _EMPTY_KEY_METADATA

View file

@ -2109,11 +2109,6 @@ async def test_get_daily_activity_aggregated_with_entity_breakdown():
@pytest.mark.asyncio
async def test_get_api_key_metadata_resolves_session_key_via_spend_log_window():
"""
A CLI session token has no verification-token row, so the active/deleted lookups
and reverse-hash all miss. Given a spend-log window, its alias and owner are
recovered from the spend-log metadata and its email is filled from the user table.
"""
from litellm.proxy.utils import hash_token
session_digest = hash_token("cli-session-user-42")

View file

@ -233,11 +233,6 @@ async def test_fill_missing_api_key_aliases_skips_named_keys_that_have_no_email(
@pytest.mark.asyncio
async def test_recover_key_metadata_from_spend_logs_resolves_session_token_from_metadata():
"""
CLI session tokens never get a verification-token row, so both the exact join and
the reverse-hash lookup miss them. Their owner survives only in the spend-log
metadata written at request time, keyed by the same hashed api_key.
"""
session_digest = hash_token("cli-session-repro-user-6852")
window = (datetime(2026, 9, 7), datetime(2026, 9, 10))
mock_prisma = MagicMock()