diff --git a/Dockerfile b/Dockerfile index b2235c1..58fa931 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,50 +1,46 @@ FROM node:22-slim +ARG TARGETARCH + # System deps for Chrome for Testing + build tools for native modules (better-sqlite3) -# Must run as root +# On ARM64 we also install system Chromium (Chrome for Testing has no ARM64 binary) RUN apt-get update && apt-get install -y --no-install-recommends \ curl ca-certificates fonts-liberation libasound2 \ libatk-bridge2.0-0 libatk1.0-0 libcups2 libdbus-1-3 \ libdrm2 libgbm1 libgtk-3-0 libnspr4 libnss3 \ libx11-xcb1 libxcomposite1 libxdamage1 libxrandr2 xdg-utils \ python3 make g++ \ + && if [ "$TARGETARCH" = "arm64" ]; then apt-get install -y --no-install-recommends chromium; fi \ && rm -rf /var/lib/apt/lists/* \ - && mkdir -p /db /conf /fredy \ - && chown node:node /db /conf /fredy + && mkdir -p /db /conf /fredy WORKDIR /fredy -# Everything from here runs as the built-in non-root node user (UID 1000) -USER node - ENV NODE_ENV=production \ IS_DOCKER=true -COPY --chown=node:node package.json yarn.lock ./ +COPY package.json yarn.lock ./ # Install dependencies and purge build tools (only needed to compile better-sqlite3) RUN yarn config set network-timeout 600000 \ && yarn --frozen-lockfile \ && yarn cache clean -# Install Chrome for Testing in a separate layer — it's ~150MB and rarely changes, -# so keeping it separate avoids re-downloading on every code/dependency change -RUN npx puppeteer browsers install chrome +# on arm64 use the system Chromium installed above +RUN if [ "$TARGETARCH" != "arm64" ]; then npx puppeteer browsers install chrome; fi # Purge build tools now that native modules are compiled -USER root RUN apt-get purge -y python3 make g++ \ && apt-get autoremove -y \ && rm -rf /var/lib/apt/lists/* -USER node -COPY --chown=node:node index.html vite.config.js ./ -COPY --chown=node:node ui ./ui -COPY --chown=node:node lib ./lib +COPY index.html vite.config.js ./ +COPY ui ./ui +COPY lib ./lib RUN yarn build:frontend -COPY --chown=node:node index.js ./ +COPY index.js ./ RUN ln -s /db /fredy/db \ && ln -s /conf /fredy/conf diff --git a/docker-test.sh b/docker-test.sh index 6ca4aa7..35d6184 100755 --- a/docker-test.sh +++ b/docker-test.sh @@ -42,19 +42,28 @@ for i in $(seq 1 30); do sleep 2 done -# Verify the process is NOT running as root -RUNNING_USER=$(docker exec fredy id -u) -if [ "$RUNNING_USER" = "0" ]; then - echo "Process is running as root!" +# Verify the DB is readable/writable via the API. +# /api/demo is unauthenticated and reads the settings table — if SQLite is broken this returns an error. +echo "Testing DB via API (/api/demo)..." +DEMO_RESPONSE=$(docker exec fredy curl -sf http://localhost:9998/api/demo 2>&1) +if echo "$DEMO_RESPONSE" | grep -q "demoMode"; then + echo "DB is readable (got demoMode from /api/demo)" +else + echo "DB check failed — unexpected response from /api/demo: $DEMO_RESPONSE" + docker logs fredy exit 1 fi -echo "Process runs as UID $RUNNING_USER (not root)" -# Verify Chrome launches without crashing +# Verify Chrome launches without crashing. +# On amd64: Chrome for Testing lives in the puppeteer cache. +# On arm64: system Chromium is used instead. echo "Testing Chrome..." -CHROME=$(docker exec fredy find /home/node/.cache/puppeteer -name chrome -type f 2>/dev/null | head -1) +CHROME=$(docker exec fredy find /root/.cache/puppeteer /home -name chrome -type f 2>/dev/null | head -1) if [ -z "$CHROME" ]; then - echo "Chrome binary not found" + CHROME=$(docker exec fredy which chromium 2>/dev/null || true) +fi +if [ -z "$CHROME" ]; then + echo "Chrome/Chromium binary not found" exit 1 fi if docker exec fredy "$CHROME" --headless --no-sandbox --disable-gpu --dump-dom https://example.com 2>&1 | grep -q "