All checks were successful
check / check (pull_request) Successful in 4m0s
Every lint run now happens inside its own container, invoked through script/lint, and linting is a build step rather than a container command: a successful build of the new root Dockerfile.lint IS a clean lint. That shape also works where the docker daemon is remote and bind mounts are impossible. Its FROM line -- golangci/golangci-lint:v2.12.2, pinned by digest -- is now the only pin of the linter version in this repo. A container per run has its own lint cache and its own golangci-lint lock, both discarded with it, so neither cross-worktree contamination nor lock contention exists any more. The machinery that defended against them is therefore gone: the per-worktree cache directories, the lock-retry loop, and script/lint-audit, which existed to catch findings replayed from a cache that no longer exists. So is the host lint path in its entirety -- the native escape hatch, its version detection, and VAULTIK_LINT_IN_CONTAINER in both script/lint and the Dockerfile. Nothing lints on the host, at any version. A cached build lints nothing, so the CHECK_EPOCH mechanism the product Dockerfile already used is what makes a green mean something: ARG CHECK_EPOCH with no default, placed below the module layers so dependency caching survives, a `RUN [ -n "$CHECK_EPOCH" ] || exit 1` guard so a build that withholds the arg fails instead of replaying, and the value expanded into the lint command itself. script/lint computes `epoch="$(date +%s%N)$$"` as a bare assignment on its own line, because inline in the argument a failing substitution does not abort under `set -eu` and yields a constant empty epoch -- which is exactly the false green being prevented. The product Dockerfile loses its lint stage rather than gaining a second linter pin. That stage ran `make lint`, which is now `docker build`: docker-in-docker inside a BuildKit step with no daemon. Calling golangci-lint directly there instead would have meant two independently bumpable digests for one tool. `make fmt-check` moves beside `make test` in the builder stage, and script/cibuild now builds Dockerfile.lint and then Dockerfile, each with its own fresh epoch, failing on either. Consequence, stated in comments rather than left to be discovered: script/docker builds the product image only and no longer lints; script/check and script/cibuild are the gates. Two decisions taken deliberately and documented where they apply. `golangci-lint config verify` is omitted: it fetches its JSON schema over an unpinned live HTTPS call, which would make the gate depend on a remote resource outside this repo's hash-pinning discipline and turn an upstream outage or an egress-less runner into a red that is not a lint verdict. script/lint-fix is kept, reimplemented as a bind-mounted docker run against the image parsed out of Dockerfile.lint -- a build step cannot write fixes back to the worktree -- and its header states outright that it is a developer convenience, never a gate, and needs a local daemon. cmd/vaultik/lintdocker_test.go parses both Dockerfiles and both scripts and fails if any part of the mechanism is dropped: the digest pin, the defaultless ARG below `go mod download`, the emptiness guard, the expansion of the epoch into each check command, the bare per-invocation epoch assignment in both scripts, cibuild building both files, and the absence of any host-lint escape hatch. Every one of those losses is silent -- the build still exits 0 and nothing is checked -- which is why they are asserted rather than trusted. script/lint takes no arguments now, and says so instead of dropping them: a build step has no command line to pass linter flags to.
127 lines
4.2 KiB
Makefile
127 lines
4.2 KiB
Makefile
.PHONY: all bootstrap setup check test lint lint-fix fmt fmt-check build clean deps test-coverage local install release release-snapshot docker hooks
|
||
|
||
# Version number, derived from git by script/version -- the tag when
|
||
# HEAD is on one, otherwise dev-<sha>. This used to be a hardcoded
|
||
# constant, which meant every local build claimed to be a release that
|
||
# had never been tagged.
|
||
VERSION := $(shell script/version)
|
||
|
||
# $(shell) discards exit status, so a script/version that is missing,
|
||
# non-executable or broken would otherwise leave VERSION empty and every
|
||
# binary built here would print "vaultik " with no version at all. A
|
||
# build that cannot determine what it is must not produce an artifact.
|
||
ifeq ($(strip $(VERSION)),)
|
||
$(error script/version produced no version string; a build that cannot \
|
||
determine its version will not be made. Check that script/version exists \
|
||
and is executable)
|
||
endif
|
||
|
||
# Build variables
|
||
GIT_REVISION := $(shell git rev-parse HEAD 2>/dev/null || echo "unknown")
|
||
GIT_COMMIT_DATE := $(shell git show -s --format=%cs HEAD 2>/dev/null || echo "unknown")
|
||
|
||
# Linker flags
|
||
LDFLAGS := -X 'sneak.berlin/go/vaultik/internal/globals.Version=$(VERSION)' \
|
||
-X 'sneak.berlin/go/vaultik/internal/globals.Commit=$(GIT_REVISION)' \
|
||
-X 'sneak.berlin/go/vaultik/internal/globals.CommitDate=$(GIT_COMMIT_DATE)'
|
||
|
||
# Default target
|
||
all: vaultik
|
||
|
||
# Install all development dependencies.
|
||
bootstrap:
|
||
@script/bootstrap
|
||
|
||
# Prepare a fresh clone: bootstrap plus pre-commit hook.
|
||
setup:
|
||
@script/setup
|
||
|
||
# Combined pre-commit/CI gate: tests, lint, format check.
|
||
check:
|
||
@script/check
|
||
|
||
# Run tests only. This runs the ENTIRE suite -- there is no separate
|
||
# integration target and no build-tagged subset held back. In
|
||
# particular internal/vaultik/integration_test.go, which does full
|
||
# chunk -> pack -> encrypt -> upload -> restore round-trips, runs here.
|
||
# A `test-integration` target used to exist and was removed: no file in
|
||
# the repo carried a build tag, so `-tags=integration` selected nothing
|
||
# extra and the target was an exact duplicate of this one.
|
||
test:
|
||
@script/test
|
||
|
||
# Check if code is formatted (read-only).
|
||
fmt-check:
|
||
@script/fmt-check
|
||
|
||
# Format code.
|
||
fmt:
|
||
@script/fmt
|
||
|
||
# Run linter only.
|
||
lint:
|
||
@script/lint
|
||
|
||
# Apply the linter's autofixes (rewrites files).
|
||
lint-fix:
|
||
@script/lint-fix
|
||
|
||
# Build binary. `build` is the name the org convention reaches for and
|
||
# the one a caller checks the exit code of; `vaultik` is the file rule
|
||
# that does the work, so an unchanged tree still short-circuits.
|
||
#
|
||
# This alias is not decorative. `build` was listed in .PHONY with no
|
||
# rule, and a phony target with no prerequisites and no recipe is
|
||
# already satisfied: `make build` printed "Nothing to be done" and
|
||
# exited 0 without producing a binary (issue #110). Every name in
|
||
# .PHONY needs a rule for that reason; TestPhonyTargetsAllHaveRules in
|
||
# cmd/vaultik keeps it that way.
|
||
build: vaultik
|
||
|
||
vaultik: internal/*/*.go cmd/vaultik/*.go
|
||
go build -ldflags "$(LDFLAGS)" -o $@ ./cmd/vaultik
|
||
|
||
# Clean build artifacts.
|
||
clean:
|
||
rm -f vaultik
|
||
go clean
|
||
|
||
# Install dependencies. The linter is deliberately not installed here:
|
||
# script/lint lints by building Dockerfile.lint, whose FROM line is the
|
||
# single source of truth for the linter version. A second, separately
|
||
# pinned copy on PATH could drift from it and make a local `make lint`
|
||
# disagree with CI.
|
||
deps:
|
||
go mod download
|
||
|
||
# Run tests with coverage. -count=1 for the same reason script/test
|
||
# uses it: without it an unchanged package is served from Go's test
|
||
# result cache, and a coverage profile assembled from cached results
|
||
# describes a run that did not happen.
|
||
test-coverage:
|
||
go test -v -count=1 -coverprofile=coverage.out ./...
|
||
go tool cover -html=coverage.out -o coverage.html
|
||
|
||
local:
|
||
VAULTIK_CONFIG=$(HOME)/etc/vaultik/config.yml ./vaultik snapshot --debug list 2>&1
|
||
VAULTIK_CONFIG=$(HOME)/etc/vaultik/config.yml ./vaultik snapshot --debug create 2>&1
|
||
|
||
install: vaultik
|
||
cp ./vaultik $(HOME)/bin/
|
||
|
||
# Build and publish release artifacts (linux/darwin × amd64/arm64) via goreleaser.
|
||
release:
|
||
@script/release
|
||
|
||
# Dry-run a release build without publishing or tagging.
|
||
release-snapshot:
|
||
@script/release-snapshot
|
||
|
||
# Build Docker image.
|
||
docker:
|
||
@script/docker
|
||
|
||
# Install pre-commit hook.
|
||
hooks:
|
||
@script/install-precommit
|