All checks were successful
check / check (push) Successful in 1m38s
Per the owner ruling the linter runs in a container invoked through the script/ entrypoint, never installed on a host. Dockerfile.lint COPYs the repo into the digest-pinned golangci/golangci-lint:v2.12.2 image and runs `golangci-lint config verify` and `golangci-lint run` as build steps, so a successful build IS a clean lint. script/lint is reduced to building it, and works with a remote docker daemon, where bind mounts are impossible. script/bootstrap loses the `go install`, the pin constants, the version parser and verify_golangci_lint: with nothing linting on the host, the $GOPATH/bin versus PATH shadowing they diagnosed has no subject. It keeps the git/make/go presence checks and `go mod download`, and warns rather than fails when docker is absent. Traps for anyone changing this. A lint build on an unchanged tree exits 0 in under a second having run no linter -- #32 and #39 again. Caching is waived by ruling: Dockerfile.lint carries ARG CHECK_EPOCH referenced inside every gate RUN, because BuildKit hashes the expanded command and a declared but unreferenced ARG invalidates nothing. script/lint passes "$(date +%s)-$$"; the PID is there because two runs land in the same second easily and a bare epoch would cache the second. Nothing inside an image build may shell out to docker. The main Dockerfile's lint stage therefore invokes golangci-lint directly rather than `make lint`, and its build stage runs `make test` and `make fmt-check` rather than the `make check` aggregate, which reaches script/lint. Both stay `make` invocations rather than bare scripts because the Makefile's `export CGO_ENABLED = 0` only reaches what it invokes. COPY --from=lint /usr/bin/golangci-lint becomes COPY --from=lint /src/go.sum /dev/null. The copied binary was the only edge forcing BuildKit to finish linting before the build stage starts; dropping it without replacing the edge would have ended fail-fast linting silently under a still-green build. That no-op copy is the ordering edge canonical REPO_POLICIES.md prescribes. Nothing in the build stage runs the linter now, so ENV PATH=/home/builder/go/bin:$PATH goes with the `go install` that justified it. script/verify-linter-pin is retired with its README entry: it compared a linter binary against GOLANGCI_LINT_VERSION in script/bootstrap and neither subject still exists. The drift moved rather than went away -- the linter is pinned twice, as the FROM line of Dockerfile.lint and the FROM line of the Dockerfile lint stage, which is what #42 made a build failure. script/verify-lint-image-pin compares those two references to each other and restates neither pin; a hardcoded digest would be a third copy and the same drift one file further out. It runs as a gate in both files, and an unreadable reference is a hard failure rather than a vacuous pass. `golangci-lint config verify` is included per the ruling, and its unpinned live HTTPS schema fetch was measured rather than assumed: under --network none the pinned binary passes a valid config and rejects an invalid one with the jsonschema error, so it validates against a schema it embeds. That holds for the gate steps, none of which makes a network call, but not for the build around them -- Dockerfile.lint runs `go mod download` above the gates, so a cold cache needs the network and only a warm one lints offline, until go.mod or go.sum changes. Verified. `make lint` green with every PATH directory containing a golangci-lint removed and `command -v golangci-lint` empty. Two consecutive script/lint runs on an untouched tree both executed the linter, 27.7s and 28.7s under distinct epochs with the COPY layer CACHED above them. A planted unused variable failed script/lint with that finding, and failed `make docker` at the lint stage with the build stage stopped before its COPY --from=lint; reverted clean. The drift guard fails on tag-only, digest-only and unreadable-reference cases, naming both sides. `make check` green; `make docker` green in 5m35s with all six gates executing and the test gate reporting real coverage rather than a cached ok. In the builder image with the Go test cache off, --user 0:0 still fails TestScanHardlinkRunFailsTogether where the unprivileged user passes, so the non-root quirk is intact.
35 lines
1.5 KiB
Bash
Executable File
35 lines
1.5 KiB
Bash
Executable File
#!/bin/sh
|
|
# script/cibuild: run the CI build. The Gitea workflow runs this on
|
|
# push.
|
|
#
|
|
# The Dockerfile runs the gates individually as build steps, not the
|
|
# make check aggregate: the lint stage runs make fmt-check,
|
|
# script/verify-lint-image-pin, golangci-lint config verify and
|
|
# golangci-lint run; the build stage, dropped to an unprivileged user,
|
|
# runs make test and make fmt-check. Neither make lint nor make check
|
|
# appears, because both reach script/lint, which is itself a docker
|
|
# build, and a docker build cannot run inside one. Lint is not skipped
|
|
# by that — the linter is invoked directly in the lint stage, and the
|
|
# build stage's COPY --from=lint makes that stage a prerequisite, so
|
|
# BuildKit must finish it first. Between the two stages everything
|
|
# make check would run has run, which is why a successful build here
|
|
# implies the repo is green.
|
|
#
|
|
# That implication holds only because of CHECK_EPOCH. A COPY layer is
|
|
# invalidated by changed content, and a merge commit's tree is
|
|
# byte-identical to the branch head it merges, so without a fresh value
|
|
# here Docker serves the gate layers from cache and the build reports a
|
|
# green it never earned. Passing the current epoch invalidates the gate
|
|
# layers on every run while leaving the pinned base images and
|
|
# go mod download cached; see the Dockerfile for the placement.
|
|
set -eu
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
|
|
|
main() {
|
|
cd "$ROOT"
|
|
docker build --build-arg CHECK_EPOCH="$(date +%s)" .
|
|
}
|
|
|
|
main "$@"
|