Commit graph

39012 commits

Author SHA1 Message Date
Ishaan Jaffer
d908e9940b
fix(proxy_server): refuse to mount agent_session routers when JWT secret is unset
When LITELLM_AGENT_JWT_SECRET is not set, the daemon JWT auth layer
cannot operate safely (no master-key fallback). Refuse to mount the
four /v2/agents+/v2/sessions routers in that case and log a clear
error pointing operators at the env var. Mounting them anyway would
expose an auth surface that can never validate a token and crash on
every request.

Greptile P1 SECURITY follow-up.
2026-05-06 15:37:42 -07:00
Ishaan Jaffer
1d44980be2
fix(internal_endpoints): use asyncio.get_running_loop() not get_event_loop
asyncio.get_event_loop() is deprecated inside a running coroutine
(Python 3.10+). Replace the two call sites in
daemon_get_next_queued_run with asyncio.get_running_loop().

Greptile P2.
2026-05-06 15:37:35 -07:00
Ishaan Jaffer
1717078971
fix(run_endpoints): use asyncio.get_running_loop() and gate writes for view-only admins
Two fixes in this file:

1. asyncio.get_event_loop() is deprecated inside a running coroutine
   (Python 3.10+). Replace both call sites in _stream_run_events with
   asyncio.get_running_loop().

2. Call assert_caller_can_mutate on create_run and cancel_run so
   view-only admins get 403 instead of bypassing ownership.

Greptile P2 (deprecation) + P1 SECURITY (view-only admin write bypass).
2026-05-06 15:37:29 -07:00
Ishaan Jaffer
19ada25e59
fix(session_endpoints): close /followup concurrency gap and gate writes for view-only admins
Two fixes in this file:

1. /followup new-run branch was bypassing the run-busy concurrency
   guard. When latest_run was terminal-or-absent, the endpoint went
   straight to litellm_agentrun.create without calling
   _has_active_run. Two concurrent /followup calls on an idle session
   both passed the latest_run.status check and both inserted runs,
   breaking the 'one active run per session' invariant that POST /runs
   enforces via 409 run_busy. Add the same _has_active_run check
   before the fallthrough create, plus a defensive insert-time retry
   that re-queries for active runs after IntegrityError and surfaces
   409 run_busy if it lost the race.

2. Call assert_caller_can_mutate on create_session, delete_session,
   and followup so view-only admins get 403 instead of bypassing
   ownership.

Greptile P1 (concurrency) + P1 SECURITY (view-only admin write bypass).
2026-05-06 15:37:23 -07:00
Ishaan Jaffer
f893105116
fix(agent_endpoints): call assert_caller_can_mutate on every write endpoint
Block PROXY_ADMIN_VIEW_ONLY from create_agent / update_agent /
delete_agent. Reads (GET) still pass through is_proxy_admin_read
so view-only admins keep cross-tenant visibility for the support UI.

Greptile P1 SECURITY follow-up (view-only admin write bypass).
2026-05-06 15:37:12 -07:00
Ishaan Jaffer
303f9a5d80
fix(agent_session_endpoints): block view-only admins from mutating other tenants' rows
is_proxy_admin previously returned True for both PROXY_ADMIN and
PROXY_ADMIN_VIEW_ONLY, letting view-only admins skip
assert_caller_owns_agent / assert_caller_owns_session on every write
endpoint and create / update / delete other tenants' agents,
sessions, and runs.

Split the helpers:
  * is_proxy_admin: now full-admin only (used for write paths via the
    fall-through to per-tenant ownership; view-only fails and gets 404).
  * is_proxy_admin_read: full + view-only, used on read paths so the
    support UI can still render any tenant's resources.
  * assert_caller_can_mutate: explicit 403 guard for view-only on
    every state-mutating endpoint.

The mutating endpoints in agent/session/run files call
assert_caller_can_mutate before any DB write — see follow-up commits.

