Migrate sonar types in a dedicated package (#604)

This commit is contained in:
Matthieu MOREL 2021-05-05 16:21:53 +02:00 committed by GitHub
parent b519743da6
commit 37639537ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 125 additions and 93 deletions

View file

@ -50,9 +50,6 @@ const (
// ReportSARIF set the output format to SARIF // ReportSARIF set the output format to SARIF
ReportSARIF // SARIF format ReportSARIF // SARIF format
//SonarqubeEffortMinutes effort to fix in minutes
SonarqubeEffortMinutes = 5
) )
var text = `Results: var text = `Results:
@ -132,51 +129,6 @@ func reportSonarqube(rootPaths []string, w io.Writer, data *reportInfo) error {
return err return err
} }
func convertToSonarIssues(rootPaths []string, data *reportInfo) (*sonarIssues, error) {
si := &sonarIssues{[]sonarIssue{}}
for _, issue := range data.Issues {
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])
if err != nil {
return si, err
}
endLine := startLine
if len(lines) > 1 {
endLine, err = strconv.Atoi(lines[1])
if err != nil {
return si, err
}
}
s := sonarIssue{
EngineID: "gosec",
RuleID: issue.RuleID,
PrimaryLocation: location{
Message: issue.What,
FilePath: sonarFilePath,
TextRange: textRange{StartLine: startLine, EndLine: endLine},
},
Type: "VULNERABILITY",
Severity: getSonarSeverity(issue.Severity.String()),
EffortMinutes: SonarqubeEffortMinutes,
Cwe: issue.Cwe,
}
si.SonarIssues = append(si.SonarIssues, s)
}
return si, nil
}
func convertToSarifReport(rootPaths []string, data *reportInfo) (*sarifReport, error) { func convertToSarifReport(rootPaths []string, data *reportInfo) (*sarifReport, error) {
sr := buildSarifReport() sr := buildSarifReport()

View file

@ -9,6 +9,7 @@ import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/sonar"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
@ -60,7 +61,7 @@ var _ = Describe("Formatter", func() {
data := &reportInfo{ data := &reportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*gosec.Issue{
&gosec.Issue{ {
Severity: 2, Severity: 2,
Confidence: 0, Confidence: 0,
RuleID: "test", RuleID: "test",
@ -77,15 +78,15 @@ var _ = Describe("Formatter", func() {
NumFound: 0, NumFound: 0,
}, },
} }
want := &sonarIssues{ want := &sonar.Report{
SonarIssues: []sonarIssue{ Issues: []*sonar.Issue{
{ {
EngineID: "gosec", EngineID: "gosec",
RuleID: "test", RuleID: "test",
PrimaryLocation: location{ PrimaryLocation: &sonar.Location{
Message: "test", Message: "test",
FilePath: "test.go", FilePath: "test.go",
TextRange: textRange{ TextRange: &sonar.TextRange{
StartLine: 1, StartLine: 1,
EndLine: 2, EndLine: 2,
}, },
@ -108,7 +109,7 @@ var _ = Describe("Formatter", func() {
data := &reportInfo{ data := &reportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*gosec.Issue{
&gosec.Issue{ {
Severity: 2, Severity: 2,
Confidence: 0, Confidence: 0,
RuleID: "test", RuleID: "test",
@ -125,15 +126,15 @@ var _ = Describe("Formatter", func() {
NumFound: 0, NumFound: 0,
}, },
} }
want := &sonarIssues{ want := &sonar.Report{
SonarIssues: []sonarIssue{ Issues: []*sonar.Issue{
{ {
EngineID: "gosec", EngineID: "gosec",
RuleID: "test", RuleID: "test",
PrimaryLocation: location{ PrimaryLocation: &sonar.Location{
Message: "test", Message: "test",
FilePath: "subfolder/test.go", FilePath: "subfolder/test.go",
TextRange: textRange{ TextRange: &sonar.TextRange{
StartLine: 1, StartLine: 1,
EndLine: 2, EndLine: 2,
}, },
@ -155,7 +156,7 @@ var _ = Describe("Formatter", func() {
data := &reportInfo{ data := &reportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*gosec.Issue{
&gosec.Issue{ {
Severity: 2, Severity: 2,
Confidence: 0, Confidence: 0,
RuleID: "test", RuleID: "test",
@ -172,8 +173,8 @@ var _ = Describe("Formatter", func() {
NumFound: 0, NumFound: 0,
}, },
} }
want := &sonarIssues{ want := &sonar.Report{
SonarIssues: []sonarIssue{}, Issues: []*sonar.Issue{},
} }
rootPath := "/home/src/project2" rootPath := "/home/src/project2"
@ -187,7 +188,7 @@ var _ = Describe("Formatter", func() {
data := &reportInfo{ data := &reportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*gosec.Issue{
&gosec.Issue{ {
Severity: 2, Severity: 2,
Confidence: 0, Confidence: 0,
RuleID: "test", RuleID: "test",
@ -196,7 +197,7 @@ var _ = Describe("Formatter", func() {
Code: "", Code: "",
Line: "1-2", Line: "1-2",
}, },
&gosec.Issue{ {
Severity: 2, Severity: 2,
Confidence: 0, Confidence: 0,
RuleID: "test", RuleID: "test",
@ -213,15 +214,15 @@ var _ = Describe("Formatter", func() {
NumFound: 0, NumFound: 0,
}, },
} }
want := &sonarIssues{ want := &sonar.Report{
SonarIssues: []sonarIssue{ Issues: []*sonar.Issue{
{ {
EngineID: "gosec", EngineID: "gosec",
RuleID: "test", RuleID: "test",
PrimaryLocation: location{ PrimaryLocation: &sonar.Location{
Message: "test", Message: "test",
FilePath: "test-project1.go", FilePath: "test-project1.go",
TextRange: textRange{ TextRange: &sonar.TextRange{
StartLine: 1, StartLine: 1,
EndLine: 2, EndLine: 2,
}, },
@ -233,10 +234,10 @@ var _ = Describe("Formatter", func() {
{ {
EngineID: "gosec", EngineID: "gosec",
RuleID: "test", RuleID: "test",
PrimaryLocation: location{ PrimaryLocation: &sonar.Location{
Message: "test", Message: "test",
FilePath: "test-project2.go", FilePath: "test-project2.go",
TextRange: textRange{ TextRange: &sonar.TextRange{
StartLine: 1, StartLine: 1,
EndLine: 2, EndLine: 2,
}, },
@ -407,7 +408,7 @@ var _ = Describe("Formatter", func() {
Expect(result).To(ContainSubstring(expectation)) Expect(result).To(ContainSubstring(expectation))
} }
}) })
It("sonarqube formatted report should contain the CWE mapping", func() { It("sonarqube formatted report shouldn't contain the CWE mapping", func() {
for _, rule := range grules { for _, rule := range grules {
cwe := gosec.IssueToCWE[rule] cwe := gosec.IssueToCWE[rule]
issue := createIssue(rule, cwe) issue := createIssue(rule, cwe)
@ -424,7 +425,7 @@ var _ = Describe("Formatter", func() {
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
expectation := stripString(expect.String()) expectation := stripString(expect.String())
Expect(result).To(ContainSubstring(expectation)) Expect(result).ShouldNot(ContainSubstring(expectation))
} }
}) })
It("golint formatted report should contain the CWE mapping", func() { It("golint formatted report should contain the CWE mapping", func() {

View file

@ -1,32 +1,79 @@
package output package output
import "github.com/securego/gosec/v2" import (
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/sonar"
"strconv"
"strings"
)
type textRange struct { const (
StartLine int `json:"startLine"` //SonarqubeEffortMinutes effort to fix in minutes
EndLine int `json:"endLine"` SonarqubeEffortMinutes = 5
StartColumn int `json:"startColumn,omitempty"` )
EtartColumn int `json:"endColumn,omitempty"`
} func convertToSonarIssues(rootPaths []string, data *reportInfo) (*sonar.Report, error) {
type location struct { si := &sonar.Report{Issues: []*sonar.Issue{}}
Message string `json:"message"` for _, issue := range data.Issues {
FilePath string `json:"filePath"` sonarFilePath := parseFilePath(issue, rootPaths)
TextRange textRange `json:"textRange,omitempty"`
if sonarFilePath == "" {
continue
} }
type sonarIssue struct { textRange, err := parseTextRange(issue)
EngineID string `json:"engineId"` if err != nil {
RuleID string `json:"ruleId"` return si, err
Cwe gosec.Cwe `json:"cwe"`
PrimaryLocation location `json:"primaryLocation"`
Type string `json:"type"`
Severity string `json:"severity"`
EffortMinutes int `json:"effortMinutes"`
SecondaryLocations []location `json:"secondaryLocations,omitempty"`
} }
type sonarIssues struct { primaryLocation := buildPrimaryLocation(issue.What, sonarFilePath, textRange)
SonarIssues []sonarIssue `json:"issues"` severity := getSonarSeverity(issue.Severity.String())
s := &sonar.Issue{
EngineID: "gosec",
RuleID: issue.RuleID,
PrimaryLocation: primaryLocation,
Type: "VULNERABILITY",
Severity: severity,
EffortMinutes: SonarqubeEffortMinutes,
}
si.Issues = append(si.Issues, s)
}
return si, nil
}
func buildPrimaryLocation(message string, filePath string, textRange *sonar.TextRange) *sonar.Location {
return &sonar.Location{
Message: message,
FilePath: filePath,
TextRange: textRange,
}
}
func parseFilePath(issue *gosec.Issue, rootPaths []string) string {
var sonarFilePath string
for _, rootPath := range rootPaths {
if strings.HasPrefix(issue.File, rootPath) {
sonarFilePath = strings.Replace(issue.File, rootPath+"/", "", 1)
}
}
return sonarFilePath
}
func parseTextRange(issue *gosec.Issue) (*sonar.TextRange, error) {
lines := strings.Split(issue.Line, "-")
startLine, err := strconv.Atoi(lines[0])
if err != nil {
return nil, err
}
endLine := startLine
if len(lines) > 1 {
endLine, err = strconv.Atoi(lines[1])
if err != nil {
return nil, err
}
}
return &sonar.TextRange{StartLine: startLine, EndLine: endLine}, nil
} }
func getSonarSeverity(s string) string { func getSonarSeverity(s string) string {

32
sonar/types.go Normal file
View file

@ -0,0 +1,32 @@
package sonar
//TextRange defines the text range of an issue's location
type TextRange struct {
StartLine int `json:"startLine"`
EndLine int `json:"endLine"`
StartColumn int `json:"startColumn,omitempty"`
EtartColumn int `json:"endColumn,omitempty"`
}
//Location defines a sonar issue's location
type Location struct {
Message string `json:"message"`
FilePath string `json:"filePath"`
TextRange *TextRange `json:"textRange,omitempty"`
}
//Issue defines a sonar issue
type Issue struct {
EngineID string `json:"engineId"`
RuleID string `json:"ruleId"`
PrimaryLocation *Location `json:"primaryLocation"`
Type string `json:"type"`
Severity string `json:"severity"`
EffortMinutes int `json:"effortMinutes"`
SecondaryLocations []*Location `json:"secondaryLocations,omitempty"`
}
//Report defines a sonar report
type Report struct {
Issues []*Issue `json:"issues"`
}