Skip to content

chore(lint): enable twenty low-noise linters and clear what they found - #6981

Merged
otavio merged 1 commit into
masterfrom
chore/lint-tier0
Aug 28, 2026
Merged

chore(lint): enable twenty low-noise linters and clear what they found#6981
otavio merged 1 commit into
masterfrom
chore/lint-tier0

Conversation

@otavio

@otavio otavio commented Aug 28, 2026

Copy link
Copy Markdown
Member

What

Enables twenty golangci-lint linters that the codebase already almost satisfies, and fixes the 29 findings they report.

Independent of #6980, though they pair well. Without that PR's node_modules exclusion, running golangci-lint run --fix at the repo root rewrites ui/node_modules/flatted/golang/pkg/flatted/flatted.go — it did that to me while I was preparing this. That is a local-workflow problem only: CI never installs the UI's node_modules for the Go jobs. The two PRs touch different hunks of .golangci.yaml and merge in either order.

Why

Conventions that only live in prose drift. I ran every candidate linter golangci-lint offers against all six modules and counted the findings; these twenty came back at zero to five each, so they cost one cleanup and then hold the line for free, on human commits and agent-written code alike.

Grouped in the config by what they defend:

  • Resource leakssqlclosecheck, rowserrcheck
  • Constructs that compile but cannot mean what they saydurationcheck, asasalint, makezero, nilnesserr, wastedassign, reassign, predeclared, recvcheck, fatcontext, nosprintfhostport, musttag, iotamixing, unqueryvet
  • Naming and idiom already followederrname, intrange, usestdlibvars, mirror, exptostd, tparallel

Changes

Three findings were worth the exercise on their own:

  • ErruthDeviceNoIdentity was missing a letter. It now matches the NewErrAuthDeviceNoIdentity constructor that wraps it (errname).
  • The Postgres URI was assembled with Sprintf, which yields an unparseable address the day the host is IPv6. Now net.JoinHostPort (nosprintfhostport).
  • Identity mixed pointer and value receivers. WriteTo keeps the pointer because it deliberately tolerates a nil receiver — that nil check is load-bearing for the anonymous path — so WithoutUserScope copies through a pointer receiver instead (recvcheck).

The rest: three dead initialisations, three params shadowing the builtin max, an unexported sentinel renamed to errValidator, a missing t.Parallel(), x/exp/slices swapped for the stdlib, and 101 for http.StatusSwitchingProtocols.

golang.org/x/exp was only reachable through that one import, so go mod tidy drops it from the tests module.

Signature json tags. musttag flagged the four local Signature structs the agent marshals for public-key auth. The server hashes and signs req.Data without ever parsing it, so the JSON keys are internal to a single round-trip and the tags are behaviour-preserving. They are worth pinning: a field rename would otherwise change what gets signed, silently.

Not included

bodyclose was in the original candidate set and is held back deliberately. Its six findings are all gorilla WebSocket dials that discard the *http.Response, so fixing them means changing handshake error paths in connection code. That belongs in its own change, not one whose premise is "these cost nothing".

Testing

Under golang:1.26.7-alpine3.24:

  • golangci-lint run ./... reports 0 issues for all seven entry points — root, server, agent, gateway, openapi, tests, pkg
  • go build ./... clean for every module, plus agent under both -tags docker and -tags native
  • go test ./... passes for root, server, and agent under -tags docker
  • go mod tidy leaves only the intended x/exp removal

https://claude.ai/code/session_01D4BSojj4fmh3ZQSZWkGbD8

@otavio
otavio requested review from a team as code owners August 28, 2026 19:39
Each of these reported at most a handful of findings on the current tree, so they cost one
cleanup and then hold the line for free. They were picked by running every candidate linter
against all six modules and keeping the ones the codebase already almost satisfies.

Three finds were worth the exercise on their own. ErruthDeviceNoIdentity was missing a
letter and now matches the NewErrAuthDeviceNoIdentity that wraps it. The Postgres URI was
assembled with Sprintf, which produces an unparseable address the day the host is IPv6.
Identity mixed pointer and value receivers, and WriteTo has to keep the pointer because it
deliberately accepts a nil receiver, so WithoutUserScope copies through one instead.

The Signature structs the agent marshals for public-key auth now carry explicit json tags.
The server signs those bytes without parsing them, so the keys are internal to a single
round-trip, and pinning them keeps a field rename from silently changing what gets signed.
@otavio
otavio changed the base branch from chore/lint-skip-node-modules to master August 28, 2026 19:43
@otavio

otavio commented Aug 28, 2026

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown

Claude finished @otavio's task in 1m 17s —— View job


Code Review Complete

Reviewed 22 files across code quality, security, testing, language patterns, and architecture — no new issues found. The code looks good as-is.

A few notes I verified while reviewing (all clean, no action needed):

  • Identity.WithoutUserScope receiver change — the only caller (server/api/routes/middleware/authn.go:106) operates on a *Identity already guarded by identity != nil, so the pointer receiver introduces no nil dereference and keeps the receiver set consistent with WriteTo.
  • auth_test.go var req *http.Request — both branches of the if/else assign req before it's used, so dropping new(http.Request) is safe.
  • Signature json tagsjson:"Username" / json:"Namespace" reproduce Go's default field-name encoding byte-for-byte, and all four structs got the same tags, so the signed/verified round-trip is unchanged.
  • net.JoinHostPort swaps (pg.go, gateway/main_test.go) — correct IPv6-safe replacements for the Sprintf("%s:%s") pattern; imports are present.

To request another review round, comment /review.

@otavio
otavio merged commit ba07f74 into master Aug 28, 2026
44 of 64 checks passed
@otavio
otavio deleted the chore/lint-tier0 branch August 28, 2026 19:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant