ci(proxy-mgmt-behavior): add auth-resolver chain diagnostic

Six runs and the underlying data (token row, user row, view row) all
verified correct in CI, but auth still returns user_id=None. This
diagnostic calls the resolver primitives directly:

  1. ``prisma.get_data(table_name="combined_view")`` → raw view object
  2. ``get_key_object(...)`` → cached/DB UserAPIKeyAuth
  3. ``get_user_object(...)`` → LiteLLM_UserTable row
  4. ``_is_user_proxy_admin`` / ``_get_user_role``

and prints each intermediate via captured stdout (-s). Whichever step
returns None/False in CI is where the chain breaks. Imports come from
``litellm.proxy.auth`` (not management_endpoints), so G3 still passes.
This commit is contained in:
Yuneng Jiang 2026-05-20 13:11:29 -07:00
parent 8816977beb
commit 6d207ffa5a
No known key found for this signature in database

View file

@ -37,6 +37,77 @@ async def test_each_actor_can_self_info(actor, proxy_client, world):
)
async def test_auth_resolver_returns_correct_user_id_and_role(
proxy_client, prisma, world
):
"""Diagnostic: call the auth-resolver primitives directly with the seeded
PROXY_ADMIN actor's hashed token, dump every intermediate so we can see
where in the chain user_id / user_role get dropped between the DB and
UserAPIKeyAuth."""
from litellm.proxy.auth.auth_checks import (
get_key_object,
get_user_object,
_is_user_proxy_admin,
_get_user_role,
)
from litellm.proxy.proxy_server import user_api_key_cache
seeder = world.keys[Actor.PROXY_ADMIN]
# 1. Raw prisma get_data → LiteLLM_VerificationTokenView
raw_view = await prisma.get_data(token=seeder.hashed, table_name="combined_view")
raw_view_user_id = getattr(raw_view, "user_id", "<no attr>")
# 2. get_key_object (cache miss → DB)
key_obj = await get_key_object(
hashed_token=seeder.hashed,
prisma_client=prisma,
user_api_key_cache=user_api_key_cache,
)
key_user_id = getattr(key_obj, "user_id", "<no attr>")
key_user_role = getattr(key_obj, "user_role", "<no attr>")
# 3. get_user_object for the resolved user_id
user_obj = None
if key_user_id and key_user_id != "<no attr>":
try:
user_obj = await get_user_object(
user_id=key_user_id,
prisma_client=prisma,
user_api_key_cache=user_api_key_cache,
user_id_upsert=False,
)
except Exception as exc:
user_obj = f"<exc: {exc!r}>"
is_admin = (
_is_user_proxy_admin(user_obj=user_obj)
if not isinstance(user_obj, str)
else "<n/a>"
)
resolved_role = (
_get_user_role(user_obj=user_obj) if not isinstance(user_obj, str) else "<n/a>"
)
diagnostic = (
f"\n expected seed.user_id : {seeder.user_id!r}"
f"\n raw_view.user_id : {raw_view_user_id!r}"
f"\n key_obj.user_id : {key_user_id!r}"
f"\n key_obj.user_role : {key_user_role!r}"
f"\n user_obj.user_role : {getattr(user_obj, 'user_role', user_obj)!r}"
f"\n _is_user_proxy_admin : {is_admin!r}"
f"\n _get_user_role : {resolved_role!r}"
)
print(f"AUTH RESOLVER DIAGNOSTIC:{diagnostic}")
assert (
key_user_id == seeder.user_id
), f"get_key_object dropped user_id: {diagnostic}"
assert (
is_admin is True
), f"_is_user_proxy_admin returned False for the seeded PROXY_ADMIN: {diagnostic}"
async def test_proxy_admin_actor_can_create_keys_for_others(
proxy_client, prisma, world
):