Skip to content

Commit 0ce48a5

Browse files
authored
Reproducible junit report (#529)
* Fix junit format ordering Signed-off-by: L. Pivarc <[email protected]> * Make ordering stable Signed-off-by: L. Pivarc <[email protected]> * Test ordering Signed-off-by: L. Pivarc <[email protected]>
1 parent 868556b commit 0ce48a5

File tree

7 files changed

+153
-31
lines changed

7 files changed

+153
-31
lines changed

cmd/gosec/sort_issues.go

+21-1
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,35 @@ package main
22

33
import (
44
"sort"
5+
"strconv"
6+
"strings"
57

68
"github.com/securego/gosec/v2"
79
)
810

11+
// handle ranges
12+
func extractLineNumber(s string) int {
13+
lineNumber, _ := strconv.Atoi(strings.Split(s, "-")[0])
14+
return lineNumber
15+
16+
}
17+
918
type sortBySeverity []*gosec.Issue
1019

1120
func (s sortBySeverity) Len() int { return len(s) }
1221

13-
func (s sortBySeverity) Less(i, j int) bool { return s[i].Severity > s[j].Severity }
22+
func (s sortBySeverity) Less(i, j int) bool {
23+
if s[i].Severity == s[j].Severity {
24+
if s[i].What == s[j].What {
25+
if s[i].File == s[j].File {
26+
return extractLineNumber(s[i].Line) > extractLineNumber(s[j].Line)
27+
}
28+
return s[i].File > s[j].File
29+
}
30+
return s[i].What > s[j].What
31+
}
32+
return s[i].Severity > s[j].Severity
33+
}
1434

1535
func (s sortBySeverity) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
1636

cmd/gosec/sort_issues_test.go

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/onsi/ginkgo"
7+
. "github.com/onsi/gomega"
8+
"github.com/securego/gosec/v2"
9+
)
10+
11+
var defaultIssue = gosec.Issue{
12+
File: "/home/src/project/test.go",
13+
Line: "1",
14+
Col: "1",
15+
RuleID: "ruleID",
16+
What: "test",
17+
Confidence: gosec.High,
18+
Severity: gosec.High,
19+
Code: "1: testcode",
20+
Cwe: gosec.GetCwe("G101"),
21+
}
22+
23+
func createIssue() gosec.Issue {
24+
return defaultIssue
25+
}
26+
27+
func TestRules(t *testing.T) {
28+
RegisterFailHandler(Fail)
29+
RunSpecs(t, "Sort issues Suite")
30+
}
31+
32+
func firstIsGreater(less, greater *gosec.Issue) {
33+
slice := []*gosec.Issue{less, greater}
34+
35+
sortIssues(slice)
36+
37+
ExpectWithOffset(0, slice[0]).To(Equal(greater))
38+
}
39+
40+
var _ = Describe("Sorting by Severity", func() {
41+
It("sortes by severity", func() {
42+
less := createIssue()
43+
less.Severity = gosec.Low
44+
greater := createIssue()
45+
less.Severity = gosec.High
46+
firstIsGreater(&less, &greater)
47+
})
48+
49+
Context("Serverity is same", func() {
50+
It("sortes by What", func() {
51+
less := createIssue()
52+
less.What = "test1"
53+
greater := createIssue()
54+
greater.What = "test2"
55+
firstIsGreater(&less, &greater)
56+
})
57+
})
58+
59+
Context("Serverity and What is same", func() {
60+
It("sortes by File", func() {
61+
less := createIssue()
62+
less.File = "test1"
63+
greater := createIssue()
64+
greater.File = "test2"
65+
66+
firstIsGreater(&less, &greater)
67+
})
68+
})
69+
70+
Context("Serverity, What and File is same", func() {
71+
It("sortes by line number", func() {
72+
less := createIssue()
73+
less.Line = "1"
74+
greater := createIssue()
75+
greater.Line = "2"
76+
77+
firstIsGreater(&less, &greater)
78+
})
79+
})
80+
})

