Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement v5 db schema to support improved matching between rpm appstream modules #944

Merged
merged 23 commits into from
Oct 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
38c78f1
adding package_qualifiers column
westonsteimel Sep 6, 2022
96442f7
add support for rpm-modularity package qualifiers when evaluating vul…
westonsteimel Sep 12, 2022
4cf7859
lint-fix
westonsteimel Oct 3, 2022
e92a8e5
rpm-modularity qualifier matching logic updates
westonsteimel Oct 10, 2022
cfd720d
update golden
westonsteimel Oct 10, 2022
ced44bd
temp update
westonsteimel Oct 11, 2022
90979f5
fix import db when referencing install from current git commit + tabl…
wagoodman Oct 11, 2022
a77d7ca
temp update
westonsteimel Oct 11, 2022
424dc00
move package qualifier changes to v5 db schema
westonsteimel Oct 13, 2022
33ba569
temp update
westonsteimel Oct 13, 2022
88fae11
bump labels submodule
westonsteimel Oct 14, 2022
c428755
update yardstick config
westonsteimel Oct 14, 2022
2051a6e
update yardstick to latest commit on main
westonsteimel Oct 14, 2022
b8d0336
temporarily point test config to staging for db
westonsteimel Oct 14, 2022
d28a94a
point to staging db build
westonsteimel Oct 17, 2022
913cf2c
update urls for db diff test
westonsteimel Oct 17, 2022
9bb72ca
update db diff test for v5
westonsteimel Oct 17, 2022
47dfb37
format string update
westonsteimel Oct 17, 2022
3d69ff4
rename NewRPMModularityQualifier => New
westonsteimel Oct 17, 2022
df98bc2
warn if qualifier lacks kind
westonsteimel Oct 17, 2022
229d8b1
add TODO note about porting version constraint logic over to package …
westonsteimel Oct 17, 2022
40ea037
revert pointing to staging db location
westonsteimel Oct 17, 2022
6697874
disable the db diff integration test
westonsteimel Oct 17, 2022
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
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (

"github.com/anchore/grype/grype"
"github.com/anchore/grype/grype/db"
grypeDb "github.com/anchore/grype/grype/db/v4"
grypeDb "github.com/anchore/grype/grype/db/v5"
"github.com/anchore/grype/grype/event"
"github.com/anchore/grype/grype/grypeerr"
"github.com/anchore/grype/grype/match"
Expand Down
2 changes: 1 addition & 1 deletion cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/stretchr/testify/assert"

"github.com/anchore/grype/grype/db"
grypeDB "github.com/anchore/grype/grype/db/v4"
grypeDB "github.com/anchore/grype/grype/db/v5"
"github.com/anchore/grype/grype/match"
"github.com/anchore/grype/grype/pkg"
"github.com/anchore/grype/grype/vulnerability"
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ require (
github.com/anchore/sqlite v1.4.6-0.20220607210448-bcc6ee5c4963
github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b
github.com/in-toto/in-toto-golang v0.3.4-0.20220709202702-fa494aaa0add
github.com/mitchellh/mapstructure v1.5.0
github.com/secure-systems-lab/go-securesystemslib v0.4.0
github.com/sigstore/cosign v1.13.0
github.com/sigstore/sigstore v1.4.2
Expand Down Expand Up @@ -185,7 +186,6 @@ require (
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
Expand Down
4 changes: 2 additions & 2 deletions grype/db/curator.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import (
partybus "github.com/wagoodman/go-partybus"
progress "github.com/wagoodman/go-progress"

grypeDB "github.com/anchore/grype/grype/db/v4"
"github.com/anchore/grype/grype/db/v4/store"
grypeDB "github.com/anchore/grype/grype/db/v5"
"github.com/anchore/grype/grype/db/v5/store"
"github.com/anchore/grype/grype/event"
"github.com/anchore/grype/grype/vulnerability"
"github.com/anchore/grype/internal/bus"
Expand Down
4 changes: 2 additions & 2 deletions grype/db/db_closer.go
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
}
2 changes: 1 addition & 1 deletion grype/db/match_exclusion_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package db
import (
"fmt"

grypeDB "github.com/anchore/grype/grype/db/v4"
grypeDB "github.com/anchore/grype/grype/db/v5"
"github.com/anchore/grype/grype/match"
)

Expand Down
7 changes: 7 additions & 0 deletions grype/db/v5/advisory.go
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"`
}
16 changes: 16 additions & 0 deletions grype/db/v5/diff.go
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"`
}
16 changes: 16 additions & 0 deletions grype/db/v5/fix.go
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"`
}
28 changes: 28 additions & 0 deletions grype/db/v5/id.go
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,
}
}
54 changes: 54 additions & 0 deletions grype/db/v5/namespace/cpe/namespace.go
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)
}
51 changes: 51 additions & 0 deletions grype/db/v5/namespace/cpe/namespace_test.go
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)
}
}
67 changes: 67 additions & 0 deletions grype/db/v5/namespace/distro/namespace.go
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)
}
81 changes: 81 additions & 0 deletions grype/db/v5/namespace/distro/namespace_test.go
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)
}
}
Loading