diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0a98ca0c0..d5ca08dea 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -290,6 +290,8 @@ jobs: test "$(yq 'select(.kind == "Deployment" and .metadata.name == "backend") | .spec.template.spec.terminationGracePeriodSeconds' /tmp/dev-rendered.yaml)" = "30" test "$(yq 'select(.kind == "Deployment" and .metadata.name == "backend") | .spec.template.spec.containers[] | select(.name == "backend") | .readinessProbe.httpGet.path' /tmp/dev-rendered.yaml)" = "/api/health/ready" test "$(yq 'select(.kind == "Deployment" and .metadata.name == "backend") | .spec.template.spec.containers[] | select(.name == "backend") | .lifecycle.preStop.exec.command[2]' /tmp/dev-rendered.yaml)" = "sleep 10" + # LiteLLM is public for its /v1 API only; `/` exposed the master-key admin login (2026-10-07). + test "$(yq 'select(.kind == "Ingress") | .spec.rules[] | select(.host == "litellm.commonly.me") | .http.paths | map(.path) | join(",")' /tmp/dev-rendered.yaml)" = "/v1" - name: Render Slack OAuth secret wiring run: | diff --git a/docs/development/LITELLM.md b/docs/development/LITELLM.md index 54301906f..6feb5b0ea 100644 --- a/docs/development/LITELLM.md +++ b/docs/development/LITELLM.md @@ -29,7 +29,7 @@ Backend services ──► LiteLLM :4000 ──► Gemini / OpenRouter / Ope ``` - **Service**: `litellm.commonly-dev.svc.cluster.local:4000` -- **Dashboard**: `https://litellm.commonly.me/ui` (login with `LITELLM_MASTER_KEY`) +- **Dashboard**: cluster-internal only. `kubectl port-forward -n commonly-dev svc/litellm 4000:4000`, then `http://localhost:4000/ui` (login with `LITELLM_MASTER_KEY`). The public host `litellm.commonly.me` serves `/v1` and nothing else; the ingress used to serve `/`, which put this master-key login on the open internet. - **Health probe**: `GET /health/readiness` (no auth required) - **Spend logs**: stored in Aiven PostgreSQL (`LiteLLM_SpendLogs` table) - **Image**: `ghcr.io/berriai/litellm:main-stable` @@ -422,7 +422,13 @@ req.write(body);req.end();" ### Using the LiteLLM Dashboard (UI) -URL: `https://litellm.commonly.me/ui` +Not public. Port-forward the service, then open the local URL: + +```bash +kubectl port-forward -n commonly-dev svc/litellm 4000:4000 +# http://localhost:4000/ui +``` + Login: username `admin`, password = value of `LITELLM_MASTER_KEY` ```bash diff --git a/k8s/helm/commonly/templates/ingress/ingress.yaml b/k8s/helm/commonly/templates/ingress/ingress.yaml index b0b3e1c90..bbc50512f 100644 --- a/k8s/helm/commonly/templates/ingress/ingress.yaml +++ b/k8s/helm/commonly/templates/ingress/ingress.yaml @@ -66,12 +66,15 @@ spec: - host: {{ .Values.ingress.hosts.litellm.host }} http: paths: - - path: {{ .Values.ingress.hosts.litellm.path }} - pathType: {{ .Values.ingress.hosts.litellm.pathType }} + {{- /* `paths` wins over a legacy single `path` so an older values file cannot re-open `/`. */}} + {{- range (.Values.ingress.hosts.litellm.paths | default (list .Values.ingress.hosts.litellm.path)) }} + - path: {{ . }} + pathType: {{ $.Values.ingress.hosts.litellm.pathType }} backend: service: name: litellm port: - number: {{ .Values.litellm.port }} + number: {{ $.Values.litellm.port }} + {{- end }} {{- end }} {{- end }} diff --git a/k8s/helm/commonly/values.yaml b/k8s/helm/commonly/values.yaml index 4665ef137..dbb44574e 100644 --- a/k8s/helm/commonly/values.yaml +++ b/k8s/helm/commonly/values.yaml @@ -370,7 +370,13 @@ ingress: aliases: [] litellm: host: litellm.commonly.me - path: / + # Only the OpenAI-compatible API is public. Clients (the pi adapter, any + # SDK) use the /v1 base URL; the admin dashboard, its login and the key / + # user / team management routes stay cluster-internal — reach them with + # `kubectl port-forward svc/litellm 4000:4000`. Serving `/` here put a + # master-key login page on the open internet. + paths: + - /v1 pathType: Prefix tls: enabled: false