2018-07-19 17:42:25 +01:00
|
|
|
package gosec_test
|
2017-07-19 22:17:00 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
|
2018-07-19 17:42:25 +01:00
|
|
|
"github.com/securego/gosec"
|
|
|
|
"github.com/securego/gosec/rules"
|
2017-07-19 22:17:00 +01:00
|
|
|
|
|
|
|
. "github.com/onsi/ginkgo"
|
|
|
|
. "github.com/onsi/gomega"
|
2018-07-19 17:42:25 +01:00
|
|
|
"github.com/securego/gosec/testutils"
|
2017-07-19 22:17:00 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
var _ = Describe("Analyzer", func() {
|
|
|
|
|
|
|
|
var (
|
2018-07-19 17:42:25 +01:00
|
|
|
analyzer *gosec.Analyzer
|
2018-04-20 00:45:04 +01:00
|
|
|
logger *log.Logger
|
|
|
|
buildTags []string
|
2019-04-28 18:33:50 +01:00
|
|
|
tests bool
|
2017-07-19 22:17:00 +01:00
|
|
|
)
|
|
|
|
BeforeEach(func() {
|
2018-01-29 23:32:04 +00:00
|
|
|
logger, _ = testutils.NewLogger()
|
2019-04-28 18:33:50 +01:00
|
|
|
analyzer = gosec.NewAnalyzer(nil, tests, logger)
|
2017-07-19 22:17:00 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
Context("when processing a package", func() {
|
|
|
|
|
|
|
|
It("should return an error if the package contains no Go files", func() {
|
2017-10-05 22:32:03 +01:00
|
|
|
analyzer.LoadRules(rules.Generate().Builders())
|
2017-07-19 22:17:00 +01:00
|
|
|
dir, err := ioutil.TempDir("", "empty")
|
|
|
|
defer os.RemoveAll(dir)
|
|
|
|
Expect(err).ShouldNot(HaveOccurred())
|
2018-04-20 00:45:04 +01:00
|
|
|
err = analyzer.Process(buildTags, dir)
|
2017-07-19 22:17:00 +01:00
|
|
|
Expect(err).Should(HaveOccurred())
|
|
|
|
Expect(err.Error()).Should(MatchRegexp("no buildable Go source files"))
|
|
|
|
})
|
|
|
|
|
|
|
|
It("should return an error if the package fails to build", func() {
|
2017-10-05 22:32:03 +01:00
|
|
|
analyzer.LoadRules(rules.Generate().Builders())
|
2017-07-19 22:17:00 +01:00
|
|
|
pkg := testutils.NewTestPackage()
|
|
|
|
defer pkg.Close()
|
|
|
|
pkg.AddFile("wonky.go", `func main(){ println("forgot the package")}`)
|
|
|
|
pkg.Build()
|
|
|
|
|
2018-04-20 00:45:04 +01:00
|
|
|
err := analyzer.Process(buildTags, pkg.Path)
|
2017-07-19 22:17:00 +01:00
|
|
|
Expect(err).Should(HaveOccurred())
|
|
|
|
Expect(err.Error()).Should(MatchRegexp(`expected 'package'`))
|
|
|
|
|
|
|
|
})
|
|
|
|
|
2018-10-11 13:45:31 +01:00
|
|
|
It("should be able to analyze multiple Go files", func() {
|
2017-10-05 22:32:03 +01:00
|
|
|
analyzer.LoadRules(rules.Generate().Builders())
|
2017-12-14 00:04:22 +00:00
|
|
|
pkg := testutils.NewTestPackage()
|
|
|
|
defer pkg.Close()
|
|
|
|
pkg.AddFile("foo.go", `
|
|
|
|
package main
|
|
|
|
func main(){
|
|
|
|
bar()
|
|
|
|
}`)
|
|
|
|
pkg.AddFile("bar.go", `
|
|
|
|
package main
|
|
|
|
func bar(){
|
|
|
|
println("package has two files!")
|
|
|
|
}`)
|
|
|
|
pkg.Build()
|
2018-04-20 00:45:04 +01:00
|
|
|
err := analyzer.Process(buildTags, pkg.Path)
|
2017-12-14 00:04:22 +00:00
|
|
|
Expect(err).ShouldNot(HaveOccurred())
|
2019-02-26 22:24:06 +00:00
|
|
|
_, metrics, _ := analyzer.Report()
|
2017-12-14 00:04:22 +00:00
|
|
|
Expect(metrics.NumFiles).To(Equal(2))
|
2018-01-07 23:02:33 +00:00
|
|
|
})
|
|
|
|
|
2018-10-11 13:45:31 +01:00
|
|
|
It("should be able to analyze multiple Go packages", func() {
|
2017-10-05 22:32:03 +01:00
|
|
|
analyzer.LoadRules(rules.Generate().Builders())
|
2018-01-07 23:02:33 +00:00
|
|
|
pkg1 := testutils.NewTestPackage()
|
|
|
|
pkg2 := testutils.NewTestPackage()
|
|
|
|
defer pkg1.Close()
|
|
|
|
defer pkg2.Close()
|
|
|
|
pkg1.AddFile("foo.go", `
|
|
|
|
package main
|
|
|
|
func main(){
|
|
|
|
}`)
|
|
|
|
pkg2.AddFile("bar.go", `
|
|
|
|
package main
|
|
|
|
func bar(){
|
|
|
|
}`)
|
|
|
|
pkg1.Build()
|
|
|
|
pkg2.Build()
|
2018-04-20 00:45:04 +01:00
|
|
|
err := analyzer.Process(buildTags, pkg1.Path, pkg2.Path)
|
2018-01-07 23:02:33 +00:00
|
|
|
Expect(err).ShouldNot(HaveOccurred())
|
2019-02-26 22:24:06 +00:00
|
|
|
_, metrics, _ := analyzer.Report()
|
2018-01-07 23:02:33 +00:00
|
|
|
Expect(metrics.NumFiles).To(Equal(2))
|
2017-12-14 00:04:22 +00:00
|
|
|
})
|
|
|
|
|
2017-07-19 22:17:00 +01:00
|
|
|
It("should find errors when nosec is not in use", func() {
|
|
|
|
|
|
|
|
// Rule for MD5 weak crypto usage
|
|
|
|
sample := testutils.SampleCodeG401[0]
|
2018-09-28 09:42:25 +01:00
|
|
|
source := sample.Code[0]
|
2017-10-05 22:32:03 +01:00
|
|
|
analyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
2017-07-19 22:17:00 +01:00
|
|
|
|
|
|
|
controlPackage := testutils.NewTestPackage()
|
|
|
|
defer controlPackage.Close()
|
|
|
|
controlPackage.AddFile("md5.go", source)
|
|
|
|
controlPackage.Build()
|
2018-04-20 00:45:04 +01:00
|
|
|
analyzer.Process(buildTags, controlPackage.Path)
|
2019-02-26 22:24:06 +00:00
|
|
|
controlIssues, _, _ := analyzer.Report()
|
2017-07-19 22:17:00 +01:00
|
|
|
Expect(controlIssues).Should(HaveLen(sample.Errors))
|
|
|
|
|
|
|
|
})
|
|
|
|
|
2019-02-26 22:24:06 +00:00
|
|
|
It("should report for Golang errors and invalid files", func() {
|
|
|
|
analyzer.LoadRules(rules.Generate().Builders())
|
|
|
|
pkg := testutils.NewTestPackage()
|
|
|
|
defer pkg.Close()
|
|
|
|
pkg.AddFile("foo.go", `
|
|
|
|
package main
|
|
|
|
func main()
|
|
|
|
}`)
|
|
|
|
pkg.Build()
|
|
|
|
err := analyzer.Process(buildTags, pkg.Path)
|
|
|
|
Expect(err).ShouldNot(HaveOccurred())
|
|
|
|
_, _, golangErrors := analyzer.Report()
|
|
|
|
keys := make([]string, len(golangErrors))
|
|
|
|
i := 0
|
|
|
|
for key := range golangErrors {
|
|
|
|
keys[i] = key
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
fileErr := golangErrors[keys[0]]
|
|
|
|
Expect(len(fileErr)).To(Equal(1))
|
|
|
|
Expect(fileErr[0].Line).To(Equal(4))
|
|
|
|
Expect(fileErr[0].Column).To(Equal(5))
|
|
|
|
Expect(fileErr[0].Err).Should(MatchRegexp(`expected declaration, found '}'`))
|
|
|
|
})
|
|
|
|
|
2017-07-19 22:17:00 +01:00
|
|
|
It("should not report errors when a nosec comment is present", func() {
|
|
|
|
// Rule for MD5 weak crypto usage
|
|
|
|
sample := testutils.SampleCodeG401[0]
|
2018-09-28 09:42:25 +01:00
|
|
|
source := sample.Code[0]
|
2017-10-05 22:32:03 +01:00
|
|
|
analyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
2017-07-19 22:17:00 +01:00
|
|
|
|
|
|
|
nosecPackage := testutils.NewTestPackage()
|
|
|
|
defer nosecPackage.Close()
|
|
|
|
nosecSource := strings.Replace(source, "h := md5.New()", "h := md5.New() // #nosec", 1)
|
|
|
|
nosecPackage.AddFile("md5.go", nosecSource)
|
|
|
|
nosecPackage.Build()
|
|
|
|
|
2018-04-20 00:45:04 +01:00
|
|
|
analyzer.Process(buildTags, nosecPackage.Path)
|
2019-02-26 22:24:06 +00:00
|
|
|
nosecIssues, _, _ := analyzer.Report()
|
2017-07-19 22:17:00 +01:00
|
|
|
Expect(nosecIssues).Should(BeEmpty())
|
|
|
|
})
|
2017-10-05 22:32:03 +01:00
|
|
|
|
|
|
|
It("should not report errors when an exclude comment is present for the correct rule", func() {
|
|
|
|
// Rule for MD5 weak crypto usage
|
|
|
|
sample := testutils.SampleCodeG401[0]
|
2018-09-28 09:42:25 +01:00
|
|
|
source := sample.Code[0]
|
2017-10-05 22:32:03 +01:00
|
|
|
analyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
|
|
|
|
|
|
|
nosecPackage := testutils.NewTestPackage()
|
|
|
|
defer nosecPackage.Close()
|
2018-03-08 19:01:00 +00:00
|
|
|
nosecSource := strings.Replace(source, "h := md5.New()", "h := md5.New() // #nosec G401", 1)
|
2017-10-05 22:32:03 +01:00
|
|
|
nosecPackage.AddFile("md5.go", nosecSource)
|
|
|
|
nosecPackage.Build()
|
|
|
|
|
2018-04-20 00:45:04 +01:00
|
|
|
analyzer.Process(buildTags, nosecPackage.Path)
|
2019-02-26 22:24:06 +00:00
|
|
|
nosecIssues, _, _ := analyzer.Report()
|
2017-10-05 22:32:03 +01:00
|
|
|
Expect(nosecIssues).Should(BeEmpty())
|
|
|
|
})
|
|
|
|
|
|
|
|
It("should report errors when an exclude comment is present for a different rule", func() {
|
|
|
|
// Rule for MD5 weak crypto usage
|
|
|
|
sample := testutils.SampleCodeG401[0]
|
2018-09-28 09:42:25 +01:00
|
|
|
source := sample.Code[0]
|
2017-10-05 22:32:03 +01:00
|
|
|
analyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
|
|
|
|
|
|
|
nosecPackage := testutils.NewTestPackage()
|
|
|
|
defer nosecPackage.Close()
|
2018-03-08 19:01:00 +00:00
|
|
|
nosecSource := strings.Replace(source, "h := md5.New()", "h := md5.New() // #nosec G301", 1)
|
2017-10-05 22:32:03 +01:00
|
|
|
nosecPackage.AddFile("md5.go", nosecSource)
|
|
|
|
nosecPackage.Build()
|
|
|
|
|
2018-04-20 00:45:04 +01:00
|
|
|
analyzer.Process(buildTags, nosecPackage.Path)
|
2019-02-26 22:24:06 +00:00
|
|
|
nosecIssues, _, _ := analyzer.Report()
|
2017-10-05 22:32:03 +01:00
|
|
|
Expect(nosecIssues).Should(HaveLen(sample.Errors))
|
|
|
|
})
|
|
|
|
|
|
|
|
It("should not report errors when an exclude comment is present for multiple rules, including the correct rule", func() {
|
|
|
|
// Rule for MD5 weak crypto usage
|
|
|
|
sample := testutils.SampleCodeG401[0]
|
2018-09-28 09:42:25 +01:00
|
|
|
source := sample.Code[0]
|
2017-10-05 22:32:03 +01:00
|
|
|
analyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
|
|
|
|
|
|
|
nosecPackage := testutils.NewTestPackage()
|
|
|
|
defer nosecPackage.Close()
|
2018-03-08 19:01:00 +00:00
|
|
|
nosecSource := strings.Replace(source, "h := md5.New()", "h := md5.New() // #nosec G301 G401", 1)
|
2017-10-05 22:32:03 +01:00
|
|
|
nosecPackage.AddFile("md5.go", nosecSource)
|
|
|
|
nosecPackage.Build()
|
|
|
|
|
2018-04-20 00:45:04 +01:00
|
|
|
analyzer.Process(buildTags, nosecPackage.Path)
|
2019-02-26 22:24:06 +00:00
|
|
|
nosecIssues, _, _ := analyzer.Report()
|
2017-10-05 22:32:03 +01:00
|
|
|
Expect(nosecIssues).Should(BeEmpty())
|
|
|
|
})
|
2018-04-20 00:45:04 +01:00
|
|
|
|
|
|
|
It("should pass the build tags", func() {
|
|
|
|
sample := testutils.SampleCode601[0]
|
2018-09-28 09:42:25 +01:00
|
|
|
source := sample.Code[0]
|
2018-04-20 00:45:04 +01:00
|
|
|
analyzer.LoadRules(rules.Generate().Builders())
|
|
|
|
pkg := testutils.NewTestPackage()
|
|
|
|
defer pkg.Close()
|
|
|
|
pkg.AddFile("tags.go", source)
|
|
|
|
|
|
|
|
buildTags = append(buildTags, "test")
|
|
|
|
err := analyzer.Process(buildTags, pkg.Path)
|
|
|
|
Expect(err).Should(HaveOccurred())
|
|
|
|
})
|
2017-07-19 22:17:00 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
It("should be possible to overwrite nosec comments, and report issues", func() {
|
|
|
|
// Rule for MD5 weak crypto usage
|
|
|
|
sample := testutils.SampleCodeG401[0]
|
2018-09-28 09:42:25 +01:00
|
|
|
source := sample.Code[0]
|
2017-07-19 22:17:00 +01:00
|
|
|
|
|
|
|
// overwrite nosec option
|
2018-07-19 17:42:25 +01:00
|
|
|
nosecIgnoreConfig := gosec.NewConfig()
|
2019-01-14 11:37:40 +00:00
|
|
|
nosecIgnoreConfig.SetGlobal(gosec.Nosec, "true")
|
2019-04-28 18:33:50 +01:00
|
|
|
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, logger)
|
2017-10-05 22:32:03 +01:00
|
|
|
customAnalyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
2017-07-19 22:17:00 +01:00
|
|
|
|
|
|
|
nosecPackage := testutils.NewTestPackage()
|
|
|
|
defer nosecPackage.Close()
|
|
|
|
nosecSource := strings.Replace(source, "h := md5.New()", "h := md5.New() // #nosec", 1)
|
|
|
|
nosecPackage.AddFile("md5.go", nosecSource)
|
|
|
|
nosecPackage.Build()
|
|
|
|
|
2018-04-20 00:45:04 +01:00
|
|
|
customAnalyzer.Process(buildTags, nosecPackage.Path)
|
2019-02-26 22:24:06 +00:00
|
|
|
nosecIssues, _, _ := customAnalyzer.Report()
|
2017-07-19 22:17:00 +01:00
|
|
|
Expect(nosecIssues).Should(HaveLen(sample.Errors))
|
|
|
|
|
|
|
|
})
|
|
|
|
})
|