diff --git a/.golangci.example.yml b/.golangci.example.yml index f2f97c92d877..12f5c2f544d4 100644 --- a/.golangci.example.yml +++ b/.golangci.example.yml @@ -1679,6 +1679,7 @@ linters: - nlreturn - noctx - nolintlint + - nosprintfhostport - paralleltest - prealloc - predeclared @@ -1769,6 +1770,7 @@ linters: - nlreturn - noctx - nolintlint + - nosprintfhostport - paralleltest - prealloc - predeclared diff --git a/go.mod b/go.mod index d9a1b2bf06a0..55d752af1034 100644 --- a/go.mod +++ b/go.mod @@ -83,6 +83,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.11.0 github.com/ssgreg/nlreturn/v2 v2.2.1 + github.com/stbenjam/no-sprintf-host-port v0.1.0 github.com/stretchr/testify v1.7.1 github.com/sylvia7788/contextcheck v1.0.4 github.com/tdakkota/asciicheck v0.1.1 diff --git a/go.sum b/go.sum index bc630033a124..77268ae7b80c 100644 --- a/go.sum +++ b/go.sum @@ -703,6 +703,8 @@ github.com/spf13/viper v1.11.0 h1:7OX/1FS6n7jHD1zGrZTM7WtY13ZELRyosK4k93oPr44= github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUsX7Zk= github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= +github.com/stbenjam/no-sprintf-host-port v0.1.0 h1:pnSetrEuD55O56B6OKROPSNwJtjUkjaiM+MDzuqNeG4= +github.com/stbenjam/no-sprintf-host-port v0.1.0/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/pkg/golinters/nosprintfhostport.go b/pkg/golinters/nosprintfhostport.go new file mode 100644 index 000000000000..a63b9bb5f567 --- /dev/null +++ b/pkg/golinters/nosprintfhostport.go @@ -0,0 +1,19 @@ +package golinters + +import ( + "github.com/stbenjam/no-sprintf-host-port/pkg/analyzer" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewNoSprintfHostPort() *goanalysis.Linter { + a := analyzer.Analyzer + + return goanalysis.NewLinter( + a.Name, + a.Doc, + []*analysis.Analyzer{a}, + nil, + ).WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index 86975c7a8665..4c405c0fcf61 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -531,6 +531,11 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithPresets(linter.PresetStyle). WithURL("https://github.com/firefart/nonamedreturns"), + linter.NewConfig(golinters.NewNoSprintfHostPort()). + WithSince("v1.46.0"). + WithPresets(linter.PresetStyle). + WithURL("https://github.com/stbenjam/no-sprintf-host-port"), + linter.NewConfig(golinters.NewParallelTest()). WithSince("v1.33.0"). WithPresets(linter.PresetStyle, linter.PresetTest). diff --git a/test/testdata/nosprintfhostport.go b/test/testdata/nosprintfhostport.go new file mode 100644 index 000000000000..e298e5a637b8 --- /dev/null +++ b/test/testdata/nosprintfhostport.go @@ -0,0 +1,47 @@ +//args: -Enosprintfhostport +package testdata + +import ( + "fmt" + "net" +) + +func _() { + + _ = fmt.Sprintf("postgres://%s:%s@127.0.0.1/%s", "foo", "bar", "baz") + + _ = fmt.Sprintf("http://api.%s/foo", "example.com") + + _ = fmt.Sprintf("http://api.%s:6443/foo", "example.com") + + _ = fmt.Sprintf("http://%s/foo", net.JoinHostPort("foo", "80")) + + _ = fmt.Sprintf("9invalidscheme://%s:%d", "myHost", 70) + + _ = fmt.Sprintf("gopher://%s/foo", net.JoinHostPort("foo", "80")) + + _ = fmt.Sprintf("telnet+ssl://%s/foo", net.JoinHostPort("foo", "80")) + + _ = fmt.Sprintf("http://%s/foo:bar", net.JoinHostPort("foo", "80")) + + _ = fmt.Sprintf("http://user:password@%s/foo:bar", net.JoinHostPort("foo", "80")) + + _ = fmt.Sprintf("http://example.com:9211") + + _ = fmt.Sprintf("gopher://%s:%d", "myHost", 70) // ERROR "host:port in url should be constructed with net.JoinHostPort and not directly with fmt.Sprintf" + + _ = fmt.Sprintf("telnet+ssl://%s:%d", "myHost", 23) // ERROR "host:port in url should be constructed with net.JoinHostPort and not directly with fmt.Sprintf" + + _ = fmt.Sprintf("weird3.6://%s:%d", "myHost", 23) // ERROR "host:port in url should be constructed with net.JoinHostPort and not directly with fmt.Sprintf" + + _ = fmt.Sprintf("https://user@%s:%d", "myHost", 8443) // ERROR "host:port in url should be constructed with net.JoinHostPort and not directly with fmt.Sprintf" + + _ = fmt.Sprintf("postgres://%s:%s@%s:5050/%s", "foo", "bar", "baz", "qux") // ERROR "host:port in url should be constructed with net.JoinHostPort and not directly with fmt.Sprintf" + + _ = fmt.Sprintf("https://%s:%d", "myHost", 8443) // ERROR "host:port in url should be constructed with net.JoinHostPort and not directly with fmt.Sprintf" + + _ = fmt.Sprintf("https://%s:9211", "myHost") // ERROR "host:port in url should be constructed with net.JoinHostPort and not directly with fmt.Sprintf" + + ip := "fd00::1" + _ = fmt.Sprintf("http://%s:1936/healthz", ip) // ERROR "host:port in url should be constructed with net.JoinHostPort and not directly with fmt.Sprintf" +}