From d7f7a6c72ed14ffb18bfc48735f4f15360ae488e Mon Sep 17 00:00:00 2001 From: Omkar Phansopkar Date: Tue, 1 Apr 2025 21:10:45 +0530 Subject: [PATCH] Use common ToolMetadata for all reporters and default-enable vuln & malware in SARIF Signed-off-by: Omkar Phansopkar --- pkg/reporter/common.go | 8 ++++++ pkg/reporter/defect_dojo.go | 14 ++-------- pkg/reporter/gitlab.go | 14 ++++------ pkg/reporter/gitlab_test.go | 11 +++++--- pkg/reporter/json_report.go | 9 +++--- pkg/reporter/json_report_test.go | 10 +++++-- pkg/reporter/markdown_summary.go | 12 ++------ pkg/reporter/sarif.go | 14 ++-------- pkg/reporter/sarif_builder.go | 23 +++++++++------- pkg/reporter/sarif_builder_test.go | 19 ++++++------- pkg/reporter/sync.go | 11 ++++---- query.go | 33 ++++++++++------------ scan.go | 44 ++++++++++++------------------ 13 files changed, 98 insertions(+), 124 deletions(-) create mode 100644 pkg/reporter/common.go diff --git a/pkg/reporter/common.go b/pkg/reporter/common.go new file mode 100644 index 0000000..d24f7a1 --- /dev/null +++ b/pkg/reporter/common.go @@ -0,0 +1,8 @@ +package reporter + +type ToolMetadata struct { + Name string + Version string + InformationURI string + VendorName string +} diff --git a/pkg/reporter/defect_dojo.go b/pkg/reporter/defect_dojo.go index 9e6f33f..04de91d 100644 --- a/pkg/reporter/defect_dojo.go +++ b/pkg/reporter/defect_dojo.go @@ -26,14 +26,8 @@ type DefectDojoProduct struct { Created time.Time `json:"created"` } -type DefectDojoToolMetadata struct { - Name string - Version string - InformationURI string -} - type DefectDojoReporterConfig struct { - Tool DefectDojoToolMetadata + Tool ToolMetadata IncludeVulns bool IncludeMalware bool ProductID int @@ -55,11 +49,7 @@ func NewDefectDojoReporter(config DefectDojoReporterConfig) (Reporter, error) { builder, err := newSarifBuilder( sarifBuilderConfig{ - Tool: sarifBuilderToolMetadata{ - Name: config.Tool.Name, - Version: config.Tool.Version, - InformationURI: config.Tool.InformationURI, - }, + Tool: config.Tool, IncludeVulns: config.IncludeVulns, IncludeMalware: config.IncludeMalware, }, diff --git a/pkg/reporter/gitlab.go b/pkg/reporter/gitlab.go index 15daf9c..2cbbf62 100644 --- a/pkg/reporter/gitlab.go +++ b/pkg/reporter/gitlab.go @@ -35,10 +35,8 @@ const ( ) type GitLabReporterConfig struct { - Path string // Report path, value of --report-gitlab - ToolName string - ToolVersion string // Tool version, value from version.go - ToolVendorName string + Path string // Report path, value of --report-gitlab + Tool ToolMetadata } // gitLabVendor represents vendor information @@ -316,11 +314,11 @@ func (r *gitLabReporter) AddAnalyzerEvent(event *analyzer.AnalyzerEvent) {} func (r *gitLabReporter) AddPolicyEvent(event *policy.PolicyEvent) {} func (r *gitLabReporter) Finish() error { - vendor := gitLabVendor{Name: r.config.ToolVendorName} + vendor := gitLabVendor{Name: r.config.Tool.VendorName} scanner := gitLabScanner{ - ID: r.config.ToolName, - Name: r.config.ToolName, - Version: r.config.ToolVersion, + ID: r.config.Tool.Name, + Name: r.config.Tool.Name, + Version: r.config.Tool.Version, Vendor: vendor, } diff --git a/pkg/reporter/gitlab_test.go b/pkg/reporter/gitlab_test.go index 2e7e30b..7f0c634 100644 --- a/pkg/reporter/gitlab_test.go +++ b/pkg/reporter/gitlab_test.go @@ -18,10 +18,13 @@ import ( func getGitLabReporter(reportPath string) (*gitLabReporter, error) { return NewGitLabReporter(GitLabReporterConfig{ - Path: reportPath, - ToolVersion: "1.0.0", - ToolName: "vet", - ToolVendorName: "safedep", + Path: reportPath, + Tool: ToolMetadata{ + Name: "vet", + Version: "latest", + InformationURI: "https://github.com/safedep/vet", + VendorName: "safedep", + }, }) } diff --git a/pkg/reporter/json_report.go b/pkg/reporter/json_report.go index 18a84e8..8c145c9 100644 --- a/pkg/reporter/json_report.go +++ b/pkg/reporter/json_report.go @@ -21,9 +21,8 @@ import ( ) type JsonReportingConfig struct { - Path string - ToolName string - ToolVersion string + Path string + Tool ToolMetadata } // Json reporter is built on top of summary reporter to @@ -199,8 +198,8 @@ func (r *jsonReportGenerator) Finish() error { func (r *jsonReportGenerator) buildSpecReport() (*schema.Report, error) { report := schema.Report{ Meta: &schema.ReportMeta{ - ToolName: r.config.ToolName, - ToolVersion: r.config.ToolVersion, + ToolName: r.config.Tool.Name, + ToolVersion: r.config.Tool.Version, CreatedAt: time.Now().UTC().Format(time.RFC3339), }, Packages: make([]*schema.PackageReport, 0), diff --git a/pkg/reporter/json_report_test.go b/pkg/reporter/json_report_test.go index beb3c57..9613a9c 100644 --- a/pkg/reporter/json_report_test.go +++ b/pkg/reporter/json_report_test.go @@ -99,9 +99,13 @@ func TestJsonRepoGenerator(t *testing.T) { for _, test := range cases { t.Run(test.name, func(t *testing.T) { r, err := NewJsonReportGenerator(JsonReportingConfig{ - Path: tmpFile.Name(), - ToolName: "vet", - ToolVersion: "latest", + Path: tmpFile.Name(), + Tool: ToolMetadata{ + Name: "vet", + Version: "latest", + InformationURI: "https://github.com/safedep/vet", + VendorName: "safedep", + }, }) assert.Nil(t, err) diff --git a/pkg/reporter/markdown_summary.go b/pkg/reporter/markdown_summary.go index 34d2cda..396d3d6 100644 --- a/pkg/reporter/markdown_summary.go +++ b/pkg/reporter/markdown_summary.go @@ -28,13 +28,8 @@ const ( markdownSummaryReportTitle = "vet Summary Report" ) -type MarkdownSummaryToolMetadata struct { - Name string - Version string -} - type MarkdownSummaryReporterConfig struct { - ToolMetadata MarkdownSummaryToolMetadata + Tool ToolMetadata Path string ReportTitle string IncludeMalwareAnalysis bool @@ -84,9 +79,8 @@ func NewMarkdownSummaryReporter(config MarkdownSummaryReporterConfig) (Reporter, tmpFile.Close() jsonReporter, err := NewJsonReportGenerator(JsonReportingConfig{ - Path: tmpFile.Name(), - ToolName: config.ToolMetadata.Name, - ToolVersion: config.ToolMetadata.Version, + Path: tmpFile.Name(), + Tool: config.Tool, }) if err != nil { return nil, err diff --git a/pkg/reporter/sarif.go b/pkg/reporter/sarif.go index 560569a..712d35c 100644 --- a/pkg/reporter/sarif.go +++ b/pkg/reporter/sarif.go @@ -20,14 +20,8 @@ import ( // We will not publish all package information. JSON // report should be used for that purpose. -type SarifToolMetadata struct { - Name string - Version string - InformationURI string -} - type SarifReporterConfig struct { - Tool SarifToolMetadata + Tool ToolMetadata IncludeVulns bool IncludeMalware bool Path string @@ -41,11 +35,7 @@ type sarifReporter struct { func NewSarifReporter(config SarifReporterConfig) (Reporter, error) { builder, err := newSarifBuilder( sarifBuilderConfig{ - Tool: sarifBuilderToolMetadata{ - Name: config.Tool.Name, - Version: config.Tool.Version, - InformationURI: config.Tool.InformationURI, - }, + Tool: config.Tool, IncludeVulns: config.IncludeVulns, IncludeMalware: config.IncludeMalware, }, diff --git a/pkg/reporter/sarif_builder.go b/pkg/reporter/sarif_builder.go index 1e988c3..cfce50b 100644 --- a/pkg/reporter/sarif_builder.go +++ b/pkg/reporter/sarif_builder.go @@ -13,14 +13,8 @@ import ( "github.com/safedep/vet/pkg/reporter/markdown" ) -type sarifBuilderToolMetadata struct { - Name string - Version string - InformationURI string -} - type sarifBuilderConfig struct { - Tool sarifBuilderToolMetadata + Tool ToolMetadata IncludeVulns bool IncludeMalware bool } @@ -112,7 +106,6 @@ func (b *sarifBuilder) recordFilterMatchEvent(event *analyzer.AnalyzerEvent) { b.violationsCache[uniqueInstance] = true result := sarif.NewRuleResult(event.Filter.GetName()) - result.WithLevel(sarifErrorLevel) result.WithMessage(b.buildFilterResultMessageMarkdown(event)) @@ -196,7 +189,12 @@ func (b *sarifBuilder) recordVulnerabilities(pkg *models.Package) { result := sarif.NewRuleResult(vulnId) result.WithLevel(sarifErrorLevel) - result.WithMessage(sarif.NewMessage().WithText(utils.SafelyGetValue(vuln.Summary))) + + vulnerabilitySummary := utils.SafelyGetValue(vuln.Summary) + if utils.IsEmptyString(vulnerabilitySummary) { + vulnerabilitySummary = fmt.Sprintf("Vulnerability in %s (%s)", pkg.GetName(), pkg.Ecosystem) + } + result.WithMessage(sarif.NewMessage().WithText(vulnerabilitySummary)) pLocation := sarif.NewPhysicalLocation(). WithArtifactLocation(sarif.NewSimpleArtifactLocation(pkg.Manifest.GetDisplayPath())) @@ -217,7 +215,12 @@ func (b *sarifBuilder) recordMalware(pkg *models.Package) { inference := utils.SafelyGetValue(malwareAnalysis.Report.GetInference()) result := sarif.NewRuleResult(malwareAnalysis.AnalysisId) result.WithLevel(sarifErrorLevel) - result.WithMessage(sarif.NewMessage().WithText(inference.GetSummary())) + + malwareSummary := inference.GetSummary() + if utils.IsEmptyString(malwareSummary) { + malwareSummary = fmt.Sprintf("Malicious code in %s (%s)", pkg.GetName(), pkg.Ecosystem) + } + result.WithMessage(sarif.NewMessage().WithText(malwareSummary)) pLocation := sarif.NewPhysicalLocation(). WithArtifactLocation(sarif.NewSimpleArtifactLocation(pkg.Manifest.GetDisplayPath())) diff --git a/pkg/reporter/sarif_builder_test.go b/pkg/reporter/sarif_builder_test.go index 68a250f..dc0f99f 100644 --- a/pkg/reporter/sarif_builder_test.go +++ b/pkg/reporter/sarif_builder_test.go @@ -117,6 +117,13 @@ var events []analyzer.AnalyzerEvent = []analyzer.AnalyzerEvent{ }, } +var toolMetadata = ToolMetadata{ + Name: "vet", + Version: "latest", + InformationURI: "https://github.com/safedep/vet", + VendorName: "safedep", +} + func TestSarifBuilderReport(t *testing.T) { tmpFile, err := os.CreateTemp("", "sarif-builder-test") assert.Nil(t, err) @@ -125,11 +132,7 @@ func TestSarifBuilderReport(t *testing.T) { builder, err := newSarifBuilder( sarifBuilderConfig{ - Tool: sarifBuilderToolMetadata{ - Name: "tool-name", - Version: "tool-version", - InformationURI: "https://github.com/safedep/vet", - }, + Tool: toolMetadata, }) assert.Nil(t, err) @@ -155,11 +158,7 @@ func TestSarifReportBuilderMarkdown(t *testing.T) { builder, err := newSarifBuilder( sarifBuilderConfig{ - Tool: sarifBuilderToolMetadata{ - Name: "tool-name", - Version: "tool-version", - InformationURI: "https://github.com/safedep/vet", - }, + Tool: toolMetadata, }) assert.Nil(t, err) diff --git a/pkg/reporter/sync.go b/pkg/reporter/sync.go index cd4c9cc..3171c0f 100644 --- a/pkg/reporter/sync.go +++ b/pkg/reporter/sync.go @@ -46,8 +46,7 @@ type SyncReporterConfig struct { WorkerCount int // Tool details - ToolName string - ToolVersion string + Tool ToolMetadata } type syncSession struct { @@ -161,8 +160,8 @@ func NewSyncReporter(config SyncReporterConfig, callbacks SyncReporterCallbacks) toolServiceClient := controltowerv1grpc.NewToolServiceClient(config.ClientConnection) toolSessionRes, err := toolServiceClient.CreateToolSession(context.Background(), &controltowerv1.CreateToolSessionRequest{ - ToolName: config.ToolName, - ToolVersion: config.ToolVersion, + ToolName: config.Tool.Name, + ToolVersion: config.Tool.Version, ProjectName: config.ProjectName, ProjectVersion: &config.ProjectVersion, ProjectSource: &source, @@ -214,8 +213,8 @@ func (s *syncReporter) AddManifest(manifest *models.PackageManifest) { toolServiceClient := controltowerv1grpc.NewToolServiceClient(s.client) toolSessionRes, err := toolServiceClient.CreateToolSession(context.Background(), &controltowerv1.CreateToolSessionRequest{ - ToolName: s.config.ToolName, - ToolVersion: s.config.ToolVersion, + ToolName: s.config.Tool.Name, + ToolVersion: s.config.Tool.Version, ProjectName: projectName, ProjectVersion: &projectVersion, ProjectSource: &source, diff --git a/query.go b/query.go index 3029836..f144b77 100644 --- a/query.go +++ b/query.go @@ -93,8 +93,8 @@ func newQueryCommand() *cobra.Command { cmd.Flags().IntVarP(&queryDefectDojoProductID, "defect-dojo-product-id", "", -1, "DefectDojo Product ID") cmd.Flags().StringVarP(&querySarifReportPath, "report-sarif", "", "", "Generate SARIF report to file") - cmd.Flags().BoolVarP(&querySarifIncludeVulns, "report-sarif-vulns", "", false, "Include vulnerabilities in SARIF report") - cmd.Flags().BoolVarP(&querySarifIncludeMalware, "report-sarif-malware", "", false, "Include malware in SARIF report") + cmd.Flags().BoolVarP(&querySarifIncludeVulns, "report-sarif-vulns", "", true, "Include vulnerabilities in SARIF report (Enabled by default)") + cmd.Flags().BoolVarP(&querySarifIncludeMalware, "report-sarif-malware", "", true, "Include malware in SARIF report (Enabled by default)") // Add validations that should trigger a fail fast condition cmd.PreRun = func(cmd *cobra.Command, args []string) { @@ -116,6 +116,13 @@ func startQuery() { } func internalStartQuery() error { + toolMetadata := reporter.ToolMetadata{ + Name: vetName, + Version: version, + InformationURI: vetInformationURI, + VendorName: vetVendorName, + } + readerList := []readers.PackageManifestReader{} analyzers := []analyzer.Analyzer{} reporters := []reporter.Reporter{} @@ -196,10 +203,7 @@ func internalStartQuery() error { if !utils.IsEmptyString(queryMarkdownSummaryReportPath) { rp, err := reporter.NewMarkdownSummaryReporter(reporter.MarkdownSummaryReporterConfig{ - ToolMetadata: reporter.MarkdownSummaryToolMetadata{ - Name: vetName, - Version: version, - }, + Tool: toolMetadata, Path: queryMarkdownSummaryReportPath, }) if err != nil { @@ -211,9 +215,8 @@ func internalStartQuery() error { if !utils.IsEmptyString(queryJsonReportPath) { rp, err := reporter.NewJsonReportGenerator(reporter.JsonReportingConfig{ - Path: queryJsonReportPath, - ToolName: vetName, - ToolVersion: version, + Path: queryJsonReportPath, + Tool: toolMetadata, }) if err != nil { return err @@ -244,11 +247,7 @@ func internalStartQuery() error { if !utils.IsEmptyString(querySarifReportPath) { rp, err := reporter.NewSarifReporter(reporter.SarifReporterConfig{ - Tool: reporter.SarifToolMetadata{ - Name: vetName, - Version: version, - InformationURI: vetInformationURI, - }, + Tool: toolMetadata, IncludeVulns: querySarifIncludeVulns, IncludeMalware: querySarifIncludeMalware, Path: querySarifReportPath, @@ -268,11 +267,7 @@ func internalStartQuery() error { engagementName := fmt.Sprintf("vet-report-%s", time.Now().Format("2006-01-02")) rp, err := reporter.NewDefectDojoReporter(reporter.DefectDojoReporterConfig{ - Tool: reporter.DefectDojoToolMetadata{ - Name: vetName, - Version: version, - InformationURI: vetInformationURI, - }, + Tool: toolMetadata, IncludeVulns: true, IncludeMalware: true, ProductID: queryDefectDojoProductID, diff --git a/scan.go b/scan.go index 9f85fda..3219ba3 100644 --- a/scan.go +++ b/scan.go @@ -175,8 +175,8 @@ func newScanCommand() *cobra.Command { "Generate consolidated JSON report to file (EXPERIMENTAL schema)") cmd.Flags().StringVarP(&sarifReportPath, "report-sarif", "", "", "Generate SARIF report to file (*.sarif or *.sarif.json)") - cmd.Flags().BoolVarP(&sarifIncludeVulns, "report-sarif-vulns", "", false, "Include vulnerabilities in SARIF report") - cmd.Flags().BoolVarP(&sarifIncludeMalware, "report-sarif-malware", "", false, "Include malware in SARIF report") + cmd.Flags().BoolVarP(&sarifIncludeVulns, "report-sarif-vulns", "", true, "Include vulnerabilities in SARIF report (Enabled by default)") + cmd.Flags().BoolVarP(&sarifIncludeMalware, "report-sarif-malware", "", true, "Include malware in SARIF report (Enabled by default)") cmd.Flags().StringVarP(&graphReportDirectory, "report-graph", "", "", "Generate dependency graph (if available) as dot files to directory") cmd.Flags().BoolVarP(&syncReport, "report-sync", "", false, @@ -269,6 +269,13 @@ func startScan() { } func internalStartScan() error { + toolMetadata := reporter.ToolMetadata{ + Name: vetName, + Version: version, + InformationURI: vetInformationURI, + VendorName: vetVendorName, + } + readerList := []readers.PackageManifestReader{} var reader readers.PackageManifestReader var err error @@ -438,10 +445,7 @@ func internalStartScan() error { if !utils.IsEmptyString(markdownSummaryReportPath) { rp, err := reporter.NewMarkdownSummaryReporter(reporter.MarkdownSummaryReporterConfig{ - ToolMetadata: reporter.MarkdownSummaryToolMetadata{ - Name: vetName, - Version: version, - }, + Tool: toolMetadata, Path: markdownSummaryReportPath, IncludeMalwareAnalysis: enrichMalware, }) @@ -454,9 +458,8 @@ func internalStartScan() error { if !utils.IsEmptyString(jsonReportPath) { rp, err := reporter.NewJsonReportGenerator(reporter.JsonReportingConfig{ - Path: jsonReportPath, - ToolName: vetName, - ToolVersion: version, + Path: jsonReportPath, + Tool: toolMetadata, }) if err != nil { return err @@ -467,11 +470,7 @@ func internalStartScan() error { if !utils.IsEmptyString(sarifReportPath) { rp, err := reporter.NewSarifReporter(reporter.SarifReporterConfig{ - Tool: reporter.SarifToolMetadata{ - Name: vetName, - Version: version, - InformationURI: vetInformationURI, - }, + Tool: toolMetadata, IncludeVulns: sarifIncludeVulns, IncludeMalware: sarifIncludeMalware, Path: sarifReportPath, @@ -491,13 +490,9 @@ func internalStartScan() error { engagementName := fmt.Sprintf("vet-report-%s", time.Now().Format("2006-01-02")) rp, err := reporter.NewDefectDojoReporter(reporter.DefectDojoReporterConfig{ - Tool: reporter.DefectDojoToolMetadata{ - Name: vetName, - Version: version, - InformationURI: vetInformationURI, - }, + Tool: toolMetadata, IncludeVulns: true, - IncludeMalware: enrichMalware, + IncludeMalware: true, ProductID: defectDojoProductID, EngagementName: engagementName, DefectDojoHostUrl: defectDojoHostUrl, @@ -532,10 +527,8 @@ func internalStartScan() error { if !utils.IsEmptyString(gitlabReportPath) { rp, err := reporter.NewGitLabReporter(reporter.GitLabReporterConfig{ - Path: gitlabReportPath, - ToolVersion: version, - ToolName: vetName, - ToolVendorName: vetVendorName, + Path: gitlabReportPath, + Tool: toolMetadata, }) if err != nil { return err @@ -554,8 +547,7 @@ func internalStartScan() error { } rp, err := reporter.NewSyncReporter(reporter.SyncReporterConfig{ - ToolName: vetName, - ToolVersion: version, + Tool: toolMetadata, ProjectName: syncReportProject, ProjectVersion: syncReportStream, EnableMultiProjectSync: syncEnableMultiProject,