From 4d099a788cd922ebf4146477cf21ad9d93960274 Mon Sep 17 00:00:00 2001 From: songkuan-zheng <252822057+songkuan-zheng@users.noreply.github.com> Date: Fri, 29 May 2026 17:29:09 +0000 Subject: [PATCH] fix(docker): make UI build robust (npm config + fail-loud validation) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #31 shipped the UI rebuild step but missed three refinements discovered during live e2e: (a) the builder image's older npm rejects the project's .npmrc `min-release-age=3d` (npm 11+ supply-chain hardening) as a fatal config error, so override it to 0 just for the docker RUN; (b) switch from `&& \` chain to `set -eux; ...; \` so a failed step actually aborts the build instead of being swallowed by the trailing `|| true`; (c) add `test -f out/index.html` validations after both the build and the copy so a silent-success build can't ship a broken image. Also adds `.gstack/` to .gitignore (gstack working dir — never useful to commit) and a trailing newline cleanup. Without (a), CI's release-docker workflow fails at `npm ci`. Without (b)+(c), failures are invisible and the image ships with a stale _experimental/out/. --- .gitignore | 3 ++- Dockerfile | 25 +++++++++++++++++-------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index c618d609f02..86af079f798 100644 --- a/.gitignore +++ b/.gitignore @@ -118,4 +118,5 @@ STABILIZATION_TODO.md litellm/proxy/_experimental/out/ ui/litellm-dashboard/out/ ui/litellm-dashboard/.next/ -ui/litellm-dashboard/node_modules/ \ No newline at end of file +ui/litellm-dashboard/node_modules/ +.gstack/ diff --git a/Dockerfile b/Dockerfile index aaac49e153e..1404f7ed862 100644 --- a/Dockerfile +++ b/Dockerfile @@ -60,14 +60,23 @@ COPY . . # layer slim. The committed bundle (now .gitignored) is treated as a # "seed for fresh clones that don't run docker build" only — it is # always overwritten by this step in any image that actually ships. -RUN cd ui/litellm-dashboard && \ - npm ci --no-audit --no-fund --prefer-offline && \ - npm run build && \ - rm -rf /app/litellm/proxy/_experimental/out && \ - cp -r out /app/litellm/proxy/_experimental/out && \ - cd /app && \ - rm -rf ui/litellm-dashboard/node_modules ui/litellm-dashboard/out && \ - npm cache clean --force 2>/dev/null || true +RUN set -eux; \ + cd ui/litellm-dashboard; \ + # Builder image's npm doesn't recognize min-release-age (npm 11+ + # config in the project's .npmrc for local-dev supply-chain + # hardening) and treats it as a fatal `npm ci` config error. The + # .npmrc comment notes "npm ci ignores this" — true for newer + # npm, not for the builder's older one. Override to 0 just for + # this RUN so the lockfile install still works. + NPM_CONFIG_MIN_RELEASE_AGE=0 npm ci --no-audit --no-fund --prefer-offline; \ + npm run build; \ + test -f out/index.html || { echo "FATAL: next build did not produce out/index.html"; ls -la out/ 2>/dev/null; exit 1; }; \ + rm -rf /app/litellm/proxy/_experimental/out; \ + cp -r out /app/litellm/proxy/_experimental/out; \ + cd /app; \ + rm -rf ui/litellm-dashboard/node_modules ui/litellm-dashboard/out; \ + { npm cache clean --force 2>/dev/null || true; }; \ + test -f /app/litellm/proxy/_experimental/out/index.html || { echo "FATAL: copy did not land the bundle"; exit 1; } # Preserved upstream hook: enterprise customizations can still override # the bundle via the canonical build_admin_ui.sh path. Default is no-op.