Skip to content

Commit 03ee599

Browse files
authored
fix(vulnfeeds): metrics being global causing concurrency issues (#4051)
Breaking #3951 into smaller PRs. Metrics being global caused some concurrency issues in the output of the metrics file.
1 parent 3fcf900 commit 03ee599

File tree

2 files changed

+20
-19
lines changed

2 files changed

+20
-19
lines changed

vulnfeeds/cmd/cvelist2osv/converter.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ const (
2121
extension = ".json"
2222
)
2323

24-
// Metrics holds the collected data about the conversion process for a single CVE.
25-
var Metrics struct {
24+
// ConversionMetrics holds the collected data about the conversion process for a single CVE.
25+
type ConversionMetrics struct {
2626
CNA string `json:"cna"` // The CNA that assigned the CVE.
2727
Outcome string `json:"outcome"` // The final outcome of the conversion (e.g., "Successful", "Failed").
2828
Repos []string `json:"repos"` // A list of repositories extracted from the CVE's references.
@@ -41,21 +41,21 @@ var RefTagDenyList = []string{
4141
}
4242

4343
// extractConversionMetrics examines a CVE and its generated OSV references to populate
44-
// the global Metrics struct with heuristics about the conversion process.
44+
// the ConversionMetrics struct with heuristics about the conversion process.
4545
// It captures the assigning CNA and counts the occurrences of each reference type.
46-
func extractConversionMetrics(cve cves.CVE5, refs []osvschema.Reference) {
46+
func extractConversionMetrics(cve cves.CVE5, refs []osvschema.Reference, metrics *ConversionMetrics) {
4747
// Capture the CNA for heuristic analysis.
48-
Metrics.CNA = cve.Metadata.AssignerShortName
48+
metrics.CNA = cve.Metadata.AssignerShortName
4949
// TODO(jesslowe): more CNA based analysis
5050

5151
// Count number of references of each type
5252
refTypeCounts := make(map[osvschema.ReferenceType]int)
5353
for _, ref := range refs {
5454
refTypeCounts[ref.Type]++
5555
}
56-
Metrics.RefTypesCount = refTypeCounts
56+
metrics.RefTypesCount = refTypeCounts
5757
for refType, count := range refTypeCounts {
58-
Metrics.Notes = append(Metrics.Notes, fmt.Sprintf("[%s]: Reference Type %s: %d", cve.Metadata.CVEID, refType, count))
58+
metrics.Notes = append(metrics.Notes, fmt.Sprintf("[%s]: Reference Type %s: %d", cve.Metadata.CVEID, refType, count))
5959
}
6060

6161
// TODO(jesslowe): Add more analysis based on ADP containers, CVSS, KEV, CWE, etc.
@@ -64,7 +64,7 @@ func extractConversionMetrics(cve cves.CVE5, refs []osvschema.Reference) {
6464
// FromCVE5 creates a `vulns.Vulnerability` object from a `cves.CVE5` object.
6565
// It populates the main fields of the OSV record, including ID, summary, details,
6666
// references, timestamps, severity, and version information.
67-
func FromCVE5(cve cves.CVE5, refs []cves.Reference) (*vulns.Vulnerability, []string) {
67+
func FromCVE5(cve cves.CVE5, refs []cves.Reference, metrics *ConversionMetrics) (*vulns.Vulnerability, []string) {
6868
aliases, related := vulns.ExtractReferencedVulns(cve.Metadata.CVEID, cve.Metadata.CVEID, refs)
6969
var notes []string
7070
v := vulns.Vulnerability{
@@ -95,7 +95,7 @@ func FromCVE5(cve cves.CVE5, refs []cves.Reference) (*vulns.Vulnerability, []str
9595
// Add affected version information.
9696
versionSources, versNotes := AddVersionInfo(cve, &v)
9797
notes = append(notes, versNotes...)
98-
Metrics.VersionSources = versionSources
98+
metrics.VersionSources = versionSources
9999
// TODO(jesslowe@): Add CWEs.
100100

101101
// Combine severity metrics from both CNA and ADP containers.
@@ -147,9 +147,9 @@ func writeOSVToFile(id cves.CVEID, cnaAssigner string, vulnDir string, v *vulns.
147147
// writeMetricToFile saves the collected conversion metrics to a JSON file.
148148
// This file provides data for analyzing the success and characteristics of the
149149
// conversion process for a given CVE.
150-
func writeMetricToFile(id cves.CVEID, vulnDir string) error {
150+
func writeMetricToFile(id cves.CVEID, vulnDir string, metrics *ConversionMetrics) error {
151151
metricsFile := filepath.Join(vulnDir, string(id)+".metrics.json")
152-
marshalledMetrics, err := json.MarshalIndent(Metrics, "", " ")
152+
marshalledMetrics, err := json.MarshalIndent(metrics, "", " ")
153153
if err != nil {
154154
logger.Warn("Failed to marshal metrics for "+string(id), slog.String("cve", string(id)), slog.Any("err", err))
155155
return err
@@ -168,18 +168,18 @@ func ConvertAndExportCVEToOSV(cve cves.CVE5, directory string) error {
168168
cveID := cve.Metadata.CVEID
169169
cnaAssigner := cve.Metadata.AssignerShortName
170170
references := identifyPossibleURLs(cve)
171-
171+
metrics := &ConversionMetrics{}
172172
// Create a base OSV record from the CVE.
173-
v, notes := FromCVE5(cve, references)
174-
Metrics.Notes = append(Metrics.Notes, notes...)
173+
v, notes := FromCVE5(cve, references, metrics)
174+
metrics.Notes = append(metrics.Notes, notes...)
175175

176176
// Collect metrics about the conversion.
177-
extractConversionMetrics(cve, v.References)
177+
extractConversionMetrics(cve, v.References, metrics)
178178

179179
// Try to extract repository URLs from references.
180180
repos, repoNotes := cves.ReposFromReferencesCVEList(string(cveID), references, RefTagDenyList)
181-
Metrics.Notes = append(Metrics.Notes, repoNotes...)
182-
Metrics.Repos = repos
181+
metrics.Notes = append(metrics.Notes, repoNotes...)
182+
metrics.Repos = repos
183183

184184
vulnDir := filepath.Join(directory, cnaAssigner)
185185

@@ -189,7 +189,7 @@ func ConvertAndExportCVEToOSV(cve cves.CVE5, directory string) error {
189189
}
190190

191191
// Save the conversion metrics to a file.
192-
if err := writeMetricToFile(cveID, vulnDir); err != nil {
192+
if err := writeMetricToFile(cveID, vulnDir, metrics); err != nil {
193193
return err
194194
}
195195

vulnfeeds/cmd/cvelist2osv/converter_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,8 @@ func TestFromCVE5(t *testing.T) {
352352

353353
for _, tc := range testCases {
354354
t.Run(tc.name, func(t *testing.T) {
355-
vuln, _ := FromCVE5(tc.cve, tc.refs)
355+
metrics := &ConversionMetrics{}
356+
vuln, _ := FromCVE5(tc.cve, tc.refs, metrics)
356357

357358
// Handle non-deterministic time.Now()
358359
if strings.Contains(tc.name, "invalid date") {

0 commit comments

Comments
 (0)