Compare commits
2 Commits
feat/ci-pu
...
litellm_in
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b02df7735a | ||
|
|
1bc132132e |
153
.github/workflows/runtime-release.yml
vendored
Normal file
153
.github/workflows/runtime-release.yml
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
name: Build LiteLLM Runtime Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [litellm_internal_staging, main]
|
||||
paths:
|
||||
- litellm/**
|
||||
- pyproject.toml
|
||||
- uv.lock
|
||||
- .github/workflows/runtime-release.yml
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: litellm-runtime-release-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build ${{ matrix.distro }}-${{ matrix.version }}-${{ matrix.arch }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
distro: [debian, ubuntu]
|
||||
version: ["11", "12", "13", "22.04", "24.04", "26.04"]
|
||||
arch: [amd64, arm64]
|
||||
exclude:
|
||||
- distro: debian
|
||||
version: "22.04"
|
||||
- distro: debian
|
||||
version: "24.04"
|
||||
- distro: debian
|
||||
version: "26.04"
|
||||
- distro: ubuntu
|
||||
version: "11"
|
||||
- distro: ubuntu
|
||||
version: "12"
|
||||
- distro: ubuntu
|
||||
version: "13"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Build target wheelhouse
|
||||
env:
|
||||
TARGET_DISTRO: ${{ matrix.distro }}
|
||||
TARGET_VERSION: ${{ matrix.version }}
|
||||
TARGET_ARCH: ${{ matrix.arch }}
|
||||
LITELLM_VERSION: "1.89.0"
|
||||
LITELLM_DEBIAN_11_VERSION: "1.74.9"
|
||||
UV_VERSION: "0.11.21"
|
||||
PORTABLE_PYTHON_VERSION: "3.13.14"
|
||||
run: |
|
||||
set -euo pipefail
|
||||
root="${PWD}/dist/runtime/litellm-runtime"
|
||||
mkdir -p "${root}/packages/pip" "${root}/packages/python" \
|
||||
"${root}/metadata" dist/assets
|
||||
image="${TARGET_DISTRO}:${TARGET_VERSION}"
|
||||
docker run --rm --platform "linux/${TARGET_ARCH}" \
|
||||
-e TARGET_DISTRO -e TARGET_VERSION -e TARGET_ARCH \
|
||||
-e LITELLM_VERSION -e LITELLM_DEBIAN_11_VERSION \
|
||||
-e UV_VERSION -e PORTABLE_PYTHON_VERSION \
|
||||
-v "${PWD}:/src:ro" \
|
||||
-v "${root}:/out" \
|
||||
"${image}" bash -lc '
|
||||
set -euo pipefail
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends \
|
||||
ca-certificates curl build-essential libpq-dev \
|
||||
python3 python3-dev python3-pip python3-venv
|
||||
python_bin=python3
|
||||
if [ "${TARGET_DISTRO}:${TARGET_VERSION}" = "ubuntu:26.04" ]; then
|
||||
case "${TARGET_ARCH}" in amd64) uv_arch=x86_64 ;; arm64) uv_arch=aarch64 ;; esac
|
||||
curl -fsSL \
|
||||
"https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-${uv_arch}-unknown-linux-gnu.tar.gz" \
|
||||
-o /tmp/uv.tar.gz
|
||||
tar -xzf /tmp/uv.tar.gz -C /tmp
|
||||
install -m 0755 "$(find /tmp -type f -path "*/uv-*/uv" -print -quit)" /usr/local/bin/uv
|
||||
uv python install "${PORTABLE_PYTHON_VERSION}" --install-dir /out/packages/python --no-bin
|
||||
python_bin="$(find -L /out/packages/python -type f -path "*/bin/python3.13" -perm /111 -print -quit)"
|
||||
find /out/packages/python -name EXTERNALLY-MANAGED -delete
|
||||
"${python_bin}" -m ensurepip --upgrade
|
||||
fi
|
||||
"${python_bin}" -m venv /tmp/wheel-builder
|
||||
/tmp/wheel-builder/bin/pip install --upgrade pip setuptools wheel
|
||||
package_spec="/src[proxy]"
|
||||
runtime_spec="litellm[proxy]==${LITELLM_VERSION}"
|
||||
if [ "${TARGET_DISTRO}:${TARGET_VERSION}" = "debian:11" ]; then
|
||||
package_spec="litellm[proxy]==${LITELLM_DEBIAN_11_VERSION}"
|
||||
runtime_spec="${package_spec}"
|
||||
fi
|
||||
/tmp/wheel-builder/bin/pip wheel --wheel-dir /out/packages/pip \
|
||||
"${package_spec}" prisma psycopg2-binary
|
||||
printf "LITELLM_PACKAGE_SPEC=%s\n" "${runtime_spec}" > /out/metadata/runtime.env
|
||||
'
|
||||
cat > "${root}/manifest.json" <<JSON
|
||||
{
|
||||
"component": "litellm",
|
||||
"commit": "${GITHUB_SHA}",
|
||||
"distro": "${TARGET_DISTRO}",
|
||||
"version": "${TARGET_VERSION}",
|
||||
"arch": "${TARGET_ARCH}"
|
||||
}
|
||||
JSON
|
||||
asset="litellm-runtime-${TARGET_DISTRO}-${TARGET_VERSION}-${TARGET_ARCH}.tar.gz"
|
||||
tar -czf "dist/assets/${asset}" -C dist/runtime litellm-runtime
|
||||
(
|
||||
cd dist/assets
|
||||
sha256sum -- "./${asset}" | sed 's# \./# #' > \
|
||||
"SHA256SUMS-${TARGET_DISTRO}-${TARGET_VERSION}-${TARGET_ARCH}"
|
||||
)
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: litellm-runtime-${{ matrix.distro }}-${{ matrix.version }}-${{ matrix.arch }}
|
||||
path: |
|
||||
dist/assets/*.tar.gz
|
||||
dist/assets/SHA256SUMS-*
|
||||
if-no-files-found: error
|
||||
|
||||
publish:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: litellm-runtime-*
|
||||
path: dist
|
||||
merge-multiple: true
|
||||
|
||||
- name: Publish runtime release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tag="runtime-${GITHUB_SHA::12}"
|
||||
cat dist/SHA256SUMS-* | sort -u > dist/SHA256SUMS
|
||||
rm -f dist/SHA256SUMS-*
|
||||
if gh release view "${tag}" --repo "${GITHUB_REPOSITORY}" >/dev/null 2>&1; then
|
||||
gh release upload "${tag}" dist/*.tar.gz dist/SHA256SUMS \
|
||||
--repo "${GITHUB_REPOSITORY}" --clobber
|
||||
else
|
||||
gh release create "${tag}" dist/*.tar.gz dist/SHA256SUMS \
|
||||
--repo "${GITHUB_REPOSITORY}" \
|
||||
--target "${GITHUB_SHA}" \
|
||||
--title "LiteLLM runtime ${GITHUB_SHA::12}" \
|
||||
--notes "Prebuilt wheelhouses for maintained Debian and Ubuntu targets."
|
||||
fi
|
||||
@ -840,7 +840,46 @@ async def google_login(
|
||||
prisma_client,
|
||||
user_api_key_cache,
|
||||
user_custom_ui_sso_sign_in_handler,
|
||||
master_key,
|
||||
)
|
||||
import secrets
|
||||
import jwt
|
||||
from fastapi.responses import RedirectResponse
|
||||
from litellm.proxy.auth.login_utils import authenticate_user, create_ui_token_object
|
||||
from litellm.proxy.utils import get_custom_url
|
||||
|
||||
if key is not None and master_key is not None:
|
||||
try:
|
||||
if secrets.compare_digest(key.encode("utf-8"), master_key.encode("utf-8")):
|
||||
ui_username = os.getenv("UI_USERNAME", "admin")
|
||||
login_result = await authenticate_user(
|
||||
username=ui_username,
|
||||
password=key,
|
||||
master_key=master_key,
|
||||
prisma_client=prisma_client,
|
||||
)
|
||||
from litellm.proxy.proxy_server import general_settings
|
||||
returned_ui_token_object = create_ui_token_object(
|
||||
login_result=login_result,
|
||||
general_settings=general_settings,
|
||||
premium_user=False,
|
||||
)
|
||||
jwt_token = jwt.encode(
|
||||
dict(returned_ui_token_object),
|
||||
master_key,
|
||||
algorithm="HS256",
|
||||
)
|
||||
litellm_dashboard_ui = get_custom_url(str(request.base_url))
|
||||
if litellm_dashboard_ui.endswith("/"):
|
||||
litellm_dashboard_ui += "ui/"
|
||||
else:
|
||||
litellm_dashboard_ui += "/ui/"
|
||||
litellm_dashboard_ui += "?login=success"
|
||||
response_redirect = RedirectResponse(url=litellm_dashboard_ui, status_code=307)
|
||||
response_redirect.set_cookie(key="token", value=jwt_token, path="/")
|
||||
return response_redirect
|
||||
except Exception as e:
|
||||
verbose_proxy_logger.error(f"Unified Auth Token SSO login failed: {e}")
|
||||
|
||||
microsoft_client_id = os.getenv("MICROSOFT_CLIENT_ID", None)
|
||||
google_client_id = os.getenv("GOOGLE_CLIENT_ID", None)
|
||||
@ -853,31 +892,6 @@ async def google_login(
|
||||
if is_disabled:
|
||||
return admin_ui_disabled()
|
||||
|
||||
####### Check if user is a Enterprise / Premium User #######
|
||||
if (
|
||||
microsoft_client_id is not None
|
||||
or google_client_id is not None
|
||||
or generic_client_id is not None
|
||||
):
|
||||
if premium_user is not True:
|
||||
# Check if under 'free SSO user' limit
|
||||
if prisma_client is not None:
|
||||
total_users = await UserRepository(prisma_client).table.count()
|
||||
if total_users and total_users > 5:
|
||||
raise ProxyException(
|
||||
message="You must be a LiteLLM Enterprise user to use SSO for more than 5 users. If you have a license please set `LITELLM_LICENSE` in your env. If you want to obtain a license meet with us here: https://enterprise.litellm.ai/demo You are seeing this error message because You set one of `MICROSOFT_CLIENT_ID`, `GOOGLE_CLIENT_ID`, or `GENERIC_CLIENT_ID` in your env. Please unset this",
|
||||
type=ProxyErrorTypes.auth_error,
|
||||
param="premium_user",
|
||||
code=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
else:
|
||||
raise ProxyException(
|
||||
message=CommonProxyErrors.db_not_connected_error.value,
|
||||
type=ProxyErrorTypes.auth_error,
|
||||
param="premium_user",
|
||||
code=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
|
||||
####### Detect DB + MASTER KEY in .env #######
|
||||
missing_env_vars = show_missing_vars_in_env()
|
||||
if missing_env_vars is not None:
|
||||
@ -901,18 +915,9 @@ async def google_login(
|
||||
|
||||
# check if user defined a custom auth sso sign in handler, if yes, use it
|
||||
if user_custom_ui_sso_sign_in_handler is not None:
|
||||
try:
|
||||
from litellm_enterprise.proxy.auth.custom_sso_handler import ( # type: ignore[import-untyped]
|
||||
EnterpriseCustomSSOHandler,
|
||||
)
|
||||
|
||||
return await EnterpriseCustomSSOHandler.handle_custom_ui_sso_sign_in(
|
||||
request=request,
|
||||
)
|
||||
except ImportError:
|
||||
raise ValueError(
|
||||
"Enterprise features are not available. Custom UI SSO sign-in requires LiteLLM Enterprise."
|
||||
)
|
||||
raise ValueError(
|
||||
"Custom UI SSO sign-in handler is not available in this MIT-only build."
|
||||
)
|
||||
|
||||
# Check if we should use SSO handler
|
||||
if (
|
||||
@ -4350,26 +4355,10 @@ async def debug_sso_login(request: Request):
|
||||
PROXY_BASE_URL should be the your deployed proxy endpoint, e.g. PROXY_BASE_URL="https://litellm-production-7002.up.railway.app/"
|
||||
Example:
|
||||
"""
|
||||
from litellm.proxy.proxy_server import premium_user
|
||||
|
||||
microsoft_client_id = os.getenv("MICROSOFT_CLIENT_ID", None)
|
||||
google_client_id = os.getenv("GOOGLE_CLIENT_ID", None)
|
||||
generic_client_id = os.getenv("GENERIC_CLIENT_ID", None)
|
||||
|
||||
####### Check if user is a Enterprise / Premium User #######
|
||||
if (
|
||||
microsoft_client_id is not None
|
||||
or google_client_id is not None
|
||||
or generic_client_id is not None
|
||||
):
|
||||
if premium_user is not True:
|
||||
raise ProxyException(
|
||||
message="You must be a LiteLLM Enterprise user to use SSO. If you have a license please set `LITELLM_LICENSE` in your env. If you want to obtain a license meet with us here: https://enterprise.litellm.ai/demo You are seeing this error message because You set one of `MICROSOFT_CLIENT_ID`, `GOOGLE_CLIENT_ID`, or `GENERIC_CLIENT_ID` in your env. Please unset this",
|
||||
type=ProxyErrorTypes.auth_error,
|
||||
param="premium_user",
|
||||
code=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
|
||||
# get url from request
|
||||
redirect_url = SSOAuthenticationHandler.get_redirect_url_for_sso(
|
||||
request=request,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user