Skip to content

Commit 015bb88

Browse files
fix(report): Fix invalid URI in SARIF report (#7645)
Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com>
1 parent ab3a3b2 commit 015bb88

File tree

2 files changed

+41
-30
lines changed

2 files changed

+41
-30
lines changed

pkg/report/sarif.go

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"html"
77
"io"
8+
"net/url"
89
"path/filepath"
910
"regexp"
1011
"strings"
@@ -15,6 +16,7 @@ import (
1516

1617
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
1718
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
19+
"github.com/aquasecurity/trivy/pkg/log"
1820
"github.com/aquasecurity/trivy/pkg/types"
1921
)
2022

@@ -61,9 +63,9 @@ type sarifData struct {
6163
helpMarkdown string
6264
resourceClass types.ResultClass
6365
severity string
64-
url string
66+
url *url.URL
6567
resultIndex int
66-
artifactLocation string
68+
artifactLocation *url.URL
6769
locationMessage string
6870
message string
6971
cvssScore string
@@ -97,8 +99,8 @@ func (sw *SarifWriter) addSarifRule(data *sarifData) {
9799
"precision": "very-high",
98100
"security-severity": data.cvssScore,
99101
})
100-
if data.url != "" {
101-
r.WithHelpURI(data.url)
102+
if data.url != nil && data.url.String() != "" {
103+
r.WithHelpURI(data.url.String())
102104
}
103105
}
104106

@@ -109,7 +111,7 @@ func (sw *SarifWriter) addSarifResult(data *sarifData) {
109111
WithRuleIndex(data.resultIndex).
110112
WithMessage(sarif.NewTextMessage(data.message)).
111113
WithLevel(toSarifErrorLevel(data.severity)).
112-
WithLocations(toSarifLocations(data.locations, data.artifactLocation, data.locationMessage))
114+
WithLocations(toSarifLocations(data.locations, data.artifactLocation.String(), data.locationMessage))
113115
sw.run.AddResult(result)
114116
}
115117

@@ -163,9 +165,9 @@ func (sw *SarifWriter) Write(ctx context.Context, report types.Report) error {
163165
vulnerabilityId: vuln.VulnerabilityID,
164166
severity: vuln.Severity,
165167
cvssScore: getCVSSScore(vuln),
166-
url: vuln.PrimaryURL,
168+
url: toUri(vuln.PrimaryURL),
167169
resourceClass: res.Class,
168-
artifactLocation: path,
170+
artifactLocation: toUri(path),
169171
locationMessage: fmt.Sprintf("%v: %v@%v", path, vuln.PkgName, vuln.InstalledVersion),
170172
locations: sw.getLocations(vuln.PkgName, vuln.InstalledVersion, path, res.Packages),
171173
resultIndex: getRuleIndex(vuln.VulnerabilityID, ruleIndexes),
@@ -186,9 +188,9 @@ func (sw *SarifWriter) Write(ctx context.Context, report types.Report) error {
186188
vulnerabilityId: misconf.ID,
187189
severity: misconf.Severity,
188190
cvssScore: severityToScore(misconf.Severity),
189-
url: misconf.PrimaryURL,
191+
url: toUri(misconf.PrimaryURL),
190192
resourceClass: res.Class,
191-
artifactLocation: locationURI,
193+
artifactLocation: toUri(locationURI),
192194
locationMessage: locationURI,
193195
locations: []location{
194196
{
@@ -213,9 +215,9 @@ func (sw *SarifWriter) Write(ctx context.Context, report types.Report) error {
213215
vulnerabilityId: secret.RuleID,
214216
severity: secret.Severity,
215217
cvssScore: severityToScore(secret.Severity),
216-
url: builtinRulesUrl,
218+
url: toUri(builtinRulesUrl),
217219
resourceClass: res.Class,
218-
artifactLocation: target,
220+
artifactLocation: toUri(target),
219221
locationMessage: target,
220222
locations: []location{
221223
{
@@ -242,9 +244,9 @@ func (sw *SarifWriter) Write(ctx context.Context, report types.Report) error {
242244
vulnerabilityId: id,
243245
severity: license.Severity,
244246
cvssScore: severityToScore(license.Severity),
245-
url: license.Link,
247+
url: toUri(license.Link),
246248
resourceClass: res.Class,
247-
artifactLocation: target,
249+
artifactLocation: toUri(target),
248250
resultIndex: getRuleIndex(id, ruleIndexes),
249251
shortDescription: desc,
250252
fullDescription: desc,
@@ -348,6 +350,15 @@ func clearURI(s string) string {
348350
return strings.ReplaceAll(strings.ReplaceAll(s, "\\", "/"), "git::https:/", "")
349351
}
350352

353+
func toUri(str string) *url.URL {
354+
uri, err := url.Parse(str)
355+
if err != nil {
356+
logger := log.WithPrefix("sarif")
357+
logger.Error("Unable to parse URI", log.String("URI", str), log.Err(err))
358+
}
359+
return uri
360+
}
361+
351362
func (sw *SarifWriter) getLocations(name, version, path string, pkgs []ftypes.Package) []location {
352363
id := fmt.Sprintf("%s@%s@%s", path, name, version)
353364
locs, ok := sw.locationCache[id]

pkg/report/sarif_test.go

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func TestReportWriter_Sarif(t *testing.T) {
4141
},
4242
Results: types.Results{
4343
{
44-
Target: "library/test",
44+
Target: "library/test 1",
4545
Class: types.ClassOSPkg,
4646
Packages: []ftypes.Package{
4747
{
@@ -137,10 +137,10 @@ func TestReportWriter_Sarif(t *testing.T) {
137137
Message: sarif.Message{Text: lo.ToPtr("Package: foo\nInstalled Version: 1.2.3\nVulnerability CVE-2020-0001\nSeverity: HIGH\nFixed Version: 3.4.5\nLink: [CVE-2020-0001](https://avd.aquasec.com/nvd/cve-2020-0001)")},
138138
Locations: []*sarif.Location{
139139
{
140-
Message: &sarif.Message{Text: lo.ToPtr("library/test: foo@1.2.3")},
140+
Message: &sarif.Message{Text: lo.ToPtr("library/test 1: foo@1.2.3")},
141141
PhysicalLocation: &sarif.PhysicalLocation{
142142
ArtifactLocation: &sarif.ArtifactLocation{
143-
URI: lo.ToPtr("library/test"),
143+
URI: lo.ToPtr("library/test%201"),
144144
URIBaseId: lo.ToPtr("ROOTPATH"),
145145
},
146146
Region: &sarif.Region{
@@ -152,10 +152,10 @@ func TestReportWriter_Sarif(t *testing.T) {
152152
},
153153
},
154154
{
155-
Message: &sarif.Message{Text: lo.ToPtr("library/test: foo@1.2.3")},
155+
Message: &sarif.Message{Text: lo.ToPtr("library/test 1: foo@1.2.3")},
156156
PhysicalLocation: &sarif.PhysicalLocation{
157157
ArtifactLocation: &sarif.ArtifactLocation{
158-
URI: lo.ToPtr("library/test"),
158+
URI: lo.ToPtr("library/test%201"),
159159
URIBaseId: lo.ToPtr("ROOTPATH"),
160160
},
161161
Region: &sarif.Region{
@@ -192,7 +192,7 @@ func TestReportWriter_Sarif(t *testing.T) {
192192
input: types.Report{
193193
Results: types.Results{
194194
{
195-
Target: "library/test",
195+
Target: "library/test 1",
196196
Class: types.ClassConfig,
197197
Misconfigurations: []types.DetectedMisconfiguration{
198198
{
@@ -283,13 +283,13 @@ func TestReportWriter_Sarif(t *testing.T) {
283283
RuleID: lo.ToPtr("KSV001"),
284284
RuleIndex: lo.ToPtr[uint](0),
285285
Level: lo.ToPtr("error"),
286-
Message: sarif.Message{Text: lo.ToPtr("Artifact: library/test\nType: \nVulnerability KSV001\nSeverity: HIGH\nMessage: Message\nLink: [KSV001](https://avd.aquasec.com/appshield/ksv001)")},
286+
Message: sarif.Message{Text: lo.ToPtr("Artifact: library/test 1\nType: \nVulnerability KSV001\nSeverity: HIGH\nMessage: Message\nLink: [KSV001](https://avd.aquasec.com/appshield/ksv001)")},
287287
Locations: []*sarif.Location{
288288
{
289-
Message: &sarif.Message{Text: lo.ToPtr("library/test")},
289+
Message: &sarif.Message{Text: lo.ToPtr("library/test 1")},
290290
PhysicalLocation: &sarif.PhysicalLocation{
291291
ArtifactLocation: &sarif.ArtifactLocation{
292-
URI: lo.ToPtr("library/test"),
292+
URI: lo.ToPtr("library/test%201"),
293293
URIBaseId: lo.ToPtr("ROOTPATH"),
294294
},
295295
Region: &sarif.Region{
@@ -306,13 +306,13 @@ func TestReportWriter_Sarif(t *testing.T) {
306306
RuleID: lo.ToPtr("KSV002"),
307307
RuleIndex: lo.ToPtr[uint](1),
308308
Level: lo.ToPtr("error"),
309-
Message: sarif.Message{Text: lo.ToPtr("Artifact: library/test\nType: \nVulnerability KSV002\nSeverity: CRITICAL\nMessage: Message\nLink: [KSV002](https://avd.aquasec.com/appshield/ksv002)")},
309+
Message: sarif.Message{Text: lo.ToPtr("Artifact: library/test 1\nType: \nVulnerability KSV002\nSeverity: CRITICAL\nMessage: Message\nLink: [KSV002](https://avd.aquasec.com/appshield/ksv002)")},
310310
Locations: []*sarif.Location{
311311
{
312-
Message: &sarif.Message{Text: lo.ToPtr("library/test")},
312+
Message: &sarif.Message{Text: lo.ToPtr("library/test 1")},
313313
PhysicalLocation: &sarif.PhysicalLocation{
314314
ArtifactLocation: &sarif.ArtifactLocation{
315-
URI: lo.ToPtr("library/test"),
315+
URI: lo.ToPtr("library/test%201"),
316316
URIBaseId: lo.ToPtr("ROOTPATH"),
317317
},
318318
Region: &sarif.Region{
@@ -341,7 +341,7 @@ func TestReportWriter_Sarif(t *testing.T) {
341341
input: types.Report{
342342
Results: types.Results{
343343
{
344-
Target: "library/test",
344+
Target: "library/test 1",
345345
Class: types.ClassSecret,
346346
Secrets: []types.DetectedSecret{
347347
{
@@ -400,13 +400,13 @@ func TestReportWriter_Sarif(t *testing.T) {
400400
RuleID: lo.ToPtr("aws-secret-access-key"),
401401
RuleIndex: lo.ToPtr[uint](0),
402402
Level: lo.ToPtr("error"),
403-
Message: sarif.Message{Text: lo.ToPtr("Artifact: library/test\nType: \nSecret AWS Secret Access Key\nSeverity: CRITICAL\nMatch: 'AWS_secret_KEY'=\"****************************************\"")},
403+
Message: sarif.Message{Text: lo.ToPtr("Artifact: library/test 1\nType: \nSecret AWS Secret Access Key\nSeverity: CRITICAL\nMatch: 'AWS_secret_KEY'=\"****************************************\"")},
404404
Locations: []*sarif.Location{
405405
{
406-
Message: &sarif.Message{Text: lo.ToPtr("library/test")},
406+
Message: &sarif.Message{Text: lo.ToPtr("library/test 1")},
407407
PhysicalLocation: &sarif.PhysicalLocation{
408408
ArtifactLocation: &sarif.ArtifactLocation{
409-
URI: lo.ToPtr("library/test"),
409+
URI: lo.ToPtr("library/test%201"),
410410
URIBaseId: lo.ToPtr("ROOTPATH"),
411411
},
412412
Region: &sarif.Region{
@@ -495,7 +495,7 @@ func TestReportWriter_Sarif(t *testing.T) {
495495
Message: sarif.NewTextMessage(""),
496496
PhysicalLocation: &sarif.PhysicalLocation{
497497
ArtifactLocation: &sarif.ArtifactLocation{
498-
URI: lo.ToPtr("OS Packages"),
498+
URI: lo.ToPtr("OS%20Packages"),
499499
URIBaseId: lo.ToPtr("ROOTPATH"),
500500
},
501501
Region: &sarif.Region{

0 commit comments

Comments
 (0)