Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions central/cve/converter/utils/convert_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,16 @@ func (c CVEType) ToStorageCVEType() storage.CVE_CVEType {
return storage.CVE_UNKNOWN_CVE
}

// NvdCVEToEmbeddedCVE converts a nvd.CVEEntry object to *storage.EmbeddedVulnerability object
func NvdCVEToEmbeddedCVE(nvdCVE *schema.NVDCVEFeedJSON10DefCVEItem, ct CVEType) (*storage.EmbeddedVulnerability, error) {
// NVDCVEToEmbeddedCVE converts a *schema.NVDCVEFeedJSON10DefCVEItem to *storage.EmbeddedVulnerability.
func NVDCVEToEmbeddedCVE(nvdCVE *schema.NVDCVEFeedJSON10DefCVEItem, ct CVEType) (*storage.EmbeddedVulnerability, error) {
if nvdCVE == nil || nvdCVE.CVE == nil || nvdCVE.CVE.CVEDataMeta == nil {
return nil, errors.Errorf("Missing CVE or CVE MetaData for type: %d", ct)
}

if nvdCVE.Impact == nil || (nvdCVE.Impact.BaseMetricV2 == nil && nvdCVE.Impact.BaseMetricV3 == nil) {
return nil, errors.New("CVE does not have either a CVSSv2 nor a CVSSv3 score")
}

cve := &storage.EmbeddedVulnerability{
Cve: nvdCVE.CVE.CVEDataMeta.ID,
}
Expand All @@ -76,7 +80,7 @@ func NvdCVEToEmbeddedCVE(nvdCVE *schema.NVDCVEFeedJSON10DefCVEItem, ct CVEType)
return nil, errors.Errorf("unknown CVE type: %d", ct)
}

if nvdCVE.Impact != nil && nvdCVE.Impact.BaseMetricV2 != nil {
if nvdCVE.Impact.BaseMetricV2 != nil {
cvssv2, err := nvdCvssv2ToProtoCvssv2(nvdCVE.Impact.BaseMetricV2)
if err != nil {
return nil, err
Expand All @@ -86,7 +90,8 @@ func NvdCVEToEmbeddedCVE(nvdCVE *schema.NVDCVEFeedJSON10DefCVEItem, ct CVEType)
cve.ScoreVersion = storage.EmbeddedVulnerability_V2
}

if nvdCVE.Impact != nil && nvdCVE.Impact.BaseMetricV3 != nil {
// If CVSSv3 is specified, prefer it over CVSSv2.
if nvdCVE.Impact.BaseMetricV3 != nil {
cvssv3, err := nvdCvssv3ToProtoCvssv3(nvdCVE.Impact.BaseMetricV3)
if err != nil {
return nil, err
Expand Down Expand Up @@ -175,11 +180,11 @@ func nvdCvssv3ToProtoCvssv3(baseMetricV3 *schema.NVDCVEFeedJSON10DefImpactBaseMe
return cvssV3, nil
}

// NvdCVEsToEmbeddedCVEs converts NVD CVEs to *storage.CVE objects
func NvdCVEsToEmbeddedCVEs(cves []*schema.NVDCVEFeedJSON10DefCVEItem, ct CVEType) ([]*storage.EmbeddedVulnerability, error) {
// NVDCVEsToEmbeddedCVEs converts *schema.NVDCVEFeedJSON10DefCVEItem CVEs to *storage.EmbeddedVulnerability objects.
func NVDCVEsToEmbeddedCVEs(cves []*schema.NVDCVEFeedJSON10DefCVEItem, ct CVEType) ([]*storage.EmbeddedVulnerability, error) {
ret := make([]*storage.EmbeddedVulnerability, 0, len(cves))
for _, cve := range cves {
ev, err := NvdCVEToEmbeddedCVE(cve, ct)
ev, err := NVDCVEToEmbeddedCVE(cve, ct)
if err != nil {
return nil, err
}
Expand All @@ -188,8 +193,8 @@ func NvdCVEsToEmbeddedCVEs(cves []*schema.NVDCVEFeedJSON10DefCVEItem, ct CVEType
return ret, nil
}

// ProtoCVEToEmbeddedCVE coverts a Proto CVEs to Embedded Vuln
// It converts all the fields except except Fixed By which gets set depending on the CVE
// ProtoCVEToEmbeddedCVE converts a *storage.CVE to *storage.EmbeddedVulnerability.
// It converts all the fields except FixedBy which gets set depending on the CVE.
func ProtoCVEToEmbeddedCVE(protoCVE *storage.CVE) *storage.EmbeddedVulnerability {
embeddedCVE := &storage.EmbeddedVulnerability{
Cve: protoCVE.GetId(),
Expand Down
74 changes: 59 additions & 15 deletions central/cve/converter/utils/convert_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,13 @@ import (
"testing"

"github.com/facebookincubator/nvdtools/cvefeed/nvd/schema"
"github.com/stackrox/rox/generated/storage"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func getTestData(t *testing.T) []*schema.NVDCVEFeedJSON10DefCVEItem {
// Fixture is generated in the following way:
// 1. took one record from CVE list downloaded from NVD feed: https://nvd.nist.gov/vuln/data-feeds#JSON_FEED
// -> save single JSON record in single-cve.json
// 2. generate all paths: https://www.convertjson.com/json-path-list.htm
// -> save result in all-paths.txt
// 3. generate versions without each path with the following command:
// cat all-paths.txt | awk '{print "jq '"'"'del(" $0 ")'"'"' -c single-cve.json >> test-fixture-cve-list.json"}' | xargs -0 bash -c
// 4. add null record and array wrapper manually
b, err := os.ReadFile("test-fixture-cve-list.json")
b, err := os.ReadFile("testdata/istio/cve-list.json")
require.NoError(t, err)

var cveEntries []*schema.NVDCVEFeedJSON10DefCVEItem
Expand All @@ -30,19 +23,70 @@ func getTestData(t *testing.T) []*schema.NVDCVEFeedJSON10DefCVEItem {
return cveEntries
}

func TestNvdCVEToEmbeddedCVE(t *testing.T) {
i := 0
func getPanicTestData(t *testing.T) []*schema.NVDCVEFeedJSON10DefCVEItem {
b, err := os.ReadFile("testdata/istio/cve-list-panic.json")
require.NoError(t, err)

var cveEntries []*schema.NVDCVEFeedJSON10DefCVEItem
err = json.Unmarshal(b, &cveEntries)
require.NoError(t, err)

return cveEntries
}

func TestNVDCVEToEmbeddedCVEs_Istio(t *testing.T) {
cveEntries := getTestData(t)

embeddedCVEs, err := NVDCVEsToEmbeddedCVEs(cveEntries, Istio)
assert.NoError(t, err)
assert.Len(t, embeddedCVEs, len(cveEntries))
}

func TestNVDCVEToEmbeddedCVE_Istio(t *testing.T) {
cveEntries := getTestData(t)

for _, cveEntry := range cveEntries {
cveEntry := cveEntry
require.NotNil(t, cveEntry)
require.NotNil(t, cveEntry.Impact)
require.True(t, cveEntry.Impact.BaseMetricV2 != nil || cveEntry.Impact.BaseMetricV3 != nil)

t.Run(cveEntry.CVE.CVEDataMeta.ID, func(t *testing.T) {
embeddedCVE, err := NVDCVEToEmbeddedCVE(cveEntry, Istio)
assert.NoError(t, err)

assert.Equal(t, cveEntry.CVE.CVEDataMeta.ID, embeddedCVE.GetCve())
assert.True(t, embeddedCVE.GetCvssV2() != nil || embeddedCVE.GetCvssV3() != nil)
if cveEntry.Impact.BaseMetricV3 != nil {
assert.Equal(t, storage.EmbeddedVulnerability_V3, embeddedCVE.GetScoreVersion())
assert.Equal(t, float32(cveEntry.Impact.BaseMetricV3.CVSSV3.BaseScore), embeddedCVE.GetCvssV3().GetScore())
assert.Equal(t, float32(cveEntry.Impact.BaseMetricV3.CVSSV3.BaseScore), embeddedCVE.GetCvss())
assert.Equal(t, cveEntry.Impact.BaseMetricV3.CVSSV3.VectorString, embeddedCVE.GetCvssV3().GetVector())
} else {
assert.Equal(t, storage.EmbeddedVulnerability_V2, embeddedCVE.GetScoreVersion())
assert.Equal(t, float32(cveEntry.Impact.BaseMetricV2.CVSSV2.BaseScore), embeddedCVE.GetCvssV2().GetScore())
assert.Equal(t, float32(cveEntry.Impact.BaseMetricV2.CVSSV2.BaseScore), embeddedCVE.GetCvss())
assert.Equal(t, cveEntry.Impact.BaseMetricV2.CVSSV2.VectorString, embeddedCVE.GetCvssV2().GetVector())
}
assert.Equal(t, storage.EmbeddedVulnerability_ISTIO_VULNERABILITY, embeddedCVE.VulnerabilityType)
assert.Equal(t, cveEntry.CVE.Description.DescriptionData[0].Value, embeddedCVE.Summary)
})
}
}

func TestNVDCVEToEmbeddedCVE_Panic(t *testing.T) {
var i int
defer func() {
assert.Nil(t, recover(), fmt.Sprintf("NvdCVEToEmbeddedCVE panicked for entry %d in CVE list", i))
assert.Nil(t, recover(), fmt.Sprintf("NVDCVEToEmbeddedCVE panicked for entry %d in CVE list", i))
}()

testData := getTestData(t)
testData := getPanicTestData(t)
for _, testRecord := range testData {
_, _ = NvdCVEToEmbeddedCVE(testRecord, Istio)
_, _ = NVDCVEToEmbeddedCVE(testRecord, Istio)

i++
}

// Ensure that all records are processed.
assert.Equal(t, 73, i)
assert.Equal(t, len(testData), i)
}
8 changes: 8 additions & 0 deletions central/cve/converter/utils/testdata/istio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Fixture is generated in the following way:
1. took one record from CVE list downloaded from NVD feed: https://nvd.nist.gov/vuln/data-feeds#JSON_FEED
-> save single JSON record in single-cve.json
2. generate all paths: https://www.convertjson.com/json-path-list.htm
-> save result in all-paths.txt
3. generate versions without each path with the following command:
cat all-paths.txt | awk '{print "jq '"'"'del(" $0 ")'"'"' -c single-cve.json >> cve-list-panic.json"}' | xargs -0 bash -c
4. add null record and array wrapper manually
Loading