All checks were successful
check / check (push) Successful in 15s
script/lint runs the linter directly when it is already inside a container and otherwise builds Dockerfile.lint, so the linter never runs on a developer host. That closes three host-only mechanisms: the result cache golangci-lint keys on file content rather than location, which produced a confirmed false green and findings reported against other checkouts; the host-global $TMPDIR/golangci-lint.lock, which fails a run in a way no caller can distinguish from findings; and host/container version skew, which hid thirteen findings on one repo. Detection is on LINT_IN_CONTAINER=1, set by every Dockerfile, and on nothing else. The two directions are not symmetric: a false negative inside a container attempts a nested docker build, finds no daemon and fails loudly, while a false positive on a host silently lints there, which is the defect this issue exists to kill. /.dockerenv is therefore rejected even as a fallback -- measured absent inside BuildKit RUN steps and present on any host that is itself a container, so it fails in both directions and one of them is the dangerous one. Nothing else changes shape. The Dockerfile still runs make check, script/check still runs test, lint and fmt-check, script/cibuild is still a single docker build with CHECK_EPOCH and VERSION, and the Go multistage lint stage and its COPY --from=lint ordering dependency survive with ENV LINT_IN_CONTAINER=1 added. Dockerfile.lint is the standalone developer-host path and carries the same CHECK_EPOCH guard, with the ARG below the dependency layer so only the lint re-runs. The script/bootstrap golangci-lint install and the per-checkout GOLANGCI_LINT_CACHE/TMPDIR wrapper are deleted as superseded. Neither has a caller left. A JS repo's yarn install stays: the rule is that no lint verdict may come from a host invocation, not that no linter binary may exist there, and in a repo whose formatter is its linter the formatter necessarily runs on the host. golangci-lint config verify is kept, on measurement. Under the pinned v2.12.2 a bogus top-level key and a bogus key under linters.settings.lll both pass `golangci-lint run` with exit 0 and `0 issues` while config verify exits 3 and names them; an unknown linter name fails run and passes config verify. It needs no network: every case reproduced byte-identically under `docker run --network none`, in a container where `getent hosts golangci-lint.run` exits 2. Comment blocks were cut hard across every file this unit touches. .dockerignore drops from 67 comment lines to 28, script/cibuild from 17 to 12, script/docker from 18 to 12, and prompts/REPO_POLICIES.md from 1182 lines to 907. What remains says why a line is load-bearing; the discovery narratives are gone.
35 lines
1.1 KiB
Bash
Executable File
35 lines
1.1 KiB
Bash
Executable File
#!/bin/sh
|
|
# script/lint: run the linter. Inside a container, run it directly;
|
|
# on a host, build Dockerfile.lint so it runs in one anyway. The linter
|
|
# is never run on a developer host, where a shared result cache, a
|
|
# host-global lock and a stale toolchain make its answer untrustworthy.
|
|
#
|
|
# LINT_IN_CONTAINER is set by this repo's Dockerfiles and is the ONLY
|
|
# accepted signal. Do not add a /.dockerenv fallback: it is absent
|
|
# inside BuildKit RUN steps and present on hosts that are themselves
|
|
# containers, so it both misses and false-positives — and a false
|
|
# positive silently restores host linting.
|
|
set -eu
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
|
|
|
main() {
|
|
cd "$ROOT"
|
|
|
|
if [ "${LINT_IN_CONTAINER:-}" = "1" ]; then
|
|
exec yarn run prettier --check '**/*.md' \
|
|
--tab-width 4 --prose-wrap always
|
|
fi
|
|
|
|
# Own line, and `$$` because busybox `date` drops %N silently.
|
|
# Without a fresh nonce the lint layer is cached and this exits 0
|
|
# having linted nothing.
|
|
epoch="$(date +%s%N)$$"
|
|
docker build \
|
|
--build-arg CHECK_EPOCH="$epoch" \
|
|
-f Dockerfile.lint \
|
|
.
|
|
}
|
|
|
|
main "$@"
|