From 2fa264ac1e5639ab665c904111429f4c8fe14486 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Wed, 23 Aug 2023 18:56:08 +0700 Subject: [PATCH] feat(report): add licenses to sarif format (#4866) * feat(report): add licenses to sarif format * update doc --- docs/docs/configuration/reporting.md | 2 +- pkg/report/sarif.go | 26 ++++++++ pkg/report/sarif_test.go | 89 ++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 1 deletion(-) diff --git a/docs/docs/configuration/reporting.md b/docs/docs/configuration/reporting.md index 30dd2bccdfb5..d23c88a7719f 100644 --- a/docs/docs/configuration/reporting.md +++ b/docs/docs/configuration/reporting.md @@ -246,7 +246,7 @@ $ trivy image -f json -o results.json golang:1.12-alpine | Vulnerability | ✓ | | Misconfiguration | ✓ | | Secret | ✓ | -| License | | +| License | ✓ | [SARIF][sarif] can be generated with the `--format sarif` flag. diff --git a/pkg/report/sarif.go b/pkg/report/sarif.go index 17eef17e4663..e942f94b13ad 100644 --- a/pkg/report/sarif.go +++ b/pkg/report/sarif.go @@ -20,6 +20,7 @@ const ( sarifLanguageSpecificVulnerability = "LanguageSpecificPackageVulnerability" sarifConfigFiles = "Misconfiguration" sarifSecretFiles = "Secret" + sarifLicenseFiles = "License" sarifUnknownIssue = "UnknownIssue" sarifError = "error" @@ -213,6 +214,29 @@ func (sw *SarifWriter) Write(report types.Report) error { res.Target, res.Type, secret.Title, secret.Severity, secret.Match), }) } + for _, license := range res.Licenses { + id := fmt.Sprintf("%s:%s", license.PkgName, license.Name) + desc := fmt.Sprintf("%s in %s", license.Name, license.PkgName) + sw.addSarifResult(&sarifData{ + title: "license", + vulnerabilityId: id, + severity: license.Severity, + cvssScore: severityToScore(license.Severity), + url: license.Link, + resourceClass: string(res.Class), + artifactLocation: target, + resultIndex: getRuleIndex(id, ruleIndexes), + shortDescription: desc, + fullDescription: desc, + helpText: fmt.Sprintf("License %s\nClassification: %s\nPkgName: %s\nPath: %s", + license.Name, license.Category, license.PkgName, license.FilePath), + helpMarkdown: fmt.Sprintf("**License %s**\n| PkgName | Classification | Path |\n| --- | --- | --- |\n|%s|%s|%s|", + license.Name, license.PkgName, license.Category, license.FilePath), + message: fmt.Sprintf("Artifact: %s\nLicense %s\nPkgName: %s\n Classification: %s\n Path: %s", + res.Target, license.Name, license.Category, license.PkgName, license.FilePath), + }) + } + } sw.run.ColumnKind = columnKind sw.run.OriginalUriBaseIDs = map[string]*sarif.ArtifactLocation{ @@ -259,6 +283,8 @@ func toSarifRuleName(class string) string { return sarifConfigFiles case types.ClassSecret: return sarifSecretFiles + case types.ClassLicense, types.ClassLicenseFile: + return sarifLicenseFiles default: return sarifUnknownIssue } diff --git a/pkg/report/sarif_test.go b/pkg/report/sarif_test.go index 595d69ba01fb..62d60309ca3a 100644 --- a/pkg/report/sarif_test.go +++ b/pkg/report/sarif_test.go @@ -425,6 +425,95 @@ func TestReportWriter_Sarif(t *testing.T) { }, }, }, + { + name: "report with licenses", + input: types.Report{ + Results: types.Results{ + { + Target: "OS Packages", + Class: "license", + Licenses: []types.DetectedLicense{ + { + Severity: "HIGH", + Category: "restricted", + PkgName: "alpine-base", + FilePath: "", + Name: "GPL-3.0", + Confidence: 1, + Link: "", + }, + }, + }, + }, + }, + want: &sarif.Report{ + Version: "2.1.0", + Schema: "https://json.schemastore.org/sarif-2.1.0.json", + Runs: []*sarif.Run{ + { + Tool: sarif.Tool{ + Driver: &sarif.ToolComponent{ + FullName: lo.ToPtr("Trivy Vulnerability Scanner"), + Name: "Trivy", + Version: lo.ToPtr(""), + InformationURI: lo.ToPtr("https://github.com/aquasecurity/trivy"), + Rules: []*sarif.ReportingDescriptor{ + { + ID: "alpine-base:GPL-3.0", + Name: lo.ToPtr("License"), + ShortDescription: sarif.NewMultiformatMessageString("GPL-3.0 in alpine-base"), + FullDescription: sarif.NewMultiformatMessageString("GPL-3.0 in alpine-base"), + DefaultConfiguration: sarif.NewReportingConfiguration().WithLevel("error"), + Help: sarif.NewMultiformatMessageString("License GPL-3.0\nClassification: restricted\nPkgName: alpine-base\nPath: "). + WithMarkdown("**License GPL-3.0**\n| PkgName | Classification | Path |\n| --- | --- | --- |\n|alpine-base|restricted||"), + Properties: map[string]interface{}{ + "tags": []interface{}{ + "license", + "security", + "HIGH", + }, + "precision": "very-high", + "security-severity": "8.0", + }, + }, + }, + }, + }, + Results: []*sarif.Result{ + { + RuleID: lo.ToPtr("alpine-base:GPL-3.0"), + RuleIndex: lo.ToPtr(uint(0)), + Level: lo.ToPtr("error"), + Message: sarif.Message{Text: lo.ToPtr("Artifact: OS Packages\nLicense GPL-3.0\nPkgName: restricted\n Classification: alpine-base\n Path: ")}, + Locations: []*sarif.Location{ + { + Message: sarif.NewTextMessage(""), + PhysicalLocation: &sarif.PhysicalLocation{ + ArtifactLocation: &sarif.ArtifactLocation{ + URI: lo.ToPtr("OS Packages"), + URIBaseId: lo.ToPtr("ROOTPATH"), + }, + Region: &sarif.Region{ + StartLine: lo.ToPtr(1), + EndLine: lo.ToPtr(1), + StartColumn: lo.ToPtr(1), + EndColumn: lo.ToPtr(1), + }, + }, + }, + }, + }, + }, + ColumnKind: "utf16CodeUnits", + OriginalUriBaseIDs: map[string]*sarif.ArtifactLocation{ + "ROOTPATH": { + URI: lo.ToPtr("file:///"), + }, + }, + }, + }, + }, + }, { name: "no vulns", want: &sarif.Report{