From ed9934fa486e0c7c642f689e06f4119ab99721b5 Mon Sep 17 00:00:00 2001 From: Cosmin Cojocar Date: Tue, 25 Jun 2019 10:29:19 +0200 Subject: [PATCH 1/5] Refactor the rules tests to be able to configure the analyzer config per test sample Signed-off-by: Cosmin Cojocar --- analyzer.go | 5 ++ rules/rules_test.go | 15 ++--- testutils/source.go | 143 ++++++++++++++++++++++---------------------- 3 files changed, 82 insertions(+), 81 deletions(-) diff --git a/analyzer.go b/analyzer.go index 1d3dd57547..77e016ca67 100644 --- a/analyzer.go +++ b/analyzer.go @@ -92,6 +92,11 @@ func NewAnalyzer(conf Config, tests bool, logger *log.Logger) *Analyzer { } } +// SetConfig upates the analyzer configuration +func (gosec *Analyzer) SetConfig(conf Config) { + gosec.config = conf +} + // LoadRules instantiates all the rules to be used when analyzing source // packages func (gosec *Analyzer) LoadRules(ruleDefinitions map[string]RuleBuilder) { diff --git a/rules/rules_test.go b/rules/rules_test.go index 521f886cb9..71ae26ff2f 100644 --- a/rules/rules_test.go +++ b/rules/rules_test.go @@ -12,18 +12,13 @@ import ( "github.com/securego/gosec/testutils" ) -type option struct { - name gosec.GlobalOption - value string -} - var _ = Describe("gosec rules", func() { var ( logger *log.Logger config gosec.Config analyzer *gosec.Analyzer - runner func(string, []testutils.CodeSample, ...option) + runner func(string, []testutils.CodeSample) buildTags []string tests bool ) @@ -32,13 +27,11 @@ var _ = Describe("gosec rules", func() { logger, _ = testutils.NewLogger() config = gosec.NewConfig() analyzer = gosec.NewAnalyzer(config, tests, logger) - runner = func(rule string, samples []testutils.CodeSample, options ...option) { - for _, o := range options { - config.SetGlobal(o.name, o.value) - } + runner = func(rule string, samples []testutils.CodeSample) { analyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, rule)).Builders()) for n, sample := range samples { analyzer.Reset() + analyzer.SetConfig(sample.Config) pkg := testutils.NewTestPackage() defer pkg.Close() for i, code := range sample.Code { @@ -75,7 +68,7 @@ var _ = Describe("gosec rules", func() { }) It("should detect errors not being checked in audit mode", func() { - runner("G104", testutils.SampleCodeG104Audit, option{name: gosec.Audit, value: "enabled"}) + runner("G104", testutils.SampleCodeG104Audit) }) It("should detect of big.Exp function", func() { diff --git a/testutils/source.go b/testutils/source.go index e9160c97d8..260a37d4f7 100644 --- a/testutils/source.go +++ b/testutils/source.go @@ -1,9 +1,12 @@ package testutils +import "github.com/securego/gosec" + // CodeSample encapsulates a snippet of source code that compiles, and how many errors should be detected type CodeSample struct { Code []string Errors int + Config gosec.Config } var ( @@ -15,7 +18,7 @@ func main() { username := "admin" password := "f62e5bcda4fae4f82370da0c6f20697b8f8447ef" fmt.Println("Doing something with: ", username, password) -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` // Entropy check should not report this error by default package main import "fmt" @@ -23,21 +26,21 @@ func main() { username := "admin" password := "secret" fmt.Println("Doing something with: ", username, password) -}`}, 0}, {[]string{` +}`}, 0, gosec.NewConfig()}, {[]string{` package main import "fmt" var password = "f62e5bcda4fae4f82370da0c6f20697b8f8447ef" func main() { username := "admin" fmt.Println("Doing something with: ", username, password) -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` package main import "fmt" const password = "f62e5bcda4fae4f82370da0c6f20697b8f8447ef" func main() { username := "admin" fmt.Println("Doing something with: ", username, password) -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` package main import "fmt" const ( @@ -46,12 +49,12 @@ const ( ) func main() { fmt.Println("Doing something with: ", username, password) -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` package main var password string func init() { password = "f62e5bcda4fae4f82370da0c6f20697b8f8447ef" -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` package main const ( ATNStateSomethingElse = 1 @@ -59,14 +62,14 @@ const ( ) func main() { println(ATNStateTokenStart) -}`}, 0}, {[]string{` +}`}, 0, gosec.NewConfig()}, {[]string{` package main const ( ATNStateTokenStart = "f62e5bcda4fae4f82370da0c6f20697b8f8447ef" ) func main() { println(ATNStateTokenStart) -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCodeG102 code snippets for network binding SampleCodeG102 = []CodeSample{ @@ -83,7 +86,7 @@ func main() { log.Fatal(err) } defer l.Close() -}`}, 1}, +}`}, 1, gosec.NewConfig()}, // Bind to all networks implicitly (default if host omitted) {[]string{` @@ -98,7 +101,7 @@ func main() { log.Fatal(err) } defer l.Close() -}`}, 1}, +}`}, 1, gosec.NewConfig()}, // Bind to all networks indirectly through a parsing function {[]string{` package main @@ -116,7 +119,7 @@ func main() { log.Fatal(err) } defer l.Close() -}`}, 1}, +}`}, 1, gosec.NewConfig()}, // Bind to all networks indirectly through a parsing function {[]string{` package main @@ -134,7 +137,7 @@ func main() { log.Fatal(err) } defer l.Close() -}`}, 1}, +}`}, 1, gosec.NewConfig()}, {[]string{` package main import ( @@ -149,7 +152,7 @@ func main() { log.Fatal(err) } defer l.Close() -}`}, 1}, +}`}, 1, gosec.NewConfig()}, } // SampleCodeG103 find instances of unsafe blocks for auditing purposes SampleCodeG103 = []CodeSample{ @@ -171,7 +174,7 @@ func main() { addressHolder := uintptr(unsafe.Pointer(intPtr)) + unsafe.Sizeof(intArray[0]) intPtr = (*int)(unsafe.Pointer(addressHolder)) fmt.Printf("\nintPtr=%p, *intPtr=%d.\n\n", intPtr, *intPtr) -}`}, 3}} +}`}, 3, gosec.NewConfig()}} // SampleCodeG104 finds errors that aren't being handled SampleCodeG104 = []CodeSample{ @@ -184,7 +187,7 @@ func test() (int,error) { func main() { v, _ := test() fmt.Println(v) -}`}, 0}, {[]string{` +}`}, 0, gosec.NewConfig()}, {[]string{` package main import ( "io/ioutil" @@ -206,7 +209,7 @@ func main() { a() b() c() -}`}, 2}, {[]string{` +}`}, 2, gosec.NewConfig()}, {[]string{` package main import "fmt" func test() error { @@ -215,7 +218,7 @@ func test() error { func main() { e := test() fmt.Println(e) -}`}, 0}, {[]string{` +}`}, 0, gosec.NewConfig()}, {[]string{` // +build go1.10 package main @@ -229,7 +232,7 @@ func main() { }`, ` package main func dummy(){} -`}, 0}} +`}, 0, gosec.NewConfig()}} // SampleCodeG104Audit finds errors that aren't being handled in audit mode SampleCodeG104Audit = []CodeSample{ @@ -242,7 +245,7 @@ func test() (int,error) { func main() { v, _ := test() fmt.Println(v) -}`}, 1}, {[]string{` +}`}, 1, gosec.Config{gosec.Globals: map[gosec.GlobalOption]string{gosec.Audit: "enabled"}}}, {[]string{` package main import ( "io/ioutil" @@ -264,7 +267,7 @@ func main() { a() b() c() -}`}, 3}, {[]string{` +}`}, 3, gosec.Config{gosec.Globals: map[gosec.GlobalOption]string{gosec.Audit: "enabled"}}}, {[]string{` package main import "fmt" func test() error { @@ -273,7 +276,7 @@ func test() error { func main() { e := test() fmt.Println(e) -}`}, 0}, {[]string{` +}`}, 0, gosec.Config{gosec.Globals: map[gosec.GlobalOption]string{gosec.Audit: "enabled"}}}, {[]string{` // +build go1.10 package main @@ -287,7 +290,7 @@ func main() { }`, ` package main func dummy(){} -`}, 0}} +`}, 0, gosec.Config{gosec.Globals: map[gosec.GlobalOption]string{gosec.Audit: "enabled"}}}} // SampleCodeG105 - bignum overflow SampleCodeG105 = []CodeSample{{[]string{` package main @@ -303,7 +306,7 @@ func main() { m := new(big.Int) m = m.SetUint64(0) z = z.Exp(x, y, m) -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCodeG106 - ssh InsecureIgnoreHostKey SampleCodeG106 = []CodeSample{{[]string{` @@ -313,7 +316,7 @@ import ( ) func main() { _ = ssh.InsecureIgnoreHostKey() -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCodeG107 - SSRF via http requests with variable url SampleCodeG107 = []CodeSample{{[]string{` @@ -341,7 +344,7 @@ func main() { panic(err) } fmt.Printf("%s", body) -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` package main import ( @@ -355,7 +358,7 @@ func main() { fmt.Println(err) } fmt.Println(resp.Status) -}`}, 0}} +}`}, 0, gosec.NewConfig()}} // SampleCodeG201 - SQL injection via format string SampleCodeG201 = []CodeSample{ {[]string{` @@ -378,7 +381,7 @@ func main(){ panic(err) } defer rows.Close() -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` // Format string false positive, safe string spec. package main import ( @@ -398,7 +401,7 @@ func main(){ panic(err) } defer rows.Close() -}`}, 0}, {[]string{` +}`}, 0, gosec.NewConfig()}, {[]string{` // Format string false positive package main import ( @@ -415,7 +418,7 @@ func main(){ panic(err) } defer rows.Close() -}`}, 0}, {[]string{` +}`}, 0, gosec.NewConfig()}, {[]string{` // Format string false positive, quoted formatter argument. package main import ( @@ -436,7 +439,7 @@ func main(){ panic(err) } defer rows.Close() -}`}, 0}, {[]string{` +}`}, 0, gosec.NewConfig()}, {[]string{` // false positive package main import ( @@ -456,7 +459,7 @@ func main(){ panic(err) } defer rows.Close() -}`}, 0}, {[]string{` +}`}, 0, gosec.NewConfig()}, {[]string{` package main import ( "fmt" @@ -464,7 +467,7 @@ import ( func main(){ fmt.Sprintln() -}`}, 0}} +}`}, 0, gosec.NewConfig()}} // SampleCodeG202 - SQL query string building via string concatenation SampleCodeG202 = []CodeSample{ @@ -484,7 +487,7 @@ func main(){ panic(err) } defer rows.Close() -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` // false positive package main import ( @@ -501,7 +504,7 @@ func main(){ panic(err) } defer rows.Close() -}`}, 0}, {[]string{` +}`}, 0, gosec.NewConfig()}, {[]string{` package main import ( "database/sql" @@ -519,7 +522,7 @@ func main(){ } defer rows.Close() } -`}, 0}, {[]string{` +`}, 0, gosec.NewConfig()}, {[]string{` package main const gender = "M" `, ` @@ -540,7 +543,7 @@ func main(){ } defer rows.Close() } -`}, 0}} +`}, 0, gosec.NewConfig()}} // SampleCodeG203 - Template checks SampleCodeG203 = []CodeSample{ @@ -560,7 +563,7 @@ func main() { "Body": template.HTML(""), } t.Execute(os.Stdout, v) -}`}, 0}, {[]string{ +}`}, 0, gosec.NewConfig()}, {[]string{ ` // Using a variable to initialize could potentially be dangerous. Under the // current model this will likely produce some false positives. @@ -578,7 +581,7 @@ func main() { "Body": template.HTML(a), } t.Execute(os.Stdout, v) -}`}, 1}, {[]string{ +}`}, 1, gosec.NewConfig()}, {[]string{ ` package main import ( @@ -594,7 +597,7 @@ func main() { "Body": template.JS(a), } t.Execute(os.Stdout, v) -}`}, 1}, {[]string{ +}`}, 1, gosec.NewConfig()}, {[]string{ ` package main import ( @@ -610,7 +613,7 @@ func main() { "Body": template.URL(a), } t.Execute(os.Stdout, v) -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCodeG204 - Subprocess auditing SampleCodeG204 = []CodeSample{{[]string{` @@ -618,7 +621,7 @@ package main import "syscall" func main() { syscall.Exec("/bin/cat", []string{ "/etc/passwd" }, nil) -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` package main import ( "log" @@ -633,7 +636,7 @@ func main() { log.Printf("Waiting for command to finish...") err = cmd.Wait() log.Printf("Command finished with error: %v", err) -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` package main import ( "log" @@ -646,7 +649,7 @@ func main() { log.Fatal(err) } log.Printf("Command finished with error: %v", err) -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` package main import ( "log" @@ -663,7 +666,7 @@ func main() { log.Printf("Waiting for command to finish...") err = cmd.Wait() log.Printf("Command finished with error: %v", err) -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCodeG301 - mkdir permission check SampleCodeG301 = []CodeSample{{[]string{` @@ -673,7 +676,7 @@ func main() { os.Mkdir("/tmp/mydir", 0777) os.Mkdir("/tmp/mydir", 0600) os.MkdirAll("/tmp/mydir/mysubidr", 0775) -}`}, 2}} +}`}, 2, gosec.NewConfig()}} // SampleCodeG302 - file create / chmod permissions check SampleCodeG302 = []CodeSample{{[]string{` @@ -684,7 +687,7 @@ func main() { os.Chmod("/tmp/someotherfile", 0600) os.OpenFile("/tmp/thing", os.O_CREATE|os.O_WRONLY, 0666) os.OpenFile("/tmp/thing", os.O_CREATE|os.O_WRONLY, 0600) -}`}, 2}} +}`}, 2, gosec.NewConfig()}} // SampleCodeG303 - bad tempfile permissions & hardcoded shared path SampleCodeG303 = []CodeSample{{[]string{` @@ -697,7 +700,7 @@ func main() { file1, _ := os.Create("/tmp/demo1") defer file1.Close() ioutil.WriteFile("/tmp/demo2", []byte("This is some data"), 0644) -}`}, 2}} +}`}, 2, gosec.NewConfig()}} // SampleCodeG304 - potential file inclusion vulnerability SampleCodeG304 = []CodeSample{{[]string{` @@ -715,7 +718,7 @@ if err != nil { } log.Print(body) -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` package main import ( @@ -739,7 +742,7 @@ func main() { fmt.Fprintf(w, "%s", body) }) log.Fatal(http.ListenAndServe(":3000", nil)) -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` package main import ( @@ -755,7 +758,7 @@ import ( log.Printf("Error: %v\n", err) } log.Print(body) - }`}, 1}, {[]string{` + }`}, 1, gosec.NewConfig()}, {[]string{` package main import ( @@ -779,7 +782,7 @@ func main() { fmt.Printf("Error: %v\n", err) } fmt.Println(string(contents)) -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` package main import ( @@ -798,7 +801,7 @@ func main() { log.Printf("Error: %v\n", err) } log.Print(body) -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCodeG305 - File path traversal when extracting zip archives SampleCodeG305 = []CodeSample{{[]string{` @@ -846,7 +849,7 @@ func unzip(archive, target string) error { } return nil -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` package unzip import ( @@ -892,7 +895,7 @@ func unzip(archive, target string) error { } return nil -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCodeG401 - Use of weak crypto MD5 SampleCodeG401 = []CodeSample{ @@ -917,7 +920,7 @@ func main() { log.Fatal(err) } fmt.Printf("%x", h.Sum(nil)) -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCodeG401b - Use of weak crypto SHA1 SampleCodeG401b = []CodeSample{ @@ -942,7 +945,7 @@ func main() { log.Fatal(err) } fmt.Printf("%x", h.Sum(nil)) -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCodeG402 - TLS settings SampleCodeG402 = []CodeSample{{[]string{` @@ -963,7 +966,7 @@ func main() { if err != nil { fmt.Println(err) } -}`}, 1}, {[]string{ +}`}, 1, gosec.NewConfig()}, {[]string{ ` // Insecure minimum version package main @@ -981,7 +984,7 @@ func main() { if err != nil { fmt.Println(err) } -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` // Insecure max version package main import ( @@ -999,7 +1002,7 @@ func main() { fmt.Println(err) } } -`}, 1}, { +`}, 1, gosec.NewConfig()}, { []string{` // Insecure ciphersuite selection package main @@ -1020,7 +1023,7 @@ func main() { if err != nil { fmt.Println(err) } -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCodeG403 - weak key strength SampleCodeG403 = []CodeSample{ @@ -1038,7 +1041,7 @@ func main() { fmt.Println(err) } fmt.Println(pvk) -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCodeG404 - weak random number SampleCodeG404 = []CodeSample{ @@ -1048,13 +1051,13 @@ import "crypto/rand" func main() { good, _ := rand.Read(nil) println(good) -}`}, 0}, {[]string{` +}`}, 0, gosec.NewConfig()}, {[]string{` package main import "math/rand" func main() { bad := rand.Int() println(bad) -}`}, 1}, {[]string{` +}`}, 1, gosec.NewConfig()}, {[]string{` package main import ( "crypto/rand" @@ -1065,7 +1068,7 @@ func main() { println(good) i := mrand.Int31() println(i) -}`}, 0}} +}`}, 0, gosec.NewConfig()}} // SampleCodeG501 - Blacklisted import MD5 SampleCodeG501 = []CodeSample{ @@ -1080,7 +1083,7 @@ func main() { for _, arg := range os.Args { fmt.Printf("%x - %s\n", md5.Sum([]byte(arg)), arg) } -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCodeG502 - Blacklisted import DES SampleCodeG502 = []CodeSample{ @@ -1108,7 +1111,7 @@ func main() { stream := cipher.NewCFBEncrypter(block, iv) stream.XORKeyStream(ciphertext[des.BlockSize:], plaintext) fmt.Println("Secret message is: %s", hex.EncodeToString(ciphertext)) -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCodeG503 - Blacklisted import RC4 SampleCodeG503 = []CodeSample{{[]string{` @@ -1127,7 +1130,7 @@ func main() { ciphertext := make([]byte, len(plaintext)) cipher.XORKeyStream(ciphertext, plaintext) fmt.Println("Secret message is: %s", hex.EncodeToString(ciphertext)) -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCodeG504 - Blacklisted import CGI SampleCodeG504 = []CodeSample{{[]string{` @@ -1138,7 +1141,7 @@ import ( ) func main() { cgi.Serve(http.FileServer(http.Dir("/usr/share/doc"))) -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCodeG505 - Blacklisted import SHA1 SampleCodeG505 = []CodeSample{ {[]string{` @@ -1152,7 +1155,7 @@ func main() { for _, arg := range os.Args { fmt.Printf("%x - %s\n", sha1.Sum([]byte(arg)), arg) } -}`}, 1}} +}`}, 1, gosec.NewConfig()}} // SampleCode601 - Go build tags SampleCode601 = []CodeSample{{[]string{` // +build tag @@ -1160,5 +1163,5 @@ func main() { package main func main() { fmt.Println("no package imported error") -}`}, 1}} +}`}, 1, gosec.NewConfig()}} ) From 78a49491a842542b201605dda0994ba5deb873fb Mon Sep 17 00:00:00 2001 From: Cosmin Cojocar Date: Tue, 25 Jun 2019 11:14:27 +0200 Subject: [PATCH 2/5] Load rules on each code sample in order to reconfigure them Signed-off-by: Cosmin Cojocar --- analyzer.go | 1 + rules/rules_test.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/analyzer.go b/analyzer.go index 77e016ca67..5828761f1a 100644 --- a/analyzer.go +++ b/analyzer.go @@ -334,4 +334,5 @@ func (gosec *Analyzer) Reset() { gosec.context = &Context{} gosec.issues = make([]*Issue, 0, 16) gosec.stats = &Metrics{} + gosec.ruleset = NewRuleSet() } diff --git a/rules/rules_test.go b/rules/rules_test.go index 71ae26ff2f..29ed663dfe 100644 --- a/rules/rules_test.go +++ b/rules/rules_test.go @@ -28,10 +28,10 @@ var _ = Describe("gosec rules", func() { config = gosec.NewConfig() analyzer = gosec.NewAnalyzer(config, tests, logger) runner = func(rule string, samples []testutils.CodeSample) { - analyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, rule)).Builders()) for n, sample := range samples { analyzer.Reset() analyzer.SetConfig(sample.Config) + analyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, rule)).Builders()) pkg := testutils.NewTestPackage() defer pkg.Close() for i, code := range sample.Code { From f3445245a2b55e066be171dfa566999f796b40bf Mon Sep 17 00:00:00 2001 From: Cosmin Cojocar Date: Tue, 25 Jun 2019 11:15:11 +0200 Subject: [PATCH 3/5] Fix the whitelist on G104 rule and add a test Signed-off-by: Cosmin Cojocar --- rules/errors.go | 19 ++++++++++++++++--- testutils/source.go | 15 ++++++++++++++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/rules/errors.go b/rules/errors.go index c50f66a721..d2e98b530e 100644 --- a/rules/errors.go +++ b/rules/errors.go @@ -88,12 +88,15 @@ func NewNoErrorCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { whitelist.Add("io.PipeWriter", "CloseWithError") if configured, ok := conf["G104"]; ok { - if whitelisted, ok := configured.(map[string][]string); ok { - for key, val := range whitelisted { - whitelist.AddAll(key, val...) + if whitelisted, ok := configured.(map[string]interface{}); ok { + for pkg, funcs := range whitelisted { + if funcs, ok := funcs.([]interface{}); ok { + whitelist.AddAll(pkg, toStringSlice(funcs)...) + } } } } + return &noErrorCheck{ MetaData: gosec.MetaData{ ID: id, @@ -104,3 +107,13 @@ func NewNoErrorCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { whitelist: whitelist, }, []ast.Node{(*ast.AssignStmt)(nil), (*ast.ExprStmt)(nil)} } + +func toStringSlice(values []interface{}) []string { + result := []string{} + for _, value := range values { + if value, ok := value.(string); ok { + result = append(result, value) + } + } + return result +} diff --git a/testutils/source.go b/testutils/source.go index 260a37d4f7..181e383021 100644 --- a/testutils/source.go +++ b/testutils/source.go @@ -232,7 +232,20 @@ func main() { }`, ` package main func dummy(){} -`}, 0, gosec.NewConfig()}} +`}, 0, gosec.NewConfig()}, {[]string{` +package main +import ( + "io/ioutil" + "os" + "fmt" +) +func a() { + fmt.Println("a") + ioutil.WriteFile("foo.txt", []byte("bar"), os.ModeExclusive) +} +func main() { + a() +}`}, 0, gosec.Config{"G104": map[string]interface{}{"io/ioutil": []interface{}{"WriteFile"}}}}} // SampleCodeG104Audit finds errors that aren't being handled in audit mode SampleCodeG104Audit = []CodeSample{ From 141235719ba533003b373c29612b3dd86dfe0d2b Mon Sep 17 00:00:00 2001 From: Cosmin Cojocar Date: Tue, 25 Jun 2019 11:26:28 +0200 Subject: [PATCH 4/5] Add some documentation for G104 whitelist configuration Signed-off-by: Cosmin Cojocar Signed-off-by: Cosmin Cojocar --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 656daff017..72784ec37d 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,16 @@ A number of global settings can be provided in a configuration file as follows: # Run with a global configuration file $ gosec -conf config.json . ``` +Also some rules accept configuration. For instance on rule `G104`, it is possible to define packages along with a list +of functions which will be skipped when auditing the not checked errors: + +```JSON +{ + "G104": { + "io/ioutil": ["WriteFile"] + } +} +``` ### Excluding files From 63b44b6681b845cf64467ee4a91f79b2ab310cee Mon Sep 17 00:00:00 2001 From: Cosmin Cojocar Date: Tue, 25 Jun 2019 11:56:26 +0200 Subject: [PATCH 5/5] Add some more tests to make codecov happy Signed-off-by: Cosmin Cojocar --- analyzer.go | 5 +++++ analyzer_test.go | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/analyzer.go b/analyzer.go index 5828761f1a..80432550a8 100644 --- a/analyzer.go +++ b/analyzer.go @@ -97,6 +97,11 @@ func (gosec *Analyzer) SetConfig(conf Config) { gosec.config = conf } +// Config returns the current configuration +func (gosec *Analyzer) Config() Config { + return gosec.config +} + // LoadRules instantiates all the rules to be used when analyzing source // packages func (gosec *Analyzer) LoadRules(ruleDefinitions map[string]RuleBuilder) { diff --git a/analyzer_test.go b/analyzer_test.go index 945c108fa8..534bf01aae 100644 --- a/analyzer_test.go +++ b/analyzer_test.go @@ -416,6 +416,22 @@ var _ = Describe("Analyzer", func() { Expect(ferr[1].Err).Should(MatchRegexp(`error2`)) } }) + + It("should set the config", func() { + config := gosec.NewConfig() + config["test"] = "test" + analyzer.SetConfig(config) + found := analyzer.Config() + Expect(config).To(Equal(found)) + }) + + It("should reset the analyzer", func() { + analyzer.Reset() + issues, metrics, errors := analyzer.Report() + Expect(issues).To(BeEmpty()) + Expect(*metrics).To(Equal(gosec.Metrics{})) + Expect(errors).To(BeEmpty()) + }) }) Context("when appending errors", func() {