From dd05e1a76d7cbf790607b29ea8e1184803166f74 Mon Sep 17 00:00:00 2001 From: Zhou Kai Date: Wed, 1 Jul 2026 23:40:35 +0800 Subject: [PATCH] fix(docker): production Postgres UV extras detection (#3897) * Fix production postgres UV extras detection * fix(backend): validate Docker build UV extras --- backend/Dockerfile | 18 +- backend/tests/test_deploy_uv_extras.py | 227 +++++++++++++++++++++++++ config.example.yaml | 6 +- scripts/deploy.sh | 68 +++++++- scripts/detect_uv_extras.py | 7 +- 5 files changed, 314 insertions(+), 12 deletions(-) create mode 100644 backend/tests/test_deploy_uv_extras.py diff --git a/backend/Dockerfile b/backend/Dockerfile index b9a3b61a5..93fee6e31 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -14,7 +14,7 @@ ARG NODE_MAJOR=22 ARG APT_MIRROR ARG UV_INDEX_URL # Optional extras to install (e.g. "postgres" for PostgreSQL support) -# Usage: docker build --build-arg UV_EXTRAS=postgres ... +# Usage: docker build --build-arg UV_EXTRAS=postgres,discord ... ARG UV_EXTRAS # Optionally override apt mirror for restricted networks (e.g. APT_MIRROR=mirrors.aliyun.com) @@ -46,9 +46,21 @@ WORKDIR /app COPY backend ./backend # Install dependencies with cache mount -# When UV_EXTRAS is set (e.g. "postgres"), installs optional dependencies. +# When UV_EXTRAS is set (comma- or whitespace-separated), installs optional dependencies. RUN --mount=type=cache,target=/root/.cache/uv \ - sh -c "cd backend && UV_INDEX_URL=${UV_INDEX_URL:-https://pypi.org/simple} uv sync ${UV_EXTRAS:+--extra $UV_EXTRAS}" + sh -c 'cd backend && \ + set -f; \ + extras_flags=""; \ + for extra in $(printf "%s" "$UV_EXTRAS" | tr "," " "); do \ + case "$extra" in \ + [!A-Za-z]* | *[!A-Za-z0-9_-]*) \ + echo "UV_EXTRAS entry $extra is invalid (must match [A-Za-z][A-Za-z0-9_-]*)" >&2; \ + exit 1; \ + ;; \ + esac; \ + extras_flags="$extras_flags --extra $extra"; \ + done; \ + UV_INDEX_URL=${UV_INDEX_URL:-https://pypi.org/simple} uv sync $extras_flags' # UTF-8 locale prevents UnicodeEncodeError on Chinese/emoji content in minimal # containers where locale configuration may be missing and the default encoding is not UTF-8. diff --git a/backend/tests/test_deploy_uv_extras.py b/backend/tests/test_deploy_uv_extras.py new file mode 100644 index 000000000..2453108b6 --- /dev/null +++ b/backend/tests/test_deploy_uv_extras.py @@ -0,0 +1,227 @@ +"""Regression coverage for production deploy.sh UV_EXTRAS propagation.""" + +from __future__ import annotations + +import os +import re +import shlex +import shutil +import subprocess +import sys +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[2] + + +def _backend_dockerfile_uv_sync_script() -> str: + dockerfile = (REPO_ROOT / "backend" / "Dockerfile").read_text(encoding="utf-8") + match = re.search(r"""sh -c (?P["'])(?P