[Infra] Mirror litellm_table_patch source changes (no binaries)

Cherry-pick source-only changes from litellm_table_patch, excluding
build artifacts from the incident response period.

- Remove destructive DROP COLUMN migration (20260311180521_schema_sync)
- Remove now-unnecessary restore migration (20260327232350)
- Bump litellm-proxy-extras 0.4.60 → 0.4.61
- Add regression test to block future DROP COLUMN migrations
- Fix double error handling in getTeamPermissionsCall

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yuneng Jiang 2026-03-27 16:45:12 -07:00
parent 46b92da0bd
commit a074d1d68b
No known key found for this signature in database
8 changed files with 31 additions and 36 deletions

View file

@ -1,11 +0,0 @@
-- DropIndex
DROP INDEX IF EXISTS "LiteLLM_MCPServerTable_approval_status_idx";
-- AlterTable
ALTER TABLE "LiteLLM_MCPServerTable" DROP COLUMN IF EXISTS "approval_status",
DROP COLUMN IF EXISTS "review_notes",
DROP COLUMN IF EXISTS "reviewed_at",
DROP COLUMN IF EXISTS "source_url",
DROP COLUMN IF EXISTS "submitted_at",
DROP COLUMN IF EXISTS "submitted_by";

View file

@ -1,14 +0,0 @@
-- AlterTable: Restore BYOM lifecycle fields to LiteLLM_MCPServerTable
-- These were dropped in 20260311180521_schema_sync due to schema drift.
-- The proxy schema (source of truth) retained them.
ALTER TABLE "LiteLLM_MCPServerTable"
ADD COLUMN IF NOT EXISTS "source_url" TEXT,
ADD COLUMN IF NOT EXISTS "approval_status" TEXT DEFAULT 'active',
ADD COLUMN IF NOT EXISTS "submitted_by" TEXT,
ADD COLUMN IF NOT EXISTS "submitted_at" TIMESTAMP(3),
ADD COLUMN IF NOT EXISTS "reviewed_at" TIMESTAMP(3),
ADD COLUMN IF NOT EXISTS "review_notes" TEXT;
-- CreateIndex
CREATE INDEX IF NOT EXISTS "LiteLLM_MCPServerTable_approval_status_idx"
ON "LiteLLM_MCPServerTable"("approval_status");

View file

@ -1,6 +1,6 @@
[tool.poetry]
name = "litellm-proxy-extras"
version = "0.4.60"
version = "0.4.61"
description = "Additional files for the LiteLLM Proxy. Reduces the size of the main litellm package."
authors = ["BerriAI"]
readme = "README.md"
@ -22,7 +22,7 @@ requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.commitizen]
version = "0.4.60"
version = "0.4.61"
version_files = [
"pyproject.toml:version",
"../requirements.txt:litellm-proxy-extras==",

8
poetry.lock generated
View file

@ -3219,15 +3219,15 @@ files = [
[[package]]
name = "litellm-proxy-extras"
version = "0.4.60"
version = "0.4.61"
description = "Additional files for the LiteLLM Proxy. Reduces the size of the main litellm package."
optional = true
python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8"
groups = ["main"]
markers = "extra == \"proxy\""
files = [
{file = "litellm_proxy_extras-0.4.60-py3-none-any.whl", hash = "sha256:7abcc811f7430e4b24e7a8ba7186219a4845a955ae7a71d8822bd03fd9fc3393"},
{file = "litellm_proxy_extras-0.4.60.tar.gz", hash = "sha256:1c122f2a7e0eb58fa4c6d8da9da82ac1fe2869de3510bcfade5c2932af202328"},
{file = "litellm_proxy_extras-0.4.61-py3-none-any.whl", hash = "sha256:9bd1e57ef51972cacff52172ef5d70b0ff689f57f3d240877667301ab8f8590e"},
{file = "litellm_proxy_extras-0.4.61.tar.gz", hash = "sha256:dce8e39b1547abf90d912ddd0f2a876beadf789d700ef04c165362d78ad56aee"},
]
[[package]]
@ -8009,4 +8009,4 @@ utils = ["numpydoc"]
[metadata]
lock-version = "2.1"
python-versions = ">=3.9,<4.0"
content-hash = "b4e3ee072f600fab9810024afdd550407d25733a9b6752476aa61826e33bc08e"
content-hash = "8dad0e86d75e574f12c57c9f32614b7b4ea2181e931874046d43a398aef1e998"

View file

@ -61,7 +61,7 @@ boto3 = { version = "^1.40.76", optional = true }
redisvl = {version = "^0.4.1", optional = true, markers = "python_version >= '3.9' and python_version < '3.14'"}
mcp = {version = ">=1.25.0,<2.0.0", optional = true, python = ">=3.10"}
a2a-sdk = {version = "^0.3.22", optional = true, python = ">=3.10"}
litellm-proxy-extras = {version = "^0.4.60", optional = true}
litellm-proxy-extras = {version = "^0.4.61", optional = true}
rich = {version = "^13.7.1", optional = true}
litellm-enterprise = {version = "0.1.35", optional = true}
diskcache = {version = "^5.6.1", optional = true}

View file

@ -57,7 +57,7 @@ grpcio>=1.75.0; python_version >= "3.14"
sentry_sdk==2.21.0 # for sentry error handling
detect-secrets==1.5.0 # Enterprise - secret detection / masking in LLM requests
tzdata==2025.1 # IANA time zone database
litellm-proxy-extras==0.4.60 # for proxy extras - e.g. prisma migrations
litellm-proxy-extras==0.4.61 # for proxy extras - e.g. prisma migrations
llm-sandbox==0.3.31 # for skill execution in sandbox
### LITELLM PACKAGE DEPENDENCIES
python-dotenv==1.0.1 # for env

View file

@ -222,6 +222,27 @@ class TestMigrationSQLIdempotency:
+ "\n".join(violations)
)
_DROP_COLUMN_ALLOWLIST = {
"20250918083359_drop_spec_version_column_from_mcp_table",
"20260213170952_access_group_change_to_model_name",
"20260224203854_add_agent_object_permissions_table",
}
def test_no_drop_column_statements(self, all_migrations):
"""Migrations must not drop columns — dropping columns is destructive
and can break running application instances during rolling deploys."""
violations = []
for migration_name, sql in all_migrations:
if migration_name in self._DROP_COLUMN_ALLOWLIST:
continue
for line_num, line in enumerate(sql.splitlines(), 1):
if re.search(r"DROP\s+COLUMN", line, re.IGNORECASE):
violations.append(f" {migration_name}:{line_num}: {line.strip()}")
assert not violations, (
"DROP COLUMN found in migrations (destructive, not allowed):\n"
+ "\n".join(violations)
)
def test_drop_index_uses_if_exists(self, all_migrations):
"""DROP INDEX statements must use IF EXISTS"""
violations = []

View file

@ -7288,12 +7288,11 @@ export const getTeamPermissionsCall = async (accessToken: string, teamId: string
if (!response.ok) {
const errorData = await response.json();
const errorMessage = deriveErrorMessage(errorData);
handleError(errorMessage);
throw new Error(errorMessage);
console.error("Available permissions fetch failed:", errorMessage);
return { all_available_permissions: [], team_member_permissions: [] };
}
const data = await response.json();
console.log("Team permissions response:", data);
return data;
} catch (error) {
console.error("Failed to get team permissions:", error);