go.mod

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ require (
99
github.com/onsi/ginkgo v1.14.0
1010
github.com/onsi/gomega v1.10.1
1111
github.com/stretchr/testify v1.4.0 // indirect
12-
golang.org/x/text v0.3.2 // indirect
1312
golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65
1413
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
1514
gopkg.in/yaml.v2 v2.3.0

go.sum

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
33
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
44
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
55
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
6+
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
67
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
78
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
89
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -36,18 +37,21 @@ github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee h1:1xJ+Xi9
3637
github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
3738
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1ORQBMvzfzBgpsctsbQikCVpvC+tX285E=
3839
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
40+
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
3941
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
4042
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
4143
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
4244
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
4345
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
4446
github.com/onsi/ginkgo v1.12.3/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
4547
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
48+
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
4649
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
4750
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
4851
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
4952
github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg=
5053
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
54+
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
5155
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
5256
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
5357
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -75,6 +79,7 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZ
7579
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
7680
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
7781
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
82+
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
7883
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
7984
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
8085
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -89,6 +94,7 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w
8994
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA=
9095
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
9196
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
97+
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
9298
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
9399
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
94100
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

output/formatter.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,7 @@ func reportGolint(w io.Writer, data *reportInfo) error {
242242
}
243243

244244
func reportJUnitXML(w io.Writer, data *reportInfo) error {
245-
groupedData := groupDataByRules(data)
246-
junitXMLStruct := createJUnitXMLStruct(groupedData)
247-
245+
junitXMLStruct := createJUnitXMLStruct(data)
248246
raw, err := xml.MarshalIndent(junitXMLStruct, "", "\t")
249247
if err != nil {
250248
return err

output/formatter_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ import (
1212
"gopkg.in/yaml.v2"
1313
)
1414

15+
func createIssueWithFileWhat(file, what string) *gosec.Issue {
16+
issue := createIssue("i1", gosec.GetCwe("G101"))
17+
issue.File = file
18+
issue.What = what
19+
return &issue
20+
}
21+
1522
func createIssue(ruleID string, cwe gosec.Cwe) gosec.Issue {
1623
return gosec.Issue{
1724
File: "/home/src/project/test.go",
@@ -248,6 +255,23 @@ var _ = Describe("Formatter", func() {
248255
Expect(*issues).To(Equal(*want))
249256
})
250257
})
258+
259+
Context("When using junit", func() {
260+
It("preserves order of issues", func() {
261+
issues := []*gosec.Issue{createIssueWithFileWhat("i1", "1"), createIssueWithFileWhat("i2", "2"), createIssueWithFileWhat("i3", "1")}
262+
263+
junitReport := createJUnitXMLStruct(&reportInfo{Issues: issues})
264+
265+
testSuite := junitReport.Testsuites[0]
266+
267+
Expect(testSuite.Testcases[0].Name).To(Equal(issues[0].File))
268+
Expect(testSuite.Testcases[1].Name).To(Equal(issues[2].File))
269+
270+
testSuite = junitReport.Testsuites[1]
271+
Expect(testSuite.Testcases[0].Name).To(Equal(issues[1].File))
272+
273+
})
274+
})
251275
Context("When using different report formats", func() {
252276

253277
grules := []string{"G101", "G102", "G103", "G104", "G106",

output/junit_xml_format.go

+21-26
Original file line numberDiff line numberDiff line change
@@ -40,35 +40,30 @@ func generatePlaintext(issue *gosec.Issue) string {
4040
", CWE: " + issue.Cwe.ID + ")\n" + "> " + htmlLib.EscapeString(issue.Code)
4141
}
4242

43-
func groupDataByRules(data *reportInfo) map[string][]*gosec.Issue {
44-
groupedData := make(map[string][]*gosec.Issue)
45-
for _, issue := range data.Issues {
46-
if _, ok := groupedData[issue.What]; !ok {
47-
groupedData[issue.What] = []*gosec.Issue{}
48-
}
49-
groupedData[issue.What] = append(groupedData[issue.What], issue)
50-
}
51-
return groupedData
52-
}
53-
54-
func createJUnitXMLStruct(groupedData map[string][]*gosec.Issue) junitXMLReport {
43+
func createJUnitXMLStruct(data *reportInfo) junitXMLReport {
5544
var xmlReport junitXMLReport
56-
for what, issues := range groupedData {
57-
testsuite := testsuite{
58-
Name: what,
59-
Tests: len(issues),
45+
testsuites := map[string]int{}
46+
47+
for _, issue := range data.Issues {
48+
index, ok := testsuites[issue.What]
49+
if !ok {
50+
xmlReport.Testsuites = append(xmlReport.Testsuites, testsuite{
51+
Name: issue.What,
52+
})
53+
index = len(xmlReport.Testsuites) - 1
54+
testsuites[issue.What] = index
6055
}
61-
for _, issue := range issues {
62-
testcase := testcase{
63-
Name: issue.File,
64-
Failure: failure{
65-
Message: "Found 1 vulnerability. See stacktrace for details.",
66-
Text: generatePlaintext(issue),
67-
},
68-
}
69-
testsuite.Testcases = append(testsuite.Testcases, testcase)
56+
testcase := testcase{
57+
Name: issue.File,
58+
Failure: failure{
59+
Message: "Found 1 vulnerability. See stacktrace for details.",
60+
Text: generatePlaintext(issue),
61+
},
7062
}
71-
xmlReport.Testsuites = append(xmlReport.Testsuites, testsuite)
63+
64+
xmlReport.Testsuites[index].Testcases = append(xmlReport.Testsuites[index].Testcases, testcase)
65+
xmlReport.Testsuites[index].Tests++
7266
}
67+
7368
return xmlReport
7469
}

0 commit comments

Comments
 (0)