mirror of
https://github.com/securego/gosec.git
synced 2024-12-25 03:55:54 +00:00
Migrate sonar types in a dedicated package (#604)
This commit is contained in:
parent
b519743da6
commit
37639537ce
4 changed files with 125 additions and 93 deletions
|
@ -50,9 +50,6 @@ const (
|
|||
|
||||
// ReportSARIF set the output format to SARIF
|
||||
ReportSARIF // SARIF format
|
||||
|
||||
//SonarqubeEffortMinutes effort to fix in minutes
|
||||
SonarqubeEffortMinutes = 5
|
||||
)
|
||||
|
||||
var text = `Results:
|
||||
|
@ -132,51 +129,6 @@ func reportSonarqube(rootPaths []string, w io.Writer, data *reportInfo) error {
|
|||
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) {
|
||||
sr := buildSarifReport()
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/sonar"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
|
@ -60,7 +61,7 @@ var _ = Describe("Formatter", func() {
|
|||
data := &reportInfo{
|
||||
Errors: map[string][]gosec.Error{},
|
||||
Issues: []*gosec.Issue{
|
||||
&gosec.Issue{
|
||||
{
|
||||
Severity: 2,
|
||||
Confidence: 0,
|
||||
RuleID: "test",
|
||||
|
@ -77,15 +78,15 @@ var _ = Describe("Formatter", func() {
|
|||
NumFound: 0,
|
||||
},
|
||||
}
|
||||
want := &sonarIssues{
|
||||
SonarIssues: []sonarIssue{
|
||||
want := &sonar.Report{
|
||||
Issues: []*sonar.Issue{
|
||||
{
|
||||
EngineID: "gosec",
|
||||
RuleID: "test",
|
||||
PrimaryLocation: location{
|
||||
PrimaryLocation: &sonar.Location{
|
||||
Message: "test",
|
||||
FilePath: "test.go",
|
||||
TextRange: textRange{
|
||||
TextRange: &sonar.TextRange{
|
||||
StartLine: 1,
|
||||
EndLine: 2,
|
||||
},
|
||||
|
@ -108,7 +109,7 @@ var _ = Describe("Formatter", func() {
|
|||
data := &reportInfo{
|
||||
Errors: map[string][]gosec.Error{},
|
||||
Issues: []*gosec.Issue{
|
||||
&gosec.Issue{
|
||||
{
|
||||
Severity: 2,
|
||||
Confidence: 0,
|
||||
RuleID: "test",
|
||||
|
@ -125,15 +126,15 @@ var _ = Describe("Formatter", func() {
|
|||
NumFound: 0,
|
||||
},
|
||||
}
|
||||
want := &sonarIssues{
|
||||
SonarIssues: []sonarIssue{
|
||||
want := &sonar.Report{
|
||||
Issues: []*sonar.Issue{
|
||||
{
|
||||
EngineID: "gosec",
|
||||
RuleID: "test",
|
||||
PrimaryLocation: location{
|
||||
PrimaryLocation: &sonar.Location{
|
||||
Message: "test",
|
||||
FilePath: "subfolder/test.go",
|
||||
TextRange: textRange{
|
||||
TextRange: &sonar.TextRange{
|
||||
StartLine: 1,
|
||||
EndLine: 2,
|
||||
},
|
||||
|
@ -155,7 +156,7 @@ var _ = Describe("Formatter", func() {
|
|||
data := &reportInfo{
|
||||
Errors: map[string][]gosec.Error{},
|
||||
Issues: []*gosec.Issue{
|
||||
&gosec.Issue{
|
||||
{
|
||||
Severity: 2,
|
||||
Confidence: 0,
|
||||
RuleID: "test",
|
||||
|
@ -172,8 +173,8 @@ var _ = Describe("Formatter", func() {
|
|||
NumFound: 0,
|
||||
},
|
||||
}
|
||||
want := &sonarIssues{
|
||||
SonarIssues: []sonarIssue{},
|
||||
want := &sonar.Report{
|
||||
Issues: []*sonar.Issue{},
|
||||
}
|
||||
|
||||
rootPath := "/home/src/project2"
|
||||
|
@ -187,7 +188,7 @@ var _ = Describe("Formatter", func() {
|
|||
data := &reportInfo{
|
||||
Errors: map[string][]gosec.Error{},
|
||||
Issues: []*gosec.Issue{
|
||||
&gosec.Issue{
|
||||
{
|
||||
Severity: 2,
|
||||
Confidence: 0,
|
||||
RuleID: "test",
|
||||
|
@ -196,7 +197,7 @@ var _ = Describe("Formatter", func() {
|
|||
Code: "",
|
||||
Line: "1-2",
|
||||
},
|
||||
&gosec.Issue{
|
||||
{
|
||||
Severity: 2,
|
||||
Confidence: 0,
|
||||
RuleID: "test",
|
||||
|
@ -213,15 +214,15 @@ var _ = Describe("Formatter", func() {
|
|||
NumFound: 0,
|
||||
},
|
||||
}
|
||||
want := &sonarIssues{
|
||||
SonarIssues: []sonarIssue{
|
||||
want := &sonar.Report{
|
||||
Issues: []*sonar.Issue{
|
||||
{
|
||||
EngineID: "gosec",
|
||||
RuleID: "test",
|
||||
PrimaryLocation: location{
|
||||
PrimaryLocation: &sonar.Location{
|
||||
Message: "test",
|
||||
FilePath: "test-project1.go",
|
||||
TextRange: textRange{
|
||||
TextRange: &sonar.TextRange{
|
||||
StartLine: 1,
|
||||
EndLine: 2,
|
||||
},
|
||||
|
@ -233,10 +234,10 @@ var _ = Describe("Formatter", func() {
|
|||
{
|
||||
EngineID: "gosec",
|
||||
RuleID: "test",
|
||||
PrimaryLocation: location{
|
||||
PrimaryLocation: &sonar.Location{
|
||||
Message: "test",
|
||||
FilePath: "test-project2.go",
|
||||
TextRange: textRange{
|
||||
TextRange: &sonar.TextRange{
|
||||
StartLine: 1,
|
||||
EndLine: 2,
|
||||
},
|
||||
|
@ -407,7 +408,7 @@ var _ = Describe("Formatter", func() {
|
|||
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 {
|
||||
cwe := gosec.IssueToCWE[rule]
|
||||
issue := createIssue(rule, cwe)
|
||||
|
@ -424,7 +425,7 @@ var _ = Describe("Formatter", func() {
|
|||
Expect(err).ShouldNot(HaveOccurred())
|
||||
|
||||
expectation := stripString(expect.String())
|
||||
Expect(result).To(ContainSubstring(expectation))
|
||||
Expect(result).ShouldNot(ContainSubstring(expectation))
|
||||
}
|
||||
})
|
||||
It("golint formatted report should contain the CWE mapping", func() {
|
||||
|
|
|
@ -1,32 +1,79 @@
|
|||
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 {
|
||||
StartLine int `json:"startLine"`
|
||||
EndLine int `json:"endLine"`
|
||||
StartColumn int `json:"startColumn,omitempty"`
|
||||
EtartColumn int `json:"endColumn,omitempty"`
|
||||
}
|
||||
type location struct {
|
||||
Message string `json:"message"`
|
||||
FilePath string `json:"filePath"`
|
||||
TextRange textRange `json:"textRange,omitempty"`
|
||||
const (
|
||||
//SonarqubeEffortMinutes effort to fix in minutes
|
||||
SonarqubeEffortMinutes = 5
|
||||
)
|
||||
|
||||
func convertToSonarIssues(rootPaths []string, data *reportInfo) (*sonar.Report, error) {
|
||||
si := &sonar.Report{Issues: []*sonar.Issue{}}
|
||||
for _, issue := range data.Issues {
|
||||
sonarFilePath := parseFilePath(issue, rootPaths)
|
||||
|
||||
if sonarFilePath == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
textRange, err := parseTextRange(issue)
|
||||
if err != nil {
|
||||
return si, err
|
||||
}
|
||||
|
||||
primaryLocation := buildPrimaryLocation(issue.What, sonarFilePath, textRange)
|
||||
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
|
||||
}
|
||||
|
||||
type sonarIssue struct {
|
||||
EngineID string `json:"engineId"`
|
||||
RuleID string `json:"ruleId"`
|
||||
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"`
|
||||
func buildPrimaryLocation(message string, filePath string, textRange *sonar.TextRange) *sonar.Location {
|
||||
return &sonar.Location{
|
||||
Message: message,
|
||||
FilePath: filePath,
|
||||
TextRange: textRange,
|
||||
}
|
||||
}
|
||||
|
||||
type sonarIssues struct {
|
||||
SonarIssues []sonarIssue `json:"issues"`
|
||||
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 {
|
||||
|
|
32
sonar/types.go
Normal file
32
sonar/types.go
Normal 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"`
|
||||
}
|
Loading…
Reference in a new issue