mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
* fix(proxy): make /team/member_delete's four cleanups atomic The team roster update, the user.teams update, the team membership delete, and the team-scoped verification token delete ran as four sequential writes with no transaction around them, so a failure between any two left the removal half applied. Thread a single prisma transaction through all four writes, following the same tx.<table> pattern /team/member_add and /team/member_update already use, so either all four land or none do. * fix(team): serialize member_add, member_delete, and delete under the team's advisory lock /team/member_add validated a team exists and then wrote the user's teams array and a membership row without holding anything across that gap, so a /team/delete could commit its reference sweeps in between and leave a member pointing at a team id that no longer exists. The write path already re-read members_with_roles under a row lock before this change, but SELECT ... FOR UPDATE can deadlock with the access-group endpoints, which lock an access group and then a team. member_add now takes pg_advisory_xact_lock(hashtext(team_id)) before re-reading the team and only writes if it is still there, so a delete that already committed is visible before any write happens. delete_team takes the same lock around its own row delete and reference sweep, so the two requests can never interleave: whichever acquires the lock first runs to completion before the other's read can proceed. Dropping the row lock from member_add's read also dropped the incidental protection it gave against a concurrent member_delete, which still wrote from the snapshot it validated against, unlocked, and could silently overwrite whatever member_add had just committed. member_delete now takes the same advisory lock and re-reads the roster under it before computing its own write, so it can never resurrect a member by overwriting from stale data. Resolves LIT-5544 * fix(team): run member writes on the advisory lock's transaction Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(team): keep member writes on the lock holder's connection after merge Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(team): keep the transactional member create an upsert on user_id The transaction path was creating the email-identified user row outright, where the regular client path upserts on user_id. Share one upsert helper between both member paths so the create stays idempotent on the lock holder's connection. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(team): read member_delete's user and key rows on the lock-holding transaction Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|---|---|---|
| .. | ||
| test-results | ||
| ui_unit_tests | ||
| .npmrc | ||
| conftest.py | ||
| test_access_group_team_sync.py | ||
| test_key_management.py | ||
| test_role_based_access.py | ||
| test_route_check_unit_tests.py | ||
| test_sso_sign_in.py | ||
| test_team_delete_member_add_race.py | ||
| test_usage_endpoints.py | ||