diff --git a/.github/workflows/golangci.yml b/.github/workflows/golangci.yml index b44810a..257420c 100644 --- a/.github/workflows/golangci.yml +++ b/.github/workflows/golangci.yml @@ -30,34 +30,18 @@ concurrency: jobs: golangci: timeout-minutes: 10 - name: golangci-lint (advisory) + name: golangci-lint runs-on: ubuntu-latest - # ============================ ADVISORY ============================ - # DELIBERATELY not a required check, and `--issues-exit-code=0` on - # the run step keeps findings from red-Xing the job: golangci-lint - # exits non-zero on any finding by default, and the pre-existing - # gosec backlog (8 findings at introduction: 4x G204, 3x G304, - # 1x G115 — sized on #423, the PR that added this job) would - # otherwise fail every PR for issues it didn't introduce. Findings - # still surface as inline annotations and in the job log. - # - # Known blind spot while advisory: typecheck (compile) errors ride - # the same issues exit path as lint findings, so under this flag - # they exit 0 too (verified empirically on #423 — this is NOT a - # separate exit code). No real signal is lost: a non-compiling PR - # reds the required Test / Lint / Build jobs anyway, and a broken - # .golangci.yml still fails THIS job via the action's - # `golangci-lint config verify` pre-step, which --issues-exit-code - # does not touch. - # - # (Job-level `continue-on-error: true` is NOT the tool for this — - # it greens the workflow run but still shows the job itself as - # failed in the PR checks list; see the first run on #423.) - # - # REMOVE the `--issues-exit-code=0` arg when the backlog hits zero - # and this check flips to required (the advisory -> required - # pattern from backend#1303; tracked under backend#1305 / epic - # #930). A required check that can't fail is worse than no check. + # ============================= GATE ============================== + # Blocking by exit code since the backlog hit zero: the gosec + # findings sized on #423 were all resolved with per-site reviewed + # #nosec waivers (#427), so any finding this job reports from now + # on is NEW and fails the job — including typecheck errors, which + # ride the same exit path. History of the advisory era (the + # --issues-exit-code=0 flag, why job-level continue-on-error was + # not the tool) is in the #423/#426 discussions if you need it. + # Final step of the flip = marking this check required in branch + # protection (backend#1305 / epic #930). # ================================================================== steps: - uses: actions/checkout@v7 @@ -73,11 +57,10 @@ jobs: # built with Go 1.26 (required: go.mod says `go 1.26.0`; v1-era # binaries can't typecheck this module). Bump deliberately, and # keep the version in step with the format expectations noted in - # .golangci.yml. + # .golangci.yml AND with GOLANGCI_LINT_VERSION in the Makefile + # (make lint-full runs the same pinned version -- the local/CI + # mirror depends on the two never drifting). - name: golangci-lint run (.golangci.yml) uses: golangci/golangci-lint-action@v9.3.0 with: version: v2.12.2 - # ADVISORY MODE — see the block comment above (incl. the - # typecheck caveat). Remove at the required-flip. - args: --issues-exit-code=0 diff --git a/.golangci.yml b/.golangci.yml index d5976f5..4b12669 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -96,3 +96,9 @@ formatters: - third_party$ - builtin$ - examples$ + +issues: + # Never cap repeated findings: the default (3) hid 10 of the 13 G304s + # behind a cache-flappy sample — "8 findings" were really 18 (#427). + # A gate must see the whole backlog, every run. + max-same-issues: 0 diff --git a/Makefile b/Makefile index 54e93dc..d415185 100644 --- a/Makefile +++ b/Makefile @@ -9,11 +9,12 @@ # ---- toggles ----------------------------------------------------- GO ?= go -GOLANGCI_LINT ?= golangci-lint PKGS := ./... # Pinned lint/analysis tool versions (reproducibility — no more @latest drift). -# Keep these in lockstep with .github/workflows/build.yml. Bump deliberately. +# Keep these in lockstep with .github/workflows/build.yml — and +# GOLANGCI_LINT_VERSION with .github/workflows/golangci.yml. Bump deliberately. +GOLANGCI_LINT_VERSION ?= v2.12.2 ERRCHECK_VERSION ?= v1.20.0 INEFFASSIGN_VERSION ?= v0.2.0 MISSPELL_VERSION ?= v0.3.4 @@ -24,8 +25,11 @@ GOIMPORTS_VERSION ?= v0.48.0 # ---- top-level targets ------------------------------------------- +# ci mirrors the PR gates exactly — including golangci-lint (lint-full), +# which fails on findings since #430. A green `make ci` must imply a green +# PR; lint-full's own guard tells you how to install the tool if missing. .PHONY: ci -ci: vet test lint fmt-check schema-check vulncheck file-budget deadcode check-style +ci: vet test lint lint-full fmt-check schema-check vulncheck file-budget deadcode check-style @echo "==> ci: all green" .PHONY: build @@ -126,15 +130,14 @@ deadcode: vulncheck: $(GO) run golang.org/x/vuln/cmd/govulncheck@$(GOVULNCHECK_VERSION) ./... +# Pinned to the exact version the golangci CI job runs (see +# .github/workflows/golangci.yml), via the same `go run tool@version` +# pattern as the tools above — no PATH dependency, so a green +# `make ci` and the PR gate can never disagree on golangci version. +# First run builds from source (~1-2 min); cached afterwards. .PHONY: lint-full lint-full: - @command -v $(GOLANGCI_LINT) >/dev/null 2>&1 || { \ - echo "==> $(GOLANGCI_LINT) not on PATH"; \ - echo " install via: brew install golangci-lint"; \ - echo " or see: https://golangci-lint.run/usage/install/"; \ - exit 1; \ - } - $(GOLANGCI_LINT) run + $(GO) run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) run .PHONY: fmt fmt: