-
Notifications
You must be signed in to change notification settings - Fork 337
/
results.go
133 lines (112 loc) · 3.44 KB
/
results.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package models
import (
"strings"
"golang.org/x/exp/slices"
)
// Combined vulnerabilities found for the scanned packages
type VulnerabilityResults struct {
Results []PackageSource `json:"results"`
}
// Flatten the grouped/nested vulnerability results into one flat array.
func (vulns *VulnerabilityResults) Flatten() []VulnerabilityFlattened {
results := []VulnerabilityFlattened{}
for _, res := range vulns.Results {
for _, pkg := range res.Packages {
for _, v := range pkg.Vulnerabilities {
results = append(results, VulnerabilityFlattened{
Source: res.Source,
Package: pkg.Package,
Vulnerability: v,
GroupInfo: getGroupInfoForVuln(pkg.Groups, v.ID),
})
}
}
}
return results
}
func getGroupInfoForVuln(groups []GroupInfo, vulnID string) GroupInfo {
// groupIdx should never be -1 since vulnerabilities should always be in one group
groupIdx := slices.IndexFunc(groups, func(g GroupInfo) bool { return slices.Contains(g.IDs, vulnID) })
return groups[groupIdx]
}
// Flattened Vulnerability Information.
type VulnerabilityFlattened struct {
Source SourceInfo
Package PackageInfo
Vulnerability Vulnerability
GroupInfo GroupInfo
}
type SourceInfo struct {
Path string `json:"path"`
Type string `json:"type"`
}
type Metadata struct {
RepoURL string `json:"repo_url"`
}
func (s SourceInfo) String() string {
return s.Type + ":" + s.Path
}
// Vulnerabilities grouped by sources
type PackageSource struct {
Source SourceInfo `json:"source"`
Packages []PackageVulns `json:"packages"`
}
// Vulnerabilities grouped by package
type PackageVulns struct {
Package PackageInfo `json:"package"`
Vulnerabilities []Vulnerability `json:"vulnerabilities"`
Groups []GroupInfo `json:"groups"`
}
type GroupInfo struct {
// IDs expected to be sorted in alphanumeric order
IDs []string `json:"ids"`
// Map of Vulnerability IDs to AnalysisInfo
ExperimentalAnalysis map[string]AnalysisInfo `json:"experimentalAnalysis,omitempty"`
}
// IsCalled returns true if any analysis performed determines that the vulnerability is being called
// Also returns true if no analysis is performed
func (groupInfo *GroupInfo) IsCalled() bool {
if len(groupInfo.ExperimentalAnalysis) == 0 {
return true
}
for _, analysis := range groupInfo.ExperimentalAnalysis {
if analysis.Called {
return true
}
}
return false
}
func (groupInfo *GroupInfo) IndexString() string {
// Assumes IDs is sorted
return strings.Join(groupInfo.IDs, ",")
}
// FixedVersions returns a map of fixed versions for each package, or a map of empty slices if no fixed versions are available
func (v *Vulnerability) FixedVersions() map[Package][]string {
output := map[Package][]string{}
for _, a := range v.Affected {
packageKey := a.Package
packageKey.Purl = ""
for _, r := range a.Ranges {
for _, e := range r.Events {
if e.Fixed != "" {
output[packageKey] = append(output[packageKey], e.Fixed)
if strings.Contains(string(packageKey.Ecosystem), ":") {
packageKey.Ecosystem = Ecosystem(strings.Split(string(packageKey.Ecosystem), ":")[0])
}
output[packageKey] = append(output[packageKey], e.Fixed)
}
}
}
}
return output
}
type AnalysisInfo struct {
Called bool `json:"called"`
}
// Specific package information
type PackageInfo struct {
Name string `json:"name"`
Version string `json:"version"`
Ecosystem string `json:"ecosystem"`
Commit string `json:"commit"`
}