Files
umami/Dockerfile
T
Roger Hoem-MartinsenandClaude Opus 4.8 413448037c fix(docker): drop bundled npm from runtime image to clear base-image CVEs
The runner stage ships the npm CLI bundled in node:22-alpine, whose
vendored dependencies carry known vulnerabilities that trivy flags on the
published postgresql-latest image:

  usr/local/lib/node_modules/npm/node_modules/...
    - sigstore 3.1.0        CVE-2026-48815 (HIGH)
    - picomatch 4.0.3       CVE-2026-33671 (HIGH)
    - @sigstore/core 2.0.0  CVE-2026-48758
    - brace-expansion 2.0.2 CVE-2026-33750
    - ip-address 10.1.0     CVE-2026-42338
    - tar 7.5.11            CVE-2026-53655

npm is only a build-time bootstrap for pnpm; it is not needed at runtime.
Install pnpm with it, then remove npm in the same layer so none of these
vendored packages are present in the final image, and run the container
via pnpm instead of npm. pnpm (and corepack) remain and were never flagged.

The curl/libcurl/c-ares HIGH findings are resolved by rebuilding alone,
since Alpine 3.24 already serves curl 8.21.0-r0 / c-ares 1.34.8-r0 (the
published image is simply stale).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 11:30:18 +02:00

84 lines
2.5 KiB
Docker

ARG NODE_IMAGE_VERSION="22-alpine"
ARG PNPM_VERSION="10.15.1"
# Keep in sync with the prisma/@prisma/* versions in package.json
ARG PRISMA_VERSION="7.8.0"
# Install dependencies only when needed
FROM node:${NODE_IMAGE_VERSION} AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm
RUN printf 'strictDepBuilds: false\n' > pnpm-workspace.yaml
RUN pnpm install --frozen-lockfile
# Rebuild the source code only when needed
FROM node:${NODE_IMAGE_VERSION} AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
COPY docker/proxy.ts ./src
ARG BASE_PATH
ENV BASE_PATH=$BASE_PATH
ENV NEXT_TELEMETRY_DISABLED=1
ENV DATABASE_URL="postgresql://user:pass@localhost:5432/dummy"
RUN npm run build-docker
# Production image, copy all the files and run next
FROM node:${NODE_IMAGE_VERSION} AS runner
WORKDIR /app
ARG NODE_OPTIONS
ARG PRISMA_VERSION
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_OPTIONS=$NODE_OPTIONS
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Bootstrap pnpm with the bundled npm, then remove npm in the same layer so the
# vulnerable packages vendored inside the npm CLI are not shipped in the final
# image. pnpm is the only package manager needed at build and runtime.
RUN set -x \
&& apk add --no-cache curl libc6-compat \
&& npm install -g pnpm \
&& rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx
RUN echo {} > package.json
RUN printf "allowBuilds:\n '@prisma/engines': true\n prisma: false\nverifyDepsBeforeRun: false\n" > pnpm-workspace.yaml
# Script dependencies
RUN pnpm add npm-run-all dotenv chalk semver \
prisma@${PRISMA_VERSION} \
@prisma/client@${PRISMA_VERSION} \
@prisma/adapter-pg@${PRISMA_VERSION}
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder /app/prisma ./prisma
COPY --from=builder /app/prisma.config.ts ./prisma.config.ts
COPY --from=builder /app/scripts ./scripts
COPY --from=builder /app/generated ./generated
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV HOSTNAME=0.0.0.0
ENV PORT=3000
CMD ["pnpm", "run", "start-docker"]