diff --git a/cmd/db_diff.go b/cmd/db_diff.go index 2bef9ce22d7..6f81455e95c 100644 --- a/cmd/db_diff.go +++ b/cmd/db_diff.go @@ -2,7 +2,6 @@ package cmd import ( "fmt" - "net/url" "os" "github.com/spf13/cobra" @@ -35,7 +34,7 @@ func init() { dbCmd.AddCommand(dbDiffCmd) } -func startDBDiffCmd(dbURL []*url.URL, deleteDatabases bool) <-chan error { +func startDBDiffCmd(base string, target string, deleteDatabases bool) <-chan error { errs := make(chan error) go func() { defer close(errs) @@ -45,10 +44,12 @@ func startDBDiffCmd(dbURL []*url.URL, deleteDatabases bool) <-chan error { return } - baseURL := dbURL[0] - targetURL := dbURL[1] + if err := d.SetBaseDB(base); err != nil { + errs <- err + return + } - if err := d.DownloadDatabases(baseURL, targetURL); err != nil { + if err := d.SetTargetDB(target); err != nil { errs <- err return } @@ -96,27 +97,29 @@ func runDBDiffCmd(cmd *cobra.Command, args []string) error { return err } - var dbURL []*url.URL + var base, target string - if len(args) < 2 { + switch len(args) { + case 0: log.Info("base_db_url and target_db_url not provided; fetching most recent") - dbURL, err = getDefaultURL() + base, target, err = getDefaultURLs() if err != nil { - return fmt.Errorf("could not fetch most recent database URL: %w", err) + return err } - } else { - for _, arg := range args { - u, err := url.Parse(arg) - if err != nil { - return fmt.Errorf("url argument is malformed: %w", err) - } - - dbURL = append(dbURL, u) + case 1: + log.Info("target_db_url not provided; fetching most recent") + base = args[0] + _, target, err = getDefaultURLs() + if err != nil { + return err } + default: + base = args[0] + target = args[1] } return eventLoop( - startDBDiffCmd(dbURL, deleteDatabases), + startDBDiffCmd(base, target, deleteDatabases), setupSignals(), eventSubscription, stereoscope.Cleanup, @@ -124,27 +127,25 @@ func runDBDiffCmd(cmd *cobra.Command, args []string) error { ) } -func getDefaultURL() (defaultURL []*url.URL, err error) { +func getDefaultURLs() (baseURL string, targetURL string, err error) { dbCurator, err := db.NewCurator(appConfig.DB.ToCuratorConfig()) if err != nil { - return nil, err + return "", "", err } listing, err := dbCurator.ListingFromURL() if err != nil { - return nil, err + return "", "", err } supportedSchema := dbCurator.SupportedSchema() available, exists := listing.Available[supportedSchema] if len(available) < 2 || !exists { - return nil, stderrPrintLnf("Not enough databases available for the current schema to diff (%d)", supportedSchema) + return "", "", stderrPrintLnf("Not enough databases available for the current schema to diff (%d)", supportedSchema) } - recent := available[:2] - for _, entry := range recent { - defaultURL = append([]*url.URL{entry.URL}, defaultURL...) - } + targetURL = available[0].URL.String() + baseURL = available[1].URL.String() - return defaultURL, nil + return baseURL, targetURL, nil } diff --git a/grype/differ/differ.go b/grype/differ/differ.go index d3e568291e4..b80e18e6acf 100644 --- a/grype/differ/differ.go +++ b/grype/differ/differ.go @@ -49,40 +49,51 @@ func NewDiffer(config db.Config) (*Differ, error) { }, nil } -func (d *Differ) DownloadDatabases(baseURL, targetURL *url.URL) error { - listing, err := d.baseCurator.ListingFromURL() - if err != nil { - return err - } +func (d *Differ) SetBaseDB(base string) error { + return d.setOrDownload(&d.baseCurator, base) +} - listings := listing.Available - dbs := listings[v5.SchemaVersion] +func (d *Differ) SetTargetDB(target string) error { + return d.setOrDownload(&d.targetCurator, target) +} - var baseListing *db.ListingEntry - var targetListing *db.ListingEntry +func (d *Differ) setOrDownload(curator *db.Curator, filenameOrURL string) error { + u, err := url.ParseRequestURI(filenameOrURL) - for _, db := range dbs { - database := db - if *db.URL == *baseURL { - baseListing = &database + if err != nil || u.Scheme == "" { + *curator, err = db.NewCurator(db.Config{ + DBRootDir: filenameOrURL, + }) + if err != nil { + return err } - if *db.URL == *targetURL { - targetListing = &database + } else { + listings, err := d.baseCurator.ListingFromURL() + if err != nil { + return err } - } - if baseListing == nil { - return fmt.Errorf("unable to find listing for base url: %s", baseURL.String()) - } else if targetListing == nil { - return fmt.Errorf("unable to find listing for target url: %s", targetURL.String()) - } + available := listings.Available + dbs := available[v5.SchemaVersion] - if err := download(&d.baseCurator, baseListing); err != nil { - return fmt.Errorf("unable to update base vulnerability database: %+v", err) - } - if err := download(&d.targetCurator, targetListing); err != nil { - return fmt.Errorf("unable to update target vulnerability database: %+v", err) + var listing *db.ListingEntry + + for _, d := range dbs { + database := d + if *d.URL == *u { + listing = &database + } + } + + if listing == nil { + return fmt.Errorf("unable to find listing for url: %s", filenameOrURL) + } + + if err := download(curator, listing); err != nil { + return fmt.Errorf("unable to download vulnerability database: %+v", err) + } } + return nil } diff --git a/grype/differ/differ_test.go b/grype/differ/differ_test.go index 190157087b5..7aee002caaa 100644 --- a/grype/differ/differ_test.go +++ b/grype/differ/differ_test.go @@ -3,6 +3,7 @@ package differ import ( "bytes" "flag" + "strconv" "testing" "github.com/sergi/go-diff/diffmatchpatch" @@ -11,6 +12,7 @@ import ( "github.com/anchore/go-testutils" "github.com/anchore/grype/grype/db" v5 "github.com/anchore/grype/grype/db/v5" + "github.com/anchore/grype/grype/vulnerability" ) var update = flag.Bool("update", false, "update the *.golden files for diff presenter") @@ -27,6 +29,25 @@ func TestNewDiffer(t *testing.T) { require.NotNil(t, differ.baseCurator) } +func Test_DifferDirectory(t *testing.T) { + d, err := NewDiffer(db.Config{ + DBRootDir: "root-dir", + }) + require.NoError(t, err) + + err = d.SetBaseDB("test-fixtures/dbs/base") + require.NoError(t, err) + + baseStatus := d.baseCurator.Status() + require.Equal(t, "test-fixtures/dbs/base/"+strconv.Itoa(vulnerability.SchemaVersion), baseStatus.Location) + + err = d.SetTargetDB("test-fixtures/dbs/target") + require.NoError(t, err) + + targetStatus := d.targetCurator.Status() + require.Equal(t, "test-fixtures/dbs/target/"+strconv.Itoa(vulnerability.SchemaVersion), targetStatus.Location) +} + func TestPresent_Json(t *testing.T) { //GIVEN diffs := []v5.Diff{ diff --git a/grype/differ/test-fixtures/dbs/base/5/metadata.json b/grype/differ/test-fixtures/dbs/base/5/metadata.json new file mode 100644 index 00000000000..979e3bdce16 --- /dev/null +++ b/grype/differ/test-fixtures/dbs/base/5/metadata.json @@ -0,0 +1,5 @@ +{ + "built": "2022-12-18T08:18:18Z", + "version": 5, + "checksum": "sha256:9d979f7320c575e7ac41c4384e9f55d578cdddd701822563cabc6b913fde7b80" +} \ No newline at end of file diff --git a/grype/differ/test-fixtures/dbs/base/5/vulnerability.db b/grype/differ/test-fixtures/dbs/base/5/vulnerability.db new file mode 100644 index 00000000000..946abdcb17a --- /dev/null +++ b/grype/differ/test-fixtures/dbs/base/5/vulnerability.db @@ -0,0 +1 @@ +an older vulnerability db \ No newline at end of file diff --git a/grype/differ/test-fixtures/dbs/target/5/metadata.json b/grype/differ/test-fixtures/dbs/target/5/metadata.json new file mode 100644 index 00000000000..90c5b117ebc --- /dev/null +++ b/grype/differ/test-fixtures/dbs/target/5/metadata.json @@ -0,0 +1,5 @@ +{ + "built": "2022-12-18T08:18:18Z", + "version": 5, + "checksum": "sha256:da2141ae7415abe5cf5390faeed60e164c5a919370ee823c8cc3ad9f4698f56e" +} \ No newline at end of file diff --git a/grype/differ/test-fixtures/dbs/target/5/vulnerability.db b/grype/differ/test-fixtures/dbs/target/5/vulnerability.db new file mode 100644 index 00000000000..2e85d70e599 --- /dev/null +++ b/grype/differ/test-fixtures/dbs/target/5/vulnerability.db @@ -0,0 +1 @@ +a vulnerability db \ No newline at end of file