mirror of
https://github.com/securego/gosec.git
synced 2024-12-25 12:05:52 +00:00
Support multiple root paths when generating the Sonarqube report
Signed-off-by: Cosmin Cojocar <cosmin.cojocar@gmx.ch>
This commit is contained in:
parent
46e55b908d
commit
020479a832
3 changed files with 134 additions and 18 deletions
|
@ -171,19 +171,27 @@ func loadRules(include, exclude string) rules.RuleList {
|
||||||
return rules.Generate(filters...)
|
return rules.Generate(filters...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveOutput(filename, format, rootPath string, issues []*gosec.Issue, metrics *gosec.Metrics, errors map[string][]gosec.Error) error {
|
func saveOutput(filename, format string, paths []string, issues []*gosec.Issue, metrics *gosec.Metrics, errors map[string][]gosec.Error) error {
|
||||||
|
rootPaths := []string{}
|
||||||
|
for _, path := range paths {
|
||||||
|
rootPath, err := gosec.RootPath(path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get the root path of the projects: %s", err)
|
||||||
|
}
|
||||||
|
rootPaths = append(rootPaths, rootPath)
|
||||||
|
}
|
||||||
if filename != "" {
|
if filename != "" {
|
||||||
outfile, err := os.Create(filename)
|
outfile, err := os.Create(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer outfile.Close()
|
defer outfile.Close()
|
||||||
err = output.CreateReport(outfile, format, rootPath, issues, metrics, errors)
|
err = output.CreateReport(outfile, format, rootPaths, issues, metrics, errors)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err := output.CreateReport(os.Stdout, format, rootPath, issues, metrics, errors)
|
err := output.CreateReport(os.Stdout, format, rootPaths, issues, metrics, errors)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -318,13 +326,8 @@ func main() {
|
||||||
os.Exit(0)
|
os.Exit(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
|
// Create output report
|
||||||
if err := saveOutput(*flagOutput, *flagFormat, rootPath, issues, metrics, errors); err != nil {
|
if err := saveOutput(*flagOutput, *flagFormat, flag.Args(), issues, metrics, errors); err != nil {
|
||||||
logger.Fatal(err)
|
logger.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ type reportInfo struct {
|
||||||
|
|
||||||
// CreateReport generates a report based for the supplied issues and metrics given
|
// CreateReport generates a report based for the supplied issues and metrics given
|
||||||
// the specified format. The formats currently accepted are: json, csv, html and text.
|
// the specified format. The formats currently accepted are: json, csv, html and text.
|
||||||
func CreateReport(w io.Writer, format, rootPath string, issues []*gosec.Issue, metrics *gosec.Metrics, errors map[string][]gosec.Error) error {
|
func CreateReport(w io.Writer, format string, rootPaths []string, issues []*gosec.Issue, metrics *gosec.Metrics, errors map[string][]gosec.Error) error {
|
||||||
data := &reportInfo{
|
data := &reportInfo{
|
||||||
Errors: errors,
|
Errors: errors,
|
||||||
Issues: issues,
|
Issues: issues,
|
||||||
|
@ -97,15 +97,15 @@ func CreateReport(w io.Writer, format, rootPath string, issues []*gosec.Issue, m
|
||||||
case "text":
|
case "text":
|
||||||
err = reportFromPlaintextTemplate(w, text, data)
|
err = reportFromPlaintextTemplate(w, text, data)
|
||||||
case "sonarqube":
|
case "sonarqube":
|
||||||
err = reportSonarqube(rootPath, w, data)
|
err = reportSonarqube(rootPaths, w, data)
|
||||||
default:
|
default:
|
||||||
err = reportFromPlaintextTemplate(w, text, data)
|
err = reportFromPlaintextTemplate(w, text, data)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func reportSonarqube(rootPath string, w io.Writer, data *reportInfo) error {
|
func reportSonarqube(rootPaths []string, w io.Writer, data *reportInfo) error {
|
||||||
si, err := convertToSonarIssues(rootPath, data)
|
si, err := convertToSonarIssues(rootPaths, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -117,11 +117,20 @@ func reportSonarqube(rootPath string, w io.Writer, data *reportInfo) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertToSonarIssues(rootPath string, data *reportInfo) (sonarIssues, error) {
|
func convertToSonarIssues(rootPaths []string, data *reportInfo) (sonarIssues, error) {
|
||||||
var si sonarIssues
|
var si sonarIssues
|
||||||
for _, issue := range data.Issues {
|
for _, issue := range data.Issues {
|
||||||
lines := strings.Split(issue.Line, "-")
|
var sonarFilePath string
|
||||||
|
for _, rootPath := range rootPaths {
|
||||||
|
if strings.HasPrefix(issue.File, rootPath) {
|
||||||
|
sonarFilePath = strings.Replace(issue.File, rootPath+"/", "", 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sonarFilePath == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
lines := strings.Split(issue.Line, "-")
|
||||||
startLine, err := strconv.Atoi(lines[0])
|
startLine, err := strconv.Atoi(lines[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return si, err
|
return si, err
|
||||||
|
@ -133,12 +142,13 @@ func convertToSonarIssues(rootPath string, data *reportInfo) (sonarIssues, error
|
||||||
return si, err
|
return si, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s := sonarIssue{
|
s := sonarIssue{
|
||||||
EngineID: "gosec",
|
EngineID: "gosec",
|
||||||
RuleID: issue.RuleID,
|
RuleID: issue.RuleID,
|
||||||
PrimaryLocation: location{
|
PrimaryLocation: location{
|
||||||
Message: issue.What,
|
Message: issue.What,
|
||||||
FilePath: strings.Replace(issue.File, rootPath+"/", "", 1),
|
FilePath: sonarFilePath,
|
||||||
TextRange: textRange{StartLine: startLine, EndLine: endLine},
|
TextRange: textRange{StartLine: startLine, EndLine: endLine},
|
||||||
},
|
},
|
||||||
Type: "VULNERABILITY",
|
Type: "VULNERABILITY",
|
||||||
|
|
|
@ -54,7 +54,7 @@ var _ = Describe("Formatter", func() {
|
||||||
|
|
||||||
rootPath := "/home/src/project"
|
rootPath := "/home/src/project"
|
||||||
|
|
||||||
issues, err := convertToSonarIssues(rootPath, data)
|
issues, err := convertToSonarIssues([]string{rootPath}, data)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
Expect(issues).To(Equal(want))
|
Expect(issues).To(Equal(want))
|
||||||
})
|
})
|
||||||
|
@ -102,7 +102,110 @@ var _ = Describe("Formatter", func() {
|
||||||
|
|
||||||
rootPath := "/home/src/project"
|
rootPath := "/home/src/project"
|
||||||
|
|
||||||
issues, err := convertToSonarIssues(rootPath, data)
|
issues, err := convertToSonarIssues([]string{rootPath}, data)
|
||||||
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
|
Expect(issues).To(Equal(want))
|
||||||
|
})
|
||||||
|
It("it should not parse the report info for files from other projects", func() {
|
||||||
|
data := &reportInfo{
|
||||||
|
Errors: map[string][]gosec.Error{},
|
||||||
|
Issues: []*gosec.Issue{
|
||||||
|
&gosec.Issue{
|
||||||
|
Severity: 2,
|
||||||
|
Confidence: 0,
|
||||||
|
RuleID: "test",
|
||||||
|
What: "test",
|
||||||
|
File: "/home/src/project1/test.go",
|
||||||
|
Code: "",
|
||||||
|
Line: "1-2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Stats: &gosec.Metrics{
|
||||||
|
NumFiles: 0,
|
||||||
|
NumLines: 0,
|
||||||
|
NumNosec: 0,
|
||||||
|
NumFound: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
want := sonarIssues{
|
||||||
|
SonarIssues: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
rootPath := "/home/src/project2"
|
||||||
|
|
||||||
|
issues, err := convertToSonarIssues([]string{rootPath}, data)
|
||||||
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
|
Expect(issues).To(Equal(want))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("it should parse the report info for multiple projects projects", func() {
|
||||||
|
data := &reportInfo{
|
||||||
|
Errors: map[string][]gosec.Error{},
|
||||||
|
Issues: []*gosec.Issue{
|
||||||
|
&gosec.Issue{
|
||||||
|
Severity: 2,
|
||||||
|
Confidence: 0,
|
||||||
|
RuleID: "test",
|
||||||
|
What: "test",
|
||||||
|
File: "/home/src/project1/test-project1.go",
|
||||||
|
Code: "",
|
||||||
|
Line: "1-2",
|
||||||
|
},
|
||||||
|
&gosec.Issue{
|
||||||
|
Severity: 2,
|
||||||
|
Confidence: 0,
|
||||||
|
RuleID: "test",
|
||||||
|
What: "test",
|
||||||
|
File: "/home/src/project2/test-project2.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-project1.go",
|
||||||
|
TextRange: textRange{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Type: "VULNERABILITY",
|
||||||
|
Severity: "BLOCKER",
|
||||||
|
EffortMinutes: SonarqubeEffortMinutes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
EngineID: "gosec",
|
||||||
|
RuleID: "test",
|
||||||
|
PrimaryLocation: location{
|
||||||
|
Message: "test",
|
||||||
|
FilePath: "test-project2.go",
|
||||||
|
TextRange: textRange{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Type: "VULNERABILITY",
|
||||||
|
Severity: "BLOCKER",
|
||||||
|
EffortMinutes: SonarqubeEffortMinutes,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
rootPaths := []string{"/home/src/project1", "/home/src/project2"}
|
||||||
|
|
||||||
|
issues, err := convertToSonarIssues(rootPaths, data)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
Expect(issues).To(Equal(want))
|
Expect(issues).To(Equal(want))
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue