# Lint stage — fast feedback on formatting and lint issues # node 22.22.0 on Alpine 3.23.3 (node:22-alpine), 2026-08-09 FROM node@sha256:e4bf2a82ad0a4037d28035ae71529873c069b13eb0455466ae0bc13363826e34 AS lint WORKDIR /app COPY script/ script/ COPY package.json yarn.lock ./ RUN script/bootstrap COPY . . RUN make fmt-check RUN make lint # Check stage — the full suite and the build # node 22.22.0 on Alpine 3.23.3 (node:22-alpine), 2026-08-09 FROM node@sha256:e4bf2a82ad0a4037d28035ae71529873c069b13eb0455466ae0bc13363826e34 AS check WORKDIR /app # Force BuildKit to run the lint stage before proceeding. Without this the # two stages run in parallel and a lint failure can lose the race. COPY --from=lint /app/yarn.lock /dev/null COPY script/ script/ COPY package.json yarn.lock ./ RUN script/bootstrap COPY . . # CHECK_EPOCH is a cache buster: without it Docker serves `make check` from # cache on an unchanged tree, the suite never executes, and the build still # exits 0. The guard makes an absent argument a hard failure — an unset ARG # is the empty string, which is a perfectly stable cache key, so a plain # `docker build .` would otherwise still get the false green. Fail closed. ARG CHECK_EPOCH RUN [ -n "$CHECK_EPOCH" ] || exit 1 RUN make check ARG CHECK_EPOCH RUN [ -n "$CHECK_EPOCH" ] || exit 1 RUN make build