Refactor properly the package error parsing and cover all test cases

Signed-off-by: Cosmin Cojocar <cosmin.cojocar@gmx.ch>
This commit is contained in:
Cosmin Cojocar 2019-04-30 13:53:22 +02:00 committed by Cosmin Cojocar
parent 625718d294
commit aac9b00845
2 changed files with 179 additions and 56 deletions

View file

@ -111,7 +111,7 @@ func (gosec *Analyzer) Process(buildTags []string, packagePaths ...string) error
} }
for _, pkg := range pkgs { for _, pkg := range pkgs {
if pkg.Name != "" { if pkg.Name != "" {
err := gosec.parseErrors(pkg) err := gosec.ParseErrors(pkg)
if err != nil { if err != nil {
return fmt.Errorf("parsing errors in pkg %q: %v", pkg.Name, err) return fmt.Errorf("parsing errors in pkg %q: %v", pkg.Name, err)
} }
@ -185,39 +185,34 @@ func (gosec *Analyzer) check(pkg *packages.Package) {
} }
} }
func (gosec *Analyzer) parseErrors(pkg *packages.Package) error { // ParseErrors parses the errors from given package
func (gosec *Analyzer) ParseErrors(pkg *packages.Package) error {
if len(pkg.Errors) == 0 { if len(pkg.Errors) == 0 {
return nil return nil
} }
for _, pkgErr := range pkg.Errors { for _, pkgErr := range pkg.Errors {
// infoErr contains information about the error parts := strings.Split(pkgErr.Pos, ":")
// at index 0 is the file path file := parts[0]
// at index 1 is the line; index 2 is for column
// at index 3 is the actual error
infoErr := strings.Split(pkgErr.Error(), ":")
filePath := infoErr[0]
var err error var err error
var line, column int var line int
var errorMsg string if len(parts) > 1 {
if len(infoErr) > 3 { if line, err = strconv.Atoi(parts[1]); err != nil {
if line, err = strconv.Atoi(infoErr[1]); err != nil {
return fmt.Errorf("parsing line: %v", err) return fmt.Errorf("parsing line: %v", err)
} }
if column, err = strconv.Atoi(infoErr[2]); err != nil { }
var column int
if len(parts) > 2 {
if column, err = strconv.Atoi(parts[2]); err != nil {
return fmt.Errorf("parsing column: %v", err) return fmt.Errorf("parsing column: %v", err)
} }
errorMsg = strings.TrimSpace(infoErr[3])
} else if len(infoErr) > 1 {
errorMsg = strings.TrimSpace(infoErr[1])
} else {
return fmt.Errorf("cannot parse error %q", infoErr)
} }
newErr := NewError(line, column, errorMsg) msg := strings.TrimSpace(pkgErr.Msg)
if errSlice, ok := gosec.errors[filePath]; ok { newErr := NewError(line, column, msg)
gosec.errors[filePath] = append(errSlice, *newErr) if errSlice, ok := gosec.errors[file]; ok {
gosec.errors[file] = append(errSlice, *newErr)
} else { } else {
errSlice = []Error{} errSlice = []Error{}
gosec.errors[filePath] = append(errSlice, *newErr) gosec.errors[file] = append(errSlice, *newErr)
} }
} }
return nil return nil

View file

@ -8,6 +8,7 @@ import (
"github.com/securego/gosec" "github.com/securego/gosec"
"github.com/securego/gosec/rules" "github.com/securego/gosec/rules"
"golang.org/x/tools/go/packages"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -234,6 +235,7 @@ var _ = Describe("Analyzer", func() {
err = analyzer.Process(buildTags, pkg.Path) err = analyzer.Process(buildTags, pkg.Path)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
}) })
It("should report an error when the package is empty", func() { It("should report an error when the package is empty", func() {
analyzer.LoadRules(rules.Generate().Builders()) analyzer.LoadRules(rules.Generate().Builders())
pkg := testutils.NewTestPackage() pkg := testutils.NewTestPackage()
@ -241,7 +243,6 @@ var _ = Describe("Analyzer", func() {
err := analyzer.Process(buildTags, pkg.Path) err := analyzer.Process(buildTags, pkg.Path)
Expect(err).Should(HaveOccurred()) 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
@ -288,4 +289,131 @@ var _ = Describe("Analyzer", func() {
_, metrics, _ := customAnalyzer.Report() _, metrics, _ := customAnalyzer.Report()
Expect(metrics.NumFiles).To(Equal(3)) Expect(metrics.NumFiles).To(Equal(3))
}) })
})
Context("when parsing errors from a package", func() {
It("should return no error when the error list is empty", func() {
pkg := &packages.Package{}
err := analyzer.ParseErrors(pkg)
Expect(err).ShouldNot(HaveOccurred())
})
It("should properly parse the errors", func() {
pkg := &packages.Package{
Errors: []packages.Error{
packages.Error{
Pos: "file:1:2",
Msg: "build error",
},
},
}
err := analyzer.ParseErrors(pkg)
Expect(err).ShouldNot(HaveOccurred())
_, _, errors := analyzer.Report()
Expect(len(errors)).To(Equal(1))
for _, ferr := range errors {
Expect(len(ferr)).To(Equal(1))
Expect(ferr[0].Line).To(Equal(1))
Expect(ferr[0].Column).To(Equal(2))
Expect(ferr[0].Err).Should(MatchRegexp(`build error`))
}
})
It("should properly parse the errors without line and column", func() {
pkg := &packages.Package{
Errors: []packages.Error{
packages.Error{
Pos: "file",
Msg: "build error",
},
},
}
err := analyzer.ParseErrors(pkg)
Expect(err).ShouldNot(HaveOccurred())
_, _, errors := analyzer.Report()
Expect(len(errors)).To(Equal(1))
for _, ferr := range errors {
Expect(len(ferr)).To(Equal(1))
Expect(ferr[0].Line).To(Equal(0))
Expect(ferr[0].Column).To(Equal(0))
Expect(ferr[0].Err).Should(MatchRegexp(`build error`))
}
})
It("should properly parse the errors without column", func() {
pkg := &packages.Package{
Errors: []packages.Error{
packages.Error{
Pos: "file",
Msg: "build error",
},
},
}
err := analyzer.ParseErrors(pkg)
Expect(err).ShouldNot(HaveOccurred())
_, _, errors := analyzer.Report()
Expect(len(errors)).To(Equal(1))
for _, ferr := range errors {
Expect(len(ferr)).To(Equal(1))
Expect(ferr[0].Line).To(Equal(0))
Expect(ferr[0].Column).To(Equal(0))
Expect(ferr[0].Err).Should(MatchRegexp(`build error`))
}
})
It("should return error when line cannot be parsed", func() {
pkg := &packages.Package{
Errors: []packages.Error{
packages.Error{
Pos: "file:line",
Msg: "build error",
},
},
}
err := analyzer.ParseErrors(pkg)
Expect(err).Should(HaveOccurred())
})
It("should return error when column cannot be parsed", func() {
pkg := &packages.Package{
Errors: []packages.Error{
packages.Error{
Pos: "file:1:column",
Msg: "build error",
},
},
}
err := analyzer.ParseErrors(pkg)
Expect(err).Should(HaveOccurred())
})
It("should append error to the same file", func() {
pkg := &packages.Package{
Errors: []packages.Error{
packages.Error{
Pos: "file:1:2",
Msg: "error1",
},
packages.Error{
Pos: "file:3:4",
Msg: "error2",
},
},
}
err := analyzer.ParseErrors(pkg)
Expect(err).ShouldNot(HaveOccurred())
_, _, errors := analyzer.Report()
Expect(len(errors)).To(Equal(1))
for _, ferr := range errors {
Expect(len(ferr)).To(Equal(2))
Expect(ferr[0].Line).To(Equal(1))
Expect(ferr[0].Column).To(Equal(2))
Expect(ferr[0].Err).Should(MatchRegexp(`error1`))
Expect(ferr[1].Line).To(Equal(3))
Expect(ferr[1].Column).To(Equal(4))
Expect(ferr[1].Err).Should(MatchRegexp(`error2`))
}
})
})
}) })