Build the binary without cgo (closes #545)
check / check (push) Waiting to run

make build now builds with CGO_ENABLED=0, and the image builds through
it. The binary's only cgo code was mattn/go-sqlite3, which
gorm.io/driver/sqlite imports and webhooker never opens: every SQLite
file is opened with modernc.org/sqlite and the connection handed to
gorm. Without cgo, mattn's package compiles to a stub nothing calls.

The Dockerfile builds the binary once. The static relink and its
netgo, osusergo and sqlite_omit_load_extension tags are gone, and with
them the Makefile's GO_LDFLAGS and GO_TAGS, which only the relink used.
The test phase keeps cgo for -race. No README or Dockerfile sentence
says the binary needs cgo any more.

Model: opus-5-5
This commit is contained in:
2026-10-15 14:18:46 +00:00
parent dfe8f3138f
commit a33af69416
4 changed files with 26 additions and 71 deletions
+4 -23
View File
@@ -76,8 +76,6 @@ RUN --network=none node_modules/.bin/prettier --check '**/*.md'
# depends on it.
#
# golangci/golangci-lint:v2.14.0 (Debian-based), 2026-09-24
# Using Debian-based image because mattn/go-sqlite3 (CGO) does not
# compile on Alpine musl (off64_t is a glibc type).
FROM golangci/golangci-lint:v2.14.0@sha256:ad862ba6b3798cbe0fd9fd7408d498fd74fbd2623a92406b2fd3898faf0bf98f AS lint
WORKDIR /src
@@ -167,9 +165,7 @@ RUN --mount=type=tmpfs,target=/tmp/tests,size=512m \
# Build stage
# golang:1.26.1-bookworm (Debian-based), 2026-03-17
# Using Debian-based image because gorm.io/driver/sqlite pulls in
# mattn/go-sqlite3 (CGO), which does not compile on Alpine musl. The image
# ships git and make, which the version step below uses.
# The image ships git and make, which the version step below uses.
FROM golang:1.26.1-bookworm@sha256:4465644228bc2857a954b092167e12aa59c006a3492282a6c820bf4755fd64a4 AS builder
# Nothing is wanted from the lint and test phases or from the stylesheet and
@@ -211,26 +207,11 @@ RUN version="$(make version VERSION="$VERSION")"; \
fi
# Builds through the Makefile's build target, which runs script/assets
# (Alpine.js, extracted from its tarball in 3p/) first.
# (Alpine.js, extracted from its tarball in 3p/) first. The target builds
# with cgo off, so the binary is statically linked and runs on the Alpine
# runtime image below as it is.
RUN make build VERSION="$VERSION"
# Rebuild with static linking for the Alpine runtime. The cgo binary the
# step above builds is dynamically linked against glibc, which Alpine
# (musl) does not have.
#
# A statically linked glibc still loads shared libraries at run time for
# getaddrinfo and dlopen, and Alpine has none to load, so the build tags
# keep both out of the binary: netgo and osusergo select Go's own DNS
# resolver and user lookup instead of glibc's, and
# sqlite_omit_load_extension leaves out SQLite extension loading, which
# webhooker never uses.
#
# The static flags and tags go in through GO_LDFLAGS and GO_TAGS rather
# than a -ldflags of their own: the build target composes them with the
# -X that stamps the version, so this relink cannot silently drop the
# stamp.
RUN CGO_ENABLED=1 make build VERSION="$VERSION" GO_TAGS=netgo,osusergo,sqlite_omit_load_extension GO_LDFLAGS='-extldflags "-static"'
# Runtime stage
# alpine:3.21, 2026-03-17
FROM alpine:3.21@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709