check / check (push) Successful in 5m33s
The vendored files are fetched from sneak/prompts commit dd4027b. This repository's own entries come after the canonical content, at the end of each file: /bin in .dockerignore, the Go lines of .gitignore and [*.go] in .editorconfig; the test-support deny list has no entries of its own. The lint phase moves to golangci-lint v2.14.0. The build stage now takes the version from git describe on the .git the build context carries, unless VERSION is passed, and fails when .git is present but no version comes out. The test phase drops -count=1, which the policy says it does not need, and keeps its tmpfs build cache. One test calls Header.Get with X-Real-IP, as canonicalheader asks. Model: opus-5-5
178 lines
7.9 KiB
Docker
178 lines
7.9 KiB
Docker
# Lint phase. The linter is invoked directly rather than through `make
|
|
# lint` or `script/lint`, which are themselves a docker build and would
|
|
# recurse into a daemon that does not exist in a build step.
|
|
#
|
|
# golangci/golangci-lint v2.14.0 (built with go1.27.0), 2026-09-24
|
|
FROM golangci/golangci-lint@sha256:ad862ba6b3798cbe0fd9fd7408d498fd74fbd2623a92406b2fd3898faf0bf98f AS lint
|
|
|
|
WORKDIR /src
|
|
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
COPY . .
|
|
|
|
RUN golangci-lint run --config .golangci.yml ./...
|
|
|
|
# Test phase, same shape and for the same reason. The go directive in
|
|
# go.mod is a minimum, so this Go may be newer than the linter's. The
|
|
# Debian image rather than the Alpine one, because the race detector
|
|
# needs the C compiler it carries.
|
|
#
|
|
# golang 1.27.1-trixie, 2026-09-19
|
|
FROM golang@sha256:3b77fc618ec235a1ab412de7737f120dd507c57e8d87de4cbb7994fb94275ed5 AS test
|
|
|
|
WORKDIR /src
|
|
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
COPY . .
|
|
|
|
# Go's build cache is kept on a tmpfs, out of the image: nothing uses it
|
|
# after this step, and writing it into the image takes seconds.
|
|
RUN --mount=type=tmpfs,target=/root/.cache/go-build \
|
|
go test -timeout 90s -race -cover ./... || \
|
|
{ echo "--- Rerunning with -v for details ---"; \
|
|
go test -timeout 90s -race -v ./...; exit 1; }
|
|
|
|
# Build stage. Nothing is wanted from the two phases above; the copies
|
|
# are what make BuildKit build them first, so the image, which needs this
|
|
# stage, cannot be produced unless lint and test passed.
|
|
#
|
|
# golang 1.27.1-trixie, 2026-09-19
|
|
FROM golang@sha256:3b77fc618ec235a1ab412de7737f120dd507c57e8d87de4cbb7994fb94275ed5 AS builder
|
|
|
|
COPY --from=lint /src/go.sum /dev/null
|
|
COPY --from=test /src/go.sum /dev/null
|
|
|
|
# This image has git. A tar-stream context keeps the sender's file
|
|
# owners, which git refuses.
|
|
RUN git config --system --add safe.directory /src
|
|
|
|
WORKDIR /src
|
|
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
COPY . .
|
|
|
|
# The VERSION build arg when one is given, otherwise
|
|
# `git describe --tags --always` on the .git in the build context. With
|
|
# .git present, a version that is still empty, dev or unknown fails the
|
|
# build: git is missing or could not read the checkout.
|
|
ARG VERSION
|
|
RUN VERSION="${VERSION:-$(git describe --tags --always)}"; \
|
|
if [ -e .git ]; then \
|
|
case "$VERSION" in ""|dev|unknown) \
|
|
echo "version is '$VERSION' although .git is present" >&2; \
|
|
exit 1 ;; \
|
|
esac; \
|
|
fi; \
|
|
CGO_ENABLED=0 go build -trimpath \
|
|
-ldflags="-s -w -X main.Version=${VERSION}" \
|
|
-o /usr/local/bin/smallwebwaf ./cmd/smallwebwaf
|
|
|
|
# runsvinit, the image's entrypoint, built at the last commit of its
|
|
# archived repository. It has no go.mod, and `go build` of its directory
|
|
# needs one; it uses only the standard library, so the one written here
|
|
# names nothing else.
|
|
#
|
|
# golang 1.27.1-trixie, 2026-09-19
|
|
FROM golang@sha256:3b77fc618ec235a1ab412de7737f120dd507c57e8d87de4cbb7994fb94275ed5 AS runsvinit
|
|
|
|
RUN git clone --quiet https://github.com/peterbourgon/runsvinit /src
|
|
WORKDIR /src
|
|
# runsvinit v2.0.0-8-gb4b2c78, 2015-10-07
|
|
RUN git checkout --quiet --detach b4b2c785308b1ce785b6155c7fe5f16879080193 \
|
|
&& go mod init github.com/peterbourgon/runsvinit \
|
|
&& CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" \
|
|
-o /usr/local/bin/runsvinit .
|
|
|
|
# The image an app's Dockerfile builds FROM, described under "Deployment"
|
|
# in SPEC.md. It is the last stage, so a plain `docker build .` builds it.
|
|
#
|
|
# ubuntu 26.04, 2026-09-27
|
|
FROM ubuntu@sha256:f144425ff09be612d6d9ad965196e9cdc23dae1f42110a8a11a3e9a8198759f7
|
|
|
|
# runit's install creates its _runit-log user with minsysusers, which
|
|
# reads this file in place of runit's /usr/lib/sysusers.d/runit.conf.
|
|
# runit's line leaves out the shell, and minsysusers prints a Perl
|
|
# warning for that; this copy of it names /sbin/nologin, the shell
|
|
# minsysusers gives when none is named.
|
|
RUN mkdir /etc/sysusers.d \
|
|
&& echo 'u _runit-log - "runit svlogd user" /nonexistent /sbin/nologin' \
|
|
> /etc/sysusers.d/runit.conf
|
|
|
|
# ca-certificates, nix-bin and runit, from Ubuntu's archive as it was at
|
|
# the snapshot moment, which is never earlier than the Ubuntu image above.
|
|
# apt checks every package against the snapshot's InRelease files, and
|
|
# this step checks those against the hashes named here, which are those
|
|
# of the amd64 archive: other architectures use Ubuntu's ports archive.
|
|
# apt also fetches the live archive's InRelease files, which change daily
|
|
# and which the install does not use. The snapshot service is HTTPS only
|
|
# and this image has no CA certificates yet, so this step uses the Go
|
|
# image's.
|
|
RUN --mount=type=bind,from=builder,source=/etc/ssl/certs/ca-certificates.crt,target=/tmp/go-image-ca.crt \
|
|
apt-get update --snapshot 20261001T000000Z \
|
|
-o Acquire::https::CaInfo=/tmp/go-image-ca.crt \
|
|
&& printf '%s\n' \
|
|
'45f95ce276cdba3e41870516a130e03c58b8b7a79e9546b0efe9e526d255740c snapshot.ubuntu.com_ubuntu_20261001T000000Z_dists_resolute_InRelease' \
|
|
'802e675dd9de4c7f3916434a95e7c1d8eec0e82886622d7805ab19a2c6fe0365 snapshot.ubuntu.com_ubuntu_20261001T000000Z_dists_resolute-updates_InRelease' \
|
|
'64b3353f0bd4970b4f7271962245bcea9ff24d4cc7bea16b433f8a60e42ca3dd snapshot.ubuntu.com_ubuntu_20261001T000000Z_dists_resolute-backports_InRelease' \
|
|
'1d5041572116a8b23aabf79ac7439ad8af83d57ad3fb0f9aa0d4523ec10c5908 snapshot.ubuntu.com_ubuntu_20261001T000000Z_dists_resolute-security_InRelease' \
|
|
| (cd /var/lib/apt/lists && sha256sum --check --strict) \
|
|
&& DEBIAN_FRONTEND=noninteractive apt-get install --yes --no-install-recommends \
|
|
--snapshot 20261001T000000Z \
|
|
-o Acquire::https::CaInfo=/tmp/go-image-ca.crt \
|
|
ca-certificates nix-bin runit \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# Nix run by root expects a group of build users, which nix-bin does not
|
|
# create; with the setting empty, root's builds run without them.
|
|
RUN mkdir /etc/nix && echo 'build-users-group =' > /etc/nix/nix.conf
|
|
|
|
# nixpkgs, from its release file, checked by SHA-256, and set up for root
|
|
# as `nixpkgs`, so that an app's Dockerfile installs a package with
|
|
# `nix-env -iA nixpkgs.<name>`. curl and xz come with nix-bin.
|
|
#
|
|
# nixpkgs nixos-26.05.11045.774debe7a0d1, 2026-10-02
|
|
RUN curl -fsSL -o /tmp/nixexprs.tar.xz \
|
|
https://releases.nixos.org/nixos/26.05/nixos-26.05.11045.774debe7a0d1/nixexprs.tar.xz \
|
|
&& echo 'b2994104605601690023a5a6a3bb5a07b2bd1716b4e3b208cba1056dacd2ab08 /tmp/nixexprs.tar.xz' \
|
|
| sha256sum --check --strict \
|
|
&& mkdir -p /root/.nix-defexpr/nixpkgs \
|
|
&& tar -xJf /tmp/nixexprs.tar.xz -C /root/.nix-defexpr/nixpkgs --strip-components=1 \
|
|
&& rm /tmp/nixexprs.tar.xz
|
|
|
|
# What root installs with nix-env lands in root's profile. This path to
|
|
# it works for every user, unlike /root/.nix-profile: only root can
|
|
# enter /root. It comes last, so that no package shadows the image's
|
|
# own tools: busybox, for one, brings an sv that looks for services
|
|
# elsewhere.
|
|
ENV PATH=${PATH}:/nix/var/nix/profiles/default/bin
|
|
|
|
COPY --from=runsvinit /usr/local/bin/runsvinit /usr/local/bin/runsvinit
|
|
COPY --from=builder /usr/local/bin/smallwebwaf /usr/local/bin/smallwebwaf
|
|
|
|
# 65532 is above the uids Ubuntu keeps for system users, which end at
|
|
# 999; useradd warns about it unless --key raises that end for this call.
|
|
RUN groupadd --system --gid 65532 smallwebwaf \
|
|
&& useradd --system --key SYS_UID_MAX=65532 --uid 65532 \
|
|
--gid smallwebwaf --no-create-home --shell /usr/sbin/nologin \
|
|
smallwebwaf
|
|
|
|
# runsvinit starts runit's runsvdir on /etc/service, where Ubuntu's sv
|
|
# looks too.
|
|
COPY --chmod=755 share/smallwebwaf.run /etc/service/smallwebwaf/run
|
|
|
|
EXPOSE 8080
|
|
|
|
# traefik sends a container no requests until it is healthy, so the
|
|
# check runs every second from the start until it first passes, for up
|
|
# to a minute, and every 30 seconds after that.
|
|
HEALTHCHECK --start-period=1m --start-interval=1s \
|
|
CMD ["/usr/local/bin/smallwebwaf", "healthcheck"]
|
|
|
|
ENTRYPOINT ["/usr/local/bin/runsvinit"]
|