Repository: safedep/vet
Pull request #441 (2025-03-31 15:31:18)

Added vulnerabilities & malware in SARIF reports
Use flags -
```bash
--report-sarif $SAMPLE_OUTNAME.sarif.json --report-sarif-vulns --report-sarif-malware
```

Sample -
[vet-rakshak.sarif.json](https://github.com/user-attachments/files/19561722/vet-rakshak.sarif.json)



Patch:
diff --git a/internal/auth/auth.go b/internal/auth/auth.go
index b7221d2..19eaf12 100644
--- a/internal/auth/auth.go
+++ b/internal/auth/auth.go
@@ -322,5 +322,5 @@ func persistConfiguration() error {
 	path = filepath.Join(path, homeRelativeConfigPath)
 
 	os.MkdirAll(filepath.Dir(path), os.ModePerm)
-	return os.WriteFile(path, data, 0600)
+	return os.WriteFile(path, data, 0o600)
 }
diff --git a/internal/connect/connect.go b/internal/connect/connect.go
index d0d7775..914babc 100644
--- a/internal/connect/connect.go
+++ b/internal/connect/connect.go
@@ -2,7 +2,6 @@ package connect
 
 import (
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"sync"
@@ -21,8 +20,10 @@ type Config struct {
 
 type ConfigUpdaterFn func(*Config)
 
-var globalConfig *Config
-var globalConfigUpdaterMutex sync.Mutex
+var (
+	globalConfig             *Config
+	globalConfigUpdaterMutex sync.Mutex
+)
 
 func init() {
 	err := loadConfiguration()
@@ -54,7 +55,7 @@ func loadConfiguration() error {
 
 	path = filepath.Join(path, homeRelativeConfigPath)
 
-	data, err := ioutil.ReadFile(path)
+	data, err := os.ReadFile(path)
 	if err != nil {
 		return err
 	}
@@ -87,5 +88,5 @@ func persistConfiguration() error {
 		logger.Debugf("Error while creatinng directory %s %v", filepath.Dir(path), err)
 	}
 
-	return ioutil.WriteFile(path, data, 0600)
+	return os.WriteFile(path, data, 0o600)
 }
diff --git a/main.go b/main.go
index 071d214..f0f5090 100644
--- a/main.go
+++ b/main.go
@@ -25,7 +25,13 @@ var (
 	globalExceptionsExtra []string
 )
 
-var banner string = `
+const (
+	vetName           = "vet"
+	vetVendorName     = "safedep"
+	vetInformationURI = "https://github.com/safedep/vet"
+)
+
+const banner string = `
 Yb    dP 888888 888888
  Yb  dP  88__     88
   YbdP   88""     88
diff --git a/pkg/analyzer/json_dump.go b/pkg/analyzer/json_dump.go
index acb6d80..f4b789c 100644
--- a/pkg/analyzer/json_dump.go
+++ b/pkg/analyzer/json_dump.go
@@ -39,8 +39,8 @@ func (j *jsonDumperAnalyzer) Name() string {
 }
 
 func (j *jsonDumperAnalyzer) Analyze(manifest *models.PackageManifest,
-	handler AnalyzerEventHandler) error {
-
+	handler AnalyzerEventHandler,
+) error {
 	logger.Infof("Running analyzer: %s", j.Name())
 	data, err := json.MarshalIndent(manifest, "", "  ")
 	if err != nil {
@@ -53,7 +53,7 @@ func (j *jsonDumperAnalyzer) Analyze(manifest *models.PackageManifest,
 		filepath.Base(manifest.Path),
 		randomSource.Int63()))
 
-	return os.WriteFile(path, data, 0600)
+	return os.WriteFile(path, data, 0o600)
 }
 
 func (j *jsonDumperAnalyzer) Finish() error {
diff --git a/pkg/analyzer/malware.go b/pkg/analyzer/malware.go
index b9de232..a068ff0 100644
--- a/pkg/analyzer/malware.go
+++ b/pkg/analyzer/malware.go
@@ -98,7 +98,7 @@ func (a *malwareAnalyzer) Analyze(manifest *models.PackageManifest,
 			Filter: &filtersuite.Filter{
 				Name:        "malware",
 				CheckType:   checks.CheckType_CheckTypeMalware,
-				Summary:     filterMsg,
+				Summary:     fmt.Sprintf("Malicious (malware) component detected by %s", a.Name()),
 				Description: fmt.Sprintf("%s analyzed the package for possible malicious behavior", a.Name()),
 				References:  []string{"https://docs.safedep.io/cloud/malware-analysis"},
 				Tags:        []string{"malware-analysis"},
diff --git a/pkg/common/logger/logger.go b/pkg/common/logger/logger.go
index 9d59a07..0bf3398 100644
--- a/pkg/common/logger/logger.go
+++ b/pkg/common/logger/logger.go
@@ -35,7 +35,7 @@ func getLogLevelFromEnv() logrus.Level {
 }
 
 func LogToFile(path string) {
-	file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600)
+	file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o600)
 	if err != nil {
 		panic(err)
 	}
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 a124a75..04de91d 100644
--- a/pkg/reporter/defect_dojo.go
+++ b/pkg/reporter/defect_dojo.go
@@ -26,13 +26,10 @@ type DefectDojoProduct struct {
 	Created       time.Time `json:"created"`
 }
 
-type DefectDojoToolMetadata struct {
-	Name    string
-	Version string
-}
-
 type DefectDojoReporterConfig struct {
-	Tool               DefectDojoToolMetadata
+	Tool               ToolMetadata
+	IncludeVulns       bool
+	IncludeMalware     bool
 	ProductID          int
 	EngagementName     string
 	DefectDojoHostUrl  string
@@ -51,9 +48,10 @@ func NewDefectDojoReporter(config DefectDojoReporterConfig) (Reporter, error) {
 		SetBaseURL(config.DefectDojoHostUrl)
 
 	builder, err := newSarifBuilder(
-		sarifBuilderToolMetadata{
-			Name:    config.Tool.Name,
-			Version: config.Tool.Version,
+		sarifBuilderConfig{
+			Tool:           config.Tool,
+			IncludeVulns:   config.IncludeVulns,
+			IncludeMalware: config.IncludeMalware,
 		},
 	)
 	if err != nil {
diff --git a/pkg/reporter/gitlab.go b/pkg/reporter/gitlab.go
index cf5fb5e..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
@@ -282,20 +280,20 @@ func (r *gitLabReporter) AddManifest(manifest *models.PackageManifest) {
 
 		// Convert each vulnerability to GitLab format
 		vulns := utils.SafelyGetValue(pkg.Insights.Vulnerabilities)
-		for i := range vulns {
+		for _, vuln := range vulns {
 			// Map severity
 			severity := SeverityUnknown
-			severities := utils.SafelyGetValue(vulns[i].Severities)
+			severities := utils.SafelyGetValue(vuln.Severities)
 			if len(severities) > 0 {
 				risk := utils.SafelyGetValue(severities[0].Risk)
 				severity = r.getVulnerabilitySeverity(risk)
 			}
 
-			summary := utils.SafelyGetValue(vulns[i].Summary)
+			summary := utils.SafelyGetValue(vuln.Summary)
 
 			// Create GitLab vulnerability entry
 			glVuln := gitLabVulnerability{
-				ID:          utils.SafelyGetValue(vulns[i].Id),
+				ID:          utils.SafelyGetValue(vuln.Id),
 				Name:        summary,
 				Description: r.getGitLabVulnerabilityDescription(pkg, summary),
 				Severity:    severity,
@@ -304,7 +302,7 @@ func (r *gitLabReporter) AddManifest(manifest *models.PackageManifest) {
 			}
 
 			// Add all relevant identifiers
-			r.gitlabAddVulnerabilityIdentifiers(&glVuln, &vulns[i])
+			r.gitlabAddVulnerabilityIdentifiers(&glVuln, &vuln)
 
 			r.vulnerabilities = append(r.vulnerabilities, glVuln)
 		}
@@ -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/json_report.go b/pkg/reporter/json_report.go
index 349a97f..8c145c9 100644
--- a/pkg/reporter/json_report.go
+++ b/pkg/reporter/json_report.go
@@ -22,6 +22,7 @@ import (
 
 type JsonReportingConfig struct {
 	Path string
+	Tool ToolMetadata
 }
 
 // Json reporter is built on top of summary reporter to
@@ -61,7 +62,6 @@ func (r *jsonReportGenerator) AddManifest(manifest *models.PackageManifest) {
 
 		return nil
 	})
-
 	if err != nil {
 		logger.Warnf("Failed to enumerate manifest packages: %v", err)
 	}
@@ -97,7 +97,6 @@ func (r *jsonReportGenerator) handleThreatEvent(event *analyzer.AnalyzerEvent) {
 		pkg := r.findPackageReport(event.Package)
 		pkg.Threats = append(pkg.Threats, event.Threat)
 	}
-
 }
 
 func (r *jsonReportGenerator) handleFilterEvent(event *analyzer.AnalyzerEvent) {
@@ -199,8 +198,8 @@ func (r *jsonReportGenerator) Finish() error {
 func (r *jsonReportGenerator) buildSpecReport() (*schema.Report, error) {
 	report := schema.Report{
 		Meta: &schema.ReportMeta{
-			ToolName:    "vet",
-			ToolVersion: "latest",
+			ToolName:    r.config.Tool.Name,
+			ToolVersion: r.config.Tool.Version,
 			CreatedAt:   time.Now().UTC().Format(time.RFC3339),
 		},
 		Packages:  make([]*schema.PackageReport, 0),
@@ -248,7 +247,6 @@ func (j *jsonReportGenerator) buildJsonPackageReportFromPackage(p *models.Packag
 				Risk:  sev.Risk,
 				Score: sev.Score,
 			})
-
 			if err != nil {
 				logger.Errorf("Failed to convert InsightAPI schema to model spec: %v", err)
 				continue
diff --git a/pkg/reporter/markdown_summary.go b/pkg/reporter/markdown_summary.go
index d93933f..396d3d6 100644
--- a/pkg/reporter/markdown_summary.go
+++ b/pkg/reporter/markdown_summary.go
@@ -29,6 +29,7 @@ const (
 )
 
 type MarkdownSummaryReporterConfig struct {
+	Tool                   ToolMetadata
 	Path                   string
 	ReportTitle            string
 	IncludeMalwareAnalysis bool
@@ -79,8 +80,8 @@ func NewMarkdownSummaryReporter(config MarkdownSummaryReporterConfig) (Reporter,
 
 	jsonReporter, err := NewJsonReportGenerator(JsonReportingConfig{
 		Path: tmpFile.Name(),
+		Tool: config.Tool,
 	})
-
 	if err != nil {
 		return nil, err
 	}
@@ -115,7 +116,6 @@ func (r *markdownSummaryReporter) AddManifest(manifest *models.PackageManifest)
 
 		return nil
 	})
-
 	if err != nil {
 		logger.Errorf("[Markdown Reporter]: Failed to enumerate packages in manifest %s: %v",
 			manifest.GetPath(), err)
@@ -158,7 +158,7 @@ func (r *markdownSummaryReporter) Finish() error {
 		return fmt.Errorf("failed to build markdown report: %w", err)
 	}
 
-	err = os.WriteFile(r.config.Path, []byte(builder.Build()), 0600)
+	err = os.WriteFile(r.config.Path, []byte(builder.Build()), 0o600)
 	if err != nil {
 		return fmt.Errorf("failed to write markdown summary to file: %w", err)
 	}
@@ -167,7 +167,8 @@ func (r *markdownSummaryReporter) Finish() error {
 }
 
 func (r *markdownSummaryReporter) buildMarkdownReport(builder *markdown.MarkdownBuilder,
-	report *jsonreportspec.Report) error {
+	report *jsonreportspec.Report,
+) error {
 	internalModel, err := r.buildInternalModel(report)
 	if err != nil {
 		return fmt.Errorf("failed to build internal data model: %w", err)
@@ -240,8 +241,7 @@ func (r *markdownSummaryReporter) buildInternalModel(report *jsonreportspec.Repo
 				internalModel.violations[violation.GetCheckType()] = make([]*violations.Violation, 0)
 			}
 
-			internalModel.violations[violation.GetCheckType()] =
-				append(internalModel.violations[violation.GetCheckType()], violation)
+			internalModel.violations[violation.GetCheckType()] = append(internalModel.violations[violation.GetCheckType()], violation)
 		}
 
 		appendThreats(pkg.GetThreats())
@@ -251,7 +251,8 @@ func (r *markdownSummaryReporter) buildInternalModel(report *jsonreportspec.Repo
 }
 
 func (r *markdownSummaryReporter) addPolicyCheckSection(builder *markdown.MarkdownBuilder,
-	internalModel *vetResultInternalModel) error {
+	internalModel *vetResultInternalModel,
+) error {
 	builder.AddHeader(2, "Policy Checks")
 
 	builder.AddBulletPoint(fmt.Sprintf("%s Vulnerability",
@@ -273,7 +274,8 @@ func (r *markdownSummaryReporter) addPolicyCheckSection(builder *markdown.Markdo
 }
 
 func (r *markdownSummaryReporter) addThreatsSection(builder *markdown.MarkdownBuilder,
-	internalModel *vetResultInternalModel) error {
+	internalModel *vetResultInternalModel,
+) error {
 	if len(internalModel.threats) == 0 {
 		return nil
 	}
@@ -321,7 +323,8 @@ func (r *markdownSummaryReporter) addThreatsSection(builder *markdown.MarkdownBu
 }
 
 func (r *markdownSummaryReporter) addChangedPackageSection(builder *markdown.MarkdownBuilder,
-	internalModel *vetResultInternalModel) error {
+	internalModel *vetResultInternalModel,
+) error {
 	if len(internalModel.packages) == 0 {
 		return nil
 	}
@@ -351,8 +354,8 @@ func (r *markdownSummaryReporter) addChangedPackageSection(builder *markdown.Mar
 }
 
 func (r *markdownSummaryReporter) addViolationSection(builder *markdown.MarkdownBuilder,
-	internalModel *vetResultInternalModel) error {
-
+	internalModel *vetResultInternalModel,
+) error {
 	section := builder.StartCollapsibleSection("Policy Violations")
 	section.Builder().AddHeader(2, "Packages Violating Policy")
 
@@ -455,7 +458,8 @@ func (r *markdownSummaryReporter) addMalwareAnalysisReportSection(builder *markd
 }
 
 func (r *markdownSummaryReporter) getCheckIconByCheckType(internalModel *vetResultInternalModel,
-	ct checks.CheckType) string {
+	ct checks.CheckType,
+) string {
 	if _, ok := internalModel.violations[ct]; !ok {
 		return markdown.EmojiWhiteCheckMark
 	} else {
diff --git a/pkg/reporter/sarif.go b/pkg/reporter/sarif.go
index 86aa7a1..712d35c 100644
--- a/pkg/reporter/sarif.go
+++ b/pkg/reporter/sarif.go
@@ -20,14 +20,11 @@ import (
 // We will not publish all package information. JSON
 // report should be used for that purpose.
 
-type SarifToolMetadata struct {
-	Name    string
-	Version string
-}
-
 type SarifReporterConfig struct {
-	Tool SarifToolMetadata
-	Path string
+	Tool           ToolMetadata
+	IncludeVulns   bool
+	IncludeMalware bool
+	Path           string
 }
 
 type sarifReporter struct {
@@ -37,9 +34,10 @@ type sarifReporter struct {
 
 func NewSarifReporter(config SarifReporterConfig) (Reporter, error) {
 	builder, err := newSarifBuilder(
-		sarifBuilderToolMetadata{
-			Name:    config.Tool.Name,
-			Version: config.Tool.Version,
+		sarifBuilderConfig{
+			Tool:           config.Tool,
+			IncludeVulns:   config.IncludeVulns,
+			IncludeMalware: config.IncludeMalware,
 		},
 	)
 	if err != nil {
diff --git a/pkg/reporter/sarif_builder.go b/pkg/reporter/sarif_builder.go
index 1b6088b..645d7f8 100644
--- a/pkg/reporter/sarif_builder.go
+++ b/pkg/reporter/sarif_builder.go
@@ -13,37 +13,44 @@ import (
 	"github.com/safedep/vet/pkg/reporter/markdown"
 )
 
-type sarifBuilderToolMetadata struct {
-	Name    string
-	Version string
+type sarifBuilderConfig struct {
+	Tool           ToolMetadata
+	IncludeVulns   bool
+	IncludeMalware bool
 }
 
 type sarifBuilder struct {
+	config          sarifBuilderConfig
 	report          *sarif.Report
 	run             *sarif.Run
 	rulesCache      map[string]bool
 	violationsCache map[string]bool
+	vulnCache       map[string]bool
 }
 
-func newSarifBuilder(toolMetadata sarifBuilderToolMetadata) (*sarifBuilder, error) {
+const sarifErrorLevel = "error"
+
+func newSarifBuilder(config sarifBuilderConfig) (*sarifBuilder, error) {
 	report, err := sarif.New(sarif.Version210)
 	if err != nil {
 		return nil, err
 	}
 
-	run := sarif.NewRunWithInformationURI(toolMetadata.Name,
-		"https://github.com/safedep/vet")
+	run := sarif.NewRunWithInformationURI(config.Tool.Name,
+		config.Tool.InformationURI)
 
-	run.Tool.Driver.Version = &toolMetadata.Version
+	run.Tool.Driver.Version = &config.Tool.Version
 	run.Tool.Driver.Properties = sarif.Properties{
-		"name":    toolMetadata.Name,
-		"version": toolMetadata.Version,
+		"name":    config.Tool.Name,
+		"version": config.Tool.Version,
 	}
 
 	return &sarifBuilder{
 		report:          report,
 		run:             run,
+		config:          config,
 		rulesCache:      make(map[string]bool),
+		vulnCache:       make(map[string]bool),
 		violationsCache: make(map[string]bool),
 	}, nil
 }
@@ -52,6 +59,16 @@ func (b *sarifBuilder) AddManifest(manifest *models.PackageManifest) {
 	a := sarif.NewArtifact().
 		WithLocation(sarif.NewSimpleArtifactLocation(manifest.GetDisplayPath()))
 	b.run.Artifacts = append(b.run.Artifacts, a)
+
+	for _, pkg := range manifest.GetPackages() {
+		if b.config.IncludeVulns {
+			b.recordVulnerabilities(pkg)
+		}
+
+		if b.config.IncludeMalware {
+			b.recordMalware(pkg)
+		}
+	}
 }
 
 func (b *sarifBuilder) AddAnalyzerEvent(event *analyzer.AnalyzerEvent) {
@@ -103,8 +120,7 @@ func (b *sarifBuilder) recordFilterMatchEvent(event *analyzer.AnalyzerEvent) {
 	b.violationsCache[uniqueInstance] = true
 
 	result := sarif.NewRuleResult(event.Filter.GetName())
-
-	result.WithLevel("error")
+	result.WithLevel(sarifErrorLevel)
 	result.WithMessage(b.buildFilterResultMessageMarkdown(event))
 
 	pLocation := sarif.NewPhysicalLocation().
@@ -166,3 +182,64 @@ func (b *sarifBuilder) buildFilterResultMessageMarkdown(event *analyzer.Analyzer
 
 	return msg
 }
+
+func (b *sarifBuilder) recordVulnerabilities(pkg *models.Package) {
+	if pkg.Insights == nil {
+		return
+	}
+
+	vulns := utils.SafelyGetValue(pkg.Insights.Vulnerabilities)
+	if len(vulns) == 0 {
+		return
+	}
+
+	for _, vuln := range vulns {
+		vulnId := utils.SafelyGetValue(vuln.Id)
+		if _, ok := b.vulnCache[vulnId]; ok {
+			continue
+		}
+
+		b.vulnCache[vulnId] = true
+
+		result := sarif.NewRuleResult(vulnId)
+		result.WithLevel(sarifErrorLevel)
+
+		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()))
+		result.Locations = append(result.Locations, sarif.NewLocation().WithPhysicalLocation(pLocation))
+
+		b.run.AddResult(result)
+	}
+}
+
+func (b *sarifBuilder) recordMalware(pkg *models.Package) {
+	if pkg.MalwareAnalysis == nil {
+		return
+	}
+
+	malwareAnalysis := utils.SafelyGetValue(pkg.MalwareAnalysis)
+
+	if malwareAnalysis.IsMalware {
+		inference := utils.SafelyGetValue(malwareAnalysis.Report.GetInference())
+		result := sarif.NewRuleResult(malwareAnalysis.AnalysisId)
+		result.WithLevel(sarifErrorLevel)
+
+		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()))
+		result.Locations = append(result.Locations, sarif.NewLocation().WithPhysicalLocation(pLocation))
+
+		b.run.AddResult(result)
+	}
+}
diff --git a/pkg/reporter/sync.go b/pkg/reporter/sync.go
index 9ca236d..3171c0f 100644
--- a/pkg/reporter/sync.go
+++ b/pkg/reporter/sync.go
@@ -21,11 +21,7 @@ import (
 	"google.golang.org/grpc"
 )
 
-const (
-	syncReporterDefaultWorkerCount = 10
-	syncReporterMaxRetries         = 3
-	syncReporterToolName           = "vet"
-)
+const syncReporterDefaultWorkerCount = 10
 
 type SyncReporterConfig struct {
 	// gRPC connection for ControlTower
@@ -50,8 +46,7 @@ type SyncReporterConfig struct {
 	WorkerCount int
 
 	// Tool details
-	ToolName    string
-	ToolVersion string
+	Tool ToolMetadata
 }
 
 type syncSession struct {
@@ -165,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,
@@ -218,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 6c90fd4..f144b77 100644
--- a/query.go
+++ b/query.go
@@ -33,6 +33,8 @@ var (
 	queryDefectDojoHostUrl              string
 	queryDefectDojoProductID            int
 	querySarifReportPath                string
+	querySarifIncludeVulns              bool
+	querySarifIncludeMalware            bool
 	queryExceptionsFile                 string
 	queryExceptionsTill                 string
 	queryExceptionsFilter               string
@@ -91,6 +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", "", 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) {
@@ -112,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{}
@@ -192,6 +203,7 @@ func internalStartQuery() error {
 
 	if !utils.IsEmptyString(queryMarkdownSummaryReportPath) {
 		rp, err := reporter.NewMarkdownSummaryReporter(reporter.MarkdownSummaryReporterConfig{
+			Tool: toolMetadata,
 			Path: queryMarkdownSummaryReportPath,
 		})
 		if err != nil {
@@ -204,6 +216,7 @@ func internalStartQuery() error {
 	if !utils.IsEmptyString(queryJsonReportPath) {
 		rp, err := reporter.NewJsonReportGenerator(reporter.JsonReportingConfig{
 			Path: queryJsonReportPath,
+			Tool: toolMetadata,
 		})
 		if err != nil {
 			return err
@@ -234,11 +247,10 @@ func internalStartQuery() error {
 
 	if !utils.IsEmptyString(querySarifReportPath) {
 		rp, err := reporter.NewSarifReporter(reporter.SarifReporterConfig{
-			Path: querySarifReportPath,
-			Tool: reporter.SarifToolMetadata{
-				Name:    "vet",
-				Version: version,
-			},
+			Tool:           toolMetadata,
+			IncludeVulns:   querySarifIncludeVulns,
+			IncludeMalware: querySarifIncludeMalware,
+			Path:           querySarifReportPath,
 		})
 		if err != nil {
 			return err
@@ -255,10 +267,9 @@ 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:    "vet",
-				Version: version,
-			},
+			Tool:               toolMetadata,
+			IncludeVulns:       true,
+			IncludeMalware:     true,
 			ProductID:          queryDefectDojoProductID,
 			EngagementName:     engagementName,
 			DefectDojoHostUrl:  queryDefectDojoHostUrl,
diff --git a/scan.go b/scan.go
index eef8c6b..3219ba3 100644
--- a/scan.go
+++ b/scan.go
@@ -63,6 +63,8 @@ var (
 	defectDojoHostUrl                string
 	defectDojoProductID              int
 	sarifReportPath                  string
+	sarifIncludeVulns                bool
+	sarifIncludeMalware              bool
 	silentScan                       bool
 	disableAuthVerifyBeforeScan      bool
 	syncReport                       bool
@@ -77,7 +79,7 @@ var (
 	malwareAnalyzerTrustToolResult   bool
 	malwareAnalysisTimeout           time.Duration
 	malwareAnalysisMinimumConfidence string
-  gitlabReportPath                 string
+	gitlabReportPath                 string
 )
 
 func newScanCommand() *cobra.Command {
@@ -172,7 +174,9 @@ func newScanCommand() *cobra.Command {
 	cmd.Flags().StringVarP(&jsonReportPath, "report-json", "", "",
 		"Generate consolidated JSON report to file (EXPERIMENTAL schema)")
 	cmd.Flags().StringVarP(&sarifReportPath, "report-sarif", "", "",
-		"Generate SARIF report to file")
+		"Generate SARIF report to file (*.sarif or *.sarif.json)")
+	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,
@@ -265,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
@@ -434,6 +445,7 @@ func internalStartScan() error {
 
 	if !utils.IsEmptyString(markdownSummaryReportPath) {
 		rp, err := reporter.NewMarkdownSummaryReporter(reporter.MarkdownSummaryReporterConfig{
+			Tool:                   toolMetadata,
 			Path:                   markdownSummaryReportPath,
 			IncludeMalwareAnalysis: enrichMalware,
 		})
@@ -447,6 +459,7 @@ func internalStartScan() error {
 	if !utils.IsEmptyString(jsonReportPath) {
 		rp, err := reporter.NewJsonReportGenerator(reporter.JsonReportingConfig{
 			Path: jsonReportPath,
+			Tool: toolMetadata,
 		})
 		if err != nil {
 			return err
@@ -457,11 +470,10 @@ func internalStartScan() error {
 
 	if !utils.IsEmptyString(sarifReportPath) {
 		rp, err := reporter.NewSarifReporter(reporter.SarifReporterConfig{
-			Tool: reporter.SarifToolMetadata{
-				Name:    "vet",
-				Version: version,
-			},
-			Path: sarifReportPath,
+			Tool:           toolMetadata,
+			IncludeVulns:   sarifIncludeVulns,
+			IncludeMalware: sarifIncludeMalware,
+			Path:           sarifReportPath,
 		})
 		if err != nil {
 			return err
@@ -478,10 +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:    "vet",
-				Version: version,
-			},
+			Tool:               toolMetadata,
+			IncludeVulns:       true,
+			IncludeMalware:     true,
 			ProductID:          defectDojoProductID,
 			EngagementName:     engagementName,
 			DefectDojoHostUrl:  defectDojoHostUrl,
@@ -516,10 +527,8 @@ func internalStartScan() error {
 
 	if !utils.IsEmptyString(gitlabReportPath) {
 		rp, err := reporter.NewGitLabReporter(reporter.GitLabReporterConfig{
-			Path:           gitlabReportPath,
-			ToolVersion:    version,
-			ToolName:       "vet",
-			ToolVendorName: "safedep",
+			Path: gitlabReportPath,
+			Tool: toolMetadata,
 		})
 		if err != nil {
 			return err
@@ -538,8 +547,7 @@ func internalStartScan() error {
 		}
 
 		rp, err := reporter.NewSyncReporter(reporter.SyncReporterConfig{
-			ToolName:               "vet",
-			ToolVersion:            version,
+			Tool:                   toolMetadata,
 			ProjectName:            syncReportProject,
 			ProjectVersion:         syncReportStream,
 			EnableMultiProjectSync: syncEnableMultiProject,


Test patch:
diff --git a/pkg/common/utils/file_test.go b/pkg/common/utils/file_test.go
index f254619..c89a660 100644
--- a/pkg/common/utils/file_test.go
+++ b/pkg/common/utils/file_test.go
@@ -2,7 +2,7 @@ package utils
 
 import (
 	"bytes"
-	"io/ioutil"
+	"io"
 	"os"
 	"testing"
 
@@ -31,7 +31,7 @@ func TestCreateEmptyTempFile(t *testing.T) {
 
 func TestCopyToTempFile(t *testing.T) {
 	srcContent := []byte("Hello, this is the source content")
-	src := ioutil.NopCloser(bytes.NewReader(srcContent))
+	src := io.NopCloser(bytes.NewReader(srcContent))
 	dir := os.TempDir()
 	pattern := "temp-file-test-"
 
@@ -41,7 +41,7 @@ func TestCopyToTempFile(t *testing.T) {
 
 	assert.FileExists(t, file.Name())
 
-	fileContent, err := ioutil.ReadFile(file.Name())
+	fileContent, err := os.ReadFile(file.Name())
 	assert.NoError(t, err)
 	assert.Equal(t, srcContent, fileContent)
 }
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_test.go b/pkg/reporter/json_report_test.go
index 0caf0ab..9613a9c 100644
--- a/pkg/reporter/json_report_test.go
+++ b/pkg/reporter/json_report_test.go
@@ -100,6 +100,12 @@ func TestJsonRepoGenerator(t *testing.T) {
 		t.Run(test.name, func(t *testing.T) {
 			r, err := NewJsonReportGenerator(JsonReportingConfig{
 				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/sarif_builder_test.go b/pkg/reporter/sarif_builder_test.go
index d4de6dd..dc0f99f 100644
--- a/pkg/reporter/sarif_builder_test.go
+++ b/pkg/reporter/sarif_builder_test.go
@@ -117,16 +117,23 @@ 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)
 
 	defer os.Remove(tmpFile.Name())
 
-	builder, err := newSarifBuilder(sarifBuilderToolMetadata{
-		Name:    "tool-name",
-		Version: "tool-version",
-	})
+	builder, err := newSarifBuilder(
+		sarifBuilderConfig{
+			Tool: toolMetadata,
+		})
 	assert.Nil(t, err)
 
 	for _, event := range events {
@@ -149,10 +156,10 @@ func TestSarifReportBuilderMarkdown(t *testing.T) {
 
 	defer os.Remove(tmpFile.Name())
 
-	builder, err := newSarifBuilder(sarifBuilderToolMetadata{
-		Name:    "tool-name",
-		Version: "tool-version",
-	})
+	builder, err := newSarifBuilder(
+		sarifBuilderConfig{
+			Tool: toolMetadata,
+		})
 	assert.Nil(t, err)
 
 	for _, event := range events {