Append the package load errors to analyser's errors

Signed-off-by: Cosmin Cojocar <cosmin.cojocar@gmx.ch>
This commit is contained in:
Cosmin Cojocar 2019-04-30 16:57:32 +02:00 committed by Cosmin Cojocar
parent aac9b00845
commit 3e69a8c8a2
3 changed files with 68 additions and 24 deletions

View file

@ -107,7 +107,7 @@ func (gosec *Analyzer) Process(buildTags []string, packagePaths ...string) error
for _, pkgPath := range packagePaths { for _, pkgPath := range packagePaths {
pkgs, err := gosec.load(pkgPath, config) pkgs, err := gosec.load(pkgPath, config)
if err != nil { if err != nil {
return fmt.Errorf("loading pkg dir %q: %v", pkgPath, err) gosec.AppendError(pkgPath, err)
} }
for _, pkg := range pkgs { for _, pkg := range pkgs {
if pkg.Name != "" { if pkg.Name != "" {
@ -124,10 +124,14 @@ func (gosec *Analyzer) Process(buildTags []string, packagePaths ...string) error
} }
func (gosec *Analyzer) pkgConfig(buildTags []string) *packages.Config { func (gosec *Analyzer) pkgConfig(buildTags []string) *packages.Config {
flags := []string{}
if len(buildTags) > 0 {
tagsFlag := "-tags=" + strings.Join(buildTags, " ") tagsFlag := "-tags=" + strings.Join(buildTags, " ")
flags = append(flags, tagsFlag)
}
return &packages.Config{ return &packages.Config{
Mode: packages.LoadSyntax, Mode: packages.LoadSyntax,
BuildFlags: []string{tagsFlag}, BuildFlags: flags,
Tests: gosec.tests, Tests: gosec.tests,
} }
} }
@ -142,7 +146,7 @@ func (gosec *Analyzer) load(pkgPath string, conf *packages.Config) ([]*packages.
gosec.logger.Println("Import directory:", abspath) gosec.logger.Println("Import directory:", abspath)
basePackage, err := build.Default.ImportDir(pkgPath, build.ImportComment) basePackage, err := build.Default.ImportDir(pkgPath, build.ImportComment)
if err != nil { if err != nil {
return []*packages.Package{}, err return []*packages.Package{}, fmt.Errorf("importing dir %q: %v", pkgPath, err)
} }
var packageFiles []string var packageFiles []string
@ -161,7 +165,7 @@ func (gosec *Analyzer) load(pkgPath string, conf *packages.Config) ([]*packages.
pkgs, err := packages.Load(conf, packageFiles...) pkgs, err := packages.Load(conf, packageFiles...)
if err != nil { if err != nil {
return []*packages.Package{}, err return []*packages.Package{}, fmt.Errorf("loading files from package %q: %v", pkgPath, err)
} }
return pkgs, nil return pkgs, nil
} }
@ -218,6 +222,22 @@ func (gosec *Analyzer) ParseErrors(pkg *packages.Package) error {
return nil return nil
} }
// AppendError appends an error to the file errors
func (gosec *Analyzer) AppendError(file string, err error) {
// Do not report the error for empty packages (e.g. files excluded from build with a tag
r := regexp.MustCompile(`no buildable Go source files in`)
if r.MatchString(err.Error()) {
return
}
errors := []Error{}
if ferrs, ok := gosec.errors[file]; ok {
errors = ferrs
}
ferr := NewError(0, 0, err.Error())
errors = append(errors, *ferr)
gosec.errors[file] = errors
}
// ignore a node (and sub-tree) if it is tagged with a "#nosec" comment // ignore a node (and sub-tree) if it is tagged with a "#nosec" comment
func (gosec *Analyzer) ignore(n ast.Node) ([]string, bool) { func (gosec *Analyzer) ignore(n ast.Node) ([]string, bool) {
if groups, ok := gosec.context.Comments[n]; ok && !gosec.ignoreNosec { if groups, ok := gosec.context.Comments[n]; ok && !gosec.ignoreNosec {

View file

@ -1,6 +1,7 @@
package gosec_test package gosec_test
import ( import (
"errors"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
@ -30,17 +31,18 @@ var _ = Describe("Analyzer", func() {
Context("when processing a package", func() { Context("when processing a package", func() {
It("should return an error if the package contains no Go files", func() { It("should not report an error if the package contains no Go files", func() {
analyzer.LoadRules(rules.Generate().Builders()) analyzer.LoadRules(rules.Generate().Builders())
dir, err := ioutil.TempDir("", "empty") dir, err := ioutil.TempDir("", "empty")
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = analyzer.Process(buildTags, dir) err = analyzer.Process(buildTags, dir)
Expect(err).Should(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(err.Error()).Should(MatchRegexp("no buildable Go source files")) _, _, errors := analyzer.Report()
Expect(len(errors)).To(Equal(0))
}) })
It("should return an error if the package fails to build", func() { It("should report an error if the package fails to build", func() {
analyzer.LoadRules(rules.Generate().Builders()) analyzer.LoadRules(rules.Generate().Builders())
pkg := testutils.NewTestPackage() pkg := testutils.NewTestPackage()
defer pkg.Close() defer pkg.Close()
@ -48,9 +50,12 @@ var _ = Describe("Analyzer", func() {
err := pkg.Build() err := pkg.Build()
Expect(err).Should(HaveOccurred()) Expect(err).Should(HaveOccurred())
err = analyzer.Process(buildTags, pkg.Path) err = analyzer.Process(buildTags, pkg.Path)
Expect(err).Should(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(err.Error()).Should(MatchRegexp(`expected 'package'`)) _, _, errors := analyzer.Report()
Expect(len(errors)).To(Equal(1))
for _, ferr := range errors {
Expect(len(ferr)).To(Equal(1))
}
}) })
It("should be able to analyze multiple Go files", func() { It("should be able to analyze multiple Go files", func() {
@ -216,9 +221,9 @@ var _ = Describe("Analyzer", func() {
pkg := testutils.NewTestPackage() pkg := testutils.NewTestPackage()
defer pkg.Close() defer pkg.Close()
pkg.AddFile("tags.go", source) pkg.AddFile("tags.go", source)
buildTags = append(buildTags, "test") tags := []string{"tag"}
err := analyzer.Process(buildTags, pkg.Path) err := analyzer.Process(tags, pkg.Path)
Expect(err).Should(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
}) })
It("should process an empty package with test file", func() { It("should process an empty package with test file", func() {
@ -236,14 +241,6 @@ var _ = Describe("Analyzer", func() {
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
}) })
It("should report an error when the package is empty", func() {
analyzer.LoadRules(rules.Generate().Builders())
pkg := testutils.NewTestPackage()
defer pkg.Close()
err := analyzer.Process(buildTags, pkg.Path)
Expect(err).Should(HaveOccurred())
})
It("should be possible to overwrite nosec comments, and report issues", func() { It("should be possible to overwrite nosec comments, and report issues", func() {
// Rule for MD5 weak crypto usage // Rule for MD5 weak crypto usage
sample := testutils.SampleCodeG401[0] sample := testutils.SampleCodeG401[0]
@ -416,4 +413,31 @@ var _ = Describe("Analyzer", func() {
} }
}) })
}) })
Context("when appending errors", func() {
It("should skip error for non-buildable packages", func() {
analyzer.AppendError("test", errors.New(`loading file from package "pkg/test": no buildable Go source files in pkg/test`))
_, _, errors := analyzer.Report()
Expect(len(errors)).To(Equal(0))
})
It("should add a new error", func() {
pkg := &packages.Package{
Errors: []packages.Error{
packages.Error{
Pos: "file:1:2",
Msg: "build error",
},
},
}
err := analyzer.ParseErrors(pkg)
Expect(err).ShouldNot(HaveOccurred())
analyzer.AppendError("file", errors.New("file build error"))
_, _, errors := analyzer.Report()
Expect(len(errors)).To(Equal(1))
for _, ferr := range errors {
Expect(len(ferr)).To(Equal(2))
}
})
})
}) })

View file

@ -1135,7 +1135,7 @@ func main() {
}`}, 1}} }`}, 1}}
// SampleCode601 - Go build tags // SampleCode601 - Go build tags
SampleCode601 = []CodeSample{{[]string{` SampleCode601 = []CodeSample{{[]string{`
// +build test // +build tag
package main package main
func main() { func main() {