Repository: anchore/grype
Pull request #2437 (2025-02-11 15:16:48)

chore(deps): bump golang.org/x/tools from 0.29.0 to 0.30.0
Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.29.0 to 0.30.0.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/tools/commit/09747cdf594a7924dcecb506312be3bd6e437962"><code>09747cd</code></a> go.mod: update golang.org/x dependencies</li>
<li><a href="https://github.com/golang/tools/commit/dc9353b60ee791ae31f3be19b8ae7ea5450e5e62"><code>dc9353b</code></a> gopls/internal/analysis/modernize: appendclipped: unclip</li>
<li><a href="https://github.com/golang/tools/commit/a886a1c2ed0dee2af11f465e11bf48b11dda984c"><code>a886a1c</code></a> internal/analysisinternal: AddImport handles dot imports</li>
<li><a href="https://github.com/golang/tools/commit/94c3c49c41819ed247e0423acff990ab4ed12cf9"><code>94c3c49</code></a> go/analysis/analysistest: RunWithSuggestedFix: assume valid fixes</li>
<li><a href="https://github.com/golang/tools/commit/5f9967d63b2b964daae36c6f0fa3e1eecdd8eb06"><code>5f9967d</code></a> gopls/internal/analysis/modernize: strings.Split -&gt; SplitSeq</li>
<li><a href="https://github.com/golang/tools/commit/a1eb5fda89ed74fd8906e27269623f679dbd0ac1"><code>a1eb5fd</code></a> go/analysis/passes/framepointer: support arm64</li>
<li><a href="https://github.com/golang/tools/commit/9c087d9bfa108039bfcaa605c16fe467d8c47940"><code>9c087d9</code></a> internal/analysis/gofix: change &quot;forward&quot; back to &quot;inline&quot;</li>
<li><a href="https://github.com/golang/tools/commit/82317cea8a3807ada2a9b6a794188f227b55595f"><code>82317ce</code></a> gopls/internal/analysis/modernize: slices.Delete: import slices</li>
<li><a href="https://github.com/golang/tools/commit/e65ea150db54e65bce06700111515e5a4598900c"><code>e65ea15</code></a> go/analysis/internal/checker: implement three-way merge</li>
<li><a href="https://github.com/golang/tools/commit/a9bf6fdf9803c2872968caff08802cf427eb875c"><code>a9bf6fd</code></a> gopls/internal/analysis/modernize: remove SortStable</li>
<li>Additional commits viewable in <a href="https://github.com/golang/tools/compare/v0.29.0...v0.30.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=golang.org/x/tools&package-manager=go_modules&previous-version=0.29.0&new-version=0.30.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/.binny.yaml b/.binny.yaml
index 136db3ab..a92586d6 100644
--- a/.binny.yaml
+++ b/.binny.yaml
@@ -26,7 +26,7 @@ tools:
   # used for linting
   - name: golangci-lint
     version:
-      want: v1.63.4
+      want: v1.64.2
     method: github-release
     with:
       repo: golangci/golangci-lint
diff --git a/.github/actions/bootstrap/action.yaml b/.github/actions/bootstrap/action.yaml
index 68f8abf6..5a3433ca 100644
--- a/.github/actions/bootstrap/action.yaml
+++ b/.github/actions/bootstrap/action.yaml
@@ -4,7 +4,7 @@ inputs:
   go-version:
     description: "Go version to install"
     required: true
-    default: "1.23.x"
+    default: "1.24.x"
   python-version:
     description: "Python version to install"
     required: true
diff --git a/.github/workflows/release-version-file.yaml b/.github/workflows/release-version-file.yaml
index 97879b30..843b93d5 100644
--- a/.github/workflows/release-version-file.yaml
+++ b/.github/workflows/release-version-file.yaml
@@ -21,7 +21,7 @@ on:
 jobs:
 
   release:
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-24.04
     steps:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
 
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index cc354d8d..c7364a00 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -12,7 +12,7 @@ permissions:
 jobs:
   quality-gate:
     environment: release
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-24.04
     steps:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
 
@@ -106,7 +106,7 @@ jobs:
   # not all actions are guaranteed to be idempotent.
   release:
     needs: [quality-gate]
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-24.04
     permissions:
       contents: write
       packages: write
diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml
index e13ac904..5bcb628c 100644
--- a/.github/workflows/validations.yaml
+++ b/.github/workflows/validations.yaml
@@ -14,7 +14,7 @@ jobs:
   Static-Analysis:
     # Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
     name: "Static analysis"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-24.04
     steps:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
 
@@ -27,7 +27,7 @@ jobs:
   Unit-Test:
     # Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
     name: "Unit tests"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-24.04
     steps:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
 
@@ -95,7 +95,7 @@ jobs:
   Integration-Test:
     # Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
     name: "Integration tests"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-24.04
     steps:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
 
@@ -113,7 +113,7 @@ jobs:
 
   Build-Snapshot-Artifacts:
     name: "Build snapshot artifacts"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-24.04
     steps:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
 
@@ -143,7 +143,7 @@ jobs:
     # Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
     name: "Acceptance tests (Linux)"
     needs: [Build-Snapshot-Artifacts]
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-24.04
     steps:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
 
@@ -203,7 +203,7 @@ jobs:
     # Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
     name: "CLI tests (Linux)"
     needs: [Build-Snapshot-Artifacts]
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-24.04
     steps:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
 
