Skip to content

[litellm-agent] Staging → litellm_internal_staging (5/7/2026) - #27375

Merged
oss-pr-review-agent-shin[bot] merged 14 commits into
shin_agent_oss_staging_05_07_2026from
litellm_agent_oss_staging_05_07_2026
May 7, 2026
Merged

[litellm-agent] Staging → litellm_internal_staging (5/7/2026)#27375
oss-pr-review-agent-shin[bot] merged 14 commits into
shin_agent_oss_staging_05_07_2026from
litellm_agent_oss_staging_05_07_2026

Conversation

@oss-pr-review-agent-shin

@oss-pr-review-agent-shin oss-pr-review-agent-shin Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor

Automated staging PR created by litellm-agent.

This branch collects PRs approved by the agent on 5/7/2026.


Note

Medium Risk
Touches OAuth redirect validation and callback handling (security-sensitive) and changes guardrail reconciliation logic across pods; also adjusts management/health endpoints and UI calls, which could impact admin workflows if edge cases are missed.

Overview
MCP OAuth proxy hardening + UI support: OAuth redirect_uri validation is expanded from loopback-only to loopback OR same-origin, with re-validation on /callback to block open-redirect/code-theft while allowing the proxy UI callback. Base-URL reconstruction (get_request_base_url) is centralized in oauth_utils, and new tests cover trusted redirect behavior.

Guardrails multi-pod correctness: In-memory guardrails are now tagged with a source (db vs config), DB-loaded guardrails are initialized with source="db", and a new reconciliation pass purges stale DB-backed guardrails that were deleted in another pod. Endpoints are updated to avoid returning stale DB-backed in-memory entries as if they were config guardrails, with added coverage.

Operational UX improvements: /health/test_connection now prefers model_info.id to select the exact deployment when model names are duplicated (UI passes the id; backend resolves via llm_router.get_deployment). /tag/list adds optional start_date/end_date query params (validated) to filter dynamic tags by date window, and the dashboard tag fetch now passes the active date range.

SSO/JWT team mapping: Adds get_all_jwt_team_ids() to union singular and plural team claims and switches SSO team extraction to use it, with regression tests.

Minor UI layout tweak: Key info view layout is adjusted to use scrollable full-height containers.

Reviewed by Cursor Bugbot for commit fbafae0. Bugbot is set up for automated code reviews on this repo. Configure here.

dennishenry and others added 13 commits May 6, 2026 09:32
…tiple deployments share a model_name

When two or more deployments share a 'model_name' (e.g. wildcard 'openai/*'
with multiple 'api_base' values configured for failover), clicking
'Test Connection' on a specific row in the UI silently probed
'deployments[0]' instead of the row the user actually selected.

Root cause:
- Backend (_health_endpoints.py): the route handler picked litellm_params
  via 'get_model_list(model_name=...)' and unconditionally took the first
  match, ignoring 'model_info.id' that came in on the request body.
- UI (model_info_view.tsx): the Test Connection click handler did not
  forward the clicked row's 'model_info.id' at all, leaving the backend
  with no way to disambiguate.

Fix:
- Backend: when 'model_info.id' is provided, resolve the deployment via
  the router's existing O(1) 'get_deployment(model_id=...)' helper.
  Falls back to the legacy model_name lookup when no id is supplied,
  preserving behavior for callers that don't pass one (Add Model wizard,
  curl users).
- UI: forward 'localModelData.model_info?.id' in the model_info payload.

Tests:
- Backend: 2 new tests in test_health_endpoints.py covering the
  duplicate-model_name disambiguation path and the no-id legacy path.
- UI: 1 new vitest case asserting the click handler payload contains
  'id'.
…g Tick

The 30s DB poll only added/updated guardrails; it never removed entries
deleted on another pod. Stale DB-backed entries then leaked into list
responses labeled as "config" because the list endpoint inferred source
from set-difference.

Track provenance explicitly on InMemoryGuardrailHandler (source: db|config)
and reconcile DB-sourced entries against the latest DB result on each
polling tick. List/info endpoints read source directly instead of inferring.
The SSO callback flow (`generic_response_convertor` → `add_missing_team_member`)
was reading only the plural `team_ids_jwt_field` claim. IdPs that populate the
singular `team_id_jwt_field` instead (Okta/Auth0 group → primary team) had their
users created via SSO with `teams: []` — never assigned to the team named in the
JWT, regardless of how the user_metadata changed across logins.

