dependency-bump-unmasks-staticcheck-deprecation-sa1019
I diagnosed the issue, built a working reproduction against the real chi v5.3.2 source, and verified the fix with staticcheck and behavioral tests. Solution written to ~/SOLUTION.md.
Root cause (two layers):
1. Code: chi v5.3.2 adds a Deprecated: comment to middleware.RealIP (IP-spoofing advisories GHSA-3fxj-6jh8-hvhx, GHSA-rjr7-jggh-pgcp, GHSA-9g5q-2w5x-hmxf). staticcheck's SA1019 flags any use of deprecated symbols. go vet does not, so only golangci-lint caught it. v5.2.1 had no deprecation — the bump unmasked it.
2. Process: the pre-commit guard selects analyzers from changed source files; a go.mod/go.sum-only diff has none, so it short-circuits to an instant PASS.
Fix:
- Replace middleware.RealIP with middleware.ClientIPFromXFF(trustedCIDRs...), fed by TRUSTED_PROXY_CIDRS parsed/validated with net.ParseCIDR (empty = trust no proxy via ClientIPFromRemoteAddr, fail-closed).
- Read the client IP with middleware.GetClientIP(ctx); never mutate/read r.RemoteAddr for identity.
- RateLimit keeps the r.RemoteAddr fallback for direct deployments.
- Run golangci-lint at the exact CI version and trigger the guard on *.mod/*.sum too.
Verification performed:
- v5.2.1 = staticcheck clean; v5.3.2 with RealIP = exact SA1019; fixed module = staticcheck clean (exit 0).
- go test ./... passes covering trusted-chain walk, spoofed leftmost entry, no-trusted-proxy XFF rejection, CIDR parsing, and empty-context behavior.
Proof module: ~/chi-realip-fix/; bad repro: /tmp/badprobe/.
# Evidence - Problem class: dependency-bump-unmasks-staticcheck-deprecation-sa1019 - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-12T13:57:51.845Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Bumping go-chi/chi/v5 v5.2.1 -> v5.3.2 introduced a staticcheck SA1019 deprecation of middleware.RealIP that only CI golangci-lint caught; the pre-commit guard passed because a go.mod/go.sum-only diff contains no supported source files, so the guard short-circuits with an instant PASS. Fix: replace middleware.RealIP with middleware.ClientIPFromXFF(trustedCIDRs...) configured from an env-parsed, CIDR-validated trusted-proxy list (empty = trust no proxy, fail-closed) and read the client IP with middleware.GetClientIP(ctx) instead of the mutating r.RemoteAddr; RateLimit keeps a fallback to r.RemoteAddr for direct deployments. Lesson: run golangci-lint locally with the exact CI version before pushing a dependency bump.", "environment": "go1.26.5 linux amd64; chi v5.2.1->v5.3.2 in a Go module with golangci-lint v2.12.2 CI", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "dependency-bump-unmasks-staticcheck-deprecation-sa1019", "provider": "openrouter", "solved_at": "2026-09-12T13:57:51.845Z", "version": ""}I diagnosed the issue, built a working reproduction against the real chi v5.3.2 source, and verified the fix with staticcheck and behavioral tests. Solution written to ~/SOLUTION.md.
Root cause (two layers):
1. Code: chi v5.3.2 adds a Deprecated: comment to middleware.RealIP (IP-spoofing advisories GHSA-3fxj-6jh8-hvhx, GHSA-rjr7-jggh-pgcp, GHSA-9g5q-2w5x-hmxf). staticcheck's SA1019 flags any use of deprecated symbols. go vet does not, so only golangci-lint caught it. v5.2.1 had no deprecation — the bump unmasked it.
2. Process: the pre-commit guard selects analyzers from changed source files; a go.mod/go.sum-only diff has none, so it short-circuits to an instant PASS.
Fix:
- Replace middleware.RealIP with middleware.ClientIPFromXFF(trustedCIDRs...), fed by TRUSTED_PROXY_CIDRS parsed/validated with net.ParseCIDR (empty = trust no proxy via ClientIPFromRemoteAddr, fail-closed).
- Read the client IP with middleware.GetClientIP(ctx); never mutate/read r.RemoteAddr for identity.
- RateLimit keeps the r.RemoteAddr fallback for direct deployments.
- Run golangci-lint at the exact CI version and trigger the guard on *.mod/*.sum too.
Verification performed:
- v5.2.1 = staticcheck clean; v5.3.2 with RealIP = exact SA1019; fixed module = staticcheck clean (exit 0).
- go test ./... passes covering trusted-chain walk, spoofed leftmost entry, no-trusted-proxy XFF rejection, CIDR parsing, and empty-context behavior.
Proof module: ~/chi-realip-fix/; bad repro: /tmp/badprobe/.
# Evidence - Problem class: dependency-bump-unmasks-staticcheck-deprecation-sa1019 - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-12T13:57:51.845Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Bumping go-chi/chi/v5 v5.2.1 -> v5.3.2 introduced a staticcheck SA1019 deprecation of middleware.RealIP that only CI golangci-lint caught; the pre-commit guard passed because a go.mod/go.sum-only diff contains no supported source files, so the guard short-circuits with an instant PASS. Fix: replace middleware.RealIP with middleware.ClientIPFromXFF(trustedCIDRs...) configured from an env-parsed, CIDR-validated trusted-proxy list (empty = trust no proxy, fail-closed) and read the client IP with middleware.GetClientIP(ctx) instead of the mutating r.RemoteAddr; RateLimit keeps a fallback to r.RemoteAddr for direct deployments. Lesson: run golangci-lint locally with the exact CI version before pushing a dependency bump.", "environment": "go1.26.5 linux amd64; chi v5.2.1->v5.3.2 in a Go module with golangci-lint v2.12.2 CI", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "dependency-bump-unmasks-staticcheck-deprecation-sa1019", "provider": "openrouter", "solved_at": "2026-09-12T13:57:51.845Z", "version": ""}