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

Simplify v6 distribution material #2277

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ tasks:
- task: check-licenses
- task: lint
- task: validate-cyclonedx-schema
- task: validate-grype-db-schema
# TODO: while developing v6, we need to disable this check (since v5 and v6 are imported in the same codebase)
# - task: validate-grype-db-schema

test:
desc: Run all levels of test
Expand Down
2 changes: 1 addition & 1 deletion cmd/grype/cli/commands/db_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func DBCheck(app clio.Application) *cobra.Command {
}

func runDBCheck(opts options.Database) error {
dbCurator, err := distribution.NewCurator(opts.ToCuratorConfig())
dbCurator, err := distribution.NewCurator(opts.ToLegacyCuratorConfig())
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/grype/cli/commands/db_delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func DBDelete(app clio.Application) *cobra.Command {
}

func runDBDelete(opts options.Database) error {
dbCurator, err := distribution.NewCurator(opts.ToCuratorConfig())
dbCurator, err := distribution.NewCurator(opts.ToLegacyCuratorConfig())
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/grype/cli/commands/db_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func DBDiff(app clio.Application) *cobra.Command {
}

func runDBDiff(opts *dbDiffOptions, base string, target string) (errs error) {
d, err := differ.NewDiffer(opts.DB.ToCuratorConfig())
d, err := differ.NewDiffer(opts.DB.ToLegacyCuratorConfig())
if err != nil {
return err
}
Expand Down Expand Up @@ -104,7 +104,7 @@ func runDBDiff(opts *dbDiffOptions, base string, target string) (errs error) {
}

func getDefaultURLs(opts options.Database) (baseURL string, targetURL string, err error) {
dbCurator, err := distribution.NewCurator(opts.ToCuratorConfig())
dbCurator, err := distribution.NewCurator(opts.ToLegacyCuratorConfig())
if err != nil {
return "", "", err
}
Expand Down
39 changes: 36 additions & 3 deletions cmd/grype/cli/commands/db_import.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ package commands

import (
"fmt"
"path/filepath"
"strings"

"github.com/spf13/cobra"

"github.com/anchore/clio"
"github.com/anchore/grype/cmd/grype/cli/options"
"github.com/anchore/grype/grype/db/legacy/distribution"
legacyDistribution "github.com/anchore/grype/grype/db/legacy/distribution"
"github.com/anchore/grype/grype/db/v6/distribution"
"github.com/anchore/grype/grype/db/v6/installation"
"github.com/anchore/grype/internal"
)

Expand All @@ -27,14 +31,43 @@ func DBImport(app clio.Application) *cobra.Command {
}

func runDBImport(opts options.Database, dbArchivePath string) error {
dbCurator, err := distribution.NewCurator(opts.ToCuratorConfig())
// TODO: tui update? better logging?

if isLegacy(dbArchivePath) {
return legacyDBImport(opts, dbArchivePath)
}
return importDB(opts, dbArchivePath)
}

func importDB(opts options.Database, dbArchivePath string) error {
client, err := distribution.NewClient(opts.ToClientConfig())
if err != nil {
return fmt.Errorf("unable to create distribution client: %w", err)
}
c, err := installation.NewCurator(opts.ToCuratorConfig(), client)
if err != nil {
return fmt.Errorf("unable to create curator: %w", err)
}

if err := c.Import(dbArchivePath); err != nil {
return fmt.Errorf("unable to import vulnerability database: %w", err)
}
return stderrPrintLnf("Vulnerability database imported")
}

func legacyDBImport(opts options.Database, dbArchivePath string) error {
dbCurator, err := legacyDistribution.NewCurator(opts.ToLegacyCuratorConfig())
if err != nil {
return err
}

if err := dbCurator.ImportFrom(dbArchivePath); err != nil {
return fmt.Errorf("unable to import vulnerability database: %+v", err)
return fmt.Errorf("unable to import vulnerability database: %w", err)
}

return stderrPrintLnf("Vulnerability database imported")
}

func isLegacy(path string) bool {
return !strings.Contains(filepath.Base(path), "vulnerability-db_v6")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since a rename might make this return true when it shouldn't, it might be worth inverting to isNew for now. It might be nice to have a config or a less brittle check or something at some point.

}
2 changes: 1 addition & 1 deletion cmd/grype/cli/commands/db_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func DBList(app clio.Application) *cobra.Command {
}

func runDBList(opts *dbListOptions) error {
dbCurator, err := distribution.NewCurator(opts.DB.ToCuratorConfig())
dbCurator, err := distribution.NewCurator(opts.DB.ToLegacyCuratorConfig())
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/grype/cli/commands/db_providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func runDBProviders(opts *dbProvidersOptions, app clio.Application) error {
}

func getMetadataFileLocation(app clio.Application) (*string, error) {
dbCurator, err := distribution.NewCurator(dbOptionsDefault(app.ID()).DB.ToCuratorConfig())
dbCurator, err := distribution.NewCurator(dbOptionsDefault(app.ID()).DB.ToLegacyCuratorConfig())
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/grype/cli/commands/db_search.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func DBSearch(app clio.Application) *cobra.Command {

func runDBSearch(opts *dbQueryOptions, vulnerabilityID string) error {
log.Debug("loading DB")
str, status, dbCloser, err := grype.LoadVulnerabilityDB(opts.DB.ToCuratorConfig(), opts.DB.AutoUpdate)
str, status, dbCloser, err := grype.LoadVulnerabilityDB(opts.DB.ToLegacyCuratorConfig(), opts.DB.AutoUpdate)
err = validateDBLoad(err, status)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion cmd/grype/cli/commands/db_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func DBStatus(app clio.Application) *cobra.Command {
}

func runDBStatus(opts options.Database) error {
dbCurator, err := distribution.NewCurator(opts.ToCuratorConfig())
dbCurator, err := distribution.NewCurator(opts.ToLegacyCuratorConfig())
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/grype/cli/commands/db_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func DBUpdate(app clio.Application) *cobra.Command {
}

func runDBUpdate(opts options.Database) error {
dbCurator, err := distribution.NewCurator(opts.ToCuratorConfig())
dbCurator, err := distribution.NewCurator(opts.ToLegacyCuratorConfig())
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/grype/cli/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,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.ToCuratorConfig(), opts.DB.AutoUpdate)
str, status, dbCloser, err = grype.LoadVulnerabilityDB(opts.DB.ToLegacyCuratorConfig(), opts.DB.AutoUpdate)
return validateDBLoad(err, status)
},
func() (err error) {
Expand Down
27 changes: 25 additions & 2 deletions cmd/grype/cli/options/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import (
"github.com/adrg/xdg"

"github.com/anchore/clio"
"github.com/anchore/grype/grype/db/legacy/distribution"
legacyDistribution "github.com/anchore/grype/grype/db/legacy/distribution"
"github.com/anchore/grype/grype/db/v6/distribution"
"github.com/anchore/grype/grype/db/v6/installation"
"github.com/anchore/grype/internal"
)

Expand Down Expand Up @@ -53,8 +55,29 @@ func DefaultDatabase(id clio.Identification) Database {
}
}

func (cfg Database) ToCuratorConfig() distribution.Config {
func (cfg Database) ToClientConfig() distribution.Config {
return distribution.Config{
ID: cfg.ID,
LatestURL: cfg.UpdateURL,
CACert: cfg.CACert,
RequireUpdateCheck: cfg.RequireUpdateCheck,
CheckTimeout: cfg.UpdateAvailableTimeout,
UpdateTimeout: cfg.UpdateDownloadTimeout,
}
}

func (cfg Database) ToCuratorConfig() installation.Config {
return installation.Config{
DBRootDir: cfg.Dir,
ValidateAge: cfg.ValidateAge,
ValidateChecksum: cfg.ValidateByHashOnStart,
MaxAllowedBuiltAge: cfg.MaxAllowedBuiltAge,
UpdateCheckMaxFrequency: cfg.MaxUpdateCheckFrequency,
}
}

func (cfg Database) ToLegacyCuratorConfig() legacyDistribution.Config {
return legacyDistribution.Config{
ID: cfg.ID,
DBRootDir: cfg.Dir,
ListingURL: cfg.UpdateURL,
Expand Down
4 changes: 2 additions & 2 deletions grype/db/v6/blobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ type VulnerabilityBlob struct {
// ProviderName of the Vunnel provider (or sub processor responsible for data records from a single specific source, e.g. "ubuntu")
ProviderName string `json:"provider"`

// Assigner is a list of names, email, or organizations who submitted the vulnerability
Assigner []string `json:"assigner,omitempty"`
// Assigners is a list of names, email, or organizations who submitted the vulnerability
Assigners []string `json:"assigner,omitempty"`

// Status conveys the actionability of the current record
Status VulnerabilityStatus `json:"status"`
Expand Down
75 changes: 23 additions & 52 deletions grype/db/v6/description.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package v6

import (
"bytes"
"crypto/sha256"
"errors"
"fmt"
"io"
Expand All @@ -25,9 +26,6 @@ type Description struct {

// Built is the timestamp the database was built
Built Time `json:"built"`

// Checksum is the self-describing digest of the database file
Checksum string `json:"checksum"`
}

type Time struct {
Expand Down Expand Up @@ -58,9 +56,7 @@ func (t Time) String() string {
return t.Time.UTC().Round(time.Second).Format(time.RFC3339)
}

func ReadDescription(dir string) (*Description, error) {
dbFilePath := filepath.Join(dir, VulnerabilityDBFileName)

func ReadDescription(dbFilePath string) (*Description, error) {
// check if exists
if _, err := os.Stat(dbFilePath); err != nil {
if errors.Is(err, os.ErrNotExist) {
Expand All @@ -69,20 +65,23 @@ func ReadDescription(dir string) (*Description, error) {
return nil, fmt.Errorf("failed to access database file: %w", err)
}

desc, err := newPartialDescriptionFromDB(dbFilePath)
// access the DB to get the built time and schema version
r, err := NewReader(Config{
DBDirPath: filepath.Dir(dbFilePath),
})
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to read DB description: %w", err)
}

// read checksums file value
checksum, err := ReadDBChecksum(dir)
meta, err := r.GetDBMetadata()
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to read DB metadata: %w", err)
}

desc.Checksum = checksum

return desc, nil
return &Description{
SchemaVersion: schemaver.New(meta.Model, meta.Revision, meta.Addition),
Built: Time{Time: *meta.BuildTimestamp},
}, nil
}

func ReadDBChecksum(dir string) (string, error) {
Expand All @@ -103,63 +102,35 @@ func ReadDBChecksum(dir string) (string, error) {
return string(checksums), nil
}

func CalculateDescription(dbFilePath string) (*Description, error) {
desc, err := newPartialDescriptionFromDB(dbFilePath)
if err != nil {
return nil, err
}

namedDigest, err := CalculateDigest(dbFilePath)
if err != nil {
return nil, err
}

desc.Checksum = namedDigest

return desc, nil
}

func CalculateDigest(dbFilePath string) (string, error) {
func CalculateDBDigest(dbFilePath string) (string, error) {
digest, err := file.HashFile(afero.NewOsFs(), dbFilePath, xxhash.New64())
if err != nil {
return "", fmt.Errorf("failed to calculate checksum for DB file: %w", err)
}
return fmt.Sprintf("xxh64:%s", digest), nil
}

func newPartialDescriptionFromDB(dbFilePath string) (*Description, error) {
// access the DB to get the built time and schema version
r, err := NewReader(Config{
DBDirPath: filepath.Dir(dbFilePath),
})
func CalculateArchiveDigest(dbFilePath string) (string, error) {
digest, err := file.HashFile(afero.NewOsFs(), dbFilePath, sha256.New())
if err != nil {
return nil, fmt.Errorf("failed to read DB description: %w", err)
return "", fmt.Errorf("failed to calculate checksum for DB archive file: %w", err)
}

meta, err := r.GetDBMetadata()
if err != nil {
return nil, fmt.Errorf("failed to read DB metadata: %w", err)
}

return &Description{
SchemaVersion: schemaver.New(meta.Model, meta.Revision, meta.Addition),
Built: Time{Time: *meta.BuildTimestamp},
}, nil
return fmt.Sprintf("sha256:%s", digest), nil
}

func (m Description) String() string {
return fmt.Sprintf("DB(version=%s built=%s checksum=%s)", m.SchemaVersion, m.Built, m.Checksum)
return fmt.Sprintf("DB(version=%s built=%s)", m.SchemaVersion, m.Built)
}

func WriteChecksums(writer io.Writer, m Description) error {
if m.Checksum == "" {
func WriteChecksums(writer io.Writer, value string) error {
if value == "" {
return fmt.Errorf("checksum is required")
}

if !strings.HasPrefix(m.Checksum, "xxh64:") {
if !strings.HasPrefix(value, "xxh64:") {
return fmt.Errorf("checksum missing algorithm prefix")
}

_, err := writer.Write([]byte(m.Checksum))
_, err := writer.Write([]byte(value))
return err
}
Loading
Loading