diff --git a/.golangci.yml b/.golangci.yml index e310c32e..253eae93 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,27 +1,66 @@ -linters-settings: - misspell: - locale: US +version: "2" -issues: - exclude-rules: - - path: _test\.go - linters: - - dupl - - err113 - - containedctx - - maintidx - - path: "internal\\/server\\/.+\\.go" - linters: - - dupl - - text: "returns interface \\(github\\.com\\/vishvananda\\/netlink\\.Link\\)" - linters: - - ireturn - - path: "internal\\/openvpn\\/pkcs8\\/descbc\\.go" - text: "newCipherDESCBCBlock returns interface \\(github\\.com\\/youmark\\/pkcs8\\.Cipher\\)" - linters: - - ireturn +formatters: + enable: + - gci + - gofumpt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ linters: + settings: + misspell: + locale: US + goconst: + ignore-string-values: + # commonly used settings strings + - "^disabled$" + # Firewall and routing strings + - "^(ACCEPT|DROP)$" + - "^--delete$" + - "^all$" + - "^(tcp|udp)$" + # Server route strings + - "^/status$" + + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - containedctx + - dupl + - err113 + - maintidx + path: _test\.go + - linters: + - dupl + path: internal\/server\/.+\.go + - linters: + - ireturn + text: returns interface \(github\.com\/vishvananda\/netlink\.Link\) + - linters: + - ireturn + path: internal\/openvpn\/pkcs8\/descbc\.go + text: newCipherDESCBCBlock returns interface \(github\.com\/youmark\/pkcs8\.Cipher\) + - linters: + - revive + path: internal\/provider\/(common|utils)\/.+\.go + text: "var-naming: avoid (bad|meaningless) package names" + + paths: + - third_party$ + - builtin$ + - examples$ enable: # - cyclop # - errorlint @@ -42,7 +81,6 @@ linters: - exhaustive - fatcontext - forcetypeassert - - gci - gocheckcompilerdirectives - gochecknoglobals - gochecknoinits @@ -51,9 +89,7 @@ linters: - gocritic - gocyclo - godot - - gofumpt - goheader - - goimports - gomoddirectives - goprintffuncname - gosec @@ -86,7 +122,6 @@ linters: - rowserrcheck - sqlclosecheck - tagalign - - tenv - thelper - tparallel - unconvert diff --git a/Dockerfile b/Dockerfile index 1415abcb..90e09ac4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ ARG ALPINE_VERSION=3.20 ARG GO_ALPINE_VERSION=3.20 ARG GO_VERSION=1.23 ARG XCPUTRANSLATE_VERSION=v0.6.0 -ARG GOLANGCI_LINT_VERSION=v1.61.0 +ARG GOLANGCI_LINT_VERSION=v2.4.0 ARG MOCKGEN_VERSION=v1.6.0 ARG BUILDPLATFORM=linux/amd64 @@ -32,7 +32,7 @@ ENTRYPOINT go test -race -coverpkg=./... -coverprofile=coverage.txt -covermode=a FROM --platform=${BUILDPLATFORM} base AS lint COPY .golangci.yml ./ -RUN golangci-lint run --timeout=10m +RUN golangci-lint run FROM --platform=${BUILDPLATFORM} base AS mocks RUN git init && \ diff --git a/internal/configuration/settings/dot.go b/internal/configuration/settings/dot.go index 064ca22e..0b6478d0 100644 --- a/internal/configuration/settings/dot.go +++ b/internal/configuration/settings/dot.go @@ -119,7 +119,7 @@ func (d DoT) toLinesNode() (node *gotree.Node) { return node } - update := "disabled" //nolint:goconst + update := "disabled" if *d.UpdatePeriod > 0 { update = "every " + d.UpdatePeriod.String() } diff --git a/internal/configuration/settings/serverselection.go b/internal/configuration/settings/serverselection.go index fc3379e1..5531da4d 100644 --- a/internal/configuration/settings/serverselection.go +++ b/internal/configuration/settings/serverselection.go @@ -17,7 +17,7 @@ import ( "github.com/qdm12/gotree" ) -type ServerSelection struct { //nolint:maligned +type ServerSelection struct { // VPN is the VPN type which can be 'openvpn' // or 'wireguard'. It cannot be the empty string // in the internal state. @@ -354,11 +354,8 @@ func (ss *ServerSelection) setDefaults(vpnProvider string, portForwardingEnabled ss.SecureCoreOnly = gosettings.DefaultPointer(ss.SecureCoreOnly, false) ss.TorOnly = gosettings.DefaultPointer(ss.TorOnly, false) ss.MultiHopOnly = gosettings.DefaultPointer(ss.MultiHopOnly, false) - defaultPortForwardOnly := false - if portForwardingEnabled && helpers.IsOneOf(vpnProvider, - providers.PrivateInternetAccess, providers.Protonvpn) { - defaultPortForwardOnly = true - } + defaultPortForwardOnly := portForwardingEnabled && + helpers.IsOneOf(vpnProvider, providers.PrivateInternetAccess, providers.Protonvpn) ss.PortForwardOnly = gosettings.DefaultPointer(ss.PortForwardOnly, defaultPortForwardOnly) ss.OpenVPN.setDefaults(vpnProvider) ss.Wireguard.setDefaults() diff --git a/internal/configuration/settings/shadowsocks.go b/internal/configuration/settings/shadowsocks.go index 7e11b74e..29a20ef3 100644 --- a/internal/configuration/settings/shadowsocks.go +++ b/internal/configuration/settings/shadowsocks.go @@ -15,7 +15,7 @@ type Shadowsocks struct { // It defaults to false, and cannot be nil in the internal state. Enabled *bool // Settings are settings for the TCP+UDP server. - tcpudp.Settings + Settings tcpudp.Settings } func (s Shadowsocks) validate() (err error) { diff --git a/internal/firewall/delete.go b/internal/firewall/delete.go index ed6a1132..616cf7f2 100644 --- a/internal/firewall/delete.go +++ b/internal/firewall/delete.go @@ -16,7 +16,7 @@ func isDeleteMatchInstruction(instruction string) bool { fields := strings.Fields(instruction) for i, field := range fields { switch { - case field != "-D" && field != "--delete": //nolint:goconst + case field != "-D" && field != "--delete": continue case i == len(fields)-1: // malformed: missing chain name return false diff --git a/internal/firewall/firewall.go b/internal/firewall/firewall.go index 8114d550..f1618443 100644 --- a/internal/firewall/firewall.go +++ b/internal/firewall/firewall.go @@ -9,7 +9,7 @@ import ( "github.com/qdm12/gluetun/internal/routing" ) -type Config struct { //nolint:maligned +type Config struct { runner CmdRunner logger Logger iptablesMutex sync.Mutex diff --git a/internal/firewall/ip6tables.go b/internal/firewall/ip6tables.go index 397ab047..0bcc3f05 100644 --- a/internal/firewall/ip6tables.go +++ b/internal/firewall/ip6tables.go @@ -58,7 +58,7 @@ var ErrPolicyNotValid = errors.New("policy is not valid") func (c *Config) setIPv6AllPolicies(ctx context.Context, policy string) error { switch policy { - case "ACCEPT", "DROP": //nolint:goconst + case "ACCEPT", "DROP": default: return fmt.Errorf("%w: %s", ErrPolicyNotValid, policy) } diff --git a/internal/firewall/iptables.go b/internal/firewall/iptables.go index 0b1002f5..da9f0b64 100644 --- a/internal/firewall/iptables.go +++ b/internal/firewall/iptables.go @@ -149,7 +149,7 @@ func (c *Config) acceptOutputTrafficToVPN(ctx context.Context, ) error { protocol := connection.Protocol if protocol == "tcp-client" { - protocol = "tcp" //nolint:goconst + protocol = "tcp" } instruction := fmt.Sprintf("%s OUTPUT -d %s -o %s -p %s -m %s --dport %d -j ACCEPT", appendOrDelete(remove), connection.IP, defaultInterface, protocol, diff --git a/internal/healthcheck/health_test.go b/internal/healthcheck/health_test.go index 15d46a19..803cb8d0 100644 --- a/internal/healthcheck/health_test.go +++ b/internal/healthcheck/health_test.go @@ -40,7 +40,11 @@ func Test_Server_healthCheck(t *testing.T) { t.Run("dial localhost:0", func(t *testing.T) { t.Parallel() - listener, err := net.Listen("tcp4", "localhost:0") + const timeout = 100 * time.Millisecond + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + listenConfig := &net.ListenConfig{} + listener, err := listenConfig.Listen(ctx, "tcp4", "localhost:0") require.NoError(t, err) t.Cleanup(func() { err = listener.Close() @@ -57,10 +61,6 @@ func Test_Server_healthCheck(t *testing.T) { }, } - const timeout = 100 * time.Millisecond - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - err = server.healthCheck(ctx) assert.NoError(t, err) diff --git a/internal/httpserver/run.go b/internal/httpserver/run.go index 4d2cc106..3a187b62 100644 --- a/internal/httpserver/run.go +++ b/internal/httpserver/run.go @@ -20,8 +20,10 @@ func (s *Server) Run(ctx context.Context, ready chan<- struct{}, done chan<- str crashed := make(chan struct{}) shutdownDone := make(chan struct{}) + listenCtx, listenCancel := context.WithCancel(ctx) go func() { defer close(shutdownDone) + defer listenCancel() select { case <-ctx.Done(): case <-crashed: @@ -37,7 +39,8 @@ func (s *Server) Run(ctx context.Context, ready chan<- struct{}, done chan<- str } }() - listener, err := net.Listen("tcp", s.address) + listenConfig := &net.ListenConfig{} + listener, err := listenConfig.Listen(listenCtx, "tcp", s.address) if err != nil { close(s.addressSet) close(crashed) // stop shutdown goroutine diff --git a/internal/mod/load.go b/internal/mod/load.go index 0dc0f184..e5ea58f8 100644 --- a/internal/mod/load.go +++ b/internal/mod/load.go @@ -76,9 +76,9 @@ func initModule(path string) (err error) { const flags = 0 err = unix.FinitModule(int(file.Fd()), moduleParams, flags) switch { - case err == nil, err == unix.EEXIST: //nolint:goerr113 + case err == nil, err == unix.EEXIST: //nolint:err113 return nil - case err != unix.ENOSYS: //nolint:goerr113 + case err != unix.ENOSYS: //nolint:err113 if strings.HasSuffix(err.Error(), "operation not permitted") { err = fmt.Errorf("%w; did you set the SYS_MODULE capability to your container?", err) } diff --git a/internal/netlink/family.go b/internal/netlink/family.go index 0bc5da0f..6c91f9bc 100644 --- a/internal/netlink/family.go +++ b/internal/netlink/family.go @@ -13,7 +13,7 @@ const ( func FamilyToString(family int) string { switch family { case FamilyAll: - return "all" //nolint:goconst + return "all" case FamilyV4: return "v4" case FamilyV6: diff --git a/internal/provider/privateinternetaccess/portforward.go b/internal/provider/privateinternetaccess/portforward.go index b36fce10..994b008f 100644 --- a/internal/provider/privateinternetaccess/portforward.go +++ b/internal/provider/privateinternetaccess/portforward.go @@ -407,7 +407,7 @@ func bindPort(ctx context.Context, client *http.Client, apiIPAddress netip.Addr, // replaceInErr is used to remove sensitive information from errors. func replaceInErr(err error, substitutions map[string]string) error { s := replaceInString(err.Error(), substitutions) - return errors.New(s) //nolint:goerr113 + return errors.New(s) //nolint:err113 } // replaceInString is used to remove sensitive information. diff --git a/internal/publicip/api/multi.go b/internal/publicip/api/multi.go index a810a0e3..fbd30fa6 100644 --- a/internal/publicip/api/multi.go +++ b/internal/publicip/api/multi.go @@ -36,7 +36,7 @@ func FetchMultiInfo(ctx context.Context, fetcher InfoFetcher, ips []netip.Addr) } results = make([]models.PublicIP, len(ips)) - for range len(ips) { + for range ips { aResult := <-resultsCh if aResult.err != nil { if err == nil { diff --git a/internal/server/dns.go b/internal/server/dns.go index 6b758e9c..1e76016c 100644 --- a/internal/server/dns.go +++ b/internal/server/dns.go @@ -26,7 +26,7 @@ type dnsHandler struct { func (h *dnsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { r.RequestURI = strings.TrimPrefix(r.RequestURI, "/dns") switch r.RequestURI { - case "/status": //nolint:goconst + case "/status": switch r.Method { case http.MethodGet: h.getStatus(w)