diff --git a/.golangci.reference.yml b/.golangci.reference.yml index 13b96049d39c..f6f0aa152513 100644 --- a/.golangci.reference.yml +++ b/.golangci.reference.yml @@ -1964,6 +1964,9 @@ linters-settings: - T any - m map[string]int + vulncheck: + vuln-database: [https://vuln.go.dev] + whitespace: # Enforces newlines (or comments) after every multi-line if statement. # Default: false @@ -2180,6 +2183,7 @@ linters: - usestdlibvars - varcheck - varnamelen + - vulncheck - wastedassign - whitespace - wrapcheck @@ -2294,6 +2298,7 @@ linters: - usestdlibvars - varcheck - varnamelen + - vulncheck - wastedassign - whitespace - wrapcheck diff --git a/go.mod b/go.mod index e9813e534bb9..ca6c68835a95 100644 --- a/go.mod +++ b/go.mod @@ -117,12 +117,14 @@ require ( gitlab.com/bosi/decorder v0.2.3 go.tmz.dev/musttag v0.7.1 golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea + golang.org/x/net v0.11.0 golang.org/x/tools v0.10.0 + golang.org/x/vuln v0.2.0 gopkg.in/yaml.v3 v3.0.1 honnef.co/go/tools v0.4.3 mvdan.cc/gofumpt v0.5.0 mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed - mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d + mvdan.cc/unparam v0.0.0-20230312165513-e84e2d14e3b8 ) require ( @@ -188,7 +190,7 @@ require ( golang.org/x/mod v0.11.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/sys v0.9.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/text v0.10.0 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index df7abf9ef1a2..5f0a858f95dd 100644 --- a/go.sum +++ b/go.sum @@ -697,6 +697,7 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -803,8 +804,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -878,6 +879,8 @@ golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= +golang.org/x/vuln v0.2.0 h1:Dlz47lW0pvPHU7tnb10S8vbMn9GnV2B6eyT7Tem5XBI= +golang.org/x/vuln v0.2.0/go.mod h1:V0eyhHwaAaHrt42J9bgrN6rd12f6GU4T0Lu0ex2wDg4= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1007,8 +1010,8 @@ mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wp mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= -mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d h1:3rvTIIM22r9pvXk+q3swxUQAQOxksVMGK7sml4nG57w= -mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d/go.mod h1:IeHQjmn6TOD+e4Z3RFiZMMsLVL+A96Nvptar8Fj71is= +mvdan.cc/unparam v0.0.0-20230312165513-e84e2d14e3b8 h1:VuJo4Mt0EVPychre4fNlDWDuE5AjXtPJpRUWqZDQhaI= +mvdan.cc/unparam v0.0.0-20230312165513-e84e2d14e3b8/go.mod h1:Oh/d7dEtzsNHGOq1Cdv8aMm3KdKhVvPbRQcM8WFpBR8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/pkg/config/linters_settings.go b/pkg/config/linters_settings.go index 68ec1118b643..cb2c33a4e0ab 100644 --- a/pkg/config/linters_settings.go +++ b/pkg/config/linters_settings.go @@ -224,6 +224,7 @@ type LintersSettings struct { UseStdlibVars UseStdlibVarsSettings Varcheck VarCheckSettings Varnamelen VarnamelenSettings + Vulncheck VulncheckSettings Whitespace WhitespaceSettings Wrapcheck WrapcheckSettings WSL WSLSettings @@ -786,6 +787,10 @@ type VarnamelenSettings struct { IgnoreDecls []string `mapstructure:"ignore-decls"` } +type VulncheckSettings struct { + VulnDatabase []string `mapstructure:"vuln-database"` +} + type WhitespaceSettings struct { MultiIf bool `mapstructure:"multi-if"` MultiFunc bool `mapstructure:"multi-func"` diff --git a/pkg/golinters/vulncheck.go b/pkg/golinters/vulncheck.go new file mode 100644 index 000000000000..278ded0103ba --- /dev/null +++ b/pkg/golinters/vulncheck.go @@ -0,0 +1,85 @@ +package golinters + +import ( + "bytes" + "path/filepath" + "sync" + + "golang.org/x/net/context" + "golang.org/x/tools/go/analysis" + "golang.org/x/vuln/scan" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" + "github.com/golangci/golangci-lint/pkg/lint/linter" + "github.com/golangci/golangci-lint/pkg/result" +) + +const ( + vulncheckName = "vulncheck" + vulncheckDoc = "vulncheck detects uses of known vulnerabilities in Go programs." +) + +func NewVulncheck(settings *config.VulncheckSettings) *goanalysis.Linter { + var mu sync.Mutex + var resIssues []goanalysis.Issue + + analyzer := &analysis.Analyzer{ + Name: vulncheckName, + Doc: vulncheckDoc, + Run: goanalysis.DummyRun, + } + + return goanalysis.NewLinter( + vulncheckName, + vulncheckDoc, + []*analysis.Analyzer{analyzer}, + nil, + ).WithContextSetter(func(lintCtx *linter.Context) { + analyzer.Run = func(pass *analysis.Pass) (any, error) { + issues, err := vulncheckRun(lintCtx, pass, settings) + if err != nil { + return nil, err + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() + + return nil, nil + } + }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { + return resIssues + }) +} + +func vulncheckRun(lintCtx *linter.Context, pass *analysis.Pass, _ *config.VulncheckSettings) ([]goanalysis.Issue, error) { + files := getFileNames(pass) + + ctx := context.Background() + lintCtx.Log.Errorf("%v\n", files) + + issues := []goanalysis.Issue{} + for _, file := range files { + lintCtx.Log.Errorf("%s %s %s %s\n", "-json", "-C", filepath.Dir(file), ".") + cmd := scan.Command(ctx, "-json", "-C", filepath.Dir(file), ".") + buf := &bytes.Buffer{} + cmd.Stderr = buf + cmd.Stdout = buf + err := cmd.Start() + if err != nil { + return issues, err + } + err = cmd.Wait() + if err != nil { + return issues, err + } + issues = append(issues, goanalysis.NewIssue(&result.Issue{ + Text: buf.String(), + FromLinter: vulncheckName}, + pass)) + } + + lintCtx.Log.Errorf("%v\n", issues) + return issues, nil +} diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index 16b1babfafd2..921e4390dbb2 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -138,6 +138,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { usestdlibvars *config.UseStdlibVarsSettings varcheckCfg *config.VarCheckSettings varnamelenCfg *config.VarnamelenSettings + vulncheckCfg *config.VulncheckSettings whitespaceCfg *config.WhitespaceSettings wrapcheckCfg *config.WrapcheckSettings wslCfg *config.WSLSettings @@ -218,6 +219,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { usestdlibvars = &m.cfg.LintersSettings.UseStdlibVars varcheckCfg = &m.cfg.LintersSettings.Varcheck varnamelenCfg = &m.cfg.LintersSettings.Varnamelen + vulncheckCfg = &m.cfg.LintersSettings.Vulncheck whitespaceCfg = &m.cfg.LintersSettings.Whitespace wrapcheckCfg = &m.cfg.LintersSettings.Wrapcheck wslCfg = &m.cfg.LintersSettings.WSL @@ -851,6 +853,11 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithLoadForGoAnalysis(). WithURL("https://github.com/blizzy78/varnamelen"), + linter.NewConfig(golinters.NewVulncheck(vulncheckCfg)). + WithSince("v1.53.0"). + WithPresets(linter.PresetModule). + WithURL("https://vuln.go.dev/"), + linter.NewConfig(golinters.NewWastedAssign()). WithSince("v1.38.0"). WithPresets(linter.PresetStyle). diff --git a/test/linters_test.go b/test/linters_test.go index dd130db3e7db..1f2de5df1bfc 100644 --- a/test/linters_test.go +++ b/test/linters_test.go @@ -32,6 +32,7 @@ func TestSourcesFromTestdataSubDir(t *testing.T) { "loggercheck", "ginkgolinter", "zerologlint", + "vulncheck", } for _, dir := range subDirs { @@ -68,6 +69,7 @@ func testSourcesFromDir(t *testing.T, dir string) { rel, err := filepath.Rel(dir, source) require.NoError(t, err) + log.Warnf("TESTING: [%v] [%v] [%v] [%v]", subTest, log, binPath, rel) testOneSource(subTest, log, binPath, rel) }) } diff --git a/test/testdata/vulncheck/go.mod b/test/testdata/vulncheck/go.mod new file mode 100644 index 000000000000..53b79c11c515 --- /dev/null +++ b/test/testdata/vulncheck/go.mod @@ -0,0 +1,5 @@ +module vulncheck + +go 1.19 + +require golang.org/x/text v0.3.7 diff --git a/test/testdata/vulncheck/go.sum b/test/testdata/vulncheck/go.sum new file mode 100644 index 000000000000..1f78e039072f --- /dev/null +++ b/test/testdata/vulncheck/go.sum @@ -0,0 +1,2 @@ +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= diff --git a/test/testdata/vulncheck/vulncheck.go b/test/testdata/vulncheck/vulncheck.go new file mode 100644 index 000000000000..573515250e0c --- /dev/null +++ b/test/testdata/vulncheck/vulncheck.go @@ -0,0 +1,13 @@ +//golangcitest:args --disable-all -Evulncheck . +package vulncheck + +import ( + "fmt" + + "golang.org/x/text/language" +) + +func ParseRegion() { + us := language.MustParseRegion("US") + fmt.Println(us) +}