-
Notifications
You must be signed in to change notification settings - Fork 587
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
implement v5 db schema to support improved matching between rpm appst…
…ream modules (#944) Adds support for a `package_qualifiers` column to allow evaluating package matches to vulnerabilities based on more than just version constraints. Currently adds an rpm-modularity qualifier in order to support matching to correct app stream module in order to reduce false positives within rpm-based distro ecosystems. In order to prevent an increase in false positive matches for previous versions of grype using the v4 schema, this change (along with the vulnerability source driver parser updates) requires bumping the schema to v5. Signed-off-by: Weston Steimel <weston.steimel@anchore.com> Signed-off-by: Alex Goodman <alex.goodman@anchore.com> Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
- Loading branch information
1 parent
b62ad70
commit 4cda526
Showing
93 changed files
with
15,413 additions
and
3,473 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
package db | ||
|
||
import v4 "github.com/anchore/grype/grype/db/v4" | ||
import v5 "github.com/anchore/grype/grype/db/v5" | ||
|
||
// Closer lets receiver close the db connection and free any allocated db resources. | ||
// It's especially useful if vulnerability DB loaded repeatedly during some periodic SBOM scanning process. | ||
type Closer struct { | ||
v4.DBCloser | ||
v5.DBCloser | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package v5 | ||
|
||
// Advisory represents published statements regarding a vulnerability (and potentially about it's resolution). | ||
type Advisory struct { | ||
ID string `json:"id"` | ||
Link string `json:"link"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package v5 | ||
|
||
type DiffReason = string | ||
|
||
const ( | ||
DiffAdded DiffReason = "added" | ||
DiffChanged DiffReason = "changed" | ||
DiffRemoved DiffReason = "removed" | ||
) | ||
|
||
type Diff struct { | ||
Reason DiffReason `json:"reason"` | ||
ID string `json:"id"` | ||
Namespace string `json:"namespace"` | ||
Packages []string `json:"packages"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package v5 | ||
|
||
type FixState string | ||
|
||
const ( | ||
UnknownFixState FixState = "unknown" | ||
FixedState FixState = "fixed" | ||
NotFixedState FixState = "not-fixed" | ||
WontFixState FixState = "wont-fix" | ||
) | ||
|
||
// Fix represents all information about known fixes for a stated vulnerability. | ||
type Fix struct { | ||
Versions []string `json:"versions"` // The version(s) which this particular vulnerability was fixed in | ||
State FixState `json:"state"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package v5 | ||
|
||
import ( | ||
"time" | ||
) | ||
|
||
// ID represents identifying information for a DB and the data it contains. | ||
type ID struct { | ||
// BuildTimestamp is the timestamp used to define the age of the DB, ideally including the age of the data | ||
// contained in the DB, not just when the DB file was created. | ||
BuildTimestamp time.Time `json:"build_timestamp"` | ||
SchemaVersion int `json:"schema_version"` | ||
} | ||
|
||
type IDReader interface { | ||
GetID() (*ID, error) | ||
} | ||
|
||
type IDWriter interface { | ||
SetID(ID) error | ||
} | ||
|
||
func NewID(age time.Time) ID { | ||
return ID{ | ||
BuildTimestamp: age.UTC(), | ||
SchemaVersion: SchemaVersion, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package cpe | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/anchore/grype/grype/db/v5/pkg/resolver" | ||
"github.com/anchore/grype/grype/db/v5/pkg/resolver/stock" | ||
) | ||
|
||
const ID = "cpe" | ||
|
||
type Namespace struct { | ||
provider string | ||
resolver resolver.Resolver | ||
} | ||
|
||
func NewNamespace(provider string) *Namespace { | ||
return &Namespace{ | ||
provider: provider, | ||
resolver: &stock.Resolver{}, | ||
} | ||
} | ||
|
||
func FromString(namespaceStr string) (*Namespace, error) { | ||
if namespaceStr == "" { | ||
return nil, errors.New("unable to create CPE namespace from empty string") | ||
} | ||
|
||
components := strings.Split(namespaceStr, ":") | ||
|
||
if len(components) != 2 { | ||
return nil, fmt.Errorf("unable to create CPE namespace from %s: incorrect number of components", namespaceStr) | ||
} | ||
|
||
if components[1] != ID { | ||
return nil, fmt.Errorf("unable to create CPE namespace from %s: type %s is incorrect", namespaceStr, components[1]) | ||
} | ||
|
||
return NewNamespace(components[0]), nil | ||
} | ||
|
||
func (n *Namespace) Provider() string { | ||
return n.provider | ||
} | ||
|
||
func (n *Namespace) Resolver() resolver.Resolver { | ||
return n.resolver | ||
} | ||
|
||
func (n Namespace) String() string { | ||
return fmt.Sprintf("%s:%s", n.provider, ID) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package cpe | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestFromString(t *testing.T) { | ||
successTests := []struct { | ||
namespaceString string | ||
result *Namespace | ||
}{ | ||
{ | ||
namespaceString: "abc.xyz:cpe", | ||
result: NewNamespace("abc.xyz"), | ||
}, | ||
} | ||
|
||
for _, test := range successTests { | ||
result, _ := FromString(test.namespaceString) | ||
assert.Equal(t, result, test.result) | ||
} | ||
|
||
errorTests := []struct { | ||
namespaceString string | ||
errorMessage string | ||
}{ | ||
{ | ||
namespaceString: "", | ||
errorMessage: "unable to create CPE namespace from empty string", | ||
}, | ||
{ | ||
namespaceString: "single-component", | ||
errorMessage: "unable to create CPE namespace from single-component: incorrect number of components", | ||
}, | ||
{ | ||
namespaceString: "too:many:components", | ||
errorMessage: "unable to create CPE namespace from too:many:components: incorrect number of components", | ||
}, | ||
{ | ||
namespaceString: "wrong:namespace_type", | ||
errorMessage: "unable to create CPE namespace from wrong:namespace_type: type namespace_type is incorrect", | ||
}, | ||
} | ||
|
||
for _, test := range errorTests { | ||
_, err := FromString(test.namespaceString) | ||
assert.EqualError(t, err, test.errorMessage) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package distro | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/anchore/grype/grype/db/v5/pkg/resolver" | ||
"github.com/anchore/grype/grype/db/v5/pkg/resolver/stock" | ||
"github.com/anchore/grype/grype/distro" | ||
) | ||
|
||
const ID = "distro" | ||
|
||
type Namespace struct { | ||
provider string | ||
distroType distro.Type | ||
version string | ||
resolver resolver.Resolver | ||
} | ||
|
||
func NewNamespace(provider string, distroType distro.Type, version string) *Namespace { | ||
return &Namespace{ | ||
provider: provider, | ||
distroType: distroType, | ||
version: version, | ||
resolver: &stock.Resolver{}, | ||
} | ||
} | ||
|
||
func FromString(namespaceStr string) (*Namespace, error) { | ||
if namespaceStr == "" { | ||
return nil, errors.New("unable to create distro namespace from empty string") | ||
} | ||
|
||
components := strings.Split(namespaceStr, ":") | ||
|
||
if len(components) != 4 { | ||
return nil, fmt.Errorf("unable to create distro namespace from %s: incorrect number of components", namespaceStr) | ||
} | ||
|
||
if components[1] != ID { | ||
return nil, fmt.Errorf("unable to create distro namespace from %s: type %s is incorrect", namespaceStr, components[1]) | ||
} | ||
|
||
return NewNamespace(components[0], distro.Type(components[2]), components[3]), nil | ||
} | ||
|
||
func (n *Namespace) Provider() string { | ||
return n.provider | ||
} | ||
|
||
func (n *Namespace) DistroType() distro.Type { | ||
return n.distroType | ||
} | ||
|
||
func (n *Namespace) Version() string { | ||
return n.version | ||
} | ||
|
||
func (n *Namespace) Resolver() resolver.Resolver { | ||
return n.resolver | ||
} | ||
|
||
func (n Namespace) String() string { | ||
return fmt.Sprintf("%s:%s:%s:%s", n.provider, ID, n.distroType, n.version) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package distro | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
|
||
grypeDistro "github.com/anchore/grype/grype/distro" | ||
) | ||
|
||
func TestFromString(t *testing.T) { | ||
successTests := []struct { | ||
namespaceString string | ||
result *Namespace | ||
}{ | ||
{ | ||
namespaceString: "alpine:distro:alpine:3.15", | ||
result: NewNamespace("alpine", grypeDistro.Alpine, "3.15"), | ||
}, | ||
{ | ||
namespaceString: "redhat:distro:redhat:8", | ||
result: NewNamespace("redhat", grypeDistro.RedHat, "8"), | ||
}, | ||
{ | ||
namespaceString: "abc.xyz:distro:unknown:abcd~~~", | ||
result: NewNamespace("abc.xyz", grypeDistro.Type("unknown"), "abcd~~~"), | ||
}, | ||
{ | ||
namespaceString: "msrc:distro:windows:10111", | ||
result: NewNamespace("msrc", grypeDistro.Type("windows"), "10111"), | ||
}, | ||
{ | ||
namespaceString: "amazon:distro:amazonlinux:2022", | ||
result: NewNamespace("amazon", grypeDistro.AmazonLinux, "2022"), | ||
}, | ||
{ | ||
namespaceString: "amazon:distro:amazonlinux:2", | ||
result: NewNamespace("amazon", grypeDistro.AmazonLinux, "2"), | ||
}, | ||
} | ||
|
||
for _, test := range successTests { | ||
result, _ := FromString(test.namespaceString) | ||
assert.Equal(t, result, test.result) | ||
} | ||
|
||
errorTests := []struct { | ||
namespaceString string | ||
errorMessage string | ||
}{ | ||
{ | ||
namespaceString: "", | ||
errorMessage: "unable to create distro namespace from empty string", | ||
}, | ||
{ | ||
namespaceString: "single-component", | ||
errorMessage: "unable to create distro namespace from single-component: incorrect number of components", | ||
}, | ||
{ | ||
namespaceString: "two:components", | ||
errorMessage: "unable to create distro namespace from two:components: incorrect number of components", | ||
}, | ||
{ | ||
namespaceString: "still:not:enough", | ||
errorMessage: "unable to create distro namespace from still:not:enough: incorrect number of components", | ||
}, | ||
{ | ||
namespaceString: "too:many:components:a:b", | ||
errorMessage: "unable to create distro namespace from too:many:components:a:b: incorrect number of components", | ||
}, | ||
{ | ||
namespaceString: "wrong:namespace_type:a:b", | ||
errorMessage: "unable to create distro namespace from wrong:namespace_type:a:b: type namespace_type is incorrect", | ||
}, | ||
} | ||
|
||
for _, test := range errorTests { | ||
_, err := FromString(test.namespaceString) | ||
assert.EqualError(t, err, test.errorMessage) | ||
} | ||
} |
Oops, something went wrong.