1
1
package ci
2
2
3
3
import (
4
- "slices"
5
-
6
4
"github.com/google/osv-scanner/internal/output"
7
5
"github.com/google/osv-scanner/pkg/grouper"
8
6
"github.com/google/osv-scanner/pkg/models"
9
7
)
10
8
11
9
// DiffVulnerabilityResults will return any new vulnerabilities that are in `newRes`
12
10
// which is not present in `oldRes`, but not the reverse.
13
- //
14
- // Current implementation is O(n^2) on the number of vulns, but can be reduced to linear time
15
11
func DiffVulnerabilityResults (oldRes , newRes models.VulnerabilityResults ) models.VulnerabilityResults {
16
12
result := models.VulnerabilityResults {}
13
+ // Initialize caches for quick lookup
14
+ sourceToIndex , packageToIndex , vulnToIndex := initializeCaches (oldRes )
15
+
17
16
for _ , ps := range newRes .Results {
18
- sourceIdx := slices . IndexFunc ( oldRes . Results , func ( elem models. PackageSource ) bool { return elem . Source == ps .Source })
19
- if sourceIdx == - 1 {
17
+ sourceIdx , sourceExists := sourceToIndex [ ps .Source ]
18
+ if ! sourceExists {
20
19
// Newly introduced source, so all results for this source are going to be new, add everything for this source
21
20
result .Results = append (result .Results , ps )
22
21
continue
@@ -27,9 +26,8 @@ func DiffVulnerabilityResults(oldRes, newRes models.VulnerabilityResults) models
27
26
})
28
27
resultPS := & result .Results [len (result .Results )- 1 ]
29
28
for _ , pv := range ps .Packages {
30
- pkgs := oldRes .Results [sourceIdx ].Packages
31
- pkgIdx := slices .IndexFunc (pkgs , func (elem models.PackageVulns ) bool { return elem .Package == pv .Package })
32
- if pkgIdx == - 1 {
29
+ pkgIdx , packageExists := packageToIndex [sourceIdx ][pv.Package ]
30
+ if ! packageExists {
33
31
// Newly introduced package, so all results for this package are going to be new, add everything for this package
34
32
resultPS .Packages = append (resultPS .Packages , pv )
35
33
continue
@@ -41,9 +39,7 @@ func DiffVulnerabilityResults(oldRes, newRes models.VulnerabilityResults) models
41
39
})
42
40
resultPV := & resultPS .Packages [len (resultPS .Packages )- 1 ]
43
41
for _ , v := range pv .Vulnerabilities {
44
- vulns := pkgs [pkgIdx ].Vulnerabilities
45
- vulnIdx := slices .IndexFunc (vulns , func (elem models.Vulnerability ) bool { return elem .ID == v .ID })
46
- if vulnIdx == - 1 {
42
+ if ! vulnToIndex [sourceIdx ][pkgIdx ][v .ID ] {
47
43
// Vulnerability is new, add it to the results
48
44
resultPV .Vulnerabilities = append (resultPV .Vulnerabilities , v )
49
45
continue
@@ -71,6 +67,38 @@ func DiffVulnerabilityResults(oldRes, newRes models.VulnerabilityResults) models
71
67
return result
72
68
}
73
69
70
+ // initializeCaches sets up maps for quick lookup of sources, packages, and vulnerabilities by their indices.
71
+ func initializeCaches (oldRes models.VulnerabilityResults ) (map [models.SourceInfo ]int , []map [models.PackageInfo ]int , [][]map [string ]bool ) {
72
+ sourceToIndex := make (map [models.SourceInfo ]int , len (oldRes .Results ))
73
+ // The index in the array corresponds to a source index, a query would look like packageToIndex[sourceIndex][packageInfo]
74
+ packageToIndex := make ([]map [models.PackageInfo ]int , len (oldRes .Results ))
75
+ // The first index in the array corresponds to a source index, and the second index corresponds to a package index
76
+ // a query would look like vulnToIndex[sourceIndex][packageIndex][vulnID]
77
+ vulnToIndex := make ([][]map [string ]bool , len (oldRes .Results ))
78
+
79
+ // Populate index maps for sources, packages, and vulnerabilities
80
+ for sourceIndex , vulnResult := range oldRes .Results {
81
+ sourceToIndex [oldRes .Results [sourceIndex ].Source ] = sourceIndex
82
+ if vulnToIndex [sourceIndex ] == nil {
83
+ vulnToIndex [sourceIndex ] = make ([]map [string ]bool , len (vulnResult .Packages ))
84
+ }
85
+ for packageIndex , pkg := range vulnResult .Packages {
86
+ if packageToIndex [sourceIndex ] == nil {
87
+ packageToIndex [sourceIndex ] = make (map [models.PackageInfo ]int , len (vulnResult .Packages ))
88
+ }
89
+ packageToIndex [sourceIndex ][pkg.Package ] = packageIndex
90
+ if vulnToIndex [sourceIndex ][packageIndex ] == nil {
91
+ vulnToIndex [sourceIndex ][packageIndex ] = make (map [string ]bool , len (pkg .Vulnerabilities ))
92
+ }
93
+ for _ , vuln := range pkg .Vulnerabilities {
94
+ vulnToIndex [sourceIndex ][packageIndex ][vuln .ID ] = true // Mark the vulnerability as present
95
+ }
96
+ }
97
+ }
98
+
99
+ return sourceToIndex , packageToIndex , vulnToIndex
100
+ }
101
+
74
102
// DiffVulnerabilityResultsByOccurrences will return the occurrence of each vulnerability that are in `newRes`
75
103
// which is not present in `oldRes`, but not the reverse. This calculates the difference by vulnerability ID,
76
104
// while ignoring the source of the vulnerability.
0 commit comments