diff --git a/cmd/grype/cli/commands/db.go b/cmd/grype/cli/commands/db.go
index d17a762d..63ef1818 100644
--- a/cmd/grype/cli/commands/db.go
+++ b/cmd/grype/cli/commands/db.go
@@ -4,7 +4,6 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/anchore/clio"
-	"github.com/anchore/grype/cmd/grype/cli/options"
 )
 
 const (
@@ -13,20 +12,6 @@ const (
 	textOutputFormat  = "text"
 )
 
-type DBOptions struct {
-	DB           options.Database     `yaml:"db" json:"db" mapstructure:"db"`
-	Experimental options.Experimental `yaml:"exp" json:"exp" mapstructure:"exp"`
-}
-
-func dbOptionsDefault(id clio.Identification) *DBOptions {
-	dbDefaults := options.DefaultDatabase(id)
-	// by default, require update check success for db operations which check for updates
-	dbDefaults.RequireUpdateCheck = true
-	return &DBOptions{
-		DB: dbDefaults,
-	}
-}
-
 func DB(app clio.Application) *cobra.Command {
 	db := &cobra.Command{
 		Use:   "db",
diff --git a/cmd/grype/cli/commands/db_check.go b/cmd/grype/cli/commands/db_check.go
index 5474f381..6f61a068 100644
--- a/cmd/grype/cli/commands/db_check.go
+++ b/cmd/grype/cli/commands/db_check.go
@@ -9,6 +9,7 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/anchore/clio"
+	"github.com/anchore/grype/cmd/grype/cli/options"
 	legacyDistribution "github.com/anchore/grype/grype/db/v5/distribution"
 	db "github.com/anchore/grype/grype/db/v6"
 	"github.com/anchore/grype/grype/db/v6/distribution"
@@ -20,8 +21,8 @@ const (
 )
 
 type dbCheckOptions struct {
-	Output    string `yaml:"output" json:"output" mapstructure:"output"`
-	DBOptions `yaml:",inline" mapstructure:",squash"`
+	Output                  string `yaml:"output" json:"output" mapstructure:"output"`
+	options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 }
 
 var _ clio.FlagAdder = (*dbCheckOptions)(nil)
@@ -32,8 +33,8 @@ func (d *dbCheckOptions) AddFlags(flags clio.FlagSet) {
 
 func DBCheck(app clio.Application) *cobra.Command {
 	opts := &dbCheckOptions{
-		Output:    textOutputFormat,
-		DBOptions: *dbOptionsDefault(app.ID()),
+		Output:          textOutputFormat,
+		DatabaseCommand: *options.DefaultDatabaseCommand(app.ID()),
 	}
 
 	cmd := &cobra.Command{
@@ -52,27 +53,27 @@ func DBCheck(app clio.Application) *cobra.Command {
 
 	// prevent from being shown in the grype config
 	type configWrapper struct {
-		Hidden     *dbCheckOptions `json:"-" yaml:"-" mapstructure:"-"`
-		*DBOptions `yaml:",inline" mapstructure:",squash"`
+		Hidden                   *dbCheckOptions `json:"-" yaml:"-" mapstructure:"-"`
+		*options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 	}
 
-	return app.SetupCommand(cmd, &configWrapper{Hidden: opts, DBOptions: &opts.DBOptions})
+	return app.SetupCommand(cmd, &configWrapper{Hidden: opts, DatabaseCommand: &opts.DatabaseCommand})
 }
 
 func runDBCheck(opts dbCheckOptions) error {
-	if opts.DBOptions.Experimental.DBv6 {
+	if opts.DatabaseCommand.Experimental.DBv6 {
 		return newDBCheck(opts)
 	}
 	return legacyDBCheck(opts)
 }
 
 func newDBCheck(opts dbCheckOptions) error {
-	client, err := distribution.NewClient(opts.DB.ToClientConfig())
+	client, err := distribution.NewClient(opts.ToClientConfig())
 	if err != nil {
 		return fmt.Errorf("unable to create distribution client: %w", err)
 	}
 
-	cfg := opts.DB.ToCuratorConfig()
+	cfg := opts.ToCuratorConfig()
 
 	current, err := db.ReadDescription(cfg.DBFilePath())
 	if err != nil {
@@ -148,7 +149,7 @@ type legacyDBCheckJSON struct {
 }
 
 func legacyDBCheck(opts dbCheckOptions) error {
-	dbCurator, err := legacyDistribution.NewCurator(opts.DB.ToLegacyCuratorConfig())
+	dbCurator, err := legacyDistribution.NewCurator(opts.ToLegacyCuratorConfig())
 	if err != nil {
 		return err
 	}
diff --git a/cmd/grype/cli/commands/db_delete.go b/cmd/grype/cli/commands/db_delete.go
index 2c4cc553..1eaed76b 100644
--- a/cmd/grype/cli/commands/db_delete.go
+++ b/cmd/grype/cli/commands/db_delete.go
@@ -13,7 +13,7 @@ import (
 )
 
 func DBDelete(app clio.Application) *cobra.Command {
-	opts := dbOptionsDefault(app.ID())
+	opts := options.DefaultDatabaseCommand(app.ID())
 
 	cmd := &cobra.Command{
 		Use:     "delete",
@@ -27,20 +27,20 @@ func DBDelete(app clio.Application) *cobra.Command {
 
 	// prevent from being shown in the grype config
 	type configWrapper struct {
-		*DBOptions `yaml:",inline" mapstructure:",squash"`
+		*options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 	}
 
 	return app.SetupCommand(cmd, &configWrapper{opts})
 }
 
-func runDBDelete(opts DBOptions) error {
+func runDBDelete(opts options.DatabaseCommand) error {
 	if opts.Experimental.DBv6 {
-		return newDBDelete(opts.DB)
+		return newDBDelete(opts)
 	}
-	return legacyDBDelete(opts.DB)
+	return legacyDBDelete(opts)
 }
 
-func newDBDelete(opts options.Database) error {
+func newDBDelete(opts options.DatabaseCommand) error {
 	client, err := distribution.NewClient(opts.ToClientConfig())
 	if err != nil {
 		return fmt.Errorf("unable to create distribution client: %w", err)
@@ -57,7 +57,7 @@ func newDBDelete(opts options.Database) error {
 	return stderrPrintLnf("Vulnerability database deleted")
 }
 
-func legacyDBDelete(opts options.Database) error {
+func legacyDBDelete(opts options.DatabaseCommand) error {
 	dbCurator, err := legacyDistribution.NewCurator(opts.ToLegacyCuratorConfig())
 	if err != nil {
 		return err
diff --git a/cmd/grype/cli/commands/db_diff.go b/cmd/grype/cli/commands/db_diff.go
index 3565d9e6..e41c4199 100644
--- a/cmd/grype/cli/commands/db_diff.go
+++ b/cmd/grype/cli/commands/db_diff.go
@@ -15,9 +15,9 @@ import (
 )
 
 type dbDiffOptions struct {
-	Output    string `yaml:"output" json:"output" mapstructure:"output"`
-	Delete    bool   `yaml:"delete" json:"delete" mapstructure:"delete"`
-	DBOptions `yaml:",inline" mapstructure:",squash"`
+	Output                  string `yaml:"output" json:"output" mapstructure:"output"`
+	Delete                  bool   `yaml:"delete" json:"delete" mapstructure:"delete"`
+	options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 }
 
 var _ clio.FlagAdder = (*dbDiffOptions)(nil)
@@ -29,8 +29,8 @@ func (d *dbDiffOptions) AddFlags(flags clio.FlagSet) {
 
 func DBDiff(app clio.Application) *cobra.Command {
 	opts := &dbDiffOptions{
-		Output:    tableOutputFormat,
-		DBOptions: *dbOptionsDefault(app.ID()),
+		Output:          tableOutputFormat,
+		DatabaseCommand: *options.DefaultDatabaseCommand(app.ID()),
 	}
 
 	cmd := &cobra.Command{
@@ -43,14 +43,14 @@ func DBDiff(app clio.Application) *cobra.Command {
 			switch len(args) {
 			case 0:
 				log.Info("base_db_url and target_db_url not provided; fetching most recent")
-				base, target, err = getDefaultURLs(opts.DB)
+				base, target, err = getDefaultURLs(opts.DatabaseCommand)
 				if err != nil {
 					return err
 				}
 			case 1:
 				log.Info("target_db_url not provided; fetching most recent")
 				base = args[0]
-				_, target, err = getDefaultURLs(opts.DB)
+				_, target, err = getDefaultURLs(opts.DatabaseCommand)
 				if err != nil {
 					return err
 				}
@@ -65,15 +65,15 @@ func DBDiff(app clio.Application) *cobra.Command {
 
 	// prevent from being shown in the grype config
 	type configWrapper struct {
-		Hidden     *dbDiffOptions `json:"-" yaml:"-" mapstructure:"-"`
-		*DBOptions `yaml:",inline" mapstructure:",squash"`
+		Hidden                   *dbDiffOptions `json:"-" yaml:"-" mapstructure:"-"`
+		*options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 	}
 
-	return app.SetupCommand(cmd, &configWrapper{Hidden: opts, DBOptions: &opts.DBOptions})
+	return app.SetupCommand(cmd, &configWrapper{Hidden: opts, DatabaseCommand: &opts.DatabaseCommand})
 }
 
 func runDBDiff(opts *dbDiffOptions, base string, target string) (errs error) {
-	d, err := differ.NewDiffer(opts.DB.ToLegacyCuratorConfig())
+	d, err := differ.NewDiffer(opts.ToLegacyCuratorConfig())
 	if err != nil {
 		return err
 	}
@@ -111,7 +111,7 @@ func runDBDiff(opts *dbDiffOptions, base string, target string) (errs error) {
 	return errs
 }
 
-func getDefaultURLs(opts options.Database) (baseURL string, targetURL string, err error) {
+func getDefaultURLs(opts options.DatabaseCommand) (baseURL string, targetURL string, err error) {
 	dbCurator, err := distribution.NewCurator(opts.ToLegacyCuratorConfig())
 	if err != nil {
 		return "", "", err
diff --git a/cmd/grype/cli/commands/db_import.go b/cmd/grype/cli/commands/db_import.go
index d5af0c00..42182f23 100644
--- a/cmd/grype/cli/commands/db_import.go
+++ b/cmd/grype/cli/commands/db_import.go
@@ -15,7 +15,7 @@ import (
 )
 
 func DBImport(app clio.Application) *cobra.Command {
-	opts := dbOptionsDefault(app.ID())
+	opts := options.DefaultDatabaseCommand(app.ID())
 
 	cmd := &cobra.Command{
 		Use:   "import FILE",
@@ -29,23 +29,23 @@ func DBImport(app clio.Application) *cobra.Command {
 
 	// prevent from being shown in the grype config
 	type configWrapper struct {
-		*DBOptions `yaml:",inline" mapstructure:",squash"`
+		*options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 	}
 
 	return app.SetupCommand(cmd, &configWrapper{opts})
 }
 
-func runDBImport(opts DBOptions, dbArchivePath string) error {
+func runDBImport(opts options.DatabaseCommand, dbArchivePath string) error {
 	// TODO: tui update? better logging?
 
 	// TODO: we will only support v6 after development is complete
 	if opts.Experimental.DBv6 {
-		return newDBImport(opts.DB, dbArchivePath)
+		return newDBImport(opts, dbArchivePath)
 	}
-	return legacyDBImport(opts.DB, dbArchivePath)
+	return legacyDBImport(opts, dbArchivePath)
 }
 
-func newDBImport(opts options.Database, dbArchivePath string) error {
+func newDBImport(opts options.DatabaseCommand, dbArchivePath string) error {
 	client, err := distribution.NewClient(opts.ToClientConfig())
 	if err != nil {
 		return fmt.Errorf("unable to create distribution client: %w", err)
@@ -65,7 +65,7 @@ func newDBImport(opts options.Database, dbArchivePath string) error {
 	return nil
 }
 
-func legacyDBImport(opts options.Database, dbArchivePath string) error {
+func legacyDBImport(opts options.DatabaseCommand, dbArchivePath string) error {
 	dbCurator, err := legacyDistribution.NewCurator(opts.ToLegacyCuratorConfig())
 	if err != nil {
 		return err
diff --git a/cmd/grype/cli/commands/db_list.go b/cmd/grype/cli/commands/db_list.go
index ed7a736f..0569dc49 100644
--- a/cmd/grype/cli/commands/db_list.go
+++ b/cmd/grype/cli/commands/db_list.go
@@ -11,13 +11,14 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/anchore/clio"
+	"github.com/anchore/grype/cmd/grype/cli/options"
 	legacyDistribution "github.com/anchore/grype/grype/db/v5/distribution"
 	"github.com/anchore/grype/grype/db/v6/distribution"
 )
 
 type dbListOptions struct {
-	Output    string `yaml:"output" json:"output" mapstructure:"output"`
-	DBOptions `yaml:",inline" mapstructure:",squash"`
+	Output                  string `yaml:"output" json:"output" mapstructure:"output"`
+	options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 }
 
 var _ clio.FlagAdder = (*dbListOptions)(nil)
@@ -28,8 +29,8 @@ func (d *dbListOptions) AddFlags(flags clio.FlagSet) {
 
 func DBList(app clio.Application) *cobra.Command {
 	opts := &dbListOptions{
-		Output:    textOutputFormat,
-		DBOptions: *dbOptionsDefault(app.ID()),
+		Output:          textOutputFormat,
+		DatabaseCommand: *options.DefaultDatabaseCommand(app.ID()),
 	}
 
 	cmd := &cobra.Command{
@@ -44,11 +45,11 @@ func DBList(app clio.Application) *cobra.Command {
 
 	// prevent from being shown in the grype config
 	type configWrapper struct {
-		Hidden     *dbListOptions `json:"-" yaml:"-" mapstructure:"-"`
-		*DBOptions `yaml:",inline" mapstructure:",squash"`
+		Hidden                   *dbListOptions `json:"-" yaml:"-" mapstructure:"-"`
+		*options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 	}
 
-	return app.SetupCommand(cmd, &configWrapper{Hidden: opts, DBOptions: &opts.DBOptions})
+	return app.SetupCommand(cmd, &configWrapper{Hidden: opts, DatabaseCommand: &opts.DatabaseCommand})
 }
 
 func runDBList(opts dbListOptions) error {
@@ -59,7 +60,7 @@ func runDBList(opts dbListOptions) error {
 }
 
 func newDBList(opts dbListOptions) error {
-	c, err := distribution.NewClient(opts.DB.ToClientConfig())
+	c, err := distribution.NewClient(opts.ToClientConfig())
 	if err != nil {
 		return fmt.Errorf("unable to create distribution client: %w", err)
 	}
@@ -109,7 +110,7 @@ func presentNewDBList(format string, u string, writer io.Writer, latest *distrib
 // all legacy processing below ////////////////////////////////////////////////////////////////////////////////////////
 
 func legacyDBList(opts dbListOptions) error {
-	dbCurator, err := legacyDistribution.NewCurator(opts.DB.ToLegacyCuratorConfig())
+	dbCurator, err := legacyDistribution.NewCurator(opts.ToLegacyCuratorConfig())
 	if err != nil {
 		return err
 	}
diff --git a/cmd/grype/cli/commands/db_providers.go b/cmd/grype/cli/commands/db_providers.go
index 9107959a..7ed5569d 100644
--- a/cmd/grype/cli/commands/db_providers.go
+++ b/cmd/grype/cli/commands/db_providers.go
@@ -13,6 +13,7 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/anchore/clio"
+	"github.com/anchore/grype/cmd/grype/cli/options"
 	legacyDistribution "github.com/anchore/grype/grype/db/v5/distribution"
 	v6 "github.com/anchore/grype/grype/db/v6"
 	"github.com/anchore/grype/grype/db/v6/distribution"
@@ -21,8 +22,8 @@ import (
 )
 
 type dbProvidersOptions struct {
-	Output    string `yaml:"output" json:"output"`
-	DBOptions `yaml:",inline" mapstructure:",squash"`
+	Output                  string `yaml:"output" json:"output"`
+	options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 }
 
 var _ clio.FlagAdder = (*dbProvidersOptions)(nil)
@@ -33,8 +34,8 @@ func (d *dbProvidersOptions) AddFlags(flags clio.FlagSet) {
 
 func DBProviders(app clio.Application) *cobra.Command {
 	opts := &dbProvidersOptions{
-		Output:    tableOutputFormat,
-		DBOptions: *dbOptionsDefault(app.ID()),
+		Output:          tableOutputFormat,
+		DatabaseCommand: *options.DefaultDatabaseCommand(app.ID()),
 	}
 
 	cmd := &cobra.Command{
@@ -48,11 +49,11 @@ func DBProviders(app clio.Application) *cobra.Command {
 
 	// prevent from being shown in the grype config
 	type configWrapper struct {
-		Hidden     *dbProvidersOptions `json:"-" yaml:"-" mapstructure:"-"`
-		*DBOptions `yaml:",inline" mapstructure:",squash"`
+		Hidden                   *dbProvidersOptions `json:"-" yaml:"-" mapstructure:"-"`
+		*options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 	}
 
-	return app.SetupCommand(cmd, &configWrapper{Hidden: opts, DBOptions: &opts.DBOptions})
+	return app.SetupCommand(cmd, &configWrapper{Hidden: opts, DatabaseCommand: &opts.DatabaseCommand})
 }
 
 func runDBProviders(opts *dbProvidersOptions, app clio.Application) error {
@@ -63,11 +64,11 @@ func runDBProviders(opts *dbProvidersOptions, app clio.Application) error {
 }
 
 func newDBProviders(opts *dbProvidersOptions) error {
-	client, err := distribution.NewClient(opts.DB.ToClientConfig())
+	client, err := distribution.NewClient(opts.ToClientConfig())
 	if err != nil {
 		return fmt.Errorf("unable to create distribution client: %w", err)
 	}
-	c, err := installation.NewCurator(opts.DB.ToCuratorConfig(), client)
+	c, err := installation.NewCurator(opts.ToCuratorConfig(), client)
 	if err != nil {
 		return fmt.Errorf("unable to create curator: %w", err)
 	}
@@ -199,7 +200,7 @@ func legacyDBProviders(opts *dbProvidersOptions, app clio.Application) error {
 }
 
 func getLegacyMetadataFileLocation(app clio.Application) (*string, error) {
-	dbCurator, err := legacyDistribution.NewCurator(dbOptionsDefault(app.ID()).DB.ToLegacyCuratorConfig())
+	dbCurator, err := legacyDistribution.NewCurator(options.DefaultDatabaseCommand(app.ID()).ToLegacyCuratorConfig())
 	if err != nil {
 		return nil, err
 	}
diff --git a/cmd/grype/cli/commands/db_search.go b/cmd/grype/cli/commands/db_search.go
index de58f6e1..873bc1ad 100644
--- a/cmd/grype/cli/commands/db_search.go
+++ b/cmd/grype/cli/commands/db_search.go
@@ -31,7 +31,7 @@ type dbSearchMatchOptions struct {
 	OS            options.DBSearchOSs             `yaml:",inline" mapstructure:",squash"`
 	Bounds        options.DBSearchBounds          `yaml:",inline" mapstructure:",squash"`
 
-	DBOptions `yaml:",inline" mapstructure:",squash"`
+	options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 }
 
 var alasPattern = regexp.MustCompile(`^alas[\w]*-\d+-\d+$`)
@@ -81,8 +81,8 @@ func DBSearch(app clio.Application) *cobra.Command {
 		Vulnerability: options.DBSearchVulnerabilities{
 			UseVulnIDFlag: true,
 		},
-		Bounds:    options.DefaultDBSearchBounds(),
-		DBOptions: *dbOptionsDefault(app.ID()),
+		Bounds:          options.DefaultDBSearchBounds(),
+		DatabaseCommand: *options.DefaultDatabaseCommand(app.ID()),
 	}
 
 	cmd := &cobra.Command{
@@ -144,20 +144,20 @@ func DBSearch(app clio.Application) *cobra.Command {
 
 	// prevent from being shown in the grype config
 	type configWrapper struct {
-		Hidden     *dbSearchMatchOptions `json:"-" yaml:"-" mapstructure:"-"`
-		*DBOptions `yaml:",inline" mapstructure:",squash"`
+		Hidden                   *dbSearchMatchOptions `json:"-" yaml:"-" mapstructure:"-"`
+		*options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 	}
 
-	return app.SetupCommand(cmd, &configWrapper{Hidden: opts, DBOptions: &opts.DBOptions})
+	return app.SetupCommand(cmd, &configWrapper{Hidden: opts, DatabaseCommand: &opts.DatabaseCommand})
 }
 
 func runDBSearchMatches(opts dbSearchMatchOptions) error {
-	client, err := distribution.NewClient(opts.DB.ToClientConfig())
+	client, err := distribution.NewClient(opts.ToClientConfig())
 	if err != nil {
 		return fmt.Errorf("unable to create distribution client: %w", err)
 	}
 
-	curator, err := installation.NewCurator(opts.DB.ToCuratorConfig(), client)
+	curator, err := installation.NewCurator(opts.ToCuratorConfig(), client)
 	if err != nil {
 		return fmt.Errorf("unable to create curator: %w", err)
 	}
@@ -234,7 +234,7 @@ func legacyDBSearchPackages(opts dbSearchMatchOptions, vulnerabilityIDs []string
 	}
 
 	log.Debug("loading DB")
-	str, status, err := grype.LoadVulnerabilityDB(opts.DB.ToLegacyCuratorConfig(), opts.DB.AutoUpdate)
+	str, status, err := grype.LoadVulnerabilityDB(opts.ToLegacyCuratorConfig(), opts.DB.AutoUpdate)
 	err = validateDBLoad(err, status)
 	if err != nil {
 		return err
diff --git a/cmd/grype/cli/commands/db_search_vuln.go b/cmd/grype/cli/commands/db_search_vuln.go
index 0fd3385d..b2049aea 100644
--- a/cmd/grype/cli/commands/db_search_vuln.go
+++ b/cmd/grype/cli/commands/db_search_vuln.go
@@ -26,7 +26,7 @@ type dbSearchVulnerabilityOptions struct {
 	Vulnerability options.DBSearchVulnerabilities `yaml:",inline" mapstructure:",squash"`
 	Bounds        options.DBSearchBounds          `yaml:",inline" mapstructure:",squash"`
 
-	DBOptions `yaml:",inline" mapstructure:",squash"`
+	options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 }
 
 func DBSearchVulnerabilities(app clio.Application) *cobra.Command {
@@ -35,8 +35,8 @@ func DBSearchVulnerabilities(app clio.Application) *cobra.Command {
 		Vulnerability: options.DBSearchVulnerabilities{
 			UseVulnIDFlag: false, // we input this through the args
 		},
-		Bounds:    options.DefaultDBSearchBounds(),
-		DBOptions: *dbOptionsDefault(app.ID()),
+		Bounds:          options.DefaultDBSearchBounds(),
+		DatabaseCommand: *options.DefaultDatabaseCommand(app.ID()),
 	}
 
 	cmd := &cobra.Command{
@@ -60,20 +60,20 @@ func DBSearchVulnerabilities(app clio.Application) *cobra.Command {
 
 	// prevent from being shown in the grype config
 	type configWrapper struct {
-		Hidden     *dbSearchVulnerabilityOptions `json:"-" yaml:"-" mapstructure:"-"`
-		*DBOptions `yaml:",inline" mapstructure:",squash"`
+		Hidden                   *dbSearchVulnerabilityOptions `json:"-" yaml:"-" mapstructure:"-"`
+		*options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 	}
 
-	return app.SetupCommand(cmd, &configWrapper{Hidden: opts, DBOptions: &opts.DBOptions})
+	return app.SetupCommand(cmd, &configWrapper{Hidden: opts, DatabaseCommand: &opts.DatabaseCommand})
 }
 
 func runDBSearchVulnerabilities(opts dbSearchVulnerabilityOptions) error {
-	client, err := distribution.NewClient(opts.DB.ToClientConfig())
+	client, err := distribution.NewClient(opts.ToClientConfig())
 	if err != nil {
 		return fmt.Errorf("unable to create distribution client: %w", err)
 	}
 
-	c, err := installation.NewCurator(opts.DB.ToCuratorConfig(), client)
+	c, err := installation.NewCurator(opts.ToCuratorConfig(), client)
 	if err != nil {
 		return fmt.Errorf("unable to create curator: %w", err)
 	}
diff --git a/cmd/grype/cli/commands/db_status.go b/cmd/grype/cli/commands/db_status.go
index f9cf68ca..f13b5d17 100644
--- a/cmd/grype/cli/commands/db_status.go
+++ b/cmd/grype/cli/commands/db_status.go
@@ -9,6 +9,7 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/anchore/clio"
+	"github.com/anchore/grype/cmd/grype/cli/options"
 	legacyDistribution "github.com/anchore/grype/grype/db/v5/distribution"
 	v6 "github.com/anchore/grype/grype/db/v6"
 	"github.com/anchore/grype/grype/db/v6/distribution"
@@ -16,8 +17,8 @@ import (
 )
 
 type dbStatusOptions struct {
-	Output    string `yaml:"output" json:"output" mapstructure:"output"`
-	DBOptions `yaml:",inline" mapstructure:",squash"`
+	Output                  string `yaml:"output" json:"output" mapstructure:"output"`
+	options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 }
 
 var _ clio.FlagAdder = (*dbStatusOptions)(nil)
@@ -28,8 +29,8 @@ func (d *dbStatusOptions) AddFlags(flags clio.FlagSet) {
 
 func DBStatus(app clio.Application) *cobra.Command {
 	opts := &dbStatusOptions{
-		Output:    textOutputFormat,
-		DBOptions: *dbOptionsDefault(app.ID()),
+		Output:          textOutputFormat,
+		DatabaseCommand: *options.DefaultDatabaseCommand(app.ID()),
 	}
 
 	cmd := &cobra.Command{
@@ -44,11 +45,11 @@ func DBStatus(app clio.Application) *cobra.Command {
 
 	// prevent from being shown in the grype config
 	type configWrapper struct {
-		Hidden     *dbStatusOptions `json:"-" yaml:"-" mapstructure:"-"`
-		*DBOptions `yaml:",inline" mapstructure:",squash"`
+		Hidden                   *dbStatusOptions `json:"-" yaml:"-" mapstructure:"-"`
+		*options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 	}
 
-	return app.SetupCommand(cmd, &configWrapper{Hidden: opts, DBOptions: &opts.DBOptions})
+	return app.SetupCommand(cmd, &configWrapper{Hidden: opts, DatabaseCommand: &opts.DatabaseCommand})
 }
 
 func runDBStatus(opts dbStatusOptions) error {
@@ -59,11 +60,11 @@ func runDBStatus(opts dbStatusOptions) error {
 }
 
 func newDBStatus(opts dbStatusOptions) error {
-	client, err := distribution.NewClient(opts.DB.ToClientConfig())
+	client, err := distribution.NewClient(opts.ToClientConfig())
 	if err != nil {
 		return fmt.Errorf("unable to create distribution client: %w", err)
 	}
-	c, err := installation.NewCurator(opts.DB.ToCuratorConfig(), client)
+	c, err := installation.NewCurator(opts.ToCuratorConfig(), client)
 	if err != nil {
 		return fmt.Errorf("unable to create distribution client: %w", err)
 	}
@@ -103,7 +104,7 @@ func presentDBStatus(format string, writer io.Writer, status v6.Status) error {
 // all legacy processing below ////////////////////////////////////////////////////////////////////////////////////////
 
 func legacyDBStatus(opts dbStatusOptions) error {
-	dbCurator, err := legacyDistribution.NewCurator(opts.DB.ToLegacyCuratorConfig())
+	dbCurator, err := legacyDistribution.NewCurator(opts.ToLegacyCuratorConfig())
 	if err != nil {
 		return err
 	}
diff --git a/cmd/grype/cli/commands/db_update.go b/cmd/grype/cli/commands/db_update.go
index ba851ccd..8f515e5b 100644
--- a/cmd/grype/cli/commands/db_update.go
+++ b/cmd/grype/cli/commands/db_update.go
@@ -15,7 +15,7 @@ import (
 )
 
 func DBUpdate(app clio.Application) *cobra.Command {
-	opts := dbOptionsDefault(app.ID())
+	opts := options.DefaultDatabaseCommand(app.ID())
 
 	cmd := &cobra.Command{
 		Use:   "update",
@@ -27,26 +27,26 @@ func DBUpdate(app clio.Application) *cobra.Command {
 			return nil
 		},
 		RunE: func(_ *cobra.Command, _ []string) error {
-			return runDBUpdate(opts.DB, opts.Experimental.DBv6)
+			return runDBUpdate(*opts, opts.Experimental.DBv6)
 		},
 	}
 
 	// prevent from being shown in the grype config
 	type configWrapper struct {
-		*DBOptions `yaml:",inline" mapstructure:",squash"`
+		*options.DatabaseCommand `yaml:",inline" mapstructure:",squash"`
 	}
 
 	return app.SetupCommand(cmd, &configWrapper{opts})
 }
 
-func runDBUpdate(opts options.Database, expUseV6 bool) error {
+func runDBUpdate(opts options.DatabaseCommand, expUseV6 bool) error {
 	if expUseV6 {
 		return newDBUpdate(opts)
 	}
 	return legacyDBUpdate(opts)
 }
 
-func newDBUpdate(opts options.Database) error {
+func newDBUpdate(opts options.DatabaseCommand) error {
 	client, err := distribution.NewClient(opts.ToClientConfig())
 	if err != nil {
 		return fmt.Errorf("unable to create distribution client: %w", err)
@@ -76,7 +76,7 @@ func newDBUpdate(opts options.Database) error {
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 // all legacy processing below ////////////////////////////////////////////////////////////////////////////////////////
 
-func legacyDBUpdate(opts options.Database) error {
+func legacyDBUpdate(opts options.DatabaseCommand) error {
 	dbCurator, err := legacyDistribution.NewCurator(opts.ToLegacyCuratorConfig())
 	if err != nil {
 		return err
diff --git a/cmd/grype/cli/commands/root.go b/cmd/grype/cli/commands/root.go
index a7f36807..c5edb823 100644
--- a/cmd/grype/cli/commands/root.go
+++ b/cmd/grype/cli/commands/root.go
@@ -153,10 +153,10 @@ func runGrype(app clio.Application, opts *options.Grype, userInput string) (errs
 		func() (err error) {
 			log.Debug("loading DB")
 			if opts.Experimental.DBv6 {
-				vp, status, err = grype.LoadVulnerabilityDBv6(opts.DB.ToClientConfig(), opts.DB.ToCuratorConfig(), opts.DB.AutoUpdate)
+				vp, status, err = grype.LoadVulnerabilityDBv6(opts.ToClientConfig(), opts.ToCuratorConfig(), opts.DB.AutoUpdate)
 				return err
 			}
-			vp, status, err = grype.LoadVulnerabilityDB(opts.DB.ToLegacyCuratorConfig(), opts.DB.AutoUpdate)
+			vp, status, err = grype.LoadVulnerabilityDB(opts.ToLegacyCuratorConfig(), opts.DB.AutoUpdate)
 			return validateDBLoad(err, status)
 		},
 		func() (err error) {
diff --git a/cmd/grype/cli/options/database.go b/cmd/grype/cli/options/database.go
index 3263e945..9488fc02 100644
--- a/cmd/grype/cli/options/database.go
+++ b/cmd/grype/cli/options/database.go
@@ -7,9 +7,6 @@ import (
 	"github.com/adrg/xdg"
 
 	"github.com/anchore/clio"
-	legacyDistribution "github.com/anchore/grype/grype/db/v5/distribution"
-	"github.com/anchore/grype/grype/db/v6/distribution"
-	"github.com/anchore/grype/grype/db/v6/installation"
 	"github.com/anchore/grype/internal"
 )
 
@@ -55,43 +52,6 @@ func DefaultDatabase(id clio.Identification) Database {
 	}
 }
 
-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,
-		CACert:                  cfg.CACert,
-		ValidateByHashOnGet:     cfg.ValidateByHashOnStart,
-		ValidateAge:             cfg.ValidateAge,
-		MaxAllowedBuiltAge:      cfg.MaxAllowedBuiltAge,
-		RequireUpdateCheck:      cfg.RequireUpdateCheck,
-		ListingFileTimeout:      cfg.UpdateAvailableTimeout,
-		UpdateTimeout:           cfg.UpdateDownloadTimeout,
-		UpdateCheckMaxFrequency: cfg.MaxUpdateCheckFrequency,
-	}
-}
-
 func (cfg *Database) DescribeFields(descriptions clio.FieldDescriptionSet) {
 	descriptions.Add(&cfg.Dir, `location to write the vulnerability database cache`)
 	descriptions.Add(&cfg.UpdateURL, `URL of the vulnerability database`)
diff --git a/cmd/grype/cli/options/database_command.go b/cmd/grype/cli/options/database_command.go
new file mode 100644
index 00000000..561671e4
--- /dev/null
+++ b/cmd/grype/cli/options/database_command.go
@@ -0,0 +1,61 @@
+package options
+
+import (
+	"github.com/anchore/clio"
+	legacyDistribution "github.com/anchore/grype/grype/db/v5/distribution"
+	"github.com/anchore/grype/grype/db/v6/distribution"
+	"github.com/anchore/grype/grype/db/v6/installation"
+)
+
+type DatabaseCommand struct {
+	DB           Database     `yaml:"db" json:"db" mapstructure:"db"`
+	Experimental Experimental `yaml:"exp" json:"exp" mapstructure:"exp"`
+	Developer    developer    `yaml:"dev" json:"dev" mapstructure:"dev"`
+}
+
+func DefaultDatabaseCommand(id clio.Identification) *DatabaseCommand {
+	dbDefaults := DefaultDatabase(id)
+	// by default, require update check success for db operations which check for updates
+	dbDefaults.RequireUpdateCheck = true
+	return &DatabaseCommand{
+		DB: dbDefaults,
+	}
+}
+
+func (cfg DatabaseCommand) ToCuratorConfig() installation.Config {
+	return installation.Config{
+		DBRootDir:               cfg.DB.Dir,
+		ValidateAge:             cfg.DB.ValidateAge,
+		ValidateChecksum:        cfg.DB.ValidateByHashOnStart,
+		MaxAllowedBuiltAge:      cfg.DB.MaxAllowedBuiltAge,
+		UpdateCheckMaxFrequency: cfg.DB.MaxUpdateCheckFrequency,
+		Debug:                   cfg.Developer.DB.Debug,
+	}
+}
+
+func (cfg DatabaseCommand) ToClientConfig() distribution.Config {
+	return distribution.Config{
+		ID:                 cfg.DB.ID,
+		LatestURL:          cfg.DB.UpdateURL,
+		CACert:             cfg.DB.CACert,
+		RequireUpdateCheck: cfg.DB.RequireUpdateCheck,
+		CheckTimeout:       cfg.DB.UpdateAvailableTimeout,
+		UpdateTimeout:      cfg.DB.UpdateDownloadTimeout,
+	}
+}
+
+func (cfg DatabaseCommand) ToLegacyCuratorConfig() legacyDistribution.Config {
+	return legacyDistribution.Config{
+		ID:                      cfg.DB.ID,
+		DBRootDir:               cfg.DB.Dir,
+		ListingURL:              cfg.DB.UpdateURL,
+		CACert:                  cfg.DB.CACert,
+		ValidateByHashOnGet:     cfg.DB.ValidateByHashOnStart,
+		ValidateAge:             cfg.DB.ValidateAge,
+		MaxAllowedBuiltAge:      cfg.DB.MaxAllowedBuiltAge,
+		RequireUpdateCheck:      cfg.DB.RequireUpdateCheck,
+		ListingFileTimeout:      cfg.DB.UpdateAvailableTimeout,
+		UpdateTimeout:           cfg.DB.UpdateDownloadTimeout,
+		UpdateCheckMaxFrequency: cfg.DB.MaxUpdateCheckFrequency,
+	}
+}
diff --git a/cmd/grype/cli/options/grype.go b/cmd/grype/cli/options/grype.go
index 43074875..4bd5b3f6 100644
--- a/cmd/grype/cli/options/grype.go
+++ b/cmd/grype/cli/options/grype.go
@@ -25,7 +25,6 @@ type Grype struct {
 	Search                     search             `yaml:"search" json:"search" mapstructure:"search"`
 	Ignore                     []match.IgnoreRule `yaml:"ignore" json:"ignore" mapstructure:"ignore"`
 	Exclusions                 []string           `yaml:"exclude" json:"exclude" mapstructure:"exclude"`
-	DB                         Database           `yaml:"db" json:"db" mapstructure:"db"`
 	ExternalSources            externalSources    `yaml:"external-sources" json:"externalSources" mapstructure:"external-sources"`
 	Match                      matchConfig        `yaml:"match" json:"match" mapstructure:"match"`
 	FailOn                     string             `yaml:"fail-on-severity" json:"fail-on-severity" mapstructure:"fail-on-severity"`
@@ -37,7 +36,15 @@ type Grype struct {
 	VexDocuments               []string           `yaml:"vex-documents" json:"vex-documents" mapstructure:"vex-documents"`
 	VexAdd                     []string           `yaml:"vex-add" json:"vex-add" mapstructure:"vex-add"`                                                                   // GRYPE_VEX_ADD
 	MatchUpstreamKernelHeaders bool               `yaml:"match-upstream-kernel-headers" json:"match-upstream-kernel-headers" mapstructure:"match-upstream-kernel-headers"` // Show matches on kernel-headers packages where the match is on kernel upstream instead of marking them as ignored, default=false
-	Experimental               Experimental       `yaml:"exp" json:"exp" mapstructure:"exp"`
+	DatabaseCommand            `yaml:",inline" json:",inline" mapstructure:",squash"`
+}
+
+type developer struct {
+	DB databaseDeveloper `yaml:"db" json:"db" mapstructure:"db"`
+}
+
+type databaseDeveloper struct {
+	Debug bool `yaml:"debug" json:"debug" mapstructure:"debug"`
 }
 
 var _ interface {
@@ -48,8 +55,10 @@ var _ interface {
 
 func DefaultGrype(id clio.Identification) *Grype {
 	return &Grype{
-		Search:                     defaultSearch(source.SquashedScope),
-		DB:                         DefaultDatabase(id),
+		Search: defaultSearch(source.SquashedScope),
+		DatabaseCommand: DatabaseCommand{
+			DB: DefaultDatabase(id),
+		},
 		Match:                      defaultMatchConfig(),
 		ExternalSources:            defaultExternalSources(),
 		CheckForAppUpdate:          true,
diff --git a/go.mod b/go.mod
index 1c338afa..c39a130b 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/anchore/grype
 
-go 1.23.2
+go 1.24.0
 
 require (
 	github.com/CycloneDX/cyclonedx-go v0.9.2
@@ -21,7 +21,7 @@ require (
 	github.com/aquasecurity/go-pep440-version v0.0.1
 	github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
 	github.com/bmatcuk/doublestar/v2 v2.0.4
-	github.com/charmbracelet/bubbletea v1.3.2
+	github.com/charmbracelet/bubbletea v1.3.3
 	github.com/charmbracelet/lipgloss v1.0.0
 	github.com/dave/jennifer v1.7.1
 	github.com/docker/docker v27.5.1+incompatible
@@ -65,7 +65,7 @@ require (
 	github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8
 	golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
 	golang.org/x/time v0.10.0
-	golang.org/x/tools v0.29.0
+	golang.org/x/tools v0.30.0
 	gopkg.in/yaml.v3 v3.0.1
 	gorm.io/gorm v1.25.12
 )
@@ -272,14 +272,14 @@ require (
 	go.opentelemetry.io/otel/trace v1.33.0 // indirect
 	go.uber.org/atomic v1.9.0 // indirect
 	go.uber.org/multierr v1.9.0 // indirect
-	golang.org/x/crypto v0.32.0 // indirect
-	golang.org/x/mod v0.22.0 // indirect
-	golang.org/x/net v0.34.0 // indirect
+	golang.org/x/crypto v0.33.0 // indirect
+	golang.org/x/mod v0.23.0 // indirect
+	golang.org/x/net v0.35.0 // indirect
 	golang.org/x/oauth2 v0.25.0 // indirect
 	golang.org/x/sync v0.11.0 // indirect
 	golang.org/x/sys v0.30.0 // indirect
-	golang.org/x/term v0.28.0 // indirect
-	golang.org/x/text v0.21.0 // indirect
+	golang.org/x/term v0.29.0 // indirect
+	golang.org/x/text v0.22.0 // indirect
 	golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
 	google.golang.org/api v0.215.0 // indirect
 	google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
diff --git a/go.sum b/go.sum
index 15b2c9fe..77b1321a 100644
--- a/go.sum
+++ b/go.sum
@@ -772,8 +772,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
 github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE=
 github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU=
-github.com/charmbracelet/bubbletea v1.3.2 h1:nc+gDivH0P8ii8CUcf3zCN/PiUz7LKbp3Iz+vYPScNY=
-github.com/charmbracelet/bubbletea v1.3.2/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo=
+github.com/charmbracelet/bubbletea v1.3.3 h1:WpU6fCY0J2vDWM3zfS3vIDi/ULq3SYphZhkAGGvmEUY=
+github.com/charmbracelet/bubbletea v1.3.3/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo=
 github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
 github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
 github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg=
@@ -1630,8 +1630,9 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
 golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
 golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
 golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
-golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
 golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
+golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
+golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
 golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1694,8 +1695,8 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
-golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
+golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1764,8 +1765,9 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
 golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
-golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
 golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
+golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
+golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1938,8 +1940,9 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
 golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
 golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
 golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
-golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
 golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
+golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
+golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1960,8 +1963,9 @@ golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
 golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
+golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -2036,8 +2040,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
 golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
-golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
-golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
+golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
+golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/grype/db/v6/affected_cpe_store.go b/grype/db/v6/affected_cpe_store.go
index e01dff1a..24171d69 100644
--- a/grype/db/v6/affected_cpe_store.go
+++ b/grype/db/v6/affected_cpe_store.go
@@ -117,6 +117,7 @@ func (s *affectedCPEStore) GetAffectedCPEs(cpe *cpe.Attributes, config *GetAffec
 	}
 
 	fields := make(logger.Fields)
+	count := 0
 	if cpe == nil {
 		fields["cpe"] = "any"
 	} else {
@@ -168,6 +169,8 @@ func (s *affectedCPEStore) GetAffectedCPEs(cpe *cpe.Attributes, config *GetAffec
 			models = append(models, *r)
 		}
 
+		count += len(results)
+
 		if config.Limit > 0 && len(models) >= config.Limit {
 			return ErrLimitReached
 		}
@@ -177,6 +180,8 @@ func (s *affectedCPEStore) GetAffectedCPEs(cpe *cpe.Attributes, config *GetAffec
 		return models, fmt.Errorf("unable to fetch affected CPE records: %w", err)
 	}
 
+	fields["records"] = count
+
 	return models, nil
 }
 
diff --git a/grype/db/v6/affected_package_store.go b/grype/db/v6/affected_package_store.go
index b6fb7279..824af95b 100644
--- a/grype/db/v6/affected_package_store.go
+++ b/grype/db/v6/affected_package_store.go
@@ -361,14 +361,23 @@ func (s *affectedPackageStore) addOs(packages ...*AffectedPackageHandle) error {
 	return nil
 }
 
-func (s *affectedPackageStore) GetAffectedPackages(pkg *PackageSpecifier, config *GetAffectedPackageOptions) ([]AffectedPackageHandle, error) {
+func (s *affectedPackageStore) GetAffectedPackages(pkg *PackageSpecifier, config *GetAffectedPackageOptions) ([]AffectedPackageHandle, error) { // nolint:funlen
 	if config == nil {
 		config = &GetAffectedPackageOptions{}
 	}
 
 	start := time.Now()
+	count := 0
 	defer func() {
-		log.WithFields("pkg", pkg.String(), "distro", config.OSs, "vulns", config.Vulnerabilities, "duration", time.Since(start)).Trace("fetched affected package record")
+		log.
+			WithFields(
+				"pkg", pkg.String(),
+				"distro", config.OSs,
+				"vulns", config.Vulnerabilities,
+				"duration", time.Since(start),
+				"records", count,
+			).
+			Trace("fetched affected package record")
 	}()
 
 	query := s.handlePackage(s.db, pkg)
@@ -416,6 +425,8 @@ func (s *affectedPackageStore) GetAffectedPackages(pkg *PackageSpecifier, config
 			models = append(models, *r)
 		}
 
+		count += len(results)
+
 		if config.Limit > 0 && len(models) >= config.Limit {
 			return ErrLimitReached
 		}
diff --git a/grype/db/v6/blobs.go b/grype/db/v6/blobs.go
index 474ab58d..f70332db 100644
--- a/grype/db/v6/blobs.go
+++ b/grype/db/v6/blobs.go
@@ -28,6 +28,10 @@ type VulnerabilityBlob struct {
 	Severities []Severity `json:"severities,omitempty"`
 }
 
+func (v VulnerabilityBlob) String() string {
+	return v.ID
+}
+
 // Reference represents a single external URL and string tags to use for organizational purposes
 type Reference struct {
 	// URL is the external resource
@@ -114,6 +118,24 @@ type AffectedPackageBlob struct {
 	Ranges []AffectedRange `json:"ranges,omitempty"`
 }
 
+func (a AffectedPackageBlob) String() string {
+	var fields []string
+
+	if len(a.Ranges) > 0 {
+		var ranges []string
+		for _, r := range a.Ranges {
+			ranges = append(ranges, r.String())
+		}
+		fields = append(fields, fmt.Sprintf("ranges=%s", strings.Join(ranges, ", ")))
+	}
+
+	if len(a.CVEs) > 0 {
+		fields = append(fields, fmt.Sprintf("cves=%s", strings.Join(a.CVEs, ", ")))
+	}
+
+	return strings.Join(fields, ", ")
+}
+
 // AffectedPackageQualifiers contains package attributes that confirm the package is affected by the vulnerability.
 type AffectedPackageQualifiers struct {
 	// RpmModularity indicates if the package follows RPM modularity for versioning.
@@ -132,6 +154,10 @@ type AffectedRange struct {
 	Fix *Fix `json:"fix,omitempty"`
 }
 
+func (a AffectedRange) String() string {
+	return fmt.Sprintf("%s (%s)", a.Version, a.Fix)
+}
+
 // Fix conveys availability of a fix for a vulnerability.
 type Fix struct {
 	// Version is the version number of the fix.
@@ -144,6 +170,16 @@ type Fix struct {
 	Detail *FixDetail `json:"detail,omitempty"`
 }
 
+func (f Fix) String() string {
+	switch f.State {
+	case FixedStatus:
+		return fmt.Sprintf("fixed in %s", f.Version)
+	case NotAffectedFixStatus:
+		return fmt.Sprintf("%s is not affected", f.Version)
+	}
+	return string(f.State)
+}
+
 // FixDetail is additional information about a fix, such as commit details and patch URLs.
 type FixDetail struct {
 	// GitCommit is the identifier for the Git commit associated with the fix.
diff --git a/grype/db/v6/data.go b/grype/db/v6/data.go
index 1a2efdf8..9de3a25e 100644
--- a/grype/db/v6/data.go
+++ b/grype/db/v6/data.go
@@ -49,8 +49,28 @@ func KnownPackageSpecifierOverrides() []PackageSpecifierOverride {
 	// when matching packages, grype will always attempt to do so based off of the package type which means
 	// that any request must be in terms of the package type (relative to syft).
 
+	// map all known language ecosystems to their respective syft package types
+	ret := []PackageSpecifierOverride{
+		{Ecosystem: pkg.Dart.String(), ReplacementEcosystem: ptr(string(pkg.DartPubPkg))},
+		{Ecosystem: pkg.Dotnet.String(), ReplacementEcosystem: ptr(string(pkg.DotnetPkg))},
+		{Ecosystem: pkg.Elixir.String(), ReplacementEcosystem: ptr(string(pkg.HexPkg))},
+		{Ecosystem: pkg.Erlang.String(), ReplacementEcosystem: ptr(string(pkg.ErlangOTPPkg))},
+		{Ecosystem: pkg.Go.String(), ReplacementEcosystem: ptr(string(pkg.GoModulePkg))},
+		{Ecosystem: pkg.Haskell.String(), ReplacementEcosystem: ptr(string(pkg.HackagePkg))},
+		{Ecosystem: pkg.Java.String(), ReplacementEcosystem: ptr(string(pkg.JavaPkg))},
+		{Ecosystem: pkg.JavaScript.String(), ReplacementEcosystem: ptr(string(pkg.NpmPkg))},
+		{Ecosystem: pkg.Lua.String(), ReplacementEcosystem: ptr(string(pkg.LuaRocksPkg))},
+		{Ecosystem: pkg.OCaml.String(), ReplacementEcosystem: ptr(string(pkg.OpamPkg))},
+		{Ecosystem: pkg.PHP.String(), ReplacementEcosystem: ptr(string(pkg.PhpComposerPkg))},
+		{Ecosystem: pkg.Python.String(), ReplacementEcosystem: ptr(string(pkg.PythonPkg))},
+		{Ecosystem: pkg.R.String(), ReplacementEcosystem: ptr(string(pkg.Rpkg))},
+		{Ecosystem: pkg.Ruby.String(), ReplacementEcosystem: ptr(string(pkg.GemPkg))},
+		{Ecosystem: pkg.Rust.String(), ReplacementEcosystem: ptr(string(pkg.RustPkg))},
+		{Ecosystem: pkg.Swift.String(), ReplacementEcosystem: ptr(string(pkg.SwiftPkg))},
+		{Ecosystem: pkg.Swipl.String(), ReplacementEcosystem: ptr(string(pkg.SwiplPackPkg))},
+	}
+
 	// remap package URL types to syft package types
-	var ret []PackageSpecifierOverride
 	for _, t := range pkg.AllPkgs {
 		purlType := t.PackageURLType()
 		if purlType == "" || purlType == string(t) || strings.HasPrefix(purlType, "generic") {
diff --git a/grype/db/v6/db.go b/grype/db/v6/db.go
index 255c1825..b10609c8 100644
--- a/grype/db/v6/db.go
+++ b/grype/db/v6/db.go
@@ -60,6 +60,7 @@ type Curator interface {
 
 type Config struct {
 	DBDirPath string
+	Debug     bool
 }
 
 func (c Config) DBFilePath() string {
@@ -86,8 +87,10 @@ func Hydrater() func(string) error {
 
 // NewLowLevelDB creates a new empty DB for writing or opens an existing one for reading from the given path. This is
 // not recommended for typical interactions with the vulnerability DB, use NewReader and NewWriter instead.
-func NewLowLevelDB(dbFilePath string, empty, writable bool) (*gorm.DB, error) {
-	var opts []gormadapter.Option
+func NewLowLevelDB(dbFilePath string, empty, writable, debug bool) (*gorm.DB, error) {
+	opts := []gormadapter.Option{
+		gormadapter.WithDebug(debug),
+	}
 
 	if empty && !writable {
 		return nil, fmt.Errorf("cannot open an empty database for reading only")
diff --git a/grype/db/v6/installation/curator.go b/grype/db/v6/installation/curator.go
index 7557e197..a4e9a41d 100644
--- a/grype/db/v6/installation/curator.go
+++ b/grype/db/v6/installation/curator.go
@@ -35,6 +35,7 @@ type monitor struct {
 
 type Config struct {
 	DBRootDir string
+	Debug     bool
 
 	// validations
 	ValidateAge             bool
@@ -81,6 +82,7 @@ func (c curator) Reader() (db.Reader, error) {
 	s, err := db.NewReader(
 		db.Config{
 			DBDirPath: c.config.DBDirectoryPath(),
+			Debug:     c.config.Debug,
 		},
 	)
 	if err != nil {
diff --git a/grype/db/v6/log_dropped.go b/grype/db/v6/log_dropped.go
index 704dda44..d843ba67 100644
--- a/grype/db/v6/log_dropped.go
+++ b/grype/db/v6/log_dropped.go
@@ -1,13 +1,15 @@
 package v6
 
-import "github.com/anchore/grype/internal/log"
+import (
+	"github.com/anchore/go-logger"
+	"github.com/anchore/grype/internal/log"
+)
 
 // logDroppedVulnerability is a hook called when vulnerabilities are dropped from consideration in a vulnerability Provider,
 // this offers a convenient location to set a breakpoint
-func logDroppedVulnerability(vulnerabilityID string, reason any, context ...any) {
-	log.WithFields(
-		"vulnerability", vulnerabilityID,
-		"reason", reason,
-		"context", context,
-	).Trace("dropped vulnerability")
+func logDroppedVulnerability(vuln string, reason any, fields logger.Fields) {
+	fields["reason"] = reason
+	fields["vulnerability"] = vuln
+
+	log.WithFields(fields).Trace("dropped vulnerability")
 }
diff --git a/grype/db/v6/models.go b/grype/db/v6/models.go
index bb0aaf0b..3054163d 100644
--- a/grype/db/v6/models.go
+++ b/grype/db/v6/models.go
@@ -162,6 +162,10 @@ type VulnerabilityHandle struct {
 	BlobValue *VulnerabilityBlob `gorm:"-"`
 }
 
+func (v VulnerabilityHandle) String() string {
+	return fmt.Sprintf("%s/%s", v.Provider, v.Name)
+}
+
 func (v VulnerabilityHandle) getBlobValue() any {
 	if v.BlobValue == nil {
 		return nil // must return untyped nil or getBlobValue() == nil will always be false
@@ -256,6 +260,48 @@ type AffectedPackageHandle struct {
 	BlobValue *AffectedPackageBlob `gorm:"-"`
 }
 
+func (aph AffectedPackageHandle) vulnerability() string {
+	if aph.Vulnerability != nil {
+		return aph.Vulnerability.Name
+	}
+	if aph.BlobValue != nil {
+		if len(aph.BlobValue.CVEs) > 0 {
+			return aph.BlobValue.CVEs[0]
+		}
+	}
+	return ""
+}
+
+func (aph AffectedPackageHandle) String() string {
+	var fields []string
+
+	if aph.BlobValue != nil {
+		v := aph.BlobValue.String()
+		if v != "" {
+			fields = append(fields, v)
+		}
+	}
+	if aph.OperatingSystem != nil {
+		fields = append(fields, fmt.Sprintf("os=%q", aph.OperatingSystem.String()))
+	} else {
+		fields = append(fields, fmt.Sprintf("os=%d", aph.OperatingSystemID))
+	}
+
+	if aph.Package != nil {
+		fields = append(fields, fmt.Sprintf("pkg=%q", aph.Package.String()))
+	} else {
+		fields = append(fields, fmt.Sprintf("pkg=%d", aph.PackageID))
+	}
+
+	if aph.Vulnerability != nil {
+		fields = append(fields, fmt.Sprintf("vuln=%q", aph.Vulnerability.String()))
+	} else {
+		fields = append(fields, fmt.Sprintf("vuln=%d", aph.VulnerabilityID))
+	}
+
+	return fmt.Sprintf("affectedPackage(%s)", strings.Join(fields, ", "))
+}
+
 func (aph AffectedPackageHandle) getBlobValue() any {
 	if aph.BlobValue == nil {
 		return nil // must return untyped nil or getBlobValue() == nil will always be false
@@ -553,28 +599,65 @@ type AffectedCPEHandle struct {
 	BlobValue *AffectedPackageBlob `gorm:"-"`
 }
 
-func (v AffectedCPEHandle) getBlobID() ID {
-	return v.BlobID
+func (ach AffectedCPEHandle) vulnerability() string {
+	if ach.Vulnerability != nil {
+		return ach.Vulnerability.Name
+	}
+	if ach.BlobValue != nil {
+		if len(ach.BlobValue.CVEs) > 0 {
+			return ach.BlobValue.CVEs[0]
+		}
+	}
+	return ""
 }
 
-func (v AffectedCPEHandle) getBlobValue() any {
-	if v.BlobValue == nil {
+func (ach AffectedCPEHandle) String() string {
+	var fields []string
+
+	if ach.BlobValue != nil {
+		v := ach.BlobValue.String()
+		if v != "" {
+			fields = append(fields, v)
+		}
+	}
+
+	if ach.CPE != nil {
+		fields = append(fields, fmt.Sprintf("cpe=%q", ach.CPE.String()))
+	} else {
+		fields = append(fields, fmt.Sprintf("cpe=%d", ach.CpeID))
+	}
+
+	if ach.Vulnerability != nil {
+		fields = append(fields, fmt.Sprintf("vuln=%q", ach.Vulnerability.String()))
+	} else {
+		fields = append(fields, fmt.Sprintf("vuln=%d", ach.VulnerabilityID))
+	}
+
+	return fmt.Sprintf("affectedCPE(%s)", strings.Join(fields, ", "))
+}
+
+func (ach AffectedCPEHandle) getBlobID() ID {
+	return ach.BlobID
+}
+
+func (ach AffectedCPEHandle) getBlobValue() any {
+	if ach.BlobValue == nil {
 		return nil // must return untyped nil or getBlobValue() == nil will always be false
 	}
-	return v.BlobValue
+	return ach.BlobValue
 }
 
-func (v *AffectedCPEHandle) setBlobID(id ID) {
-	v.BlobID = id
+func (ach *AffectedCPEHandle) setBlobID(id ID) {
+	ach.BlobID = id
 }
 
-func (v *AffectedCPEHandle) setBlob(rawBlobValue []byte) error {
+func (ach *AffectedCPEHandle) setBlob(rawBlobValue []byte) error {
 	var blobValue AffectedPackageBlob
 	if err := json.Unmarshal(rawBlobValue, &blobValue); err != nil {
 		return fmt.Errorf("unable to unmarshal affected cpe blob value: %w", err)
 	}
 
-	v.BlobValue = &blobValue
+	ach.BlobValue = &blobValue
 	return nil
 }
 
diff --git a/grype/db/v6/store.go b/grype/db/v6/store.go
index 6f7eaccf..17404edc 100644
--- a/grype/db/v6/store.go
+++ b/grype/db/v6/store.go
@@ -50,7 +50,7 @@ func newStore(cfg Config, empty, writable bool) (*store, error) {
 		path = cfg.DBFilePath()
 	}
 
-	db, err := NewLowLevelDB(path, empty, writable)
+	db, err := NewLowLevelDB(path, empty, writable, cfg.Debug)
 	if err != nil {
 		return nil, fmt.Errorf("failed to open db: %w", err)
 	}
diff --git a/grype/db/v6/vulnerability_provider.go b/grype/db/v6/vulnerability_provider.go
index f2e11689..592df0d9 100644
--- a/grype/db/v6/vulnerability_provider.go
+++ b/grype/db/v6/vulnerability_provider.go
@@ -6,6 +6,7 @@ import (
 
 	"github.com/iancoleman/strcase"
 
+	"github.com/anchore/go-logger"
 	"github.com/anchore/grype/grype/search"
 	"github.com/anchore/grype/grype/version"
 	"github.com/anchore/grype/grype/vulnerability"
@@ -119,6 +120,12 @@ func (s vulnerabilityProvider) FindVulnerabilities(criteria ...vulnerability.Cri
 			}
 		}
 
+		if len(osSpecs) == 0 {
+			// we don't want to search across all distros, instead if the user did not specify a distro we should assume that
+			// they want to search across affected packages not associated with any distro.
+			osSpecs = append(osSpecs, NoOSSpecified)
+		}
+
 		versionMatcher, remainingCriteria := splitConstraintMatcher(criteriaSet...)
 
 		var affectedPackages []AffectedPackageHandle
@@ -185,7 +192,10 @@ func (s vulnerabilityProvider) filterVulnerabilities(vulns []vulnerability.Vulne
 			}
 			matches, err := c.MatchesVulnerability(v)
 			if !matches || err != nil {
-				logDroppedVulnerability(v.Reference.ID, err, c)
+				logDroppedVulnerability(v.ID, err, logger.Fields{
+					"vulnerability": v,
+					"criteria":      c,
+				})
 				return false, err
 			}
 		}
@@ -275,13 +285,9 @@ func filterAffectedPackageVersions(constraintMatcher search.VersionConstraintMat
 			continue // keep this handle
 		}
 
-		id := ""
-		if handle.Vulnerability != nil {
-			id = handle.Vulnerability.Name
-		} else if len(handle.BlobValue.CVEs) > 0 {
-			id = handle.BlobValue.CVEs[0]
-		}
-		logDroppedVulnerability(id, "constraints", handle, constraintMatcher)
+		logDroppedVulnerability(handle.vulnerability(), "package version not within vulnerability constraints", logger.Fields{
+			"affectedPackage": handle,
+		})
 
 		// if we haven't matched a constraint, remove the package
 		packages = append(packages[0:packageIdx], packages[packageIdx+1:]...)
@@ -303,13 +309,9 @@ func filterAffectedCPEVersions(constraintMatcher search.VersionConstraintMatcher
 			continue // keep this handle
 		}
 
-		id := ""
-		if handle.Vulnerability != nil {
-			id = handle.Vulnerability.Name
-		} else if len(handle.BlobValue.CVEs) > 0 {
-			id = handle.BlobValue.CVEs[0]
-		}
-		logDroppedVulnerability(id, "constraints", handle, constraintMatcher)
+		logDroppedVulnerability(handle.vulnerability(), "package version not within vulnerability constraints", logger.Fields{
+			"affectedCPE": handle,
+		})
 	}
 	return out
 }
diff --git a/grype/matcher/internal/only_vulnerable_targets.go b/grype/matcher/internal/only_vulnerable_targets.go
index c6f31a66..a7c86876 100644
--- a/grype/matcher/internal/only_vulnerable_targets.go
+++ b/grype/matcher/internal/only_vulnerable_targets.go
@@ -48,8 +48,8 @@ func isVulnerableTarget(p pkg.Package, vuln vulnerability.Vulnerability) bool {
 		return true
 	}
 
-	// Do not filter by target software for any binary type packages since the composition is unknown
-	if p.Type == syftPkg.BinaryPkg {
+	// Do not filter by target software for any binary or unknown type packages since the composition is unknown
+	if p.Type == syftPkg.BinaryPkg || p.Type == syftPkg.UnknownPkg {
 		return true
 	}
 
diff --git a/grype/search/version_constraint.go b/grype/search/version_constraint.go
index 9757a1a4..c3d41e6d 100644
--- a/grype/search/version_constraint.go
+++ b/grype/search/version_constraint.go
@@ -25,6 +25,13 @@ func ByVersion(v version.Version) vulnerability.Criteria {
 	return ByConstraintFunc(func(constraint version.Constraint) (bool, error) {
 		satisfied, err := constraint.Satisfied(&v)
 		if err != nil {
+			var formatErr *version.UnsupportedFormatError
+			if errors.As(err, &formatErr) {
+				// if the format is unsupported, then the constraint is not satisfied, but this should not be conveyed as an error
+				log.WithFields("reason", err).Trace("unsatisfied constraint")
+				return false, nil
+			}
+
 			var e *version.NonFatalConstraintError
 			if errors.As(err, &e) {
 				log.Warn(e)
diff --git a/grype/version/apk_constraint.go b/grype/version/apk_constraint.go
index 37e69cad..679a4058 100644
--- a/grype/version/apk_constraint.go
+++ b/grype/version/apk_constraint.go
@@ -54,7 +54,7 @@ func (c apkConstraint) Satisfied(version *Version) (bool, error) {
 	}
 
 	if !c.supported(version.Format) {
-		return false, fmt.Errorf("(apk) unsupported format: %s", version.Format)
+		return false, NewUnsupportedFormatError(ApkFormat, version.Format)
 	}
 
 	if version.rich.apkVer == nil {
diff --git a/grype/version/deb_constraint.go b/grype/version/deb_constraint.go
index 5950bf17..d70125f1 100644
--- a/grype/version/deb_constraint.go
+++ b/grype/version/deb_constraint.go
@@ -49,7 +49,7 @@ func (c debConstraint) Satisfied(version *Version) (bool, error) {
 	}
 
 	if !c.supported(version.Format) {
-		return false, fmt.Errorf("(deb) unsupported format: %s", version.Format)
+		return false, NewUnsupportedFormatError(DebFormat, version.Format)
 	}
 
 	if version.rich.debVer == nil {
diff --git a/grype/version/error.go b/grype/version/error.go
new file mode 100644
index 00000000..f6775fd3
--- /dev/null
+++ b/grype/version/error.go
@@ -0,0 +1,34 @@
+package version
+
+import (
+	"errors"
+	"fmt"
+)
+
+// UnsupportedFormatError represents an error when a format doesn't match the expected format
+type UnsupportedFormatError struct {
+	Left  Format
+	Right Format
+}
+
+// NewUnsupportedFormatError creates a new UnsupportedFormatError
+func NewUnsupportedFormatError(left, right Format) *UnsupportedFormatError {
+	return &UnsupportedFormatError{
+		Left:  left,
+		Right: right,
+	}
+}
+
+func (e *UnsupportedFormatError) Error() string {
+	return fmt.Sprintf("(%s) unsupported format: %s", e.Left, e.Right)
+}
+
+func (e *UnsupportedFormatError) Is(target error) bool {
+	var t *UnsupportedFormatError
+	ok := errors.As(target, &t)
+	if !ok {
+		return false
+	}
+	return (t.Left == UnknownFormat || t.Left == e.Left) &&
+		(t.Right == UnknownFormat || t.Right == e.Right)
+}
diff --git a/grype/version/golang_version.go b/grype/version/golang_version.go
index a9c21005..a52256ee 100644
--- a/grype/version/golang_version.go
+++ b/grype/version/golang_version.go
@@ -16,7 +16,7 @@ type golangVersion struct {
 
 func (g golangVersion) Compare(version *Version) (int, error) {
 	if version.Format != GolangFormat {
-		return -1, fmt.Errorf("cannot compare %v to golang version", version.Format)
+		return -1, NewUnsupportedFormatError(GolangFormat, version.Format)
 	}
 	if version.rich.golangVersion == nil {
 		return -1, fmt.Errorf("cannot compare version with nil golang version to golang version")
diff --git a/grype/version/jvm_version.go b/grype/version/jvm_version.go
index f07a15d1..91c296d0 100644
--- a/grype/version/jvm_version.go
+++ b/grype/version/jvm_version.go
@@ -57,7 +57,7 @@ func (v *jvmVersion) Compare(other *Version) (int, error) {
 		return other.rich.semVer.verObj.Compare(v.semVer), nil
 	}
 
-	return -1, fmt.Errorf("unable to compare JVM to given format: %s", other.Format)
+	return -1, NewUnsupportedFormatError(JVMFormat, other.Format)
 }
 
 func (v jvmVersion) compare(other jvmVersion) int {
diff --git a/grype/version/kb_contraint.go b/grype/version/kb_contraint.go
index dc8d2e92..c2367d7e 100644
--- a/grype/version/kb_contraint.go
+++ b/grype/version/kb_contraint.go
@@ -51,7 +51,7 @@ func (c kbConstraint) Satisfied(version *Version) (bool, error) {
 	}
 
 	if !c.supported(version.Format) {
-		return false, fmt.Errorf("(kb) unsupported format: %s", version.Format)
+		return false, NewUnsupportedFormatError(KBFormat, version.Format)
 	}
 
 	return c.expression.satisfied(version)
diff --git a/grype/version/maven_constraint.go b/grype/version/maven_constraint.go
index 8a191d67..77c4e95e 100644
--- a/grype/version/maven_constraint.go
+++ b/grype/version/maven_constraint.go
@@ -53,7 +53,7 @@ func (c mavenConstraint) Satisfied(version *Version) (satisfied bool, err error)
 	}
 
 	if !c.supported(version.Format) {
-		return false, fmt.Errorf("(maven) unsupported format: %s", version.Format)
+		return false, NewUnsupportedFormatError(MavenFormat, version.Format)
 	}
 
 	if version.rich.mavenVer == nil {
diff --git a/grype/version/pep440_constraint.go b/grype/version/pep440_constraint.go
index 2aa39caa..cc0c0b31 100644
--- a/grype/version/pep440_constraint.go
+++ b/grype/version/pep440_constraint.go
@@ -26,7 +26,7 @@ func (p pep440Constraint) Satisfied(version *Version) (bool, error) {
 		return true, nil
 	}
 	if version.Format != PythonFormat {
-		return false, fmt.Errorf("(python) unsupported format: %s", version.Format)
+		return false, NewUnsupportedFormatError(PythonFormat, version.Format)
 	}
 
 	if version.rich.pep440version == nil {
diff --git a/grype/version/portage_constraint.go b/grype/version/portage_constraint.go
index dd34d5e5..d04dc56b 100644
--- a/grype/version/portage_constraint.go
+++ b/grype/version/portage_constraint.go
@@ -48,7 +48,7 @@ func (c portageConstraint) Satisfied(version *Version) (bool, error) {
 	}
 
 	if !c.supported(version.Format) {
-		return false, fmt.Errorf("(portage) unsupported format: %s", version.Format)
+		return false, NewUnsupportedFormatError(PortageFormat, version.Format)
 	}
 
 	if version.rich.portVer == nil {
diff --git a/grype/version/rpm_constraint.go b/grype/version/rpm_constraint.go
index 0565f3e8..4973139b 100644
--- a/grype/version/rpm_constraint.go
+++ b/grype/version/rpm_constraint.go
@@ -51,7 +51,7 @@ func (c rpmConstraint) Satisfied(version *Version) (bool, error) {
 	}
 
 	if !c.supported(version.Format) {
-		return false, fmt.Errorf("(rpm) unsupported format: %s", version.Format)
+		return false, NewUnsupportedFormatError(RpmFormat, version.Format)
 	}
 
 	if version.rich.rpmVer == nil {
diff --git a/grype/version/semantic_constraint.go b/grype/version/semantic_constraint.go
index 00fe9523..69192dff 100644
--- a/grype/version/semantic_constraint.go
+++ b/grype/version/semantic_constraint.go
@@ -56,7 +56,7 @@ func (c semanticConstraint) Satisfied(version *Version) (bool, error) {
 	}
 
 	if !c.supported(version.Format) {
-		return false, fmt.Errorf("(semantic) unsupported format: %s", version.Format)
+		return false, NewUnsupportedFormatError(SemanticFormat, version.Format)
 	}
 
 	if version.rich.semVer == nil {
diff --git a/grype/vulnerability_matcher.go b/grype/vulnerability_matcher.go
index acfbdc6d..e2c69446 100644
--- a/grype/vulnerability_matcher.go
+++ b/grype/vulnerability_matcher.go
@@ -64,11 +64,7 @@ func (m *VulnerabilityMatcher) FindMatches(pkgs []pkg.Package, context pkg.Conte
 		}
 	}()
 
-	remainingMatches, ignoredMatches, err = m.findDBMatches(pkgs, context, progressMonitor)
-	if err != nil {
-		// errors returned from matchers during findDBMatches were being logged and not returned, so just log them here
-		log.WithFields("error", err).Debug("error(s) returned from findDBMatches")
-	}
+	remainingMatches, ignoredMatches = m.findDBMatches(pkgs, context, progressMonitor)
 
 	remainingMatches, ignoredMatches, err = m.findVEXMatches(context, remainingMatches, ignoredMatches, progressMonitor)
 	if err != nil {
@@ -88,13 +84,14 @@ func (m *VulnerabilityMatcher) FindMatches(pkgs []pkg.Package, context pkg.Conte
 	return remainingMatches, ignoredMatches, nil
 }
 
-func (m *VulnerabilityMatcher) findDBMatches(pkgs []pkg.Package, context pkg.Context, progressMonitor *monitorWriter) (*match.Matches, []match.IgnoredMatch, error) {
+func (m *VulnerabilityMatcher) findDBMatches(pkgs []pkg.Package, context pkg.Context, progressMonitor *monitorWriter) (*match.Matches, []match.IgnoredMatch) {
 	var ignoredMatches []match.IgnoredMatch
 
 	log.Trace("finding matches against DB")
 	matches, err := m.searchDBForMatches(context.Distro, pkgs, progressMonitor)
 	if err != nil {
-		return nil, nil, fmt.Errorf("unable to find matches in DB: %w", err)
+		// errors returned from matchers during searchDBForMatches were being logged and not returned, so just log them here
+		log.WithFields("error", err).Debug("error(s) returned from searchDBForMatches")
 	}
 
 	matches, ignoredMatches = m.applyIgnoreRules(matches)
@@ -114,7 +111,7 @@ func (m *VulnerabilityMatcher) findDBMatches(pkgs []pkg.Package, context pkg.Con
 		ignoredMatches = m.mergeIgnoredMatches(originalIgnoredMatches, ignoredMatches)
 	}
 
-	return &matches, ignoredMatches, nil
+	return &matches, ignoredMatches
 }
 
 func (m *VulnerabilityMatcher) mergeIgnoredMatches(allIgnoredMatches ...[]match.IgnoredMatch) []match.IgnoredMatch {


Test patch:
diff --git a/cmd/grype/cli/commands/db_list_test.go b/cmd/grype/cli/commands/db_list_test.go
index 77fa488b..e5b9d9f9 100644
--- a/cmd/grype/cli/commands/db_list_test.go
+++ b/cmd/grype/cli/commands/db_list_test.go
@@ -12,6 +12,7 @@ import (
 	"github.com/stretchr/testify/require"
 
 	"github.com/anchore/clio"
+	"github.com/anchore/grype/cmd/grype/cli/options"
 	db "github.com/anchore/grype/grype/db/v6"
 	"github.com/anchore/grype/grype/db/v6/distribution"
 	"github.com/anchore/grype/internal/schemaver"
@@ -34,7 +35,7 @@ func Test_ListingUserAgent(t *testing.T) {
 		mockSrv := httptest.NewServer(handler)
 		defer mockSrv.Close()
 
-		dbOptions := *dbOptionsDefault(clio.Identification{
+		dbOptions := *options.DefaultDatabaseCommand(clio.Identification{
 			Name:    "the-app",
 			Version: "v3.2.1",
 		})
@@ -42,8 +43,8 @@ func Test_ListingUserAgent(t *testing.T) {
 		dbOptions.DB.UpdateURL = mockSrv.URL + listingFile
 
 		_ = legacyDBList(dbListOptions{
-			Output:    "",
-			DBOptions: dbOptions,
+			Output:          "",
+			DatabaseCommand: dbOptions,
 		})
 
 		if got != "the-app v3.2.1" {
@@ -76,7 +77,7 @@ func Test_ListingUserAgent(t *testing.T) {
 		mockSrv := httptest.NewServer(handler)
 		defer mockSrv.Close()
 
-		dbOptions := *dbOptionsDefault(clio.Identification{
+		dbOptions := *options.DefaultDatabaseCommand(clio.Identification{
 			Name:    "new-app",
 			Version: "v4.0.0",
 		})
@@ -84,8 +85,8 @@ func Test_ListingUserAgent(t *testing.T) {
 		dbOptions.DB.UpdateURL = mockSrv.URL + listingFile
 
 		err := newDBList(dbListOptions{
-			Output:    textOutputFormat,
-			DBOptions: dbOptions,
+			Output:          textOutputFormat,
+			DatabaseCommand: dbOptions,
 		})
 		require.NoError(t, err)
 
diff --git a/grype/db/v5/distribution/curator_test.go b/grype/db/v5/distribution/curator_test.go
index 6a0bacbc..c1882d6d 100644
--- a/grype/db/v5/distribution/curator_test.go
+++ b/grype/db/v5/distribution/curator_test.go
@@ -133,7 +133,7 @@ func generateCertFixture(t *testing.T) string {
 		return path
 	}
 
-	t.Logf(color.Bold.Sprint("Generating Key/Cert Fixture"))
+	t.Log(color.Bold.Sprint("Generating Key/Cert Fixture"))
 
 	cwd, err := os.Getwd()
 	if err != nil {
diff --git a/grype/db/v6/installation/curator_test.go b/grype/db/v6/installation/curator_test.go
index 10898f8f..1954dd2b 100644
--- a/grype/db/v6/installation/curator_test.go
+++ b/grype/db/v6/installation/curator_test.go
@@ -117,7 +117,7 @@ func writeTestChecksumsFile(t *testing.T, fs afero.Fs, dir string, checksums str
 
 func writeTestDescriptionToDB(t *testing.T, dir string, desc db.Description) string {
 	c := db.Config{DBDirPath: dir}
-	d, err := db.NewLowLevelDB(c.DBFilePath(), false, false)
+	d, err := db.NewLowLevelDB(c.DBFilePath(), false, false, true)
 	require.NoError(t, err)
 
 	if err := d.Unscoped().Where("true").Delete(&db.DBMetadata{}).Error; err != nil {
diff --git a/grype/matcher/internal/cpe_test.go b/grype/matcher/internal/cpe_test.go
index ee39b79b..afc45718 100644
--- a/grype/matcher/internal/cpe_test.go
+++ b/grype/matcher/internal/cpe_test.go
@@ -752,6 +752,56 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
 				},
 			},
 		},
+		{
+			name: "Ensure target_sw mismatch does not apply to unknown packages",
+			p: pkg.Package{
+				CPEs: []cpe.CPE{
+					cpe.Must("cpe:2.3:a:handlebarsjs:handlebars:*:*:*:*:*:*:*:*", ""),
+				},
+				Name:     "handlebars",
+				Version:  "0.1",
+				Language: syftPkg.UnknownLanguage,
+				Type:     syftPkg.UnknownPkg,
+			},
+			expected: []match.Match{
+				{
+					Vulnerability: vulnerability.Vulnerability{
+						Reference: vulnerability.Reference{ID: "CVE-2021-23369"},
+					},
+					Package: pkg.Package{
+						CPEs: []cpe.CPE{
+							cpe.Must("cpe:2.3:a:handlebarsjs:handlebars:*:*:*:*:*:*:*:*", ""),
+						},
+						Name:     "handlebars",
+						Version:  "0.1",
+						Language: syftPkg.UnknownLanguage,
+						Type:     syftPkg.UnknownPkg,
+					},
+					Details: []match.Detail{
+						{
+							Type:       match.CPEMatch,
+							Confidence: 0.9,
+							SearchedBy: match.CPEParameters{
+								CPEs:      []string{"cpe:2.3:a:handlebarsjs:handlebars:0.1:*:*:*:*:*:*:*"},
+								Namespace: "nvd:cpe",
+								Package: match.CPEPackageParameter{
+									Name:    "handlebars",
+									Version: "0.1",
+								},
+							},
+							Found: match.CPEResult{
+								CPEs: []string{
+									"cpe:2.3:a:handlebarsjs:handlebars:*:*:*:*:*:node.js:*:*",
+								},
+								VersionConstraint: "< 4.7.7 (unknown)",
+								VulnerabilityID:   "CVE-2021-23369",
+							},
+							Matcher: matcher,
+						},
+					},
+				},
+			},
+		},
 		{
 			name: "package without CPEs returns error",
 			p: pkg.Package{
diff --git a/test/quality/vulnerability-match-labels b/test/quality/vulnerability-match-labels
index 8ad561f7..8915ebaa 160000
--- a/test/quality/vulnerability-match-labels
+++ b/test/quality/vulnerability-match-labels
@@ -1,1 +1,1 @@
-Subproject commit 8ad561f7eee84ebf3026812dd6f945946a1faa31
+Subproject commit 8915ebaa90638c15512afa1299a5cc4015d6a3b5