From a80358621fa656818d39d1018ae6b62f9b63dbf7 Mon Sep 17 00:00:00 2001 From: lukasWuttke <54042461+LukasWodka@users.noreply.github.com> Date: Wed, 29 Jul 2026 14:38:57 +0200 Subject: [PATCH 1/4] ci(golangci): drop the advisory flag + uncap max-same-issues (backend#1305) Backlog is zero after the reviewed #nosec waivers (#427): findings now fail the job. max-same-issues: 0 so repeated findings can never hide behind the default cap of 3 again (the '8 findings were really 18' lesson). Branch-protection required-flip follows once this merges. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/golangci.yml | 41 +++++++++------------------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/.github/workflows/golangci.yml b/.github/workflows/golangci.yml index b44810a..93ca040 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 @@ -78,6 +62,3 @@ jobs: 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 From 6f7634a79d0df7b634c179d264c8b28f4413d38f Mon Sep 17 00:00:00 2001 From: lukasWuttke <54042461+LukasWodka@users.noreply.github.com> Date: Wed, 29 Jul 2026 14:38:58 +0200 Subject: [PATCH 2/4] ci(golangci): drop the advisory flag + uncap max-same-issues (backend#1305) Backlog is zero after the reviewed #nosec waivers (#427): findings now fail the job. max-same-issues: 0 so repeated findings can never hide behind the default cap of 3 again (the '8 findings were really 18' lesson). Branch-protection required-flip follows once this merges. Co-Authored-By: Claude Opus 4.8 --- .golangci.yml | 6 ++++++ 1 file changed, 6 insertions(+) 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 From 57d797c93c9839819c909bd506a0c97e90632cac Mon Sep 17 00:00:00 2001 From: lukasWuttke <54042461+LukasWodka@users.noreply.github.com> Date: Wed, 29 Jul 2026 14:48:43 +0200 Subject: [PATCH 3/4] =?UTF-8?q?build:=20make=20ci=20runs=20lint-full=20?= =?UTF-8?q?=E2=80=94=20mirror=20the=20now-failing=20golangci=20gate=20(Bug?= =?UTF-8?q?bot)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit golangci-lint fails PRs on findings since this branch; make ci skipping it broke the 'make ci mirrors CI exactly' rule (green local, red PR). lint-full's guard already gives install instructions when the tool is missing, which is correct mirroring rather than a soft skip. Co-Authored-By: Claude Opus 4.8 --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 54e93dc..808a7c3 100644 --- a/Makefile +++ b/Makefile @@ -24,8 +24,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 From 01e573804cfab5726b20fc40c2e92e3ad1a0477e Mon Sep 17 00:00:00 2001 From: lukasWuttke <54042461+LukasWodka@users.noreply.github.com> Date: Wed, 29 Jul 2026 14:53:27 +0200 Subject: [PATCH 4/4] build: pin lint-full to the CI golangci version via go run (Bugbot) lint-full ran whatever golangci-lint was on PATH while CI pins v2.12.2 -- with ci depending on lint-full, version drift could green a local run that reds the PR gate. Now runs the exact pinned version through the Makefile's own 'go run tool@version' pattern (like errcheck/ staticcheck/govulncheck): no PATH dependency, no brew-version drift. GOLANGCI_LINT var removed (unused); lockstep note added on both sides. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/golangci.yml | 4 +++- Makefile | 18 +++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/.github/workflows/golangci.yml b/.github/workflows/golangci.yml index 93ca040..257420c 100644 --- a/.github/workflows/golangci.yml +++ b/.github/workflows/golangci.yml @@ -57,7 +57,9 @@ 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: diff --git a/Makefile b/Makefile index 808a7c3..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 @@ -129,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: