fix(jwt-auth): narrow HTTPException catch to 404 (greptile review)

Address Greptile review comments on #28913:

* `find_and_validate_specific_team_id`: re-raise HTTPException when
  `status_code != 404`, pinning the catch to the "team doesn't exist
  in db" path documented for `get_team_object`. A future change that
  introduces a different status code (e.g. 403 for a blocked team)
  will now propagate instead of silently falling through to the
  single-team DB fallback.

* Add `test_find_and_validate_specific_team_id_non_404_http_exception_propagates`
  parametrised over 400 / 403 / 500 to lock in the contract.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Milan 2026-05-27 02:46:51 +03:00
parent 5d80376bd9
commit 639a18af1d
No known key found for this signature in database
2 changed files with 39 additions and 3 deletions

View file

@ -1048,6 +1048,8 @@ class JWTAuthManager:
)
return individual_team_id, team_object
except HTTPException as e:
if e.status_code != 404:
raise
# Claim doesn't map to a known team — defer to fallback.
verbose_proxy_logger.debug(
"JWT team_id claim '%s' did not resolve to a team: %s",

View file

@ -2839,9 +2839,10 @@ async def test_find_team_with_model_access_unresolved_group_claim_returns_none(
@pytest.mark.asyncio
async def test_find_and_validate_specific_team_id_non_http_exception_still_propagates():
"""Regression guard: only HTTPException (the "team doesn't exist in db"
404 raised by get_team_object) is softened. Other errors — e.g. "No DB
Connected" — must still propagate so operator-side problems are loud."""
"""Regression guard: only the 404 HTTPException raised by
`get_team_object` ("team doesn't exist in db") is softened. Other
errors — e.g. "No DB Connected" — must still propagate so operator-side
problems are loud."""
jwt_handler = JWTHandler()
jwt_handler.litellm_jwtauth = LiteLLM_JWTAuth(team_id_jwt_field="team_id")
token = {"sub": "user-1", "team_id": "some-claim-team"}
@ -2863,6 +2864,39 @@ async def test_find_and_validate_specific_team_id_non_http_exception_still_propa
)
@pytest.mark.asyncio
async def test_find_and_validate_specific_team_id_non_404_http_exception_propagates():
"""Regression guard: only 404 HTTPException is softened. If
`get_team_object` is ever updated to raise a different HTTP status code
(e.g. 403 for a blocked team), that error must still propagate rather
than silently fall through to the single-team DB fallback."""
from fastapi import HTTPException
jwt_handler = JWTHandler()
jwt_handler.litellm_jwtauth = LiteLLM_JWTAuth(team_id_jwt_field="team_id")
token = {"sub": "user-1", "team_id": "some-claim-team"}
for status_code in (400, 403, 500):
with patch(
"litellm.proxy.auth.handle_jwt.get_team_object",
new_callable=AsyncMock,
) as mock_get_team:
mock_get_team.side_effect = HTTPException(
status_code=status_code, detail="non-404 failure"
)
with pytest.raises(HTTPException) as exc_info:
await JWTAuthManager.find_and_validate_specific_team_id(
jwt_handler=jwt_handler,
jwt_valid_token=token,
prisma_client=None,
user_api_key_cache=None,
parent_otel_span=None,
proxy_logging_obj=None,
)
assert exc_info.value.status_code == status_code
@pytest.mark.asyncio
async def test_find_team_with_model_access_enforce_team_based_access_still_raises():
"""Regression guard: when no group claims are present and