Skip to content

Commit a3ed304

Browse files
authored
Merge pull request #30 from puerco/latest-statement
Add vex.EffectiveStatement deprecate StatementFromID
2 parents 88cbbf4 + 1088af6 commit a3ed304

File tree

2 files changed

+119
-4
lines changed

2 files changed

+119
-4
lines changed

pkg/vex/vex.go

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,39 @@ func (vexDoc *VEX) ToJSON(w io.Writer) error {
169169
return nil
170170
}
171171

172+
// EffectiveStatement returns the latest VEX statement for a given product and
173+
// vulnerability, that is the statement that contains the latest data about
174+
// impact to a given product.
175+
func (vexDoc *VEX) EffectiveStatement(product, vulnID string) (s *Statement) {
176+
statements := vexDoc.Statements
177+
var t time.Time
178+
if vexDoc.Timestamp != nil {
179+
t = *vexDoc.Timestamp
180+
}
181+
182+
SortStatements(statements, t)
183+
184+
for i := len(statements) - 1; i >= 0; i-- {
185+
if statements[i].Vulnerability != vulnID {
186+
continue
187+
}
188+
for _, p := range statements[i].Products {
189+
if p == product {
190+
return &statements[i]
191+
}
192+
}
193+
}
194+
return nil
195+
}
196+
172197
// StatementFromID returns a statement for a given vulnerability if there is one.
198+
//
199+
// Deprecated: vex.StatementFromID is deprecated and will be removed in an upcoming version
173200
func (vexDoc *VEX) StatementFromID(id string) *Statement {
174-
for _, statement := range vexDoc.Statements { //nolint:gocritic // turning off for rule rangeValCopy
175-
if statement.Vulnerability == id {
176-
logrus.Infof("VEX doc contains statement for CVE %s", id)
177-
return &statement
201+
logrus.Warn("vex.StatementFromID is deprecated and will be removed in an upcoming version")
202+
for i := range vexDoc.Statements {
203+
if vexDoc.Statements[i].Vulnerability == id && len(vexDoc.Statements[i].Products) > 0 {
204+
return vexDoc.EffectiveStatement(vexDoc.Statements[i].Products[0], id)
178205
}
179206
}
180207
return nil

pkg/vex/vex_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,94 @@ func TestLoadCSAF(t *testing.T) {
3030
require.Equal(t, vexDoc.Metadata.ID, "2022-EVD-UC-01-NA-001")
3131
}
3232

33+
func TestEffectiveStatement(t *testing.T) {
34+
date1 := time.Date(2023, 4, 17, 20, 34, 58, 0, time.UTC)
35+
date2 := time.Date(2023, 4, 18, 20, 34, 58, 0, time.UTC)
36+
for _, tc := range []struct {
37+
vexDoc *VEX
38+
vulnID string
39+
product string
40+
shouldNil bool
41+
expectedDate *time.Time
42+
expectedStatus Status
43+
}{
44+
{
45+
// Single statement
46+
vexDoc: &VEX{
47+
Statements: []Statement{
48+
{
49+
Vulnerability: "CVE-2014-123456",
50+
Timestamp: &date1,
51+
Products: []string{"pkg://[email protected]"},
52+
Status: StatusNotAffected,
53+
},
54+
},
55+
},
56+
vulnID: "CVE-2014-123456",
57+
product: "pkg://[email protected]",
58+
shouldNil: false,
59+
expectedDate: &date1,
60+
expectedStatus: StatusNotAffected,
61+
},
62+
{
63+
// Two consecutive statemente
64+
vexDoc: &VEX{
65+
Statements: []Statement{
66+
{
67+
Vulnerability: "CVE-2014-123456",
68+
Timestamp: &date1,
69+
Products: []string{"pkg://[email protected]"},
70+
Status: StatusUnderInvestigation,
71+
},
72+
{
73+
Vulnerability: "CVE-2014-123456",
74+
Timestamp: &date2,
75+
Products: []string{"pkg://[email protected]"},
76+
Status: StatusNotAffected,
77+
},
78+
},
79+
},
80+
vulnID: "CVE-2014-123456",
81+
product: "pkg://[email protected]",
82+
shouldNil: false,
83+
expectedDate: &date2,
84+
expectedStatus: StatusNotAffected,
85+
},
86+
{
87+
// Different products
88+
vexDoc: &VEX{
89+
Statements: []Statement{
90+
{
91+
Vulnerability: "CVE-2014-123456",
92+
Timestamp: &date1,
93+
Products: []string{"pkg://[email protected]"},
94+
Status: StatusUnderInvestigation,
95+
},
96+
{
97+
Vulnerability: "CVE-2014-123456",
98+
Timestamp: &date2,
99+
Products: []string{"pkg://[email protected]"},
100+
Status: StatusNotAffected,
101+
},
102+
},
103+
},
104+
vulnID: "CVE-2014-123456",
105+
product: "pkg://[email protected]",
106+
shouldNil: false,
107+
expectedDate: &date1,
108+
expectedStatus: StatusUnderInvestigation,
109+
},
110+
} {
111+
s := tc.vexDoc.EffectiveStatement(tc.product, tc.vulnID)
112+
if tc.shouldNil {
113+
require.Nil(t, s)
114+
} else {
115+
require.Equal(t, tc.expectedDate, s.Timestamp)
116+
require.Equal(t, tc.expectedStatus, s.Status)
117+
}
118+
}
119+
}
120+
33121
func genTestDoc(t *testing.T) VEX {
34122
ts, err := time.Parse(time.RFC3339, "2022-12-22T16:36:43-05:00")
35123
require.NoError(t, err)

0 commit comments

Comments
 (0)