mirror of
https://github.com/securego/gosec.git
synced 2024-12-25 12:05:52 +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 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()
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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
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