Skip to content

Commit

Permalink
fix: orient by cve merging (#1046)
Browse files Browse the repository at this point in the history
  • Loading branch information
kzantow committed Jan 4, 2023
1 parent 3ff1d64 commit 04a84a4
Show file tree
Hide file tree
Showing 27 changed files with 312 additions and 287 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ require (
require (
github.com/anchore/go-logger v0.0.0-20220728155337-03b66a5207d8
github.com/anchore/sqlite v1.4.6-0.20220607210448-bcc6ee5c4963
github.com/anchore/syft v0.64.0
github.com/anchore/syft v0.65.0
github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b
github.com/in-toto/in-toto-golang v0.4.1-0.20221018183522-731d0640b65f
github.com/mitchellh/mapstructure v1.5.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,8 @@ github.com/anchore/sqlite v1.4.6-0.20220607210448-bcc6ee5c4963 h1:vrf2PYH77vqVJo
github.com/anchore/sqlite v1.4.6-0.20220607210448-bcc6ee5c4963/go.mod h1:AVRyXOUP0hTz9Cb8OlD1XnwA8t4lBPfTuwPHmEUuiLc=
github.com/anchore/stereoscope v0.0.0-20221208011002-c5ff155d72f1 h1:DXUAm/H9chRTEzMfkFyduBIcCiJyFXhCmv3zH3C0HGs=
github.com/anchore/stereoscope v0.0.0-20221208011002-c5ff155d72f1/go.mod h1:/zjVnu2Jdl7xQCUtASegzeEg+IHKrM7SyMqdao3e+Nc=
github.com/anchore/syft v0.64.0 h1:+hyo6Z34BLPZDDl//Bde5RiNhjN3wIT8AYlCiLAgLwg=
github.com/anchore/syft v0.64.0/go.mod h1:jJu1mN1B602p4qS6sE28pAgcv5Xfx9h9M/jECMjIb6Q=
github.com/anchore/syft v0.65.0 h1:w67aEZBeUSBZGiFy/u2wWwhbcq785xKl0tnvhsMlVm4=
github.com/anchore/syft v0.65.0/go.mod h1:jJu1mN1B602p4qS6sE28pAgcv5Xfx9h9M/jECMjIb6Q=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
Expand Down
12 changes: 6 additions & 6 deletions grype/cpe/cpe.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ package cpe

import (
"github.com/anchore/grype/internal/log"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/cpe"
)

func NewSlice(cpeStrs ...string) ([]pkg.CPE, error) {
var cpes []pkg.CPE
func NewSlice(cpeStrs ...string) ([]cpe.CPE, error) {
var cpes []cpe.CPE
for _, c := range cpeStrs {
value, err := pkg.NewCPE(c)
value, err := cpe.New(c)
if err != nil {
log.Warnf("excluding invalid CPE %q: %v", c, err)
continue
Expand All @@ -19,8 +19,8 @@ func NewSlice(cpeStrs ...string) ([]pkg.CPE, error) {
return cpes, nil
}

func MatchWithoutVersion(c pkg.CPE, candidates []pkg.CPE) []pkg.CPE {
matches := make([]pkg.CPE, 0)
func MatchWithoutVersion(c cpe.CPE, candidates []cpe.CPE) []cpe.CPE {
matches := make([]cpe.CPE, 0)
for _, candidate := range candidates {
canCopy := candidate
if c.MatchWithoutVersion(&canCopy) {
Expand Down
127 changes: 60 additions & 67 deletions grype/cpe/cpe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,107 +5,100 @@ import (

"github.com/sergi/go-diff/diffmatchpatch"

"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/cpe"
)

func must(c pkg.CPE, e error) pkg.CPE {
if e != nil {
panic(e)
}
return c
}

func TestMatchWithoutVersion(t *testing.T) {
tests := []struct {
name string
compare pkg.CPE
candidates []pkg.CPE
expected []pkg.CPE
compare cpe.CPE
candidates []cpe.CPE
expected []cpe.CPE
}{
{
name: "GoCase",
compare: must(pkg.NewCPE("cpe:2.3:*:python-requests:requests:2.3.0:*:*:*:*:python:*:*")),
candidates: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:a:python-requests:requests:2.2.1:*:*:*:*:*:*:*")),
compare: cpe.Must("cpe:2.3:*:python-requests:requests:2.3.0:*:*:*:*:python:*:*"),
candidates: []cpe.CPE{
cpe.Must("cpe:2.3:a:python-requests:requests:2.2.1:*:*:*:*:*:*:*"),
},
expected: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:a:python-requests:requests:2.2.1:*:*:*:*:*:*:*")),
expected: []cpe.CPE{
cpe.Must("cpe:2.3:a:python-requests:requests:2.2.1:*:*:*:*:*:*:*"),
},
},
{
name: "IgnoreVersion",
compare: must(pkg.NewCPE("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*")),
candidates: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name:name:3.3:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name:name:5.5:*:*:*:*:java:*:*")),
compare: cpe.Must("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*"),
candidates: []cpe.CPE{
cpe.Must("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name:name:3.3:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name:name:5.5:*:*:*:*:java:*:*"),
},
expected: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name:name:3.3:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name:name:5.5:*:*:*:*:java:*:*")),
expected: []cpe.CPE{
cpe.Must("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name:name:3.3:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name:name:5.5:*:*:*:*:java:*:*"),
},
},
{
name: "MatchByTargetSW",
compare: must(pkg.NewCPE("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*")),
candidates: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name:name:3.2:*:*:*:*:maven:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name:name:3.2:*:*:*:*:jenkins:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name:name:3.2:*:*:*:*:cloudbees_jenkins:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name:name:3.2:*:*:*:*:*:*:*")),
compare: cpe.Must("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*"),
candidates: []cpe.CPE{
cpe.Must("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name:name:3.2:*:*:*:*:maven:*:*"),
cpe.Must("cpe:2.3:*:name:name:3.2:*:*:*:*:jenkins:*:*"),
cpe.Must("cpe:2.3:*:name:name:3.2:*:*:*:*:cloudbees_jenkins:*:*"),
cpe.Must("cpe:2.3:*:name:name:3.2:*:*:*:*:*:*:*"),
},
expected: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name:name:3.2:*:*:*:*:*:*:*")),
expected: []cpe.CPE{
cpe.Must("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name:name:3.2:*:*:*:*:*:*:*"),
},
},
{
name: "MatchByName",
compare: must(pkg.NewCPE("cpe:2.3:*:name:name5:3.2:*:*:*:*:java:*:*")),
candidates: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:name:name1:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name:name2:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name:name3:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name:name4:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name:name5:3.2:*:*:*:*:*:*:*")),
compare: cpe.Must("cpe:2.3:*:name:name5:3.2:*:*:*:*:java:*:*"),
candidates: []cpe.CPE{
cpe.Must("cpe:2.3:*:name:name1:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name:name2:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name:name3:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name:name4:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name:name5:3.2:*:*:*:*:*:*:*"),
},
expected: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:name:name5:3.2:*:*:*:*:*:*:*")),
expected: []cpe.CPE{
cpe.Must("cpe:2.3:*:name:name5:3.2:*:*:*:*:*:*:*"),
},
},
{
name: "MatchByVendor",
compare: must(pkg.NewCPE("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*")),
candidates: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:name1:name:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name3:name:3.2:*:*:*:*:jaba-no-bother:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name4:name:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name5:name:3.2:*:*:*:*:*:*:*")),
compare: cpe.Must("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*"),
candidates: []cpe.CPE{
cpe.Must("cpe:2.3:*:name1:name:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name3:name:3.2:*:*:*:*:jaba-no-bother:*:*"),
cpe.Must("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name4:name:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name5:name:3.2:*:*:*:*:*:*:*"),
},
expected: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*")),
expected: []cpe.CPE{
cpe.Must("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*"),
},
},
{
name: "MatchAnyVendorOrTargetSW",
compare: must(pkg.NewCPE("cpe:2.3:*:*:name:3.2:*:*:*:*:*:*:*")),
candidates: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:name1:name:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name3:name:3.2:*:*:*:*:jaba-no-bother:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name4:name:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name5:name:3.2:*:*:*:*:*:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name5:NOMATCH:3.2:*:*:*:*:*:*:*")),
compare: cpe.Must("cpe:2.3:*:*:name:3.2:*:*:*:*:*:*:*"),
candidates: []cpe.CPE{
cpe.Must("cpe:2.3:*:name1:name:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name3:name:3.2:*:*:*:*:jaba-no-bother:*:*"),
cpe.Must("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name4:name:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name5:name:3.2:*:*:*:*:*:*:*"),
cpe.Must("cpe:2.3:*:name5:NOMATCH:3.2:*:*:*:*:*:*:*"),
},
expected: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:name1:name:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name3:name:3.2:*:*:*:*:jaba-no-bother:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name4:name:3.2:*:*:*:*:java:*:*")),
must(pkg.NewCPE("cpe:2.3:*:name5:name:3.2:*:*:*:*:*:*:*")),
expected: []cpe.CPE{
cpe.Must("cpe:2.3:*:name1:name:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name3:name:3.2:*:*:*:*:jaba-no-bother:*:*"),
cpe.Must("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name4:name:3.2:*:*:*:*:java:*:*"),
cpe.Must("cpe:2.3:*:name5:name:3.2:*:*:*:*:*:*:*"),
},
},
}
Expand Down
11 changes: 6 additions & 5 deletions grype/db/vulnerability_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import (

"github.com/facebookincubator/nvdtools/wfn"

"github.com/anchore/grype/grype/cpe"
cpeUtil "github.com/anchore/grype/grype/cpe"
grypeDB "github.com/anchore/grype/grype/db/v5"
"github.com/anchore/grype/grype/db/v5/namespace"
"github.com/anchore/grype/grype/distro"
"github.com/anchore/grype/grype/pkg"
"github.com/anchore/grype/grype/vulnerability"
"github.com/anchore/grype/internal/log"
"github.com/anchore/syft/syft/cpe"
syftPkg "github.com/anchore/syft/syft/pkg"
)

Expand Down Expand Up @@ -131,7 +132,7 @@ func (pr *VulnerabilityProvider) GetByLanguage(l syftPkg.Language, p pkg.Package
return vulnerabilities, nil
}

func (pr *VulnerabilityProvider) GetByCPE(requestCPE syftPkg.CPE) ([]vulnerability.Vulnerability, error) {
func (pr *VulnerabilityProvider) GetByCPE(requestCPE cpe.CPE) ([]vulnerability.Vulnerability, error) {
vulns := make([]vulnerability.Vulnerability, 0)
namespaces := pr.namespaceIndex.CPENamespaces()

Expand All @@ -150,20 +151,20 @@ func (pr *VulnerabilityProvider) GetByCPE(requestCPE syftPkg.CPE) ([]vulnerabili
return nil, fmt.Errorf("provider failed to fetch namespace=%q product=%q: %w", ns, requestCPE.Product, err)
}

normalizedRequestCPE, err := syftPkg.NewCPE(ns.Resolver().Normalize(requestCPE.BindToFmtString()))
normalizedRequestCPE, err := cpe.New(ns.Resolver().Normalize(requestCPE.BindToFmtString()))

if err != nil {
normalizedRequestCPE = requestCPE
}

for _, vuln := range allPkgVulns {
vulnCPEs, err := cpe.NewSlice(vuln.CPEs...)
vulnCPEs, err := cpeUtil.NewSlice(vuln.CPEs...)
if err != nil {
return nil, err
}

// compare the request CPE to the potential matches (excluding version, which is handled downstream)
candidateMatchCpes := cpe.MatchWithoutVersion(normalizedRequestCPE, vulnCPEs)
candidateMatchCpes := cpeUtil.MatchWithoutVersion(normalizedRequestCPE, vulnCPEs)

if len(candidateMatchCpes) > 0 {
vulnObj, err := vulnerability.NewVulnerability(vuln)
Expand Down
41 changes: 17 additions & 24 deletions grype/db/vulnerability_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/anchore/grype/grype/pkg/qualifier"
"github.com/anchore/grype/grype/version"
"github.com/anchore/grype/grype/vulnerability"
syftPkg "github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/cpe"
)

func Test_GetByDistro(t *testing.T) {
Expand All @@ -37,15 +37,15 @@ func Test_GetByDistro(t *testing.T) {
ID: "CVE-2014-fake-1",
Namespace: "debian:distro:debian:8",
PackageQualifiers: []qualifier.Qualifier{},
CPEs: []syftPkg.CPE{},
CPEs: []cpe.CPE{},
Advisories: []vulnerability.Advisory{},
},
{
Constraint: version.MustGetConstraint("< 2013.0.2-1", version.DebFormat),
ID: "CVE-2013-fake-2",
Namespace: "debian:distro:debian:8",
PackageQualifiers: []qualifier.Qualifier{},
CPEs: []syftPkg.CPE{},
CPEs: []cpe.CPE{},
Advisories: []vulnerability.Advisory{},
},
}
Expand Down Expand Up @@ -74,30 +74,23 @@ func Test_GetByDistro_nilDistro(t *testing.T) {
assert.NoError(t, err)
}

func must(c syftPkg.CPE, e error) syftPkg.CPE {
if e != nil {
panic(e)
}
return c
}

func Test_GetByCPE(t *testing.T) {

tests := []struct {
name string
cpe syftPkg.CPE
cpe cpe.CPE
expected []vulnerability.Vulnerability
err bool
}{
{
name: "match from name and target SW",
cpe: must(syftPkg.NewCPE("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:ruby:*:*")),
cpe: cpe.Must("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:ruby:*:*"),
expected: []vulnerability.Vulnerability{
{
Constraint: version.MustGetConstraint("< 3.7.4", version.UnknownFormat),
ID: "CVE-2014-fake-4",
CPEs: []syftPkg.CPE{
must(syftPkg.NewCPE("cpe:2.3:*:activerecord:activerecord:*:*:something:*:*:ruby:*:*")),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:*:activerecord:activerecord:*:*:something:*:*:ruby:*:*"),
},
Namespace: "nvd:cpe",
PackageQualifiers: []qualifier.Qualifier{},
Expand All @@ -107,13 +100,13 @@ func Test_GetByCPE(t *testing.T) {
},
{
name: "match with normalization",
cpe: must(syftPkg.NewCPE("cpe:2.3:*:ActiVERecord:ACTiveRecord:*:*:*:*:*:ruby:*:*")),
cpe: cpe.Must("cpe:2.3:*:ActiVERecord:ACTiveRecord:*:*:*:*:*:ruby:*:*"),
expected: []vulnerability.Vulnerability{
{
Constraint: version.MustGetConstraint("< 3.7.4", version.UnknownFormat),
ID: "CVE-2014-fake-4",
CPEs: []syftPkg.CPE{
must(syftPkg.NewCPE("cpe:2.3:*:activerecord:activerecord:*:*:something:*:*:ruby:*:*")),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:*:activerecord:activerecord:*:*:something:*:*:ruby:*:*"),
},
Namespace: "nvd:cpe",
PackageQualifiers: []qualifier.Qualifier{},
Expand All @@ -123,13 +116,13 @@ func Test_GetByCPE(t *testing.T) {
},
{
name: "match from vendor & name",
cpe: must(syftPkg.NewCPE("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:*:*:*")),
cpe: cpe.Must("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:*:*:*"),
expected: []vulnerability.Vulnerability{
{
Constraint: version.MustGetConstraint("< 3.7.6", version.UnknownFormat),
ID: "CVE-2014-fake-3",
CPEs: []syftPkg.CPE{
must(syftPkg.NewCPE("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:rails:*:*")),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:rails:*:*"),
},
Namespace: "nvd:cpe",
PackageQualifiers: []qualifier.Qualifier{},
Expand All @@ -138,8 +131,8 @@ func Test_GetByCPE(t *testing.T) {
{
Constraint: version.MustGetConstraint("< 3.7.4", version.UnknownFormat),
ID: "CVE-2014-fake-4",
CPEs: []syftPkg.CPE{
must(syftPkg.NewCPE("cpe:2.3:*:activerecord:activerecord:*:*:something:*:*:ruby:*:*")),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:*:activerecord:activerecord:*:*:something:*:*:ruby:*:*"),
},
Namespace: "nvd:cpe",
PackageQualifiers: []qualifier.Qualifier{},
Expand All @@ -150,7 +143,7 @@ func Test_GetByCPE(t *testing.T) {

{
name: "dont allow any name",
cpe: must(syftPkg.NewCPE("cpe:2.3:*:couldntgetthisrightcouldyou:*:*:*:*:*:*:*:*:*")),
cpe: cpe.Must("cpe:2.3:*:couldntgetthisrightcouldyou:*:*:*:*:*:*:*:*:*"),
err: true,
},
}
Expand Down Expand Up @@ -193,7 +186,7 @@ func Test_Get(t *testing.T) {
ID: "CVE-2014-fake-1",
Namespace: "debian:distro:debian:8",
PackageQualifiers: []qualifier.Qualifier{},
CPEs: []syftPkg.CPE{},
CPEs: []cpe.CPE{},
Advisories: []vulnerability.Advisory{},
},
}
Expand Down
Loading

0 comments on commit 04a84a4

Please sign in to comment.