mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-26 22:37:03 +00:00
7c9f29b2f3
* fix(ci): Go toolchain 1.26.10 for GO-2026-6809, markdown-it 14.3.3 for npm audit (TASK-4007) Main CI is red on both gates. - govulncheck: GO-2026-6809 (crypto/x509) is fixed in go1.26.10. The go.mod toolchain line and the Dockerfile's golang image move to 1.26.10. The workflow comments that name the toolchain value follow it, and go.mod's comment records the raise. - Nix: its artifact is built with nixos-26.05's go, which predates 1.26.10, so GO-2026-6809 joins nix/accepted-advisories.txt the way the 1.26.9 block did, with the same removal condition. - npm audit: markdown-it up to 14.3.2 has two high quadratic-time DoS advisories (GHSA-vfgh-jcmw-g37q, GHSA-gfr2-rv44-r23c). The overrides pin goes ^14.3.0 -> ^14.3.3; the lock moves markdown-it 14.3.2 -> 14.3.3 and nothing else. Claude-Session: https://claude.ai/code/session_01JRXHP9ZVfEN3YEuzmucxP3 * ci(deps): allow markdown-it 14.3.3 under the 7-day age check, a security fix (TASK-4007) Dependency age (advisory) flagged only markdown-it@14.3.3, published 2026-10-16: the fix for GHSA-vfgh-jcmw-g37q and GHSA-gfr2-rv44-r23c. pad-merge-pr requires every check at the head to be SUCCESS, so the advisory red blocked the merge. A security fix cannot wait out the window. The allow line is the file's own remedy for this case; its removal after the version ages past 7 days is a filed follow-up. Claude-Session: https://claude.ai/code/session_01JRXHP9ZVfEN3YEuzmucxP3
98 lines
4.2 KiB
Docker
98 lines
4.2 KiB
Docker
# Stage 1: Build web UI
|
|
FROM node:26-alpine AS web-builder
|
|
WORKDIR /app/web
|
|
COPY web/package.json web/package-lock.json ./
|
|
RUN npm ci
|
|
COPY web/ ./
|
|
RUN npm run build
|
|
|
|
# Stage 2: Build Go binary
|
|
# Pinned to the toolchain go.mod names, so a self-built image ships the same
|
|
# standard library as the release binaries (govulncheck, 2026-10-08).
|
|
FROM golang:1.26.10-alpine AS go-builder
|
|
WORKDIR /app
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
COPY . .
|
|
COPY --from=web-builder /app/web/build ./web/build
|
|
COPY --from=web-builder /app/web/build-materializer ./web/build-materializer
|
|
|
|
# Build metadata. All three are caller-passed via --build-arg (see
|
|
# pad-cloud/scripts/build-pad.sh for the production wrapper that
|
|
# resolves them from the host's pad checkout).
|
|
#
|
|
# Why all three are passed in vs. computed inside the container:
|
|
#
|
|
# - .dockerignore intentionally excludes .git/, so an in-container
|
|
# `git rev-parse` substitution returns empty (with `2>/dev/null`
|
|
# swallowing the error) — the previous Dockerfile shipped "dev"
|
|
# forever because of this. We don't want to add .git/ to the
|
|
# context just for this; pre-computing on the host is the
|
|
# standard pattern.
|
|
# - `date` would work in-container but a fresh `date` value on
|
|
# every build invalidates layer caching for this RUN. Passing
|
|
# as ARG lets the caller decide cache semantics.
|
|
#
|
|
# Defaults are deliberately ugly-but-honest so a `docker build .`
|
|
# without args produces a binary whose pad_version makes the
|
|
# misconfiguration obvious ("dev (unknown)") rather than hiding it.
|
|
ARG VERSION=dev
|
|
ARG COMMIT=unknown
|
|
ARG BUILD_TIME=
|
|
RUN CGO_ENABLED=0 go build \
|
|
-ldflags="-s -w -X main.version=${VERSION} -X main.commit=${COMMIT} -X main.buildTime=${BUILD_TIME}" \
|
|
-o pad ./cmd/pad
|
|
|
|
# Stage 3: Runtime
|
|
FROM alpine:3.24
|
|
# ca-certificates: TLS roots for outbound HTTPS (e.g. Maileroo email).
|
|
# tzdata: timezone names for Go's time package.
|
|
# shadow: provides usermod / groupmod (BusyBox's adduser/addgroup don't
|
|
# ship modify equivalents — needed by docker-entrypoint.sh).
|
|
# su-exec: lightweight alpine equivalent of gosu — execs the target in
|
|
# the same process so SIGTERM propagates correctly. Used by the
|
|
# entrypoint shim AND by the conditional healthcheck below.
|
|
RUN apk add --no-cache ca-certificates tzdata shadow su-exec
|
|
COPY --from=go-builder /app/pad /usr/local/bin/pad
|
|
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
|
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
|
|
|
# In-image `pad` user/group at uid/gid 1000 — the entrypoint shim remaps
|
|
# these to match PUID/PGID at container start (defaults 99/100, the
|
|
# Unraid `nobody:users` convention). The actual numeric IDs can be
|
|
# anything; 1000 is just the historical default.
|
|
RUN addgroup -g 1000 pad \
|
|
&& adduser -D -u 1000 -G pad -h /home/pad pad \
|
|
&& mkdir -p /data \
|
|
&& chown -R pad:pad /data
|
|
ENV PAD_DATA_DIR=/data
|
|
ENV PAD_HOST=0.0.0.0
|
|
|
|
# IMPORTANT: NO `USER pad` directive — container starts as root so the
|
|
# entrypoint shim can chown /data + remap user/group ids before
|
|
# dropping privileges via `su-exec pad`. See TASK-1168 / PLAN-1166.
|
|
|
|
EXPOSE 7777
|
|
VOLUME /data
|
|
|
|
# Healthcheck adapts to the caller's chosen execution model:
|
|
#
|
|
# • Default invocation (container starts as root, entrypoint drops to pad):
|
|
# healthcheck runs as ROOT (Docker uses the image USER, which is root
|
|
# because we removed the USER directive). Wrap with su-exec so it
|
|
# matches the main process's unprivileged UID.
|
|
#
|
|
# • `docker run --user 1234` invocation: healthcheck ALSO runs as 1234.
|
|
# `su-exec pad ...` would fail because 1234 lacks the privilege to
|
|
# switch to user `pad`. Just run wget directly in that branch.
|
|
#
|
|
# start-period bumped 10s → 60s. The always-chown-R policy (D4) means a
|
|
# user restoring a backup with a large attachment store can legitimately
|
|
# spend tens of seconds in the entrypoint before pad starts listening;
|
|
# 60s covers ~600k files at 10k files/sec on local SSD.
|
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
|
|
CMD sh -c 'if [ "$(id -u)" = "0" ]; then exec su-exec pad wget -q --spider http://localhost:7777/api/v1/health; fi; exec wget -q --spider http://localhost:7777/api/v1/health'
|
|
|
|
ENTRYPOINT ["docker-entrypoint.sh", "pad"]
|
|
CMD ["server", "start"]
|