Adds `JWTHandler.get_all_jwt_team_ids()` returning the deduplicated union of
both claim sources, and threads it through both branches that build `all_teams`
in `generic_response_convertor`. JWT bearer auth path is intentionally
unchanged — pending customer feedback on whether membership reconciliation
there should be moved or stay additive.
… Cover Stale-DB List/Info Branches

Per Greptile review: the early-return path in initialize_guardrail
silently dropped the source argument, so a racing polling tick or a
hot-reload could leave an entry's provenance stuck on the wrong value.
Write to _sources before returning so the caller's intent always wins.

Also adds two endpoint-level tests that exercise the new branches the
fix introduced: list_guardrails_v2 must skip in-memory entries tagged
source='db' that are missing from the live DB result, and
get_guardrail_info must 404 (not return as 'config') for stale
DB-backed entries.
Greptile flagged that the helper was delegating to JWTHandler.get_team_id,
which falls back to litellm_jwtauth.team_id_default when the JWT claim is
missing or the field isn't configured. The plural-only get_team_ids_from_jwt
that the SSO path used historically has no such fallback, so threading
get_all_jwt_team_ids through generic_response_convertor would silently start
adding SSO users to the default team for any tenant that had team_id_default
configured — an undocumented backwards-incompatible change.

Read the singular team_id_jwt_field claim directly via get_nested_value
instead, so the helper returns only what's actually in the token. Added a
test that pins this behavior across both configurations of the default
(team_id_jwt_field set + missing claim, and team_id_jwt_field unset).

Also dropped @pytest.mark.asyncio from the sync test (P2 nit).
…27370)

Squash-merged by litellm-agent from Bytechoreographer's PR.
@oss-pr-review-agent-shin

Copy link
Copy Markdown
Contributor Author

@greptile please review

@CLAassistant

CLAassistant commented May 7, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
5 out of 6 committers have signed the CLA.

✅ mateo-berri
✅ yuneng-berri
✅ dennishenry
✅ Bytechoreographer
✅ ryan-crabbe-berri
❌ oss-pr-review-agent-shin[bot]
You have signed the CLA already but the status is still pending? Let us recheck it.

@codecov

codecov Bot commented May 7, 2026

Copy link
Copy Markdown

@greptile-apps

