Skip to content

Commit c779530

Browse files
committed
internal/genericosv: add function to convert OSV to Go Report
Add function ToReport which converts a generic OSV entry to a Report (the representation for our YAML reports). To start, this function simply translates between the formats and doesn't do anything clever. This change also adds a number of real GHSAs that can be used as test cases, and to see how the function behaves on real data as it evolves. Lint errors are added as notes to generated reports, so that we can more easily target areas for improvement. For golang/go#61769 Change-Id: Ifd99796f96aa662e887a643276b3b2d7456e826b Reviewed-on: https://go-review.googlesource.com/c/vulndb/+/515399 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Damien Neil <[email protected]> Run-TryBot: Tatiana Bradley <[email protected]>
1 parent 0cee1e6 commit c779530

File tree

66 files changed

+4794
-6
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+4794
-6
lines changed

internal/genericosv/report.go

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package genericosv
6+
7+
import (
8+
"fmt"
9+
"sort"
10+
"strings"
11+
12+
osvschema "github.com/google/osv-scanner/pkg/models"
13+
"golang.org/x/exp/slices"
14+
"golang.org/x/vulndb/internal/cveschema5"
15+
"golang.org/x/vulndb/internal/ghsa"
16+
"golang.org/x/vulndb/internal/osv"
17+
"golang.org/x/vulndb/internal/report"
18+
"golang.org/x/vulndb/internal/version"
19+
)
20+
21+
// ToReport converts OSV into a Go Report with the given ID.
22+
func (osv *Entry) ToReport(goID string) *report.Report {
23+
r := &report.Report{
24+
ID: goID,
25+
Summary: osv.Summary,
26+
Description: osv.Details,
27+
}
28+
addNote := func(note string) {
29+
r.Notes = append(r.Notes, note)
30+
}
31+
addAlias := func(alias string) {
32+
switch {
33+
case cveschema5.IsCVE(alias):
34+
r.CVEs = append(r.CVEs, alias)
35+
case ghsa.IsGHSA(alias):
36+
r.GHSAs = append(r.GHSAs, alias)
37+
default:
38+
addNote(fmt.Sprintf("create: found alias %s that is not a GHSA or CVE", alias))
39+
}
40+
}
41+
addAlias(osv.ID)
42+
for _, alias := range osv.Aliases {
43+
addAlias(alias)
44+
}
45+
for _, ref := range osv.References {
46+
r.References = append(r.References, convertRef(ref))
47+
}
48+
r.Modules = affectedToModules(osv.Affected, addNote)
49+
r.Credits = convertCredits(osv.Credits)
50+
r.Fix()
51+
if lints := r.Lint(); len(lints) > 0 {
52+
slices.Sort(lints)
53+
for _, lint := range lints {
54+
addNote(fmt.Sprintf("lint: %s", lint))
55+
}
56+
}
57+
return r
58+
}
59+
60+
type addNoteFunc func(string)
61+
62+
func affectedToModules(as []osvschema.Affected, addNote addNoteFunc) []*report.Module {
63+
var modules []*report.Module
64+
for _, a := range as {
65+
if a.Package.Ecosystem != osvschema.EcosystemGo {
66+
continue
67+
}
68+
69+
modules = append(modules, &report.Module{
70+
Module: a.Package.Name,
71+
Versions: convertVersions(a.Ranges, addNote),
72+
})
73+
}
74+
75+
for _, m := range modules {
76+
m.FixVersions()
77+
}
78+
79+
sortModules(modules)
80+
return modules
81+
}
82+
83+
func sortModules(ms []*report.Module) {
84+
sort.Slice(ms, func(i, j int) bool {
85+
m1, m2 := ms[i], ms[j]
86+
// Break ties by lowest affected version, assuming the version list is sorted.
87+
if m1.Module == m2.Module {
88+
vr1, vr2 := m1.Versions, m2.Versions
89+
if len(vr1) == 0 {
90+
return true
91+
} else if len(vr2) == 0 {
92+
return false
93+
}
94+
return version.Before(first(vr1), first(vr2))
95+
}
96+
return m1.Module < m2.Module
97+
})
98+
}
99+
100+
func first(vrs []report.VersionRange) string {
101+
for _, vr := range vrs {
102+
for _, v := range []string{vr.Introduced, vr.Fixed} {
103+
if v != "" {
104+
return v
105+
}
106+
}
107+
}
108+
return ""
109+
}
110+
111+
func convertVersions(rs []osvschema.Range, addNote addNoteFunc) []report.VersionRange {
112+
var vrs []report.VersionRange
113+
for _, r := range rs {
114+
for _, e := range r.Events {
115+
var vr report.VersionRange
116+
switch {
117+
case e.Introduced == "0":
118+
continue
119+
case e.Introduced != "":
120+
vr.Introduced = e.Introduced
121+
case e.Fixed != "":
122+
vr.Fixed = e.Fixed
123+
default:
124+
addNote(fmt.Sprintf("create: unsupported version range event %#v", e))
125+
continue
126+
}
127+
vrs = append(vrs, vr)
128+
}
129+
}
130+
return vrs
131+
}
132+
133+
func convertRef(ref osvschema.Reference) *report.Reference {
134+
return &report.Reference{
135+
Type: osv.ReferenceType(ref.Type),
136+
URL: ref.URL,
137+
}
138+
}
139+
140+
func convertCredits(cs []osvschema.Credit) []string {
141+
var credits []string
142+
for _, c := range cs {
143+
credit := c.Name
144+
if len(c.Contact) != 0 {
145+
credit = fmt.Sprintf("%s (%s)", c.Name, strings.Join(c.Contact, ","))
146+
}
147+
credits = append(credits, credit)
148+
}
149+
return credits
150+
}

0 commit comments

Comments
 (0)