go-bananas/.golangci.yml
Daniel Noulet 951dd8d26b
Some checks failed
ci / go (push) Has been cancelled
ci / admin-ui (push) Has been cancelled
ci / runtime-sdk (push) Has been cancelled
ci / helm (push) Has been cancelled
ci / openapi (push) Has been cancelled
ci / container (push) Has been cancelled
ci / release-config (push) Has been cancelled
ci / shared styling (push) Has been cancelled
ci / security (push) Has been cancelled
ci / all green (push) Has been cancelled
initial commit
2026-10-07 15:11:35 +02:00

275 lines
10 KiB
YAML

# golangci-lint configuration.
#
# The enabled set is chosen for signal, not coverage. A linter that fires on
# stylistic preferences nobody agreed to trains the team to ignore the output, which
# costs more than the findings are worth. Every linter here catches a class of bug
# or a readability problem we actually care about; the exclusions below are
# deliberate and commented.
version: "2"
run:
timeout: 5m
# Tests are linted. A lint failure in a test is a lint failure.
tests: true
build-tags: []
modules-download-mode: readonly
issues-exit-code: 1
formatters:
enable:
- gofmt
- goimports
- gci
settings:
gci:
sections:
- standard
- default
- prefix(github.com/urpi/go-bananas)
no-lex-order: true
goimports:
local-prefixes: [github.com/urpi/go-bananas]
linters:
enable:
# --- correctness -------------------------------------------------------
- errcheck # an unchecked error is a bug waiting for a bad day
- govet
- ineffassign
- staticcheck # the staticcheck suite, at its default strictness
- unused
- bodyclose # an unclosed response body leaks a connection
- rowserrcheck # a rows.Err() not checked hides a mid-iteration failure
- sqlclosecheck
- noctx # an HTTP request without a context cannot be cancelled
- contextcheck # a context stored in a struct cannot be cancelled
- errorlint # %w and errors.Is, so wrapping and matching actually work
- nilerr # returning nil after checking err != nil is almost always wrong
# --- readability -------------------------------------------------------
- revive # exported comments, naming, control-flow clarity
- goconst # a repeated literal is a constant waiting to be named
- godot # comments end in a period
- misspell # a typo in a comment is a typo a reader will trust
- unconvert
- prealloc
- whitespace
- nolintlint # a nolint that no longer applies is misleading
- copyloopvar # Go 1.22+ loop variables; the old idiom is now a bug
# --- security ----------------------------------------------------------
- gosec # integer overflows, weak randomness, unsafe, etc.
# --- testing -----------------------------------------------------------
- thelper # t.Helper() in a test helper
- tparallel # a parallel test that does not call t.Parallel
settings:
errcheck:
# A type assertion or conversion that cannot fail needs no check.
check-type-assertions: false
# A blank assignment to an error is a deliberate, documented decision, not an
# oversight, so errcheck is asked to flag it too. The ones that remain are
# marked with an explicit nolint and a reason.
check-blank: true
exclude-functions:
# Writing to an http.ResponseWriter returns an error only when the client has
# gone away, and there is nothing a handler can do about that: the response
# is already committed and the connection is already being torn down.
- (net/http.ResponseWriter).Write
- (net/http.ResponseWriter).WriteHeader
# A Rollback after a successful Commit is expected to report
# sql.ErrTxDone, and a Rollback on the error path is immediately followed by
# returning that error. Checking either produces a branch that can only ever
# discard a result.
- (*database/sql.Tx).Rollback
# Deferred Close on a read-only database handle: the only error it can
# report is already lost by the time the process exits.
- (*database/sql.Rows).Close
- (io.Closer).Close
- (*os.File).Close
- (*bytes.Buffer).Write
- (*bytes.Buffer).WriteByte
- (*bytes.Buffer).WriteString
- (io.Writer).Write
- (hash.Hash).Write
- fmt.Fprintf
- fmt.Fprint
- fmt.Fprintln
- fmt.Print
- fmt.Println
- fmt.Sprintf
- sort.Slice
govet:
enable-all: true
disable:
# Field alignment is a micro-optimisation that makes every struct
# declaration a puzzle. It is not worth the readability cost.
- fieldalignment
# The shadow linter fires on ordinary, readable `err :=` inside an if.
- shadow
revive:
rules:
# requireDoc is deliberately not set. Every exported item in this codebase
# carries a doc comment by convention and by review, but the rule's argument
# name is not "requireDoc" in this version of revive, so setting it disables
# the whole revive rule set with a configuration error rather than enforcing
# anything.
- name: exported
arguments:
- checkPrivateReceivers
- name: package-comments
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: error-return
# No arguments: the rule takes none. Passing "error-strings" as an argument
# makes revive look for a custom function of that name, fails to find it, and
# then silently disables the rule along with every other revive rule.
- name: error-strings
- name: error-naming
- name: increment-decrement
# The allowlist has to be a slice. Given as a bare string it is a
# configuration error, which stops every revive rule from loading rather
# than enabling this one.
- name: var-naming
arguments:
- [ID, VM, HTTP, URL, API, TLS, CSS, JSON, SQL, UUID, OIDC, ACL, CPU, RAM, WAC]
- name: receiver-naming
- name: indent-error-flow
- name: range
- name: unreachable-code
- name: redefines-builtin-id
goconst:
min-len: 3
# Raised from 4 to 6, and the wire vocabulary below is exempted. The strings
# that repeat in this codebase are JSON field names ("status", "version",
# "slug"), theme token vocabulary ("primary-hover", "normal") and the auth
# method "anonymous". Those are the wire and CSS contract rather than repeated
# logic, and hoisting them into Go constants would make them less greppable
# without changing anything the compiler checks.
min-occurrences: 6
ignore-string-values:
- anonymous
- none
- normal
- primary
- primary-hover
- focus-ring
- link
- version
- status
- slug
- items
- must not be empty
# Test data legitimately repeats literals like "200" and "published".
ignore-tests: true
godot:
scope: declarations
capital: false
gosec:
excludes:
# G304: a file path from configuration is intentional. The path comes from
# the operator's own configuration, not from a request.
- G304
# Everything gosec ships is enabled by default; only the exclusions above
# narrow it. G115 (integer overflow) is intentionally left on: it fires on
# the token engine's length arithmetic, and the two or three places that
# could genuinely overflow carry an explicit nolint with a reason.
staticcheck:
checks:
- all
# SA1019: deprecation notices for dependencies we control the version of.
- -SA1019
misspell:
# US, deliberately, and this is a real decision rather than a default.
#
# misspell's locale setting makes it *require* one dialect. With UK it
# rewrites the checker's idea of a correct word, which means it flags every
# occurrence of the US spelling -- including identifiers that are part of the
# published API contract: the JSON error code "unauthorized", the CSS custom
# property and colour-scheme vocabulary, the OpenAPI document.
#
# The codebase writes prose in British English, which misspell has nothing to
# say about under a US locale (it only corrects genuine misspellings, it does
# not enforce a dialect). So: British prose, US locale, and no linter
# pressure to rename a wire-format string.
locale: US
# misspell enforces one dialect even under a locale setting, so every British
# spelling in the prose has to be listed explicitly. This keeps the check
# worth having -- a genuine typo in a comment is still caught -- while
# accepting the dialect the documentation is written in.
#
# No identifier is in this list: exported names and JSON keys are American
# throughout, because they are wire and API surface rather than prose. Only
# comments, documentation and doc strings use the British forms.
ignore-rules:
- artefact
- artefacts
- authorises
- behaviour
- cancelled
- colour
- colours
- defence
- honoured
- honouring
- honours
- initialise
- licence
- localise
- marshalled
- materialise
- materialises
- materialising
- maximises
- modelled
- neutralises
- recognised
- recognises
- sanitise
- sanitised
- sanitising
- serialise
- serialised
- serialises
- summarises
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
# A test function legitimately ignores the error from a deliberate failure.
- path: _test\.go
linters:
- gosec
- errcheck
# The SQL query constants and their arguments are checked by the store tests,
# which assert on behaviour rather than on the statement text.
- path: internal/store/
linters:
- goconst
paths:
- third_party$
- builtin$
- examples$
issues:
# 0 disables the cap. A linter that stops reporting after 50 findings is worse
# than one that reports everything, because the tail is where the surprises are.
max-issues-per-linter: 0
max-same-issues: 0
new: false
fix: false