Greptile P1 SECURITY (review #PRR_kwDOKALCgc78uM7F).
2026-05-06 15:37:07 -07:00
Ishaan Jaffer
5037026d75
fix(agent_session_endpoints): require LITELLM_AGENT_JWT_SECRET, no master-key fallback
The daemon JWT secret must be a SEPARATE credential from the proxy
master key. The previous fallback to LITELLM_MASTER_KEY conflated
two distinct auth surfaces — a captured daemon JWT could be used
to mint regular API keys with master-key authority.

Replace _get_signing_secret with a strict check that raises
AgentJWTSecretNotConfiguredError if the dedicated env var is unset.
Add is_agent_jwt_secret_configured() so proxy_server.py can refuse
to mount the routers when the secret is missing.

Greptile P1 SECURITY (review #PRR_kwDOKALCgc78uM7F).
2026-05-06 15:36:58 -07:00
Ishaan Jaffer
f6e5951556
test(agent_session_endpoints): validate cleanup sweeper for expiry/dead-daemon/stuck-runs (LIT-2877 #13) 2026-05-06 15:10:37 -07:00
Ishaan Jaffer
6a815d2b1f
test(agent_session_endpoints): validate JWT scope/exp/cross-session/terminated rejection (LIT-2877 #12) 2026-05-06 15:10:35 -07:00
Ishaan Jaffer
306df1aecc
test(agent_session_endpoints): validate cascade delete + provider.terminate (LIT-2877 #11) 2026-05-06 15:10:34 -07:00
Ishaan Jaffer
5e93b44177
test(agent_session_endpoints): validate cross-tenant isolation at all 3 levels (LIT-2877 #10) 2026-05-06 15:10:32 -07:00
Ishaan Jaffer
3f60ae6a90
test(agent_session_endpoints): validate session + run idempotency (LIT-2877 #9) 2026-05-06 15:10:31 -07:00
Ishaan Jaffer
1b481e4949
test(agent_session_endpoints): validate SSE resume + Last-Event-ID header (LIT-2877 #8) 2026-05-06 15:10:29 -07:00
Ishaan Jaffer
8feafae5b9
test(agent_session_endpoints): validate concurrent run-create returns 409 run_busy (LIT-2877 #7) 2026-05-06 15:10:28 -07:00
Ishaan Jaffer
42d8fdb741
test(agent_session_endpoints): validate /followup smart inject vs new-run (LIT-2877 #6) 2026-05-06 15:10:26 -07:00
Ishaan Jaffer
1567c00c20
test(agent_session_endpoints): validate run state transitions + cancel (LIT-2877 #5) 2026-05-06 15:10:25 -07:00
Ishaan Jaffer
a271a73276
test(agent_session_endpoints): validate session state transitions (LIT-2877 #4) 2026-05-06 15:10:23 -07:00
Ishaan Jaffer
46266b1dd3
test(agent_session_endpoints): validate agent reused across sessions (LIT-2877 #3) 2026-05-06 15:10:22 -07:00
Ishaan Jaffer
1801c1cf15
test(agent_session_endpoints): add in-memory Prisma fake + multi-tenant TestClient fixtures 2026-05-06 15:10:21 -07:00
Ishaan Jaffer
b483dbe7e9
test(agent_session_endpoints): add package marker 2026-05-06 15:10:19 -07:00
Ishaan Jaffer
266081ff30
feat(proxy): mount /v2/agents+sessions routers + start cleanup sweeper 2026-05-06 15:03:25 -07:00
Ishaan Jaffer
68d11f445f
feat(agent_session_endpoints): add cleanup sweeper for expired sessions, dead daemons, stuck runs 2026-05-06 15:03:24 -07:00
Ishaan Jaffer
d8c66623ee
feat(agent_session_endpoints): add daemon callbacks (register/heartbeat/next-run/events:append) 2026-05-06 15:03:22 -07:00
Ishaan Jaffer
6ee24a5cbc
feat(agent_session_endpoints): add /v2/sessions/{sid}/runs CRUD + SSE + cancel 2026-05-06 15:03:21 -07:00
Ishaan Jaffer
bca9abeaef
feat(agent_session_endpoints): add module init exposing routers 2026-05-06 15:03:19 -07:00
Ishaan Jaffer
f69ac9e029
feat(agent_session_endpoints): add /v2/agents CRUD endpoints 2026-05-06 14:59:53 -07:00
Ishaan Jaffer
996427ae70
feat(agent_session_endpoints): add /v2/sessions CRUD + followup + conversation 2026-05-06 14:59:52 -07:00
Ishaan Jaffer
e892489aa7
feat(agent_session_endpoints): add Prisma row to response serialization 2026-05-06 14:59:50 -07:00
Ishaan Jaffer
c8679dfca1
feat(agent_session_endpoints): add Pydantic request/response schemas 2026-05-06 14:59:49 -07:00
Ishaan Jaffer
546c8702de
feat(agent_session_endpoints): add ownership/access-control helpers 2026-05-06 14:59:48 -07:00
Ishaan Jaffer
b8e1121eff
feat(agent_session_endpoints): add ID generation helpers 2026-05-06 14:59:43 -07:00
Ishaan Jaffer
fc4d40fb1e
feat(agent_session_endpoints): add VM provider registry 2026-05-06 14:52:21 -07:00
Ishaan Jaffer
6ab7f7700e
feat(agent_session_endpoints): add NoopVMProvider for tests 2026-05-06 14:52:21 -07:00
Ishaan Jaffer
6c322cfa60
feat(agent_session_endpoints): add AgentVMProvider ABC 2026-05-06 14:52:21 -07:00
Ishaan Jaffer
6b123c4698
feat(agent_session_endpoints): add daemon JWT auth helpers 2026-05-06 14:52:21 -07:00
Ishaan Jaffer
bcc48e43d7
feat(agent_session_endpoints): add session/run state machine 2026-05-06 14:52:21 -07:00
Ishaan Jaffer
1cadabfc4c
feat(agent_session_endpoints): add module constants 2026-05-06 14:52:21 -07:00
Ishaan Jaffer
2ccf626669
feat(proxy-extras): add migration for agent/session/run tables 2026-05-06 14:52:17 -07:00
Ishaan Jaffer
b386b94282
feat(proxy-extras): mirror agent/session/run models 2026-05-06 14:52:17 -07:00
Ishaan Jaffer
bb8b76adfc
feat(proxy): mirror agent/session/run models in litellm/proxy/schema.prisma 2026-05-06 14:52:17 -07:00
Ishaan Jaffer
725a9c7311
feat(proxy): add agent/session/run Prisma models
Add 4 new tables for the agent_session_endpoints module (Cursor SDK on LiteLLM):

- LiteLLM_Agent: agent definition (model, system prompt, default repos)
- LiteLLM_AgentSession: VM-backed conversation owned by an agent
- LiteLLM_AgentRun: single turn within a session
- LiteLLM_AgentRunEvent: append-only event log for resumable SSE

Includes cascade deletes, idempotency unique constraints, and indexes
for the cleanup sweeper and ownership lookups.
2026-05-06 14:52:01 -07:00
ishaan-berri
487479eff7
perf: cap Prometheus end-user metric cardinality with TTL + LRU eviction (#27272)
Co-authored-by: Yassin Kortam <yassinkortam@g.ucla.edu>
2026-05-06 13:35:13 -07:00
oss-agent-shin
c8e47dcb43
Fix early proxy request size enforcement (#27311)
* Add early proxy request size guard

Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>

* Address request size review feedback

Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>

---------

Co-authored-by: oss-agent-shin <279349115+oss-agent-shin@users.noreply.github.com>
Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>
2026-05-06 12:29:11 -07:00
Dibyo Mukherjee
169c436684
Fix/member access group team (#27317)
* fix(auth): pass team_id in member-level model access check

_check_team_member_model_access calls _can_object_call_model without
team_id, so access groups defined via model_info.access_groups cannot
resolve for team-scoped DB models (their internal router name is
model_name_<team>_<uuid>, not the public name). The team-level check
already passes team_id; this mirrors that.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test(auth): add tests for member-level access group resolution with team_id

Eight tests covering _can_object_call_model and
_check_team_member_model_access with team-scoped DB models:

- access group resolves when team_id is passed
- access group fails without team_id (pre-fix behavior)
- literal model name still works with team_id (no regression)
- denied model still denied with team_id
- second model in group also reachable
- end-to-end member access via access group (mocked membership)
- end-to-end member denied for model not in allowed list
- no-override member inherits team-level check

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-06 12:05:22 -07:00
oss-agent-shin
d90cf56245
Fix SCIM user lookup filters (#27308)
* Fix SCIM Okta userName lookup

Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>

* fix scim user filter typing

Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>

---------

Co-authored-by: oss-agent-shin <279349115+oss-agent-shin@users.noreply.github.com>
Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>
2026-05-06 11:58:47 -07:00
ishaan-berri
c92a08a307
Fix team member budget enforcement without user row (#27273)
* Fix team member budget enforcement without user row

Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>

* Clarify regenerated key budget repro

Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>

---------

Co-authored-by: oss-agent-shin <279349115+oss-agent-shin@users.noreply.github.com>
Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>
2026-05-06 11:42:29 -07:00
Yassin Kortam
b1f577199a
fix(proxy): keep spend log cleanup running after batch failures and surface DB errors (#27303)
Co-authored-by: Yassin Kortam <yassinkortam@g.ucla.edu>
2026-05-06 18:39:15 +00:00
Mateo Wang
b83d11351f
proxy: hot-reload config YAML when --reload is set (#27274)
* proxy: hot-reload config YAML when --reload is set

Uvicorn's --reload only watches *.py by default, so editing the
--config YAML did not restart the proxy. _get_reload_options() now
extends reload_dirs/reload_includes with the config file's directory
and basename when --config is provided.

* proxy: qualify reload_includes with absolute config path

Address Greptile review on PR #27274. When the --config file lives
outside cwd, reload_includes previously stored only the basename, which
meant uvicorn/watchfiles would also reload on edits to any same-named
file inside cwd. Use the absolute config path as the include pattern in
that case so only the actual proxy config triggers a restart.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>

* fix(proxy): use basename for reload_includes config pattern

Uvicorn's resolve_reload_patterns() calls pathlib.Path.glob(), which
raises NotImplementedError on absolute patterns (uvicorn discussion
2156). Passing config_abs (an absolute path) when the config file lived
outside cwd crashed startup under --reload. The config_dir is already
added to reload_dirs, so using just the basename as the include pattern
is sufficient to match the specific config file.

* fix: make it reload app when yaml changes

* style: remove unneeded comments

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-05-06 16:06:58 +00:00
Yassin Kortam
bd1ea0252a
perf(proxy): run daily activity aggregation off the event loop (#27264)
Some checks are pending
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / schema-migration (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests: Security / security (push) Waiting to run
Unit Tests: Caching (Redis) / caching-redis (push) Waiting to run
Co-authored-by: Yassin Kortam <yassinkortam@g.ucla.edu>
2026-05-05 20:19:28 -07:00
ishaan-berri
c32ad90823
Fix Prometheus custom metadata label counts (#27268) (#27271)
* Fix Prometheus custom metadata label counts (#27268)

Co-authored-by: oss-agent-shin <279349115+oss-agent-shin@users.noreply.github.com>
Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>

* fix enterprise test: update positional label assertions to keyword args

prometheus_label_factory now calls .labels() with keyword arguments.
Update test_async_log_failure_event assertion to match.

---------

Co-authored-by: oss-agent-shin <ext-agent-shin@berri.ai>
Co-authored-by: oss-agent-shin <279349115+oss-agent-shin@users.noreply.github.com>
Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>
2026-05-05 20:04:56 -07:00