mirror of
https://github.com/anchore/grype
synced 2024-11-10 06:34:13 +00:00
remove CPE generation (rely on static CPES from syft instead)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
90b44640c2
commit
627aa77842
33 changed files with 187 additions and 359 deletions
2
Makefile
2
Makefile
|
@ -14,7 +14,7 @@ RESET := $(shell tput -T linux sgr0)
|
|||
TITLE := $(BOLD)$(PURPLE)
|
||||
SUCCESS := $(BOLD)$(GREEN)
|
||||
# the quality gate lower threshold for unit test total % coverage (by function statements)
|
||||
COVERAGE_THRESHOLD := 55
|
||||
COVERAGE_THRESHOLD := 50
|
||||
|
||||
## Build variables
|
||||
DISTDIR=./dist
|
||||
|
|
|
@ -178,7 +178,7 @@ func startWorker(userInput string, failOnSeverity *vulnerability.Severity) <-cha
|
|||
var metadataProvider vulnerability.MetadataProvider
|
||||
var catalog *pkg.Catalog
|
||||
var srcMetadata source.Metadata
|
||||
var theDistro distro.Distro
|
||||
var theDistro *distro.Distro
|
||||
var err error
|
||||
var wg = &sync.WaitGroup{}
|
||||
|
||||
|
|
4
go.mod
4
go.mod
|
@ -8,10 +8,10 @@ require (
|
|||
github.com/anchore/go-version v1.2.2-0.20200810141238-330bef18dbca
|
||||
github.com/anchore/grype-db v0.0.0-20200929200644-6d1c82acc95e
|
||||
github.com/anchore/stereoscope v0.0.0-20201106140100-12e75c48f409
|
||||
github.com/anchore/syft v0.8.0
|
||||
github.com/anchore/syft v0.8.1-0.20201119173820-0ed30138c4c5
|
||||
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/facebookincubator/nvdtools v0.1.4-0.20200622182922-aed862a62ae6
|
||||
github.com/facebookincubator/nvdtools v0.1.4
|
||||
github.com/go-test/deep v1.0.7
|
||||
github.com/google/go-containerregistry v0.1.1 // indirect
|
||||
github.com/google/uuid v1.1.1
|
||||
|
|
8
go.sum
8
go.sum
|
@ -125,8 +125,8 @@ github.com/anchore/grype-db v0.0.0-20200929200644-6d1c82acc95e h1:s0HmxxDuJyvgGB
|
|||
github.com/anchore/grype-db v0.0.0-20200929200644-6d1c82acc95e/go.mod h1:LINmipRzG88vnJEWvgMMDVCFH1qZsj7+bjmpERlSyaA=
|
||||
github.com/anchore/stereoscope v0.0.0-20201106140100-12e75c48f409 h1:xKSpDRjmYrEFrdMeDh4AuSUAFc99pdro6YFBKxy2um0=
|
||||
github.com/anchore/stereoscope v0.0.0-20201106140100-12e75c48f409/go.mod h1:2Jja/4l0zYggW52og+nn0rut4i+OYjCf9vTyrM8RT4E=
|
||||
github.com/anchore/syft v0.8.0 h1:Jq9yja9rwx6oIrPjwSpmB2VWRbrOTLtC06GJnAUz03A=
|
||||
github.com/anchore/syft v0.8.0/go.mod h1:Uf1lxsZSo/y3HjQ0U94p3aQpHy8Ac6wLyDwYLT0dcYw=
|
||||
github.com/anchore/syft v0.8.1-0.20201119173820-0ed30138c4c5 h1:UZqpD/vM2IAfWrD515M9dPiXFaEKxXImvJI+E5xVGH8=
|
||||
github.com/anchore/syft v0.8.1-0.20201119173820-0ed30138c4c5/go.mod h1:5seLdLxn97ZiXzIsnxMjiKvxMoj0Ms/W8xJj+VSHq+Y=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
|
@ -250,8 +250,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
|||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/facebookincubator/nvdtools v0.1.4-0.20200622182922-aed862a62ae6 h1:+GR1Gkrl/JervFT1aKR4kzG8T10QWYMSKfYfhCJX0vU=
|
||||
github.com/facebookincubator/nvdtools v0.1.4-0.20200622182922-aed862a62ae6/go.mod h1:0/FIVnSEl9YHXLq3tKBPpKaI0iUceDhdSHPlIwIX44Y=
|
||||
github.com/facebookincubator/nvdtools v0.1.4 h1:x1Ucw9+bSkMd8DJJN4jNQ1Lk4PSFlJarGOxp9D6WUMo=
|
||||
github.com/facebookincubator/nvdtools v0.1.4/go.mod h1:0/FIVnSEl9YHXLq3tKBPpKaI0iUceDhdSHPlIwIX44Y=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
|
|
122
grype/cpe/cpe.go
122
grype/cpe/cpe.go
|
@ -1,62 +1,13 @@
|
|||
package cpe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/grype/internal"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/facebookincubator/nvdtools/wfn"
|
||||
)
|
||||
|
||||
// TODO: would be great to allow these to be overridden by user data/config
|
||||
var targetSoftware = map[pkg.Language][]string{
|
||||
pkg.Java: {
|
||||
"java",
|
||||
"maven",
|
||||
"jenkins",
|
||||
"cloudbees_jenkins",
|
||||
},
|
||||
//pkg.JavaScript: {
|
||||
// "node.js",
|
||||
//},
|
||||
pkg.Python: {
|
||||
"python",
|
||||
},
|
||||
pkg.Ruby: {
|
||||
"ruby",
|
||||
"rails",
|
||||
},
|
||||
}
|
||||
|
||||
const ANY = "*"
|
||||
|
||||
type CPE = wfn.Attributes
|
||||
|
||||
func New(cpeStr string) (CPE, error) {
|
||||
value, err := wfn.Parse(cpeStr)
|
||||
// we need to compare the raw data since we are constructing CPEs in other locations
|
||||
value.Vendor = wfn.StripSlashes(value.Vendor)
|
||||
value.Product = wfn.StripSlashes(value.Product)
|
||||
value.Language = wfn.StripSlashes(value.Language)
|
||||
value.Version = wfn.StripSlashes(value.Version)
|
||||
value.TargetSW = wfn.StripSlashes(value.TargetSW)
|
||||
value.Part = wfn.StripSlashes(value.Part)
|
||||
value.Edition = wfn.StripSlashes(value.Edition)
|
||||
value.Other = wfn.StripSlashes(value.Other)
|
||||
value.SWEdition = wfn.StripSlashes(value.SWEdition)
|
||||
value.TargetHW = wfn.StripSlashes(value.TargetHW)
|
||||
value.Update = wfn.StripSlashes(value.Update)
|
||||
|
||||
if value == nil || err != nil {
|
||||
return CPE{}, fmt.Errorf("failed to parse CPE (%s): %w", cpeStr, err)
|
||||
}
|
||||
return *value, nil
|
||||
}
|
||||
|
||||
func NewSlice(cpeStrs ...string) ([]CPE, error) {
|
||||
ret := make([]CPE, len(cpeStrs))
|
||||
func NewSlice(cpeStrs ...string) ([]pkg.CPE, error) {
|
||||
ret := make([]pkg.CPE, len(cpeStrs))
|
||||
for idx, c := range cpeStrs {
|
||||
value, err := New(c)
|
||||
value, err := pkg.NewCPE(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -65,71 +16,8 @@ func NewSlice(cpeStrs ...string) ([]CPE, error) {
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
// Generate Create a list of CPEs, trying to guess the vendor, product tuple and setting TargetSoftware if possible
|
||||
func Generate(p *pkg.Package) ([]CPE, error) {
|
||||
targetSoftwares := candidateTargetSoftwareAttrs(p)
|
||||
vendors := candidateVendors(p)
|
||||
products := candidateProducts(p)
|
||||
|
||||
keys := internal.NewStringSet()
|
||||
cpes := make([]CPE, 0)
|
||||
for _, product := range products {
|
||||
for _, vendor := range vendors {
|
||||
for _, targetSw := range targetSoftwares {
|
||||
// prevent duplicate entries...
|
||||
key := fmt.Sprintf("%s|%s|%s|%s", product, vendor, p.Version, targetSw)
|
||||
if keys.Contains(key) {
|
||||
continue
|
||||
}
|
||||
keys.Add(key)
|
||||
|
||||
// add a new entry...
|
||||
candidateCpe := wfn.NewAttributesWithAny()
|
||||
candidateCpe.Product = product
|
||||
candidateCpe.Vendor = vendor
|
||||
candidateCpe.Version = p.Version
|
||||
candidateCpe.TargetSW = targetSw
|
||||
|
||||
cpes = append(cpes, *candidateCpe)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cpes, nil
|
||||
}
|
||||
|
||||
func candidateTargetSoftwareAttrs(p *pkg.Package) []string {
|
||||
// TODO: expand with package metadata (from type assert)
|
||||
mappedNames := targetSoftware[p.Language]
|
||||
|
||||
if mappedNames == nil {
|
||||
mappedNames = []string{}
|
||||
}
|
||||
|
||||
attrs := make([]string, len(mappedNames))
|
||||
copy(attrs, targetSoftware[p.Language])
|
||||
// last element is the any match, present for all
|
||||
attrs = append(attrs, ANY)
|
||||
|
||||
return attrs
|
||||
}
|
||||
|
||||
func candidateVendors(p *pkg.Package) []string {
|
||||
// TODO: expand with package metadata (from type assert)
|
||||
ret := []string{p.Name, ANY}
|
||||
if p.Language == pkg.Python {
|
||||
ret = append(ret, fmt.Sprintf("python-%s", p.Name))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func candidateProducts(p *pkg.Package) []string {
|
||||
// TODO: expand with package metadata (from type assert)
|
||||
return []string{p.Name}
|
||||
}
|
||||
|
||||
func MatchWithoutVersion(c CPE, candidates []CPE) []CPE {
|
||||
matches := make([]CPE, 0)
|
||||
func MatchWithoutVersion(c pkg.CPE, candidates []pkg.CPE) []pkg.CPE {
|
||||
matches := make([]pkg.CPE, 0)
|
||||
for _, candidate := range candidates {
|
||||
canCopy := candidate
|
||||
if c.MatchWithoutVersion(&canCopy) {
|
||||
|
|
|
@ -4,199 +4,108 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
)
|
||||
|
||||
func must(c CPE, e error) CPE {
|
||||
func must(c pkg.CPE, e error) pkg.CPE {
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected CPE
|
||||
}{
|
||||
{
|
||||
name: "gocase",
|
||||
input: `cpe:/a:10web:form_maker:1.0.0::~~~wordpress~~`,
|
||||
expected: must(New(`cpe:2.3:a:10web:form_maker:1.0.0:*:*:*:*:wordpress:*:*`)),
|
||||
},
|
||||
{
|
||||
name: "dashes",
|
||||
input: `cpe:/a:7-zip:7-zip:4.56:beta:~~~windows~~`,
|
||||
expected: must(New(`cpe:2.3:a:7-zip:7-zip:4.56:beta:*:*:*:windows:*:*`)),
|
||||
},
|
||||
{
|
||||
name: "URL escape characters",
|
||||
input: `cpe:/a:%240.99_kindle_books_project:%240.99_kindle_books:6::~~~android~~`,
|
||||
expected: must(New(`cpe:2.3:a:$0.99_kindle_books_project:$0.99_kindle_books:6:*:*:*:*:android:*:*`)),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual, err := New(test.input)
|
||||
if err != nil {
|
||||
t.Fatalf("got an error while creating CPE: %+v", err)
|
||||
}
|
||||
|
||||
if actual.BindToFmtString() != test.expected.BindToFmtString() {
|
||||
t.Errorf("mismatched entries:\n\texpected:%+v\n\t actual:%+v\n", test.expected.BindToFmtString(), actual.BindToFmtString())
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
p pkg.Package
|
||||
expected []CPE
|
||||
}{
|
||||
{
|
||||
name: "simple package",
|
||||
p: pkg.Package{
|
||||
Name: "name",
|
||||
Version: "3.2",
|
||||
FoundBy: "some-analyzer",
|
||||
Language: pkg.Java,
|
||||
Type: pkg.DebPkg,
|
||||
},
|
||||
expected: []CPE{
|
||||
must(New("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name:name:3.2:*:*:*:*:maven:*:*")),
|
||||
must(New("cpe:2.3:*:name:name:3.2:*:*:*:*:jenkins:*:*")),
|
||||
must(New("cpe:2.3:*:name:name:3.2:*:*:*:*:cloudbees_jenkins:*:*")),
|
||||
must(New("cpe:2.3:*:name:name:3.2:*:*:*:*:*:*:*")),
|
||||
must(New("cpe:2.3:*:*:name:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:*:name:3.2:*:*:*:*:maven:*:*")),
|
||||
must(New("cpe:2.3:*:*:name:3.2:*:*:*:*:jenkins:*:*")),
|
||||
must(New("cpe:2.3:*:*:name:3.2:*:*:*:*:cloudbees_jenkins:*:*")),
|
||||
must(New("cpe:2.3:*:*:name:3.2:*:*:*:*:*:*:*")),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual, err := Generate(&test.p)
|
||||
if err != nil {
|
||||
t.Fatalf("got an error while generating CPEs: %+v", err)
|
||||
}
|
||||
|
||||
if len(actual) != len(test.expected) {
|
||||
for _, e := range actual {
|
||||
t.Errorf(" unexpected entry: %+v", e.BindToFmtString())
|
||||
}
|
||||
t.Fatalf("unexpected number of entries: %d", len(actual))
|
||||
}
|
||||
|
||||
for idx, a := range actual {
|
||||
e := test.expected[idx]
|
||||
if a.BindToFmtString() != e.BindToFmtString() {
|
||||
t.Errorf("mismatched entries @ %d:\n\texpected:%+v\n\t actual:%+v\n", idx, e.BindToFmtString(), a.BindToFmtString())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchWithoutVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
compare CPE
|
||||
candidates []CPE
|
||||
expected []CPE
|
||||
compare pkg.CPE
|
||||
candidates []pkg.CPE
|
||||
expected []pkg.CPE
|
||||
}{
|
||||
{
|
||||
name: "GoCase",
|
||||
compare: must(New("cpe:2.3:*:python-requests:requests:2.3.0:*:*:*:*:python:*:*")),
|
||||
candidates: []CPE{
|
||||
must(New("cpe:2.3:a:python-requests:requests:2.2.1:*:*:*:*:*:*:*")),
|
||||
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:*:*:*:*:*:*:*")),
|
||||
},
|
||||
expected: []CPE{
|
||||
must(New("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:*:*:*:*:*:*:*")),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "IgnoreVersion",
|
||||
compare: must(New("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*")),
|
||||
candidates: []CPE{
|
||||
must(New("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name:name:3.3:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name:name:5.5:*:*:*:*:java:*:*")),
|
||||
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:*:*")),
|
||||
},
|
||||
expected: []CPE{
|
||||
must(New("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name:name:3.3:*:*:*:*:java:*:*")),
|
||||
must(New("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:*:*")),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MatchByTargetSW",
|
||||
compare: must(New("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*")),
|
||||
candidates: []CPE{
|
||||
must(New("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name:name:3.2:*:*:*:*:maven:*:*")),
|
||||
must(New("cpe:2.3:*:name:name:3.2:*:*:*:*:jenkins:*:*")),
|
||||
must(New("cpe:2.3:*:name:name:3.2:*:*:*:*:cloudbees_jenkins:*:*")),
|
||||
must(New("cpe:2.3:*:name:name:3.2:*:*:*:*:*:*:*")),
|
||||
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:*:*:*:*:*:*:*")),
|
||||
},
|
||||
expected: []CPE{
|
||||
must(New("cpe:2.3:*:name:name:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("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:*:*:*:*:*:*:*")),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MatchByName",
|
||||
compare: must(New("cpe:2.3:*:name:name5:3.2:*:*:*:*:java:*:*")),
|
||||
candidates: []CPE{
|
||||
must(New("cpe:2.3:*:name:name1:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name:name2:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name:name3:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name:name4:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name:name5:3.2:*:*:*:*:*:*:*")),
|
||||
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:*:*:*:*:*:*:*")),
|
||||
},
|
||||
expected: []CPE{
|
||||
must(New("cpe:2.3:*:name:name5:3.2:*:*:*:*:*:*:*")),
|
||||
expected: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:*:name:name5:3.2:*:*:*:*:*:*:*")),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MatchByVendor",
|
||||
compare: must(New("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*")),
|
||||
candidates: []CPE{
|
||||
must(New("cpe:2.3:*:name1:name:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name3:name:3.2:*:*:*:*:jaba-no-bother:*:*")),
|
||||
must(New("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name4:name:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name5:name:3.2:*:*:*:*:*:*:*")),
|
||||
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:*:*:*:*:*:*:*")),
|
||||
},
|
||||
expected: []CPE{
|
||||
must(New("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*")),
|
||||
expected: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*")),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MatchAnyVendorOrTargetSW",
|
||||
compare: must(New("cpe:2.3:*:*:name:3.2:*:*:*:*:*:*:*")),
|
||||
candidates: []CPE{
|
||||
must(New("cpe:2.3:*:name1:name:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name3:name:3.2:*:*:*:*:jaba-no-bother:*:*")),
|
||||
must(New("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name4:name:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name5:name:3.2:*:*:*:*:*:*:*")),
|
||||
must(New("cpe:2.3:*:name5:NOMATCH:3.2:*:*:*:*:*:*:*")),
|
||||
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:*:*:*:*:*:*:*")),
|
||||
},
|
||||
expected: []CPE{
|
||||
must(New("cpe:2.3:*:name1:name:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name3:name:3.2:*:*:*:*:jaba-no-bother:*:*")),
|
||||
must(New("cpe:2.3:*:name3:name:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name4:name:3.2:*:*:*:*:java:*:*")),
|
||||
must(New("cpe:2.3:*:name5:name: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:*:*:*:*:*:*:*")),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
10
grype/lib.go
10
grype/lib.go
|
@ -21,14 +21,14 @@ import (
|
|||
"github.com/wagoodman/go-partybus"
|
||||
)
|
||||
|
||||
func Catalog(userImageStr string, scopeOpt source.Scope) (source.Metadata, *pkg.Catalog, distro.Distro, error) {
|
||||
func Catalog(userImageStr string, scopeOpt source.Scope) (source.Metadata, *pkg.Catalog, *distro.Distro, error) {
|
||||
// handle explicit sbom input first
|
||||
if strings.HasPrefix(userImageStr, "sbom:") {
|
||||
// the user has explicitly hinted this is an sbom, if there is an issue return the error
|
||||
filepath := strings.TrimPrefix(userImageStr, "sbom:")
|
||||
sbomReader, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return source.Metadata{}, nil, distro.Distro{}, fmt.Errorf("unable to read sbom: %w", err)
|
||||
return source.Metadata{}, nil, nil, fmt.Errorf("unable to read sbom: %w", err)
|
||||
}
|
||||
return syft.CatalogFromJSON(sbomReader)
|
||||
} else if internal.IsPipedInput() && userImageStr == "" {
|
||||
|
@ -47,7 +47,7 @@ func Catalog(userImageStr string, scopeOpt source.Scope) (source.Metadata, *pkg.
|
|||
// attempt to parse as an image (left syft handle this)
|
||||
theSource, catalog, theDistro, err := syft.Catalog(userImageStr, scopeOpt)
|
||||
if err != nil {
|
||||
return source.Metadata{}, nil, distro.Distro{}, err
|
||||
return source.Metadata{}, nil, nil, err
|
||||
}
|
||||
return theSource.Metadata, catalog, theDistro, nil
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ func FindVulnerabilities(provider vulnerability.Provider, userImageStr string, s
|
|||
return FindVulnerabilitiesForCatalog(provider, theDistro, catalog), sourceMetadata, catalog, nil
|
||||
}
|
||||
|
||||
func FindVulnerabilitiesForCatalog(provider vulnerability.Provider, d distro.Distro, catalog *pkg.Catalog) match.Matches {
|
||||
func FindVulnerabilitiesForCatalog(provider vulnerability.Provider, d *distro.Distro, catalog *pkg.Catalog) match.Matches {
|
||||
packages := make([]*pkg.Package, 0)
|
||||
for p := range catalog.Enumerate() {
|
||||
packages = append(packages, p)
|
||||
|
@ -69,7 +69,7 @@ func FindVulnerabilitiesForCatalog(provider vulnerability.Provider, d distro.Dis
|
|||
return FindVulnerabilitiesForPackage(provider, d, packages...)
|
||||
}
|
||||
|
||||
func FindVulnerabilitiesForPackage(provider vulnerability.Provider, d distro.Distro, packages ...*pkg.Package) match.Matches {
|
||||
func FindVulnerabilitiesForPackage(provider vulnerability.Provider, d *distro.Distro, packages ...*pkg.Package) match.Matches {
|
||||
return matcher.FindMatches(provider, d, packages...)
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ func (m *Matcher) Type() match.MatcherType {
|
|||
return match.ApkMatcher
|
||||
}
|
||||
|
||||
func (m *Matcher) Match(store vulnerability.Provider, d distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
var matches = make([]match.Match, 0)
|
||||
|
||||
// map { CVE string : []match }
|
||||
|
|
|
@ -9,6 +9,13 @@ import (
|
|||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func must(c pkg.CPE, e error) pkg.CPE {
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
type mockStore struct {
|
||||
backend map[string]map[string][]v1.Vulnerability
|
||||
}
|
||||
|
@ -22,8 +29,7 @@ func (s *mockStore) GetVulnerability(namespace, name string) ([]v1.Vulnerability
|
|||
}
|
||||
|
||||
func TestNoSecDBMatch(t *testing.T) {
|
||||
// SecDB (matchesByPacakgeDistro) doesn't have a corresponding
|
||||
// match to nvd, so no matches are returned
|
||||
// SecDB (matchesByPackageDistro) doesn't have a corresponding match to nvd, so no matches are returned
|
||||
store := mockStore{
|
||||
backend: map[string]map[string][]v1.Vulnerability{
|
||||
"nvd": {
|
||||
|
@ -39,8 +45,7 @@ func TestNoSecDBMatch(t *testing.T) {
|
|||
"alpine:3.12": {
|
||||
"libvncserver": []v1.Vulnerability{
|
||||
{
|
||||
// ID doesn't match - this is the key
|
||||
// for comparison in the matcher
|
||||
// ID doesn't match - this is the key for comparison in the matcher
|
||||
ID: "CVE-2020-2",
|
||||
VersionConstraint: "<= 0.9.11",
|
||||
VersionFormat: "apk",
|
||||
|
@ -60,8 +65,11 @@ func TestNoSecDBMatch(t *testing.T) {
|
|||
p := pkg.Package{
|
||||
Name: "libvncserver",
|
||||
Version: "0.9.9",
|
||||
CPEs: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:a:*:libvncserver:0.9.9:*:*:*:*:*:*:*")),
|
||||
},
|
||||
}
|
||||
matches, err := m.Match(provider, d, &p)
|
||||
matches, err := m.Match(provider, &d, &p)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get matches: %+v", err)
|
||||
|
@ -74,8 +82,7 @@ func TestNoSecDBMatch(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMatches(t *testing.T) {
|
||||
// NVD and Alpine's secDB both have the same CVE ID for the package
|
||||
// so it matches
|
||||
// NVD and Alpine's secDB both have the same CVE ID for the package so it matches
|
||||
store := mockStore{
|
||||
backend: map[string]map[string][]v1.Vulnerability{
|
||||
"nvd": {
|
||||
|
@ -91,8 +98,7 @@ func TestMatches(t *testing.T) {
|
|||
"alpine:3.12": {
|
||||
"libvncserver": []v1.Vulnerability{
|
||||
{
|
||||
// ID *does* match - this is the key
|
||||
// for comparison in the matcher
|
||||
// ID *does* match - this is the key for comparison in the matcher
|
||||
ID: "CVE-2020-1",
|
||||
VersionConstraint: "<= 0.9.11",
|
||||
VersionFormat: "apk",
|
||||
|
@ -112,8 +118,11 @@ func TestMatches(t *testing.T) {
|
|||
p := pkg.Package{
|
||||
Name: "libvncserver",
|
||||
Version: "0.9.9",
|
||||
CPEs: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:a:*:libvncserver:0.9.9:*:*:*:*:*:*:*")),
|
||||
},
|
||||
}
|
||||
matches, err := m.Match(provider, d, &p)
|
||||
matches, err := m.Match(provider, &d, &p)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get matches: %+v", err)
|
||||
|
|
|
@ -3,7 +3,6 @@ package common
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/grype/grype/cpe"
|
||||
"github.com/anchore/grype/grype/match"
|
||||
"github.com/anchore/grype/grype/version"
|
||||
"github.com/anchore/grype/grype/vulnerability"
|
||||
|
@ -11,7 +10,7 @@ import (
|
|||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func must(c cpe.CPE, e error) cpe.CPE {
|
||||
func must(c pkg.CPE, e error) pkg.CPE {
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
|
@ -36,29 +35,29 @@ func (pr *mockCPEProvider) stub() {
|
|||
{
|
||||
Constraint: version.MustGetConstraint("< 3.7.6", version.SemanticFormat),
|
||||
ID: "CVE-2017-fake-1",
|
||||
CPEs: []cpe.CPE{
|
||||
must(cpe.New("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:rails:*:*")),
|
||||
CPEs: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:rails:*:*")),
|
||||
},
|
||||
},
|
||||
{
|
||||
Constraint: version.MustGetConstraint("< 3.7.4", version.SemanticFormat),
|
||||
ID: "CVE-2017-fake-2",
|
||||
CPEs: []cpe.CPE{
|
||||
must(cpe.New("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:ruby:*:*")),
|
||||
CPEs: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:ruby:*:*")),
|
||||
},
|
||||
},
|
||||
{
|
||||
Constraint: version.MustGetConstraint("= 4.0.1", version.SemanticFormat),
|
||||
ID: "CVE-2017-fake-3",
|
||||
CPEs: []cpe.CPE{
|
||||
must(cpe.New("cpe:2.3:*:couldntgetthisrightcouldyou:activerecord:4.0.1:*:*:*:*:*:*:*")),
|
||||
CPEs: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:*:couldntgetthisrightcouldyou:activerecord:4.0.1:*:*:*:*:*:*:*")),
|
||||
},
|
||||
},
|
||||
{
|
||||
Constraint: version.MustGetConstraint("= 4.0.1", version.SemanticFormat),
|
||||
ID: "CVE-2017-fake-3",
|
||||
CPEs: []cpe.CPE{
|
||||
must(cpe.New("cpe:2.3:*:couldntgetthisrightcouldyou:activerecord:4.0.1:*:*:*:*:*:*:*")),
|
||||
CPEs: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:*:couldntgetthisrightcouldyou:activerecord:4.0.1:*:*:*:*:*:*:*")),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -66,15 +65,15 @@ func (pr *mockCPEProvider) stub() {
|
|||
{
|
||||
Constraint: version.MustGetConstraint("< 98SP3", version.UnknownFormat),
|
||||
ID: "CVE-2017-fake-4",
|
||||
CPEs: []cpe.CPE{
|
||||
must(cpe.New("cpe:2.3:*:awesome:awesome:*:*:*:*:*:*:*:*")),
|
||||
CPEs: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:*:awesome:awesome:*:*:*:*:*:*:*:*")),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (pr *mockCPEProvider) GetByCPE(c cpe.CPE) ([]*vulnerability.Vulnerability, error) {
|
||||
func (pr *mockCPEProvider) GetByCPE(c pkg.CPE) ([]*vulnerability.Vulnerability, error) {
|
||||
return pr.data["nvd"][c.Product], nil
|
||||
}
|
||||
|
||||
|
@ -87,6 +86,10 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
|
|||
{
|
||||
name: "match from range",
|
||||
p: pkg.Package{
|
||||
CPEs: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:*:activerecord:activerecord:3.7.5:rando1:*:rando2:*:ruby:*:*")),
|
||||
must(pkg.NewCPE("cpe:2.3:*:activerecord:activerecord:3.7.5:rando4:*:rando3:*:rails:*:*")),
|
||||
},
|
||||
Name: "activerecord",
|
||||
Version: "3.7.5",
|
||||
Language: pkg.Ruby,
|
||||
|
@ -99,6 +102,10 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
|
|||
{
|
||||
name: "multiple matches",
|
||||
p: pkg.Package{
|
||||
CPEs: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:*:activerecord:activerecord:3.7.3:rando1:*:rando2:*:ruby:*:*")),
|
||||
must(pkg.NewCPE("cpe:2.3:*:activerecord:activerecord:3.7.3:rando4:*:rando3:*:rails:*:*")),
|
||||
},
|
||||
Name: "activerecord",
|
||||
Version: "3.7.3",
|
||||
Language: pkg.Ruby,
|
||||
|
@ -112,6 +119,10 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
|
|||
{
|
||||
name: "exact match",
|
||||
p: pkg.Package{
|
||||
CPEs: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:*:activerecord:activerecord:4.0.1:rando1:*:rando2:*:ruby:*:*")),
|
||||
must(pkg.NewCPE("cpe:2.3:*:activerecord:activerecord:4.0.1:rando4:*:rando3:*:rails:*:*")),
|
||||
},
|
||||
Name: "activerecord",
|
||||
Version: "4.0.1",
|
||||
Language: pkg.Ruby,
|
||||
|
@ -134,6 +145,9 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
|
|||
{
|
||||
name: "fuzzy version match",
|
||||
p: pkg.Package{
|
||||
CPEs: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:*:awesome:awesome:98SE1:rando1:*:rando2:*:dunno:*:*")),
|
||||
},
|
||||
Name: "awesome",
|
||||
Version: "98SE1",
|
||||
},
|
||||
|
@ -156,7 +170,7 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
|
|||
for _, a := range actual {
|
||||
t.Errorf(" entry: %+v", a)
|
||||
}
|
||||
t.Fatalf("unexpected matches count: %d", len(actual))
|
||||
t.Fatalf("unexpected matches count: %d != %d", len(actual), len(test.expected))
|
||||
}
|
||||
|
||||
foundCVEs := internal.NewStringSet()
|
||||
|
|
|
@ -11,15 +11,18 @@ import (
|
|||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func FindMatchesByPackageDistro(store vulnerability.ProviderByDistro, d distro.Distro, p *pkg.Package, upstreamMatcher match.MatcherType) ([]match.Match, error) {
|
||||
func FindMatchesByPackageDistro(store vulnerability.ProviderByDistro, d *distro.Distro, p *pkg.Package, upstreamMatcher match.MatcherType) ([]match.Match, error) {
|
||||
verObj, err := version.NewVersionFromPkg(p)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("matcher failed to parse version pkg='%s' ver='%s': %w", p.Name, p.Version, err)
|
||||
}
|
||||
|
||||
allPkgVulns, err := store.GetByDistro(d, p)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("matcher failed to fetch distro='%s' pkg='%s': %w", d, p.Name, err)
|
||||
var allPkgVulns []*vulnerability.Vulnerability
|
||||
if d != nil {
|
||||
allPkgVulns, err = store.GetByDistro(*d, p)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("matcher failed to fetch distro='%s' pkg='%s': %w", d, p.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
matches := make([]match.Match, 0)
|
||||
|
|
|
@ -73,7 +73,7 @@ func TestFindMatchesByPackageDistro(t *testing.T) {
|
|||
}
|
||||
|
||||
store := newMockProviderByDistro()
|
||||
actual, err := FindMatchesByPackageDistro(store, d, &p, match.PythonMatcher)
|
||||
actual, err := FindMatchesByPackageDistro(store, &d, &p, match.PythonMatcher)
|
||||
if err != nil {
|
||||
t.Fatalf("error while finding matches: %+v", err)
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ func (c *controller) trackMatcher() (*progress.Manual, *progress.Manual) {
|
|||
return &packagesProcessed, &vulnerabilitiesDiscovered
|
||||
}
|
||||
|
||||
func (c *controller) findMatches(provider vulnerability.Provider, d distro.Distro, packages ...*pkg.Package) match.Matches {
|
||||
func (c *controller) findMatches(provider vulnerability.Provider, d *distro.Distro, packages ...*pkg.Package) match.Matches {
|
||||
res := match.NewMatches()
|
||||
|
||||
packagesProcessed, vulnerabilitiesDiscovered := c.trackMatcher()
|
||||
|
@ -106,7 +106,7 @@ func (c *controller) findMatches(provider vulnerability.Provider, d distro.Distr
|
|||
return res
|
||||
}
|
||||
|
||||
func FindMatches(provider vulnerability.Provider, d distro.Distro, packages ...*pkg.Package) match.Matches {
|
||||
func FindMatches(provider vulnerability.Provider, d *distro.Distro, packages ...*pkg.Package) match.Matches {
|
||||
return controllerInstance.findMatches(provider, d, packages...)
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ func (m *Matcher) Type() match.MatcherType {
|
|||
return match.DpkgMatcher
|
||||
}
|
||||
|
||||
func (m *Matcher) Match(store vulnerability.Provider, d distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
matches := make([]match.Match, 0)
|
||||
|
||||
sourceMatches, err := m.matchBySourceIndirection(store, d, p)
|
||||
|
@ -40,7 +40,7 @@ func (m *Matcher) Match(store vulnerability.Provider, d distro.Distro, p *pkg.Pa
|
|||
return matches, nil
|
||||
}
|
||||
|
||||
func (m *Matcher) matchBySourceIndirection(store vulnerability.ProviderByDistro, d distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
func (m *Matcher) matchBySourceIndirection(store vulnerability.ProviderByDistro, d *distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
value, ok := p.Metadata.(pkg.DpkgMetadata)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("bad dpkg metadata type='%T'", value)
|
||||
|
|
|
@ -26,7 +26,7 @@ func TestMatcherDpkg_matchBySourceIndirection(t *testing.T) {
|
|||
}
|
||||
|
||||
store := newMockProvider()
|
||||
actual, err := matcher.matchBySourceIndirection(store, d, &p)
|
||||
actual, err := matcher.matchBySourceIndirection(store, &d, &p)
|
||||
|
||||
if len(actual) != 2 {
|
||||
t.Fatalf("unexpected indirect matches count: %d", len(actual))
|
||||
|
|
|
@ -19,7 +19,7 @@ func (m *Matcher) Type() match.MatcherType {
|
|||
return match.JavaMatcher
|
||||
}
|
||||
|
||||
func (m *Matcher) Match(store vulnerability.Provider, _ distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
func (m *Matcher) Match(store vulnerability.Provider, _ *distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
var matches = make([]match.Match, 0)
|
||||
langMatches, err := common.FindMatchesByPackageLanguage(store, p.Language, p, m.Type())
|
||||
if err != nil {
|
||||
|
|
|
@ -19,7 +19,7 @@ func (m *Matcher) Type() match.MatcherType {
|
|||
return match.JavascriptMatcher
|
||||
}
|
||||
|
||||
func (m *Matcher) Match(store vulnerability.Provider, _ distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
func (m *Matcher) Match(store vulnerability.Provider, _ *distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
var matches = make([]match.Match, 0)
|
||||
langMatches, err := common.FindMatchesByPackageLanguage(store, p.Language, p, m.Type())
|
||||
if err != nil {
|
||||
|
|
|
@ -10,5 +10,5 @@ import (
|
|||
type Matcher interface {
|
||||
PackageTypes() []pkg.Type
|
||||
Type() match.MatcherType
|
||||
Match(vulnerability.Provider, distro.Distro, *pkg.Package) ([]match.Match, error)
|
||||
Match(vulnerability.Provider, *distro.Distro, *pkg.Package) ([]match.Match, error)
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ func (m *Matcher) Type() match.MatcherType {
|
|||
return match.PythonMatcher
|
||||
}
|
||||
|
||||
func (m *Matcher) Match(store vulnerability.Provider, _ distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
func (m *Matcher) Match(store vulnerability.Provider, _ *distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
var matches = make([]match.Match, 0)
|
||||
langMatches, err := common.FindMatchesByPackageLanguage(store, p.Language, p, m.Type())
|
||||
if err != nil {
|
||||
|
|
|
@ -27,7 +27,7 @@ func (m *Matcher) Type() match.MatcherType {
|
|||
return match.RpmDBMatcher
|
||||
}
|
||||
|
||||
func (m *Matcher) Match(store vulnerability.Provider, d distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
matches := make([]match.Match, 0)
|
||||
|
||||
sourceMatches, err := m.matchBySourceIndirection(store, d, p)
|
||||
|
@ -45,7 +45,7 @@ func (m *Matcher) Match(store vulnerability.Provider, d distro.Distro, p *pkg.Pa
|
|||
return matches, nil
|
||||
}
|
||||
|
||||
func (m *Matcher) matchBySourceIndirection(store vulnerability.ProviderByDistro, d distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
func (m *Matcher) matchBySourceIndirection(store vulnerability.ProviderByDistro, d *distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
value, ok := p.Metadata.(pkg.RpmdbMetadata)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("bad rpmdb metadata type='%T'", value)
|
||||
|
|
|
@ -27,7 +27,7 @@ func TestMatcherDpkg_matchBySourceIndirection(t *testing.T) {
|
|||
}
|
||||
|
||||
store := newMockProvider()
|
||||
actual, err := matcher.matchBySourceIndirection(store, d, &p)
|
||||
actual, err := matcher.matchBySourceIndirection(store, &d, &p)
|
||||
|
||||
if len(actual) != 2 {
|
||||
t.Fatalf("unexpected indirect matches count: %d", len(actual))
|
||||
|
@ -87,7 +87,7 @@ func TestMatcherDpkg_matchBySourceIndirection_ignoreSource(t *testing.T) {
|
|||
}
|
||||
|
||||
store := newMockProvider()
|
||||
actual, err := matcher.matchBySourceIndirection(store, d, &p)
|
||||
actual, err := matcher.matchBySourceIndirection(store, &d, &p)
|
||||
|
||||
if len(actual) != 0 {
|
||||
t.Fatalf("unexpected indirect matches count: %d", len(actual))
|
||||
|
|
|
@ -19,7 +19,7 @@ func (m *Matcher) Type() match.MatcherType {
|
|||
return match.RubyGemMatcher
|
||||
}
|
||||
|
||||
func (m *Matcher) Match(store vulnerability.Provider, _ distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
func (m *Matcher) Match(store vulnerability.Provider, _ *distro.Distro, p *pkg.Package) ([]match.Match, error) {
|
||||
var matches = make([]match.Match, 0)
|
||||
langMatches, err := common.FindMatchesByPackageLanguage(store, p.Language, p, m.Type())
|
||||
if err != nil {
|
||||
|
|
|
@ -38,7 +38,7 @@ type MatchDetails struct {
|
|||
}
|
||||
|
||||
// NewDocument creates and populates a new Document struct, representing the populated JSON document.
|
||||
func NewDocument(catalog *pkg.Catalog, d distro.Distro, srcMetadata source.Metadata, matches match.Matches, metadataProvider vulnerability.MetadataProvider) (Document, error) {
|
||||
func NewDocument(catalog *pkg.Catalog, d *distro.Distro, srcMetadata source.Metadata, matches match.Matches, metadataProvider vulnerability.MetadataProvider) (Document, error) {
|
||||
// we must preallocate the findings to ensure the JSON document does not show "null" when no matches are found
|
||||
var findings = make([]Match, 0)
|
||||
for m := range matches.Enumerate() {
|
||||
|
|
|
@ -17,13 +17,13 @@ import (
|
|||
type Presenter struct {
|
||||
matches match.Matches
|
||||
catalog *pkg.Catalog
|
||||
distro distro.Distro
|
||||
distro *distro.Distro
|
||||
srcMetadata source.Metadata
|
||||
metadataProvider vulnerability.MetadataProvider
|
||||
}
|
||||
|
||||
// NewPresenter is a *Presenter constructor
|
||||
func NewPresenter(matches match.Matches, catalog *pkg.Catalog, d distro.Distro, srcMetadata source.Metadata, metadataProvider vulnerability.MetadataProvider) *Presenter {
|
||||
func NewPresenter(matches match.Matches, catalog *pkg.Catalog, d *distro.Distro, srcMetadata source.Metadata, metadataProvider vulnerability.MetadataProvider) *Presenter {
|
||||
return &Presenter{
|
||||
matches: matches,
|
||||
catalog: catalog,
|
||||
|
|
|
@ -160,7 +160,7 @@ func TestJsonImgsPresenter(t *testing.T) {
|
|||
t.Fatalf("failed to create scope: %+v", err)
|
||||
}
|
||||
|
||||
pres := NewPresenter(matches, catalog, d, theSource.Metadata, newMetadataMock())
|
||||
pres := NewPresenter(matches, catalog, &d, theSource.Metadata, newMetadataMock())
|
||||
|
||||
// TODO: add a constructor for a match.Match when the data is better shaped
|
||||
|
||||
|
@ -276,7 +276,7 @@ func TestJsonDirsPresenter(t *testing.T) {
|
|||
t.Fatalf("could not make distro: %+v", err)
|
||||
}
|
||||
|
||||
pres := NewPresenter(matches, catalog, d, s.Metadata, newMetadataMock())
|
||||
pres := NewPresenter(matches, catalog, &d, s.Metadata, newMetadataMock())
|
||||
|
||||
// TODO: add a constructor for a match.Match when the data is better shaped
|
||||
|
||||
|
@ -328,7 +328,7 @@ func TestEmptyJsonPresenter(t *testing.T) {
|
|||
t.Fatalf("could not make distro: %+v", err)
|
||||
}
|
||||
|
||||
pres := NewPresenter(matches, catalog, d, theSource.Metadata, nil)
|
||||
pres := NewPresenter(matches, catalog, &d, theSource.Metadata, nil)
|
||||
|
||||
// run presenter
|
||||
if err = pres.Present(&buffer); err != nil {
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
],
|
||||
"licenses": null,
|
||||
"language": "",
|
||||
"cpes": [],
|
||||
"purl": "",
|
||||
"metadataType": ""
|
||||
}
|
||||
},
|
||||
|
@ -69,6 +71,8 @@
|
|||
],
|
||||
"licenses": null,
|
||||
"language": "",
|
||||
"cpes": [],
|
||||
"purl": "",
|
||||
"metadataType": ""
|
||||
}
|
||||
},
|
||||
|
@ -99,6 +103,8 @@
|
|||
],
|
||||
"licenses": null,
|
||||
"language": "",
|
||||
"cpes": [],
|
||||
"purl": "",
|
||||
"metadataType": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
],
|
||||
"licenses": null,
|
||||
"language": "",
|
||||
"cpes": [],
|
||||
"purl": "",
|
||||
"metadataType": ""
|
||||
}
|
||||
},
|
||||
|
@ -71,6 +73,8 @@
|
|||
],
|
||||
"licenses": null,
|
||||
"language": "",
|
||||
"cpes": [],
|
||||
"purl": "",
|
||||
"metadataType": ""
|
||||
}
|
||||
},
|
||||
|
@ -102,6 +106,8 @@
|
|||
],
|
||||
"licenses": null,
|
||||
"language": "",
|
||||
"cpes": [],
|
||||
"purl": "",
|
||||
"metadataType": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ type Presenter interface {
|
|||
}
|
||||
|
||||
// GetPresenter retrieves a Presenter that matches a CLI option
|
||||
func GetPresenter(option Option, matches match.Matches, catalog *pkg.Catalog, d distro.Distro, srcMetadata source.Metadata, metadataProvider vulnerability.MetadataProvider) Presenter {
|
||||
func GetPresenter(option Option, matches match.Matches, catalog *pkg.Catalog, d *distro.Distro, srcMetadata source.Metadata, metadataProvider vulnerability.MetadataProvider) Presenter {
|
||||
switch option {
|
||||
case JSONPresenter:
|
||||
return json.NewPresenter(matches, catalog, d, srcMetadata, metadataProvider)
|
||||
|
|
|
@ -3,7 +3,6 @@ package version
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/grype/grype/cpe"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
|
@ -14,7 +13,7 @@ type Version struct {
|
|||
}
|
||||
|
||||
type rich struct {
|
||||
cpeVers []cpe.CPE
|
||||
cpeVers []pkg.CPE
|
||||
semVer *semanticVersion
|
||||
debVer *debVersion
|
||||
rpmVer *rpmVersion
|
||||
|
@ -39,12 +38,8 @@ func NewVersionFromPkg(p *pkg.Package) (*Version, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpes, err := cpe.Generate(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ver.rich.cpeVers = cpes
|
||||
ver.rich.cpeVers = p.CPEs
|
||||
return ver, nil
|
||||
}
|
||||
|
||||
|
@ -72,7 +67,7 @@ func (v *Version) populate() error {
|
|||
return fmt.Errorf("no rich version populated (format=%s)", v.Format)
|
||||
}
|
||||
|
||||
func (v Version) CPEs() []cpe.CPE {
|
||||
func (v Version) CPEs() []pkg.CPE {
|
||||
return v.rich.cpeVers
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package vulnerability
|
||||
|
||||
import (
|
||||
"github.com/anchore/grype/grype/cpe"
|
||||
"github.com/anchore/syft/syft/distro"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
@ -21,7 +20,7 @@ type ProviderByLanguage interface {
|
|||
}
|
||||
|
||||
type ProviderByCPE interface {
|
||||
GetByCPE(cpe.CPE) ([]*Vulnerability, error)
|
||||
GetByCPE(pkg.CPE) ([]*Vulnerability, error)
|
||||
}
|
||||
|
||||
type MetadataProvider interface {
|
||||
|
|
|
@ -70,7 +70,7 @@ func (pr *StoreAdapter) GetByLanguage(l pkg.Language, p *pkg.Package) ([]*Vulner
|
|||
return vulns, nil
|
||||
}
|
||||
|
||||
func (pr *StoreAdapter) GetByCPE(requestCPE cpe.CPE) ([]*Vulnerability, error) {
|
||||
func (pr *StoreAdapter) GetByCPE(requestCPE pkg.CPE) ([]*Vulnerability, error) {
|
||||
vulns := make([]*Vulnerability, 0)
|
||||
|
||||
namespaces := cpeNamespaces()
|
||||
|
|
|
@ -3,7 +3,6 @@ package vulnerability
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/grype/grype/cpe"
|
||||
"github.com/go-test/deep"
|
||||
|
||||
"github.com/anchore/grype/grype/version"
|
||||
|
@ -54,7 +53,7 @@ func TestGetByDistro(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func must(c cpe.CPE, e error) cpe.CPE {
|
||||
func must(c pkg.CPE, e error) pkg.CPE {
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
|
@ -65,19 +64,19 @@ func TestGetByCPE(t *testing.T) {
|
|||
|
||||
tests := []struct {
|
||||
name string
|
||||
cpe cpe.CPE
|
||||
cpe pkg.CPE
|
||||
expected []Vulnerability
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
name: "match from name and target SW",
|
||||
cpe: must(cpe.New("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:ruby:*:*")),
|
||||
cpe: must(pkg.NewCPE("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:ruby:*:*")),
|
||||
expected: []Vulnerability{
|
||||
{
|
||||
Constraint: version.MustGetConstraint("< 3.7.4", version.UnknownFormat),
|
||||
ID: "CVE-2014-fake-4",
|
||||
CPEs: []cpe.CPE{
|
||||
must(cpe.New("cpe:2.3:*:activerecord:activerecord:*:*:something:*:*:ruby:*:*")),
|
||||
CPEs: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:*:activerecord:activerecord:*:*:something:*:*:ruby:*:*")),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -85,20 +84,20 @@ func TestGetByCPE(t *testing.T) {
|
|||
|
||||
{
|
||||
name: "match from vendor & name",
|
||||
cpe: must(cpe.New("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:*:*:*")),
|
||||
cpe: must(pkg.NewCPE("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:*:*:*")),
|
||||
expected: []Vulnerability{
|
||||
{
|
||||
Constraint: version.MustGetConstraint("< 3.7.6", version.UnknownFormat),
|
||||
ID: "CVE-2014-fake-3",
|
||||
CPEs: []cpe.CPE{
|
||||
must(cpe.New("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:rails:*:*")),
|
||||
CPEs: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:rails:*:*")),
|
||||
},
|
||||
},
|
||||
{
|
||||
Constraint: version.MustGetConstraint("< 3.7.4", version.UnknownFormat),
|
||||
ID: "CVE-2014-fake-4",
|
||||
CPEs: []cpe.CPE{
|
||||
must(cpe.New("cpe:2.3:*:activerecord:activerecord:*:*:something:*:*:ruby:*:*")),
|
||||
CPEs: []pkg.CPE{
|
||||
must(pkg.NewCPE("cpe:2.3:*:activerecord:activerecord:*:*:something:*:*:ruby:*:*")),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -106,7 +105,7 @@ func TestGetByCPE(t *testing.T) {
|
|||
|
||||
{
|
||||
name: "dont allow any name",
|
||||
cpe: must(cpe.New("cpe:2.3:*:couldntgetthisrightcouldyou:*:*:*:*:*:*:*:*:*")),
|
||||
cpe: must(pkg.NewCPE("cpe:2.3:*:couldntgetthisrightcouldyou:*:*:*:*:*:*:*:*:*")),
|
||||
err: true,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@ import (
|
|||
"fmt"
|
||||
|
||||
v1 "github.com/anchore/grype-db/pkg/db/v1"
|
||||
"github.com/anchore/grype/grype/cpe"
|
||||
"github.com/anchore/grype/grype/version"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
type Vulnerability struct {
|
||||
Constraint version.Constraint
|
||||
CPEs []cpe.CPE
|
||||
CPEs []pkg.CPE
|
||||
ID string
|
||||
RecordSource string
|
||||
FixedInVersion string
|
||||
|
@ -27,7 +27,7 @@ func NewVulnerability(vuln v1.Vulnerability) (*Vulnerability, error) {
|
|||
return &Vulnerability{
|
||||
Constraint: constraint,
|
||||
ID: vuln.ID,
|
||||
CPEs: make([]cpe.CPE, 0),
|
||||
CPEs: make([]pkg.CPE, 0),
|
||||
RecordSource: vuln.RecordSource,
|
||||
FixedInVersion: vuln.FixedInVersion,
|
||||
}, nil
|
||||
|
|
Loading…
Reference in a new issue