diff --git a/cmd/gosec/main.go b/cmd/gosec/main.go index d740aa0..83e7692 100644 --- a/cmd/gosec/main.go +++ b/cmd/gosec/main.go @@ -318,7 +318,11 @@ func main() { os.Exit(0) } - rootPath := packages[0] + rootPath, err := gosec.RootPath(flag.Args()[0]) + if err != nil { + logger.Fatalf("Failed to get the root path of the project: %s", err) + } + // Create output report if err := saveOutput(*flagOutput, *flagFormat, rootPath, issues, metrics, errors); err != nil { logger.Fatal(err) diff --git a/helpers.go b/helpers.go index b2e5176..3fddae3 100644 --- a/helpers.go +++ b/helpers.go @@ -387,3 +387,11 @@ func PackagePaths(root string, exclude *regexp.Regexp) ([]string, error) { } return result, nil } + +// RootPath returns the absolute root path of a scan +func RootPath(root string) (string, error) { + if strings.HasSuffix(root, "...") { + root = root[0 : len(root)-3] + } + return filepath.Abs(root) +} diff --git a/helpers_test.go b/helpers_test.go index 636ef6d..f797203 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -3,6 +3,7 @@ package gosec_test import ( "io/ioutil" "os" + "path/filepath" "regexp" . "github.com/onsi/ginkgo" @@ -53,4 +54,23 @@ var _ = Describe("Helpers", func() { Expect(paths).Should(BeEmpty()) }) }) + + Context("when getting the root path", func() { + It("should return the absolute path from relative path", func() { + base := "test" + cwd, err := os.Getwd() + Expect(err).ShouldNot(HaveOccurred()) + root, err := gosec.RootPath(base) + Expect(err).ShouldNot(HaveOccurred()) + Expect(root).Should(Equal(filepath.Join(cwd, base))) + }) + It("should retrun the absolute path from ellipsis path", func() { + base := "test" + cwd, err := os.Getwd() + Expect(err).ShouldNot(HaveOccurred()) + root, err := gosec.RootPath(filepath.Join(base, "...")) + Expect(err).ShouldNot(HaveOccurred()) + Expect(root).Should(Equal(filepath.Join(cwd, base))) + }) + }) }) diff --git a/output/formatter.go b/output/formatter.go index e29664c..a63b51f 100644 --- a/output/formatter.go +++ b/output/formatter.go @@ -105,19 +105,32 @@ func CreateReport(w io.Writer, format, rootPath string, issues []*gosec.Issue, m } func reportSonarqube(rootPath string, w io.Writer, data *reportInfo) error { + si, err := convertToSonarIssues(rootPath, data) + if err != nil { + return err + } + raw, err := json.MarshalIndent(si, "", "\t") + if err != nil { + return err + } + _, err = w.Write(raw) + return err +} + +func convertToSonarIssues(rootPath string, data *reportInfo) (sonarIssues, error) { var si sonarIssues for _, issue := range data.Issues { lines := strings.Split(issue.Line, "-") startLine, err := strconv.Atoi(lines[0]) if err != nil { - return err + return si, err } endLine := startLine if len(lines) > 1 { endLine, err = strconv.Atoi(lines[1]) if err != nil { - return err + return si, err } } s := sonarIssue{ @@ -134,12 +147,7 @@ func reportSonarqube(rootPath string, w io.Writer, data *reportInfo) error { } si.SonarIssues = append(si.SonarIssues, s) } - raw, err := json.MarshalIndent(si, "", "\t") - if err != nil { - return err - } - _, err = w.Write(raw) - return err + return si, nil } func reportJSON(w io.Writer, data *reportInfo) error { diff --git a/output/formatter_suite_test.go b/output/formatter_suite_test.go new file mode 100644 index 0000000..62b1404 --- /dev/null +++ b/output/formatter_suite_test.go @@ -0,0 +1,13 @@ +package output + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestRules(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Formatters Suite") +} diff --git a/output/formatter_test.go b/output/formatter_test.go new file mode 100644 index 0000000..1d016f6 --- /dev/null +++ b/output/formatter_test.go @@ -0,0 +1,110 @@ +package output + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/securego/gosec" +) + +var _ = Describe("Formatter", func() { + BeforeEach(func() { + }) + Context("when converting to Sonarqube issues", func() { + It("it should parse the report info", func() { + data := &reportInfo{ + Errors: map[string][]gosec.Error{}, + Issues: []*gosec.Issue{ + &gosec.Issue{ + Severity: 2, + Confidence: 0, + RuleID: "test", + What: "test", + File: "/home/src/project/test.go", + Code: "", + Line: "1-2", + }, + }, + Stats: &gosec.Metrics{ + NumFiles: 0, + NumLines: 0, + NumNosec: 0, + NumFound: 0, + }, + } + want := sonarIssues{ + SonarIssues: []sonarIssue{ + { + EngineID: "gosec", + RuleID: "test", + PrimaryLocation: location{ + Message: "test", + FilePath: "test.go", + TextRange: textRange{ + StartLine: 1, + EndLine: 2, + }, + }, + Type: "VULNERABILITY", + Severity: "BLOCKER", + EffortMinutes: SonarqubeEffortMinutes, + }, + }, + } + + rootPath := "/home/src/project" + + issues, err := convertToSonarIssues(rootPath, data) + Expect(err).ShouldNot(HaveOccurred()) + Expect(issues).To(Equal(want)) + }) + + It("it should parse the report info with files in subfolders", func() { + data := &reportInfo{ + Errors: map[string][]gosec.Error{}, + Issues: []*gosec.Issue{ + &gosec.Issue{ + Severity: 2, + Confidence: 0, + RuleID: "test", + What: "test", + File: "/home/src/project/subfolder/test.go", + Code: "", + Line: "1-2", + }, + }, + Stats: &gosec.Metrics{ + NumFiles: 0, + NumLines: 0, + NumNosec: 0, + NumFound: 0, + }, + } + want := sonarIssues{ + SonarIssues: []sonarIssue{ + { + EngineID: "gosec", + RuleID: "test", + PrimaryLocation: location{ + Message: "test", + FilePath: "subfolder/test.go", + TextRange: textRange{ + StartLine: 1, + EndLine: 2, + }, + }, + Type: "VULNERABILITY", + Severity: "BLOCKER", + EffortMinutes: SonarqubeEffortMinutes, + }, + }, + } + + rootPath := "/home/src/project" + + issues, err := convertToSonarIssues(rootPath, data) + Expect(err).ShouldNot(HaveOccurred()) + Expect(issues).To(Equal(want)) + }) + }) +})