Skip to content

Commit

Permalink
chore: refactor v5-specific code out of core packages (#2299)
Browse files Browse the repository at this point in the history
Signed-off-by: Keith Zantow <kzantow@gmail.com>
  • Loading branch information
kzantow authored Dec 4, 2024
1 parent 7d4ef8c commit eee0fe5
Show file tree
Hide file tree
Showing 43 changed files with 433 additions and 461 deletions.
4 changes: 2 additions & 2 deletions cmd/grype/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/anchore/grype/cmd/grype/cli/commands"
grypeHandler "github.com/anchore/grype/cmd/grype/cli/ui"
"github.com/anchore/grype/cmd/grype/internal/ui"
"github.com/anchore/grype/grype/vulnerability"
"github.com/anchore/grype/grype/db"
"github.com/anchore/grype/internal/bus"
"github.com/anchore/grype/internal/log"
"github.com/anchore/grype/internal/redact"
Expand Down Expand Up @@ -106,5 +106,5 @@ func syftVersion() (string, any) {
}

func dbVersion() (string, any) {
return "Supported DB Schema", vulnerability.SchemaVersion
return "Supported DB Schema", db.SchemaVersion
}
6 changes: 2 additions & 4 deletions cmd/grype/cli/commands/db_search.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,12 @@ func newDBSearch(opts dbQueryOptions, vulnerabilityID string) error {

func legacyDBSearch(opts dbQueryOptions, vulnerabilityID string) error {
log.Debug("loading DB")
str, status, dbCloser, err := grype.LoadVulnerabilityDB(opts.DB.ToLegacyCuratorConfig(), opts.DB.AutoUpdate)
str, status, err := grype.LoadVulnerabilityDB(opts.DB.ToLegacyCuratorConfig(), opts.DB.AutoUpdate)
err = validateDBLoad(err, status)
if err != nil {
return err
}
if dbCloser != nil {
defer dbCloser.Close()
}
defer log.CloseAndLogError(str, status.Location)

vulnerabilities, err := str.Get(vulnerabilityID, "")
if err != nil {
Expand Down
22 changes: 9 additions & 13 deletions cmd/grype/cli/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ import (
"github.com/anchore/clio"
"github.com/anchore/grype/cmd/grype/cli/options"
"github.com/anchore/grype/grype"
"github.com/anchore/grype/grype/db"
"github.com/anchore/grype/grype/db/legacy/distribution"
grypeDb "github.com/anchore/grype/grype/db/v5"
"github.com/anchore/grype/grype/event"
"github.com/anchore/grype/grype/event/parsers"
"github.com/anchore/grype/grype/grypeerr"
Expand All @@ -30,6 +28,7 @@ import (
"github.com/anchore/grype/grype/presenter/models"
"github.com/anchore/grype/grype/store"
"github.com/anchore/grype/grype/vex"
"github.com/anchore/grype/grype/vulnerability"
"github.com/anchore/grype/internal"
"github.com/anchore/grype/internal/bus"
"github.com/anchore/grype/internal/format"
Expand Down Expand Up @@ -89,13 +88,13 @@ You can also pipe in Syft JSON directly:
}

var ignoreNonFixedMatches = []match.IgnoreRule{
{FixState: string(grypeDb.NotFixedState)},
{FixState: string(grypeDb.WontFixState)},
{FixState: string(grypeDb.UnknownFixState)},
{FixState: string(vulnerability.FixStateNotFixed)},
{FixState: string(vulnerability.FixStateWontFix)},
{FixState: string(vulnerability.FixStateUnknown)},
}

var ignoreFixedMatches = []match.IgnoreRule{
{FixState: string(grypeDb.FixedState)},
{FixState: string(vulnerability.FixStateFixed)},
}

var ignoreVEXFixedNotAffected = []match.IgnoreRule{
Expand All @@ -121,7 +120,6 @@ func runGrype(app clio.Application, opts *options.Grype, userInput string) (errs

var str *store.Store
var status *distribution.Status
var dbCloser *db.Closer
var packages []pkg.Package
var s *sbom.SBOM
var pkgContext pkg.Context
Expand All @@ -139,8 +137,8 @@ func runGrype(app clio.Application, opts *options.Grype, userInput string) (errs
}

for _, ignoreState := range stringutil.SplitCommaSeparatedString(opts.IgnoreStates) {
switch grypeDb.FixState(ignoreState) {
case grypeDb.UnknownFixState, grypeDb.FixedState, grypeDb.NotFixedState, grypeDb.WontFixState:
switch vulnerability.FixState(ignoreState) {
case vulnerability.FixStateUnknown, vulnerability.FixStateFixed, vulnerability.FixStateNotFixed, vulnerability.FixStateWontFix:
opts.Ignore = append(opts.Ignore, match.IgnoreRule{FixState: ignoreState})
default:
return fmt.Errorf("unknown fix state %s was supplied for --ignore-states", ignoreState)
Expand All @@ -154,7 +152,7 @@ func runGrype(app clio.Application, opts *options.Grype, userInput string) (errs
},
func() (err error) {
log.Debug("loading DB")
str, status, dbCloser, err = grype.LoadVulnerabilityDB(opts.DB.ToLegacyCuratorConfig(), opts.DB.AutoUpdate)
str, status, err = grype.LoadVulnerabilityDB(opts.DB.ToLegacyCuratorConfig(), opts.DB.AutoUpdate)
return validateDBLoad(err, status)
},
func() (err error) {
Expand All @@ -175,9 +173,7 @@ func runGrype(app clio.Application, opts *options.Grype, userInput string) (errs
return err
}

if dbCloser != nil {
defer dbCloser.Close()
}
defer log.CloseAndLogError(str, status.Location)

if err = applyVexRules(opts); err != nil {
return fmt.Errorf("applying vex rules: %w", err)
Expand Down
9 changes: 0 additions & 9 deletions grype/db/db_closer.go

This file was deleted.

16 changes: 7 additions & 9 deletions grype/db/legacy/distribution/curator.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,16 @@ import (
"github.com/wagoodman/go-progress"

"github.com/anchore/clio"
grypeDB "github.com/anchore/grype/grype/db/v5"
v5 "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"
"github.com/anchore/grype/internal/file"
"github.com/anchore/grype/internal/log"
)

const (
FileName = grypeDB.VulnerabilityStoreFileName
FileName = v5.VulnerabilityStoreFileName
lastUpdateCheckFileName = "last_update_check"
)

Expand Down Expand Up @@ -62,7 +61,7 @@ type Curator struct {
}

func NewCurator(cfg Config) (Curator, error) {
dbDir := path.Join(cfg.DBRootDir, strconv.Itoa(vulnerability.SchemaVersion))
dbDir := path.Join(cfg.DBRootDir, strconv.Itoa(v5.SchemaVersion))

fs := afero.NewOsFs()
listingClient, err := defaultHTTPClient(fs, cfg.CACert)
Expand All @@ -79,7 +78,7 @@ func NewCurator(cfg Config) (Curator, error) {

return Curator{
fs: fs,
targetSchema: vulnerability.SchemaVersion,
targetSchema: v5.SchemaVersion,
listingDownloader: file.NewGetter(cfg.ID, listingClient),
updateDownloader: file.NewGetter(cfg.ID, dbClient),
dbDir: dbDir,
Expand All @@ -97,15 +96,14 @@ func (c Curator) SupportedSchema() int {
return c.targetSchema
}

func (c *Curator) GetStore() (grypeDB.StoreReader, grypeDB.DBCloser, error) {
func (c *Curator) GetStore() (v5.StoreReader, error) {
// ensure the DB is ok
_, err := c.validateIntegrity(c.dbDir)
if err != nil {
return nil, nil, fmt.Errorf("vulnerability database is invalid (run db update to correct): %+v", err)
return nil, fmt.Errorf("vulnerability database is invalid (run db update to correct): %+v", err)
}

s, err := store.New(c.dbPath, false)
return s, s, err
return store.New(c.dbPath, false)
}

func (c *Curator) Status() Status {
Expand Down
5 changes: 5 additions & 0 deletions grype/db/schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package db

import v5 "github.com/anchore/grype/grype/db/v5"

const SchemaVersion = v5.SchemaVersion
25 changes: 25 additions & 0 deletions grype/db/v5/cvss.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package v5

import (
"github.com/anchore/grype/grype/vulnerability"
)

func NewCvss(m []Cvss) []vulnerability.Cvss {
//nolint:prealloc
var cvss []vulnerability.Cvss
for _, score := range m {
cvss = append(cvss, vulnerability.Cvss{
Source: score.Source,
Type: score.Type,
Version: score.Version,
Vector: score.Vector,
Metrics: vulnerability.CvssMetrics{
BaseScore: score.Metrics.BaseScore,
ExploitabilityScore: score.Metrics.ExploitabilityScore,
ImpactScore: score.Metrics.ImpactScore,
},
VendorMetadata: score.VendorMetadata,
})
}
return cvss
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
package db
package v5

import (
"fmt"

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

var _ match.ExclusionProvider = (*MatchExclusionProvider)(nil)

type MatchExclusionProvider struct {
reader grypeDB.VulnerabilityMatchExclusionStoreReader
reader VulnerabilityMatchExclusionStoreReader
}

func NewMatchExclusionProvider(reader grypeDB.VulnerabilityMatchExclusionStoreReader) *MatchExclusionProvider {
func NewMatchExclusionProvider(reader VulnerabilityMatchExclusionStoreReader) *MatchExclusionProvider {
return &MatchExclusionProvider{
reader: reader,
}
}

func buildIgnoreRulesFromMatchExclusion(e grypeDB.VulnerabilityMatchExclusion) []match.IgnoreRule {
func buildIgnoreRulesFromMatchExclusion(e VulnerabilityMatchExclusion) []match.IgnoreRule {
var ignoreRules []match.IgnoreRule

if len(e.Constraints) == 0 {
Expand Down
9 changes: 4 additions & 5 deletions grype/db/v5/store.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package v5

import "io"

type Store interface {
StoreReader
StoreWriter
DBCloser
}

type StoreReader interface {
Expand All @@ -12,19 +13,17 @@ type StoreReader interface {
VulnerabilityStoreReader
VulnerabilityMetadataStoreReader
VulnerabilityMatchExclusionStoreReader
io.Closer
}

type StoreWriter interface {
IDWriter
VulnerabilityStoreWriter
VulnerabilityMetadataStoreWriter
VulnerabilityMatchExclusionStoreWriter
io.Closer
}

type DiffReader interface {
DiffStore(s StoreReader) (*[]Diff, error)
}

type DBCloser interface {
Close()
}
4 changes: 3 additions & 1 deletion grype/db/v5/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,13 +286,15 @@ func (s *store) AddVulnerabilityMatchExclusion(exclusions ...v5.VulnerabilityMat
return nil
}

func (s *store) Close() {
func (s *store) Close() error {
s.db.Exec("VACUUM;")

sqlDB, _ := s.db.DB()
if sqlDB != nil {
_ = sqlDB.Close()
}

return nil
}

// GetAllVulnerabilities gets all vulnerabilities in the database
Expand Down
56 changes: 53 additions & 3 deletions grype/db/v5/vulnerability.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
package v5

import (
"fmt"
"sort"
"strings"

"github.com/anchore/grype/grype/db/v5/pkg/qualifier"
qualifierV5 "github.com/anchore/grype/grype/db/v5/pkg/qualifier"
"github.com/anchore/grype/grype/pkg/qualifier"
"github.com/anchore/grype/grype/version"
"github.com/anchore/grype/grype/vulnerability"
"github.com/anchore/syft/syft/cpe"
)

// Vulnerability represents the minimum data fields necessary to perform package-to-vulnerability matching. This can represent a CVE, 3rd party advisory, or any source that relates back to a CVE.
type Vulnerability struct {
ID string `json:"id"` // The identifier of the vulnerability or advisory
PackageName string `json:"package_name"` // The name of the package that is vulnerable
Namespace string `json:"namespace"` // The ecosystem where the package resides
PackageQualifiers []qualifier.Qualifier `json:"package_qualifiers"` // The qualifiers for determining if a package is vulnerable
PackageQualifiers []qualifierV5.Qualifier `json:"package_qualifiers"` // The qualifiers for determining if a package is vulnerable
VersionConstraint string `json:"version_constraint"` // The version range which the given package is vulnerable
VersionFormat string `json:"version_format"` // The format which all version fields should be interpreted as
CPEs []string `json:"cpes"` // The CPEs which are considered vulnerable
Expand Down Expand Up @@ -106,9 +111,54 @@ func sortAdvisories(advisories []Advisory) []Advisory {
return advisories
}

func sortPackageQualifiers(qualifiers []qualifier.Qualifier) []qualifier.Qualifier {
func sortPackageQualifiers(qualifiers []qualifierV5.Qualifier) []qualifierV5.Qualifier {
sort.SliceStable(qualifiers, func(i, j int) bool {
return qualifiers[i].String() < qualifiers[j].String()
})
return qualifiers
}

func NewVulnerability(vuln Vulnerability) (*vulnerability.Vulnerability, error) {
format := version.ParseFormat(vuln.VersionFormat)

constraint, err := version.GetConstraint(vuln.VersionConstraint, format)
if err != nil {
return nil, fmt.Errorf("failed to parse constraint='%s' format='%s': %w", vuln.VersionConstraint, format, err)
}

pkgQualifiers := make([]qualifier.Qualifier, len(vuln.PackageQualifiers))
for idx, q := range vuln.PackageQualifiers {
pkgQualifiers[idx] = q.Parse()
}

advisories := make([]vulnerability.Advisory, len(vuln.Advisories))
for idx, advisory := range vuln.Advisories {
advisories[idx] = vulnerability.Advisory{
ID: advisory.ID,
Link: advisory.Link,
}
}

var relatedVulnerabilities []vulnerability.Reference
for _, r := range vuln.RelatedVulnerabilities {
relatedVulnerabilities = append(relatedVulnerabilities, vulnerability.Reference{
ID: r.ID,
Namespace: r.Namespace,
})
}

return &vulnerability.Vulnerability{
PackageName: vuln.PackageName,
Constraint: constraint,
ID: vuln.ID,
CPEs: make([]cpe.CPE, 0),
Namespace: vuln.Namespace,
PackageQualifiers: pkgQualifiers,
Fix: vulnerability.Fix{
Versions: vuln.Fix.Versions,
State: vulnerability.FixState(vuln.Fix.State),
},
Advisories: advisories,
RelatedVulnerabilities: relatedVulnerabilities,
}, nil
}
Loading

0 comments on commit eee0fe5

Please sign in to comment.