lint: adopt org-standard .golangci.yml and golangci-lint v2.12.2 (closes #14) #31

Open
clawbot wants to merge 1 commits from feat/golangci-standard-config into main
6 changed files with 64 additions and 28 deletions

View File

@@ -3,8 +3,8 @@ FROM golang:1.25-alpine@sha256:f6751d823c26342f9506c03797d2527668d095b0a15f1862c
RUN apk add --no-cache git make gcc musl-dev
# golangci-lint v2.7.2 (2026-02-27)
RUN CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@9f61b0f53f80672872fced07b6874397c3ed197b
# golangci-lint v2.12.2 (2026-08-09)
RUN CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@c0d3ddc9cf3faa61a4e378e879ece580256d76e5
WORKDIR /repo/backend
COPY backend/go.mod backend/go.sum ./

33
TODO.md
View File

@@ -10,23 +10,31 @@
# Status
pre-1.0. No git tags. Backend work in flight on feat/reportbuf-storage (dirty:
src/main.js). Frontend is functional; backend is new and unmerged.
pre-1.0. No git tags. `feat/reportbuf-storage` is merged; the backend, the CI
workflow, and the backend repo standard files are all on `main`. Frontend and
backend are both functional. Working toward the 1.0.0 milestone by closing the
remaining repo-compliance issues on the tracker.
# Next Step
Land feat/reportbuf-storage: finish the in-progress src/main.js change, get make
check green, and merge the branch to main. The branch adds the backend (buffered
zstd-compressed report storage), the CI workflow, and backend repo standard
files, so merging it also closes most compliance gaps.
Compliance top-up as one small commit: add an `.editorconfig` at the repo root.
`backend/.editorconfig` exists but the root has none. (The `hooks` target this
step used to also name is already present in both the root `Makefile` and
`backend/Makefile`.)
# Completed Steps
- 2026-08-09: adopted the org-standard `backend/.golangci.yml` verbatim and
bumped the pinned golangci-lint to v2.12.2; the previous config declared
`version: "2"` but used v1 schema keys, so every threshold in it was inert and
its green result was meaningless. `backend/Makefile`'s `lint` target now
asserts the config's sha256 against the canonical file first, so drift from
the org standard fails the build instead of silently degrading to defaults
- 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints, Makefile
shims, README Entrypoints section
- 2026-02-27: backend with buffered zstd-compressed report storage; CI workflow
and backend repo standard files; backend Dockerfile fixed (Go 1.25,
golangci-lint) and moved to repo root (feat/reportbuf-storage, unmerged)
golangci-lint) and moved to repo root (feat/reportbuf-storage)
- 2026-02-26: host row layout redesigned with CSS grid; overflow and spacing
fixes; nginx config extracted; port hardcoded to 8080
- 2026-02-26: debug log panel, median stats, recovery probe, Docker build fix,
@@ -39,9 +47,12 @@ files, so merging it also closes most compliance gaps.
# Future Steps
- Compliance top-up as one small commit: add .editorconfig and add the hooks
target to the Makefile
- After merge, confirm .gitea/workflows/check.yml is on main and CI is green
(main always green policy)
- Confirm `.gitea/workflows/check.yml` is on `main` and CI is green (main always
green policy)
- Decide what to do with untracked resume.sh: commit it, gitignore it, or delete
it
- Upstream fix needed in `sneak/prompts`: the org-standard `.golangci.yml`
enables `gomodguard`, which golangci-lint v2.12.2 reports as deprecated since
v2.12.0 and replaced by `gomodguard_v2`, so every backend lint run prints a
deprecation warning. The file is standardized and must never be edited in this
repo, so nothing can be done here beyond tracking it

View File

@@ -1,5 +1,9 @@
version: "2"
# Config schema uses the golangci-lint v2 layout (settings live under
# linters.settings, not top-level linters-settings) so that the
# thresholds below are actually applied by golangci-lint >= v2.
run:
timeout: 5m
modules-download-mode: readonly
@@ -14,8 +18,7 @@ linters:
- wsl # Deprecated, replaced by wsl_v5
- wrapcheck # Too verbose for internal packages
- varnamelen # Short names like db, id are idiomatic Go
linters-settings:
settings:
lll:
line-length: 88
funlen:
@@ -27,6 +30,5 @@ linters-settings:
threshold: 100
issues:
exclude-use-default: false
max-issues-per-linter: 0
max-same-issues: 0

View File

@@ -8,10 +8,20 @@ GOLDFLAGS += -X main.Buildarch=$(BUILDARCH)
ifeq ($(UNAME_S),Darwin)
GOFLAGS := -ldflags "$(GOLDFLAGS)"
SHA256SUM := shasum -a 256
else
GOFLAGS = -ldflags "-linkmode external -extldflags -static $(GOLDFLAGS)"
SHA256SUM := sha256sum
endif
# .golangci.yml is standardized org-wide and must never be edited here
# (REPO_POLICIES.md). Its last silent drift replaced the v2 schema with
# v1 keys, which left every threshold in the file inert while the build
# stayed green. The lint target therefore asserts the file still matches
# the canonical copy byte for byte. The check is a local hash comparison:
# no network, no remote schema, nothing unpinned in the build path.
GOLANGCI_CONFIG_SHA256 := 021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb
.PHONY: all build test lint fmt fmt-check check docker hooks run clean
all: build
@@ -25,6 +35,14 @@ test:
timeout 30 go test ./...
lint:
@actual=$$($(SHA256SUM) .golangci.yml | cut -d' ' -f1); \
if [ "$$actual" != "$(GOLANGCI_CONFIG_SHA256)" ]; then \
echo ".golangci.yml has drifted from the org standard."; \
echo " expected $(GOLANGCI_CONFIG_SHA256)"; \
echo " actual $$actual"; \
echo "Restore it verbatim from sneak/prompts; do not edit it."; \
exit 1; \
fi
golangci-lint run ./...
fmt:

View File

@@ -163,7 +163,9 @@ func (b *Buffer) writeFile(data []byte) {
name := fmt.Sprintf("reports-%s.jsonl.zst", ts)
path := filepath.Join(b.dataDir, name)
f, err := os.OpenFile( //nolint:gosec // path built from controlled dataDir + timestamp
// path is built from the operator-supplied dataDir plus a
// generated timestamp, so it carries no external input.
f, err := os.OpenFile( //nolint:gosec // see comment above
path,
os.O_WRONLY|os.O_CREATE|os.O_EXCL,
filePerms,

View File

@@ -62,7 +62,10 @@ func New(
OnStart: func(_ context.Context) error {
s.startupTime = time.Now().UTC()
go func() { //nolint:contextcheck // fx OnStart ctx is startup-only; run() creates its own
// The fx OnStart context is scoped to startup and is
// cancelled once the hook returns; run() derives its
// own context instead of inheriting this one.
go func() { //nolint:contextcheck // see comment above
s.run()
}()
@@ -94,7 +97,7 @@ func (s *Server) run() {
}
func (s *Server) serve() int {
var ctx context.Context //nolint:wsl // ctx must be declared before multi-assign
var ctx context.Context
ctx, s.cancelFunc = context.WithCancel(
context.Background(),