build: Dockerfile.backend multistage lint stage (closes #17)
All checks were successful
check / check (push) Successful in 16s
All checks were successful
check / check (push) Successful in 16s
Dockerfile.backend did not follow the Go multistage lint-stage pattern REPO_POLICIES.md mandates, and dragged the whole git history into the build context to resolve a version string. - Add an `AS lint` stage on the hash-pinned golangci/golangci-lint image (v2.7.2, the same golangci-lint commit main already pins), which ships Go, gofmt, make and the linter, so nothing is installed in it. It runs `make fmt-check` then `make lint`. - Add `COPY --from=lint /src/go.sum /dev/null` to the build stage so BuildKit cannot run the two stages in parallel and let a lint failure through. - Stop compiling golangci-lint from source in the build stage. - Drop `COPY .git /repo/.git`; the version now comes from `ARG VERSION=dev`, passed to the build via `make build VERSION=...`. - Drop gcc and musl-dev, and the corresponding `-linkmode external -extldflags -static` in backend/Makefile. The build is now `CGO_ENABLED=0 go build -trimpath` with `-ldflags "-s -w -X main.Version=... -X main.Buildarch=..."`, which is static without a C toolchain. - backend/Makefile's VERSION is now overridable and degrades to `dev` when git or .git is unavailable instead of emitting a git error and building an empty version string. - Every FROM stays pinned by @sha256 with a version and date comment. Runtime stage, exposed port and entrypoint are unchanged.
This commit is contained in:
@@ -1,25 +1,50 @@
|
|||||||
|
# Lint stage — fast feedback on formatting and lint issues. The
|
||||||
|
# golangci/golangci-lint image ships Go, gofmt, make and the linter, so
|
||||||
|
# nothing is installed here.
|
||||||
|
# golangci/golangci-lint:v2.7.2 (2026-08-09)
|
||||||
|
FROM golangci/golangci-lint@sha256:5d6d5c70a61f1356adfd9dd6316ce286799fefc9d743421356ff1b00842368ba AS lint
|
||||||
|
|
||||||
|
WORKDIR /src
|
||||||
|
COPY backend/go.mod backend/go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
COPY backend/ .
|
||||||
|
RUN make fmt-check
|
||||||
|
RUN make lint
|
||||||
|
|
||||||
|
# Build stage
|
||||||
# golang:1.25-alpine (2026-02-27)
|
# golang:1.25-alpine (2026-02-27)
|
||||||
FROM golang:1.25-alpine@sha256:f6751d823c26342f9506c03797d2527668d095b0a15f1862cddb4d927a7a4ced AS builder
|
FROM golang:1.25-alpine@sha256:f6751d823c26342f9506c03797d2527668d095b0a15f1862cddb4d927a7a4ced AS builder
|
||||||
|
|
||||||
RUN apk add --no-cache git make gcc musl-dev
|
RUN apk add --no-cache make
|
||||||
|
|
||||||
# golangci-lint v2.7.2 (2026-02-27)
|
WORKDIR /src
|
||||||
RUN CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@9f61b0f53f80672872fced07b6874397c3ed197b
|
|
||||||
|
# Force BuildKit to run the lint stage before proceeding. BuildKit runs
|
||||||
|
# stages in parallel by default; without this no-op copy a lint failure
|
||||||
|
# would not gate compilation.
|
||||||
|
COPY --from=lint /src/go.sum /dev/null
|
||||||
|
|
||||||
WORKDIR /repo/backend
|
|
||||||
COPY backend/go.mod backend/go.sum ./
|
COPY backend/go.mod backend/go.sum ./
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
COPY .git /repo/.git
|
|
||||||
COPY backend/ .
|
COPY backend/ .
|
||||||
|
|
||||||
RUN make check
|
RUN make test
|
||||||
RUN make build
|
|
||||||
|
|
||||||
|
# The build is driven through the Makefile so there is exactly one
|
||||||
|
# definition of the build command; it expands to
|
||||||
|
# CGO_ENABLED=0 go build -trimpath -ldflags "-s -w -X main.Version=... -X main.Buildarch=..."
|
||||||
|
# VERSION is handed over in the environment rather than as a make
|
||||||
|
# variable so it still reaches the build if the target is ever turned
|
||||||
|
# into a shim around a script.
|
||||||
|
ARG VERSION=dev
|
||||||
|
RUN VERSION="${VERSION}" make build
|
||||||
|
|
||||||
|
# Runtime stage
|
||||||
# alpine:3.23 (2026-02-27)
|
# alpine:3.23 (2026-02-27)
|
||||||
FROM alpine:3.23@sha256:25109184c71bdad752c8312a8623239686a9a2071e8825f20acb8f2198c3f659
|
FROM alpine:3.23@sha256:25109184c71bdad752c8312a8623239686a9a2071e8825f20acb8f2198c3f659
|
||||||
|
|
||||||
RUN apk add --no-cache ca-certificates
|
RUN apk add --no-cache ca-certificates
|
||||||
COPY --from=builder /repo/backend/netwatch-server /usr/local/bin/netwatch-server
|
COPY --from=builder /src/netwatch-server /usr/local/bin/netwatch-server
|
||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
ENTRYPOINT ["netwatch-server"]
|
ENTRYPOINT ["netwatch-server"]
|
||||||
|
|||||||
4
TODO.md
4
TODO.md
@@ -22,6 +22,10 @@ files, so merging it also closes most compliance gaps.
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
|
- 2026-08-09: `Dockerfile.backend` reworked to the mandated Go multistage
|
||||||
|
lint-stage pattern: separate `lint` stage on the hash-pinned
|
||||||
|
`golangci/golangci-lint` image, `COPY --from=lint` stage dependency,
|
||||||
|
`CGO_ENABLED=0` static build driven by `ARG VERSION`, and no more `COPY .git`
|
||||||
- 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints, Makefile
|
- 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints, Makefile
|
||||||
shims, README Entrypoints section
|
shims, README Entrypoints section
|
||||||
- 2026-02-27: backend with buffered zstd-compressed report storage; CI workflow
|
- 2026-02-27: backend with buffered zstd-compressed report storage; CI workflow
|
||||||
|
|||||||
@@ -1,25 +1,22 @@
|
|||||||
UNAME_S := $(shell uname -s)
|
# VERSION is overridable (the Dockerfile passes its ARG VERSION in) and
|
||||||
VERSION := $(shell git describe --always --dirty)
|
# degrades to "dev" when git is unavailable or there is no .git — the
|
||||||
|
# build must not depend on the repository history being in the build
|
||||||
|
# context.
|
||||||
|
VERSION ?= $(shell { git describe --always --dirty; } 2>/dev/null || echo dev)
|
||||||
BUILDARCH := $(shell uname -m)
|
BUILDARCH := $(shell uname -m)
|
||||||
BINARY := netwatch-server
|
BINARY := netwatch-server
|
||||||
|
|
||||||
|
GOLDFLAGS += -s -w
|
||||||
GOLDFLAGS += -X main.Version=$(VERSION)
|
GOLDFLAGS += -X main.Version=$(VERSION)
|
||||||
GOLDFLAGS += -X main.Buildarch=$(BUILDARCH)
|
GOLDFLAGS += -X main.Buildarch=$(BUILDARCH)
|
||||||
|
|
||||||
ifeq ($(UNAME_S),Darwin)
|
|
||||||
GOFLAGS := -ldflags "$(GOLDFLAGS)"
|
|
||||||
else
|
|
||||||
GOFLAGS = -ldflags "-linkmode external -extldflags -static $(GOLDFLAGS)"
|
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: all build test lint fmt fmt-check check docker hooks run clean
|
.PHONY: all build test lint fmt fmt-check check docker hooks run clean
|
||||||
|
|
||||||
all: build
|
all: build
|
||||||
|
|
||||||
build: ./$(BINARY)
|
build:
|
||||||
|
CGO_ENABLED=0 go build -trimpath -ldflags "$(GOLDFLAGS)" \
|
||||||
./$(BINARY): $(shell find . -name '*.go' -type f) go.mod go.sum
|
-o ./$(BINARY) ./cmd/netwatch-server/
|
||||||
go build -o $@ $(GOFLAGS) ./cmd/netwatch-server/
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
timeout 30 go test ./...
|
timeout 30 go test ./...
|
||||||
|
|||||||
Reference in New Issue
Block a user