build: run golangci-lint in a pinned container via script/lint (closes #41)
golangci-lint is no longer invoked on the host anywhere in the repo.
Dockerfile.lint pins golangci/golangci-lint:v2.12.2 by digest and runs
the linter as a build step, so a successful build IS a clean lint, and
`make lint` becomes a thin shim over script/lint. This removes the host
linter install that produced a false green here, where a branch that was
genuinely red with a goconst finding reported "0 issues" off the shared
host cache; a container per run has its own cache and lock.
Two deliberate divergences from the sneak/homoicon reference shape:
- Two stages rather than one. A cached `deps` stage holds
`go mod download`, then `FROM deps AS lint` carries the source copy
and the lint run, and script/lint builds with
`--no-cache-filter=lint`. Caching of the lint result is explicitly
waived (a cached build lints nothing), and splitting the stages means
busting the lint layer does not re-fetch the module cache over the
network on every run.
- No `golangci-lint config verify` step. It resolves its JSON schema
over a live, unpinned HTTPS call: an unpinned network input inside
the one step whose purpose is a pinned, reproducible gate, and a
schema-host outage would surface as a red build. `golangci-lint run`
already fails on a malformed config. The reason is recorded in a
comment in Dockerfile.lint.
.dockerignore excludes .git only; the lint reads the Go sources,
go.mod/go.sum and .golangci.yml, none of which come from there.
The TODO.md scaffold-exemption note is narrowed rather than dropped:
Dockerfile.lint and script/lint are now permitted and required, while CI
config, REPO_POLICIES.md, an application Dockerfile and any other
script/ entrypoint still are not.
Verified, since a green docker build is the classic false green: two
consecutive script/lint runs on an unchanged tree each showed the
`golangci-lint run` layer executing (9.8s and 7.9s, both "0 issues.")
while the deps layers reported CACHED; a deliberate indent-error-flow
violation failed the build naming that finding and the unused one, and a
revert went clean again. `make check` green.
This commit is contained in:
16
Makefile
16
Makefile
@@ -1,8 +1,10 @@
|
||||
# Development convenience targets. This repo is exempt from the standard
|
||||
# policy scaffold (no Dockerfile, CI, or REPO_POLICIES.md); this Makefile
|
||||
# is only a thin wrapper around the Go toolchain, golangci-lint, and
|
||||
# prettier so `make fmt` / `make check` behave the same as in sneak's
|
||||
# other repos.
|
||||
# policy scaffold (no CI config, no REPO_POLICIES.md, no application
|
||||
# Dockerfile) except for the lint container: per sneak's 2026-08-09
|
||||
# ruling, linting runs in docker only, so Dockerfile.lint and script/lint
|
||||
# are part of this repo. This Makefile is otherwise only a thin wrapper
|
||||
# around the Go toolchain and prettier so `make fmt` / `make check` behave
|
||||
# the same as in sneak's other repos.
|
||||
|
||||
GO_PKGS := ./...
|
||||
MD_FILES := $(shell git ls-files '*.md')
|
||||
@@ -26,9 +28,11 @@ fmt-check:
|
||||
fi
|
||||
$(PRETTIER) --check $(MD_FILES)
|
||||
|
||||
# Run the house linter (config in .golangci.yml).
|
||||
# Run the house linter. golangci-lint is never installed on the host: the
|
||||
# work happens inside the pinned container built by Dockerfile.lint, and
|
||||
# this target is a thin shim over the script that builds it.
|
||||
lint:
|
||||
golangci-lint run $(GO_PKGS)
|
||||
./script/lint
|
||||
|
||||
# Run the test suite. Quiet on success; on failure, rerun verbosely for the
|
||||
# full output and still fail the target (the first run already proved the
|
||||
|
||||
Reference in New Issue
Block a user