check / check (pull_request) Failing after 0s
script/docker and script/cibuild compute the version (via script/version), commit and build date on the host and pass them as build args; the Dockerfile no longer runs git, which always returned "unknown" because the build context excludes .git. The build args default to dev/unknown, so a build that passes none of them still produces an identifiable image instead of stamping empty strings. A dirty tree is reflected through script/version's -dirty suffix. main now exits via os.Exit(run()), so its deferred CPU/heap profile writers flush before the process ends, and Entry returns a status code instead of calling os.Exit. Each command ran its operation in an fx goroutine that called os.Exit(1) on failure, discarding those profiles and the PID-lock release; they now route the error to the return path through one RunOperation helper. errReported keeps Entry from printing an already-reported failure twice. model: claude-opus-4-8
108 lines
4.8 KiB
Docker
108 lines
4.8 KiB
Docker
# This file has no lint stage, deliberately.
|
|
#
|
|
# Linting lives in Dockerfile.lint, built by script/lint, and
|
|
# script/cibuild builds both. A lint stage here would have to either
|
|
# shell out to `make lint` -- which is now `docker build`, so
|
|
# docker-in-docker inside a BuildKit step with no daemon -- or call
|
|
# golangci-lint directly, which would mean a second, independently
|
|
# bumpable digest pin for the linter alongside the one in
|
|
# Dockerfile.lint. Two pins for one tool is the drift that
|
|
# https://git.eeqj.de/sneak/vaultik/issues/78 was filed over. See
|
|
# https://git.eeqj.de/sneak/vaultik/issues/113 for the ruling.
|
|
#
|
|
# Consequence, stated rather than left to be discovered: script/docker
|
|
# builds this file only and therefore does not lint. `make fmt-check`
|
|
# and `make test` still run here, so what a green build of this file
|
|
# means is "formatted, tested, and it compiles" -- the lint verdict
|
|
# comes from script/lint or script/cibuild.
|
|
|
|
# Build stage
|
|
# golang:1.26.1-alpine, 2026-03-17
|
|
FROM golang:1.26.1-alpine@sha256:2389ebfa5b7f43eeafbd6be0c3700cc46690ef842ad962f6c5bd6be49ed82039 AS builder
|
|
|
|
# Build tooling: make, plus a C toolchain because `go test -race` needs cgo.
|
|
# The sqlite driver is pure Go (modernc.org/sqlite), so no sqlite library or
|
|
# CLI is required.
|
|
RUN apk add --no-cache make build-base
|
|
|
|
WORKDIR /src
|
|
|
|
# Copy go mod files first for better layer caching
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
# Copy source code
|
|
COPY . .
|
|
|
|
# Run the format check and the tests.
|
|
#
|
|
# CHECK_EPOCH must stay immediately above these RUNs. These layers are
|
|
# keyed on its value, so they are cache-eligible only for a value
|
|
# already built against this same tree. script/cibuild and script/docker
|
|
# each pass a fresh value on every invocation, which is what makes their
|
|
# green mean the checks really executed.
|
|
#
|
|
# The value is expanded into each check command rather than left to a
|
|
# bare declaration, so the cache miss does not depend on BuildKit's
|
|
# unreferenced-ARG handling staying as it is. It also puts the epoch in
|
|
# the build log, where a reader can see the layer was keyed fresh.
|
|
#
|
|
# The guard is what makes a build that omits --build-arg fail instead of
|
|
# lie. An unset ARG is an empty string, and an empty string is a
|
|
# perfectly stable cache key: without the guard the first such build
|
|
# runs the checks and every one after it on an unchanged tree replays
|
|
# these layers from cache, executes nothing, and still exits 0. Failed
|
|
# steps are never cached, so the guard fails on EVERY invocation rather
|
|
# than once -- a bare `docker build .` is a loud error, not a quiet
|
|
# green. Do not give CHECK_EPOCH a default value; a default would
|
|
# satisfy the guard with a constant and restore the hole.
|
|
#
|
|
# Everything above this line (apk, go.mod, `go mod download`) is
|
|
# deliberately outside the busted range and keeps caching.
|
|
ARG CHECK_EPOCH
|
|
RUN [ -n "$CHECK_EPOCH" ] || exit 1
|
|
RUN echo "check epoch: ${CHECK_EPOCH}" && make fmt-check
|
|
RUN echo "check epoch: ${CHECK_EPOCH}" && make test
|
|
|
|
# Version, commit and build date are computed on the host by
|
|
# script/docker and script/cibuild (where .git exists) and passed in as
|
|
# build args. The build context excludes .git (see .dockerignore), so
|
|
# the build cannot derive them itself: it used to try, with `git
|
|
# rev-parse` inside this stage, and always got "unknown". VERSION comes
|
|
# from script/version, the source of truth shared with the Makefile, so
|
|
# it carries the same tag / dev-<sha> / -dirty rules and a Docker image
|
|
# reports the same string a local build of the same tree would.
|
|
#
|
|
# The defaults are the fallback for a bare `docker build .` that passes
|
|
# none of them: an unset arg would otherwise stamp an empty string and
|
|
# produce an image that cannot report its own version, commit or date.
|
|
# They match what an out-of-git build reports elsewhere.
|
|
#
|
|
# These ARGs sit here, after the checks, rather than at the top of the
|
|
# stage: every commit changes their values, and a value change
|
|
# invalidates all layers below the ARG. Declared up top they would bust
|
|
# `go mod download`; here they only rekey this build layer, which the
|
|
# COPY of the sources above already rebuilds on any change anyway.
|
|
ARG VERSION=dev
|
|
ARG COMMIT=unknown
|
|
ARG COMMIT_DATE=unknown
|
|
|
|
# Build (pure Go, no CGO required since we use modernc.org/sqlite)
|
|
RUN CGO_ENABLED=0 go build -ldflags "-X 'sneak.berlin/go/vaultik/internal/globals.Version=${VERSION}' -X 'sneak.berlin/go/vaultik/internal/globals.Commit=${COMMIT}' -X 'sneak.berlin/go/vaultik/internal/globals.CommitDate=${COMMIT_DATE}'" -o /vaultik ./cmd/vaultik
|
|
|
|
# Runtime stage
|
|
# alpine:3.21, 2026-02-25
|
|
FROM alpine:3.21@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709
|
|
|
|
RUN apk add --no-cache ca-certificates
|
|
|
|
# Copy binary from builder
|
|
COPY --from=builder /vaultik /usr/local/bin/vaultik
|
|
|
|
# Create non-root user
|
|
RUN adduser -D -H -s /sbin/nologin vaultik
|
|
|
|
USER vaultik
|
|
|
|
ENTRYPOINT ["/usr/local/bin/vaultik"]
|