# golangci-lint v2 config for the AO backend. # Run: golangci-lint run ./... (from backend/) version: "2" run: timeout: 5m issues: # Report every finding, not the default first-50-per-linter / 3-same. max-issues-per-linter: 0 max-same-issues: 0 linters: default: none enable: # --- correctness --- - errcheck # unchecked errors - govet # suspicious constructs - ineffassign # ineffectual assignments - staticcheck # the big static analyzer - unused # dead code (funcs/vars/types/fields) - errorlint # error wrapping / comparison bugs - bodyclose # unclosed HTTP response bodies - sqlclosecheck # unclosed sql.Rows/Stmt - rowserrcheck # missing rows.Err() - nilerr # `return nil` after a non-nil err check - makezero # append to a non-zero-len make() slice - gocheckcompilerdirectives # malformed //go: directives - reassign # reassigning package-level vars from other pkgs # --- dead code / boilerplate (the "nuke" linters) --- - unparam # unused function params / always-same returns - unconvert # unnecessary type conversions - wastedassign # assignments never read - copyloopvar # redundant loop-var copies (Go 1.22+) - prealloc # slices that could be preallocated - dupl # copy-pasted code blocks # --- style / quality --- - revive # configurable golint successor - gocritic # opinionated diagnostics + style - misspell # typos in comments/strings - usestdlibvars # use stdlib consts (http.MethodGet, etc.) - predeclared # shadowing predeclared identifiers - nakedret # naked returns in long funcs # --- security --- - gosec settings: errcheck: check-type-assertions: true govet: enable-all: true disable: - fieldalignment # struct field ordering is not worth the churn - shadow # shadowing `err` in nested scopes is idiomatic Go revive: rules: - { name: exported } # doc comments on every exported symbol - { name: blank-imports } - { name: context-as-argument } - { name: context-keys-type } - { name: dot-imports } - { name: error-return } - { name: error-strings } - { name: error-naming } - { name: indent-error-flow } - { name: errorf } - { name: empty-block } - { name: superfluous-else } - { name: unreachable-code } - { name: redefines-builtin-id } - { name: range } - { name: time-naming } - { name: var-declaration } gocritic: enabled-tags: [diagnostic, performance, style] disabled-checks: - ifElseChain # overlaps revive/superfluous-else - commentedOutCode - hugeParam # pass-by-pointer micro-opt; hurts clarity, risks nil/aliasing - rangeValCopy # same — copying a struct in range is usually fine - unnamedResult # named returns are a style choice, not a defect dupl: threshold: 140 gosec: excludes: - G104 # unchecked errors — errcheck owns this - G304 # file inclusion via variable — paths are config/run-file/worktree-derived, not user input - G703 # path traversal via taint analysis — same as G304: binary-resolution and worktree-derived paths, not user input - G704 # SSRF via taint analysis — the daemon client's host is hardcoded loopback; only the request path varies, so it cannot be steered to an external host exclusions: generated: lax # skip sqlc/codegen ("Code generated ... DO NOT EDIT") rules: # Tests: relax the noisiest checks (deliberate error-drops, repeated setup, # preallocation, and upgrade-response bodies that don't need closing). - path: _test\.go linters: [errcheck, dupl, gosec, unparam, gocritic, prealloc, bodyclose] # status.go deliberately reports probe failures in the result struct # (st.State/st.Error) and returns nil — a down daemon is the status being # reported, not a failure of the status command itself. - path: internal/cli/status\.go linters: [nilerr] # The reflect/unsafe field-inspection test is intentional. - path: wiring_test\.go linters: [gosec] # Spawning git/agent subprocesses with computed args is the point. - linters: [gosec] text: "G204" formatters: enable: - goimports settings: goimports: local-prefixes: - github.com/aoagents/agent-orchestrator