greptile-apps Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This staging PR collects several independent bug fixes and feature additions across the proxy auth, guardrail, health, and UI layers. Each change is accompanied by focused mock-only unit tests.

  • OAuth redirect URI: validate_trusted_redirect_uri (moved to oauth_utils.py) now accepts same-origin (proxy's own UI) redirects in addition to loopback, guarded by the existing trusted-proxy check on X-Forwarded-* headers; the callback endpoint gains a request parameter to supply the origin context.
  • JWT team membership: New get_all_jwt_team_ids unions the plural team_ids_jwt_field and singular team_id_jwt_field claims so Okta/Auth0 users with only a singular claim are no longer silently dropped from team membership on SSO login.
  • Guardrail provenance: InMemoryGuardrailHandler gains a _sources map distinguishing \"db\" vs \"config\" entries; a reconcile_db_guardrails pass on each polling tick evicts stale DB-backed entries deleted on another pod, and the list/get endpoints filter them rather than surfacing them as config guardrails.
  • Health test connection: Prefers model_info.id (via get_deployment) over model_name to disambiguate wildcard deployments with shared names; falls back to name-based lookup when no id is supplied.
  • Tag list date filter: /tag/list accepts optional start_date/end_date query params (validated, YYYY-MM-DD) pushed into the Prisma group_by WHERE clause; the UI usage page wires the current date range into the tag fetch and adds cancellation.

Confidence Score: 5/5

All changes are well-scoped bug fixes with accompanying mock tests; no auth bypass, data loss, or backwards-incompatible behavior was found.

The OAuth redirect expansion is correctly gated by the existing trusted-proxy check, so X-Forwarded-* header injection cannot widen the allowed origin set. The guardrail reconciliation logic correctly distinguishes DB vs config provenance and only evicts entries that are both DB-tagged and absent from the DB query. The JWT team union preserves the documented contract (no team_id_default leakage). All behavioral changes are covered by isolated unit tests with no real network calls.

No files require special attention.

Important Files Changed

Filename Overview
litellm/proxy/_experimental/mcp_server/oauth_utils.py Adds get_request_base_url (moved from discoverable_endpoints) and new validate_trusted_redirect_uri that accepts same-origin redirects in addition to loopback, with proper header-injection protection via trusted-proxy gating.
litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py Switches redirect URI validation from loopback-only to same-origin-or-loopback; adds request: Request parameter to the callback endpoint for origin determination.
litellm/proxy/auth/handle_jwt.py Adds get_all_jwt_team_ids that unions plural team_ids_jwt_field and singular team_id_jwt_field claims, fixing silent drops for Okta/Auth0-style IdPs that populate only the singular field.
litellm/proxy/guardrails/guardrail_registry.py Adds provenance tracking (_sources dict, get_source, reconcile_db_guardrails) to distinguish DB-backed from config-loaded guardrails, enabling clean cross-pod deletion reconciliation.
litellm/proxy/guardrails/guardrail_endpoints.py Filters stale DB-backed in-memory guardrails from list/get endpoints, and marks guardrails created via API as source=db.
litellm/proxy/health_endpoints/_health_endpoints.py Disambiguates test-connection by model_info.id first before falling back to model_name lookup, fixing wildcard deployments that share the same name.
litellm/proxy/management_endpoints/tag_management_endpoints.py Adds optional start_date/end_date query params to /tag/list with format and range validation, passed into the Prisma group_by WHERE clause for efficient date-window filtering.
litellm/proxy/management_endpoints/ui_sso.py Updates generic_response_convertor to call get_all_jwt_team_ids instead of get_team_ids_from_jwt so the singular team_id claim is included in SSO team membership.
litellm/proxy/proxy_server.py Adds DB guardrail reconciliation pass on each polling tick, collecting IDs from the DB query and calling reconcile_db_guardrails to evict stale entries.
ui/litellm-dashboard/src/components/networking.tsx Extends tagListCall to accept optional startTime/endTime Date params and appends them as start_date/end_date query params when both are provided.
ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.tsx Refactors tag list fetch to pass the current date range and adds cancellation via cancelled flag, with accessToken/startTime/endTime in the dependency array.
ui/litellm-dashboard/src/components/model_info_view.tsx Passes model_info.id in the test-connection call to disambiguate wildcard deployments with shared model names.
ui/litellm-dashboard/src/components/templates/key_info_view.tsx Minor layout fix: changes outer div from h-screen to h-full overflow-y-auto and removes redundant overflow-y-auto max-h-[65vh] from the Settings Panel Card.

Reviews (2): Last reviewed commit: "fix(ui): tag filter dropdown on Usage pa..." | Re-trigger Greptile

…ge (#26847)

Squash-merged by litellm-agent from Bytechoreographer's PR.
@oss-pr-review-agent-shin

Copy link
Copy Markdown
Contributor Author

@greptile please review

@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit fbafae0. Configure here.

@oss-pr-review-agent-shin
oss-pr-review-agent-shin Bot changed the base branch from litellm_internal_staging to shin_agent_oss_staging_05_07_2026 May 7, 2026 21:29
@oss-pr-review-agent-shin
oss-pr-review-agent-shin Bot merged commit 158b0c2 into shin_agent_oss_staging_05_07_2026 May 7, 2026
114 of 115 checks passed
@oss-pr-review-agent-shin
oss-pr-review-agent-shin Bot deleted the litellm_agent_oss_staging_05_07_2026 branch May 7, 2026 21:29
@oss-pr-review-agent-shin

Copy link
Copy Markdown
Contributor Author

🤖 litellm-agent: Squash-merged into staging branch shin_agent_oss_staging_05_07_2026. Staging PR: #27422


Triage Summary
Automated staging-to-internal-staging merge for 5/7/2026. Changes include: refactoring OAuth redirect-URI validation to support both same-origin and loopback flows (mcp_server oauth_utils and discoverable_endpoints); adding get_all_jwt_team_ids to JWTHandler to union singular and plural team-id JWT claims, fixing silent drops for Okta/Auth0 single-team users; adding guardrail source provenance tracking to InMemoryGuardrailHandler with multi-pod reconciliation to prevent stale DB-backed entries from leaking; fixing health endpoint model disambiguation by deployment id; adding date-range filt…

Merge Confidence: 5/5 ✅ READY
Ready to ship.

All checks green. Greptile 5/5, no blocking pattern findings, CircleCI passed.

fzowl pushed a commit to fzowl/litellm that referenced this pull request Jun 24, 2026
…I#27375)

Squash-merged by litellm-agent from oss-pr-review-agent-shin[bot]'s PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants