Use common ToolMetadata for all reporters and default-enable vuln & malware in SARIF

Signed-off-by: Omkar Phansopkar <omkarphansopkar@gmail.com>
This commit is contained in:
Omkar Phansopkar 2025-04-01 21:10:45 +05:30
parent 976c5317ac
commit d7f7a6c72e
No known key found for this signature in database
GPG Key ID: 187B0ADCE943CA3D
13 changed files with 98 additions and 124 deletions

8
pkg/reporter/common.go Normal file
View File

@ -0,0 +1,8 @@
package reporter
type ToolMetadata struct {
Name string
Version string
InformationURI string
VendorName string
}

View File

@ -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,
},

View File

@ -36,9 +36,7 @@ const (
type GitLabReporterConfig struct {
Path string // Report path, value of --report-gitlab
ToolName string
ToolVersion string // Tool version, value from version.go
ToolVendorName string
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,
}

View File

@ -19,9 +19,12 @@ import (
func getGitLabReporter(reportPath string) (*gitLabReporter, error) {
return NewGitLabReporter(GitLabReporterConfig{
Path: reportPath,
ToolVersion: "1.0.0",
ToolName: "vet",
ToolVendorName: "safedep",
Tool: ToolMetadata{
Name: "vet",
Version: "latest",
InformationURI: "https://github.com/safedep/vet",
VendorName: "safedep",
},
})
}

View File

@ -22,8 +22,7 @@ import (
type JsonReportingConfig struct {
Path string
ToolName string
ToolVersion 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),

View File

@ -100,8 +100,12 @@ func TestJsonRepoGenerator(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
r, err := NewJsonReportGenerator(JsonReportingConfig{
Path: tmpFile.Name(),
ToolName: "vet",
ToolVersion: "latest",
Tool: ToolMetadata{
Name: "vet",
Version: "latest",
InformationURI: "https://github.com/safedep/vet",
VendorName: "safedep",
},
})
assert.Nil(t, err)

View File

@ -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
@ -85,8 +80,7 @@ func NewMarkdownSummaryReporter(config MarkdownSummaryReporterConfig) (Reporter,
jsonReporter, err := NewJsonReportGenerator(JsonReportingConfig{
Path: tmpFile.Name(),
ToolName: config.ToolMetadata.Name,
ToolVersion: config.ToolMetadata.Version,
Tool: config.Tool,
})
if err != nil {
return nil, err

View File

@ -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,
},

View File

@ -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()))

View File

@ -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)

View File

@ -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,

View File

@ -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 {
@ -212,8 +216,7 @@ func internalStartQuery() error {
if !utils.IsEmptyString(queryJsonReportPath) {
rp, err := reporter.NewJsonReportGenerator(reporter.JsonReportingConfig{
Path: queryJsonReportPath,
ToolName: vetName,
ToolVersion: version,
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,

40
scan.go
View File

@ -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,
})
@ -455,8 +459,7 @@ func internalStartScan() error {
if !utils.IsEmptyString(jsonReportPath) {
rp, err := reporter.NewJsonReportGenerator(reporter.JsonReportingConfig{
Path: jsonReportPath,
ToolName: vetName,
ToolVersion: version,
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,
@ -533,9 +528,7 @@ func internalStartScan() error {
if !utils.IsEmptyString(gitlabReportPath) {
rp, err := reporter.NewGitLabReporter(reporter.GitLabReporterConfig{
Path: gitlabReportPath,
ToolVersion: version,
ToolName: vetName,
ToolVendorName: vetVendorName,
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,