Repository: anchore/grype
Pull request #2322 (2024-12-12 15:21:53)

chore: move v5-specific interfaces and implementations to the v5 package
This PR moves the remaining DBv5-specific interfaces and implementations under the `db/v5` package.

This is a prerequisite for #2132 

Outstanding questions (answered over Slack):
- [x] should the `v5/matcher/*` configs be shared between v5 and v6? (no)
Matchers are created very early, [in the root CLI](https://github.com/anchore/grype/blob/main/cmd/grype/cli/commands/root.go#L281), we can easily keep the CLI the same and when switching between v5 and v6, we will just return a different set of matchers with their own config that will evolve separately (e.g. we won't be updating the v5 configs much, if at all).

- [x] should we move https://github.com/anchore/grype/tree/main/grype/differ under v5? (yes, done)



Patch:
diff --git a/README.md b/README.md
index 14ea6bfa..f6ec1c09 100644
--- a/README.md
+++ b/README.md
@@ -108,7 +108,7 @@ Checksums are applied to all artifacts, and the resulting checksum file is signe
 
 You need the following tool to verify signature:
 
-- [Cosign](https://docs.sigstore.dev/cosign/installation/)
+- [Cosign](https://docs.sigstore.dev/cosign/system_config/installation/)
 
 Verification steps are as follow:
 
diff --git a/cmd/grype/cli/commands/db_diff.go b/cmd/grype/cli/commands/db_diff.go
index c41a8496..6ff85f3e 100644
--- a/cmd/grype/cli/commands/db_diff.go
+++ b/cmd/grype/cli/commands/db_diff.go
@@ -9,7 +9,7 @@ import (
 	"github.com/anchore/clio"
 	"github.com/anchore/grype/cmd/grype/cli/options"
 	"github.com/anchore/grype/grype/db/legacy/distribution"
-	"github.com/anchore/grype/grype/differ"
+	"github.com/anchore/grype/grype/db/v5/differ"
 	"github.com/anchore/grype/internal/bus"
 	"github.com/anchore/grype/internal/log"
 )
diff --git a/cmd/grype/cli/commands/root.go b/cmd/grype/cli/commands/root.go
index 255b33ac..fd640c29 100644
--- a/cmd/grype/cli/commands/root.go
+++ b/cmd/grype/cli/commands/root.go
@@ -12,21 +12,21 @@ import (
 	"github.com/anchore/grype/cmd/grype/cli/options"
 	"github.com/anchore/grype/grype"
 	"github.com/anchore/grype/grype/db/legacy/distribution"
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/matcher"
+	"github.com/anchore/grype/grype/db/v5/matcher/dotnet"
+	"github.com/anchore/grype/grype/db/v5/matcher/golang"
+	"github.com/anchore/grype/grype/db/v5/matcher/java"
+	"github.com/anchore/grype/grype/db/v5/matcher/javascript"
+	"github.com/anchore/grype/grype/db/v5/matcher/python"
+	"github.com/anchore/grype/grype/db/v5/matcher/ruby"
+	"github.com/anchore/grype/grype/db/v5/matcher/stock"
 	"github.com/anchore/grype/grype/event"
 	"github.com/anchore/grype/grype/event/parsers"
 	"github.com/anchore/grype/grype/grypeerr"
 	"github.com/anchore/grype/grype/match"
-	"github.com/anchore/grype/grype/matcher"
-	"github.com/anchore/grype/grype/matcher/dotnet"
-	"github.com/anchore/grype/grype/matcher/golang"
-	"github.com/anchore/grype/grype/matcher/java"
-	"github.com/anchore/grype/grype/matcher/javascript"
-	"github.com/anchore/grype/grype/matcher/python"
-	"github.com/anchore/grype/grype/matcher/ruby"
-	"github.com/anchore/grype/grype/matcher/stock"
 	"github.com/anchore/grype/grype/pkg"
 	"github.com/anchore/grype/grype/presenter/models"
-	"github.com/anchore/grype/grype/store"
 	"github.com/anchore/grype/grype/vex"
 	"github.com/anchore/grype/grype/vulnerability"
 	"github.com/anchore/grype/internal"
@@ -118,7 +118,7 @@ func runGrype(app clio.Application, opts *options.Grype, userInput string) (errs
 		return err
 	}
 
-	var str *store.Store
+	var str *v5.ProviderStore
 	var status *distribution.Status
 	var packages []pkg.Package
 	var s *sbom.SBOM
diff --git a/cmd/grype/cli/options/datasources.go b/cmd/grype/cli/options/datasources.go
index 987e0f76..5e7c03b7 100644
--- a/cmd/grype/cli/options/datasources.go
+++ b/cmd/grype/cli/options/datasources.go
@@ -2,7 +2,7 @@ package options
 
 import (
 	"github.com/anchore/clio"
-	"github.com/anchore/grype/grype/matcher/java"
+	"github.com/anchore/grype/grype/db/v5/matcher/java"
 )
 
 const (
diff --git a/go.mod b/go.mod
index c2979614..ad1c454d 100644
--- a/go.mod
+++ b/go.mod
@@ -244,7 +244,7 @@ require (
 	go.opentelemetry.io/otel/trace v1.24.0 // indirect
 	go.uber.org/atomic v1.9.0 // indirect
 	go.uber.org/multierr v1.9.0 // indirect
-	golang.org/x/crypto v0.30.0 // indirect
+	golang.org/x/crypto v0.31.0 // indirect
 	golang.org/x/mod v0.22.0 // indirect
 	golang.org/x/net v0.32.0 // indirect
 	golang.org/x/oauth2 v0.19.0 // indirect
diff --git a/go.sum b/go.sum
index b984a5be..5a61758a 100644
--- a/go.sum
+++ b/go.sum
@@ -1071,8 +1071,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
-golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
+golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
diff --git a/grype/db/v5/advisory.go b/grype/db/v5/advisory.go
index f94176db..7a856338 100644
--- a/grype/db/v5/advisory.go
+++ b/grype/db/v5/advisory.go
@@ -1,6 +1,6 @@
 package v5
 
-// Advisory represents published statements regarding a vulnerability (and potentially about it's resolution).
+// Advisory represents published statements regarding a vulnerability (and potentially about its resolution).
 type Advisory struct {
 	ID   string `json:"id"`
 	Link string `json:"link"`
diff --git a/grype/differ/differ.go b/grype/db/v5/differ/differ.go
similarity index 100%
rename from grype/differ/differ.go
rename to grype/db/v5/differ/differ.go
diff --git a/grype/differ/differ_test.go b/grype/db/v5/differ/differ_test.go
similarity index 100%
rename from grype/differ/differ_test.go
rename to grype/db/v5/differ/differ_test.go
diff --git a/grype/differ/test-fixtures/dbs/base/5/metadata.json b/grype/db/v5/differ/test-fixtures/dbs/base/5/metadata.json
similarity index 100%
rename from grype/differ/test-fixtures/dbs/base/5/metadata.json
rename to grype/db/v5/differ/test-fixtures/dbs/base/5/metadata.json
diff --git a/grype/differ/test-fixtures/dbs/base/5/vulnerability.db b/grype/db/v5/differ/test-fixtures/dbs/base/5/vulnerability.db
similarity index 100%
rename from grype/differ/test-fixtures/dbs/base/5/vulnerability.db
rename to grype/db/v5/differ/test-fixtures/dbs/base/5/vulnerability.db
diff --git a/grype/differ/test-fixtures/dbs/target/5/metadata.json b/grype/db/v5/differ/test-fixtures/dbs/target/5/metadata.json
similarity index 100%
rename from grype/differ/test-fixtures/dbs/target/5/metadata.json
rename to grype/db/v5/differ/test-fixtures/dbs/target/5/metadata.json
diff --git a/grype/differ/test-fixtures/dbs/target/5/vulnerability.db b/grype/db/v5/differ/test-fixtures/dbs/target/5/vulnerability.db
similarity index 100%
rename from grype/differ/test-fixtures/dbs/target/5/vulnerability.db
rename to grype/db/v5/differ/test-fixtures/dbs/target/5/vulnerability.db
diff --git a/grype/differ/test-fixtures/snapshot/TestPresent_Json.golden b/grype/db/v5/differ/test-fixtures/snapshot/TestPresent_Json.golden
similarity index 100%
rename from grype/differ/test-fixtures/snapshot/TestPresent_Json.golden
rename to grype/db/v5/differ/test-fixtures/snapshot/TestPresent_Json.golden
diff --git a/grype/differ/test-fixtures/snapshot/TestPresent_Table.golden b/grype/db/v5/differ/test-fixtures/snapshot/TestPresent_Table.golden
similarity index 100%
rename from grype/differ/test-fixtures/snapshot/TestPresent_Table.golden
rename to grype/db/v5/differ/test-fixtures/snapshot/TestPresent_Table.golden
diff --git a/grype/matcher/apk/matcher.go b/grype/db/v5/matcher/apk/matcher.go
similarity index 90%
rename from grype/matcher/apk/matcher.go
rename to grype/db/v5/matcher/apk/matcher.go
index 9cfc87c1..bb6e4f41 100644
--- a/grype/matcher/apk/matcher.go
+++ b/grype/db/v5/matcher/apk/matcher.go
@@ -4,10 +4,11 @@ import (
 	"errors"
 	"fmt"
 
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/search"
 	"github.com/anchore/grype/grype/version"
 	"github.com/anchore/grype/grype/vulnerability"
 	"github.com/anchore/grype/internal/log"
@@ -25,7 +26,7 @@ func (m *Matcher) Type() match.MatcherType {
 	return match.ApkMatcher
 }
 
-func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) Match(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	var matches = make([]match.Match, 0)
 
 	// direct matches with package itself
@@ -46,7 +47,7 @@ func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Pa
 }
 
 //nolint:funlen
-func (m *Matcher) cpeMatchesWithoutSecDBFixes(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) cpeMatchesWithoutSecDBFixes(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	// find CPE-indexed vulnerability matches specific to the given package name and version
 	cpeMatches, err := search.ByPackageCPE(store, d, p, m.Type())
 	if err != nil {
@@ -157,7 +158,7 @@ func vulnerabilitiesByID(vulns []vulnerability.Vulnerability) map[string][]vulne
 	return results
 }
 
-func (m *Matcher) findMatchesForPackage(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) findMatchesForPackage(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	// find SecDB matches for the given package name and version
 	secDBMatches, err := search.ByPackageDistro(store, d, p, m.Type())
 	if err != nil {
@@ -181,7 +182,7 @@ func (m *Matcher) findMatchesForPackage(store vulnerability.Provider, d *distro.
 	return matches, nil
 }
 
-func (m *Matcher) findMatchesForOriginPackage(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) findMatchesForOriginPackage(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	var matches []match.Match
 
 	for _, indirectPackage := range pkg.UpstreamPackages(p) {
diff --git a/grype/matcher/dotnet/matcher.go b/grype/db/v5/matcher/dotnet/matcher.go
similarity index 77%
rename from grype/matcher/dotnet/matcher.go
rename to grype/db/v5/matcher/dotnet/matcher.go
index ef2af398..02df5235 100644
--- a/grype/matcher/dotnet/matcher.go
+++ b/grype/db/v5/matcher/dotnet/matcher.go
@@ -1,11 +1,11 @@
 package dotnet
 
 import (
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/search"
-	"github.com/anchore/grype/grype/vulnerability"
 	syftPkg "github.com/anchore/syft/syft/pkg"
 )
 
@@ -31,7 +31,7 @@ func (m *Matcher) Type() match.MatcherType {
 	return match.DotnetMatcher
 }
 
-func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) Match(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	criteria := search.CommonCriteria
 	if m.cfg.UseCPEs {
 		criteria = append(criteria, search.ByCPE)
diff --git a/grype/matcher/dpkg/matcher.go b/grype/db/v5/matcher/dpkg/matcher.go
similarity index 81%
rename from grype/matcher/dpkg/matcher.go
rename to grype/db/v5/matcher/dpkg/matcher.go
index ca94d28c..f3848a03 100644
--- a/grype/matcher/dpkg/matcher.go
+++ b/grype/db/v5/matcher/dpkg/matcher.go
@@ -3,11 +3,11 @@ package dpkg
 import (
 	"fmt"
 
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/search"
-	"github.com/anchore/grype/grype/vulnerability"
 	syftPkg "github.com/anchore/syft/syft/pkg"
 )
 
@@ -22,7 +22,7 @@ func (m *Matcher) Type() match.MatcherType {
 	return match.DpkgMatcher
 }
 
-func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) Match(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	matches := make([]match.Match, 0)
 
 	sourceMatches, err := m.matchUpstreamPackages(store, d, p)
@@ -40,7 +40,7 @@ func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Pa
 	return matches, nil
 }
 
-func (m *Matcher) matchUpstreamPackages(store vulnerability.ProviderByDistro, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) matchUpstreamPackages(store v5.ProviderByDistro, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	var matches []match.Match
 
 	for _, indirectPackage := range pkg.UpstreamPackages(p) {
diff --git a/grype/matcher/dpkg/matcher_test.go b/grype/db/v5/matcher/dpkg/matcher_test.go
similarity index 100%
rename from grype/matcher/dpkg/matcher_test.go
rename to grype/db/v5/matcher/dpkg/matcher_test.go
diff --git a/grype/matcher/golang/matcher.go b/grype/db/v5/matcher/golang/matcher.go
similarity index 90%
rename from grype/matcher/golang/matcher.go
rename to grype/db/v5/matcher/golang/matcher.go
index b9b7b24a..377ce871 100644
--- a/grype/matcher/golang/matcher.go
+++ b/grype/db/v5/matcher/golang/matcher.go
@@ -3,11 +3,11 @@ package golang
 import (
 	"strings"
 
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/search"
-	"github.com/anchore/grype/grype/vulnerability"
 	syftPkg "github.com/anchore/syft/syft/pkg"
 )
 
@@ -35,7 +35,7 @@ func (m *Matcher) Type() match.MatcherType {
 	return match.GoModuleMatcher
 }
 
-func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) Match(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	matches := make([]match.Match, 0)
 
 	mainModule := ""
diff --git a/grype/matcher/java/matcher.go b/grype/db/v5/matcher/java/matcher.go
similarity index 85%
rename from grype/matcher/java/matcher.go
rename to grype/db/v5/matcher/java/matcher.go
index 340c2697..c26338e4 100644
--- a/grype/matcher/java/matcher.go
+++ b/grype/db/v5/matcher/java/matcher.go
@@ -4,11 +4,11 @@ import (
 	"fmt"
 	"net/http"
 
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/search"
-	"github.com/anchore/grype/grype/vulnerability"
 	"github.com/anchore/grype/internal/log"
 	syftPkg "github.com/anchore/syft/syft/pkg"
 )
@@ -50,7 +50,7 @@ func (m *Matcher) Type() match.MatcherType {
 	return match.JavaMatcher
 }
 
-func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) Match(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	var matches []match.Match
 	if m.cfg.SearchMavenUpstream {
 		upstreamMatches, err := m.matchUpstreamMavenPackages(store, d, p)
@@ -73,7 +73,7 @@ func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Pa
 	return matches, nil
 }
 
-func (m *Matcher) matchUpstreamMavenPackages(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) matchUpstreamMavenPackages(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	var matches []match.Match
 
 	if metadata, ok := p.Metadata.(pkg.JavaMetadata); ok {
diff --git a/grype/matcher/java/matcher_test.go b/grype/db/v5/matcher/java/matcher_test.go
similarity index 100%
rename from grype/matcher/java/matcher_test.go
rename to grype/db/v5/matcher/java/matcher_test.go
diff --git a/grype/matcher/java/maven_search.go b/grype/db/v5/matcher/java/maven_search.go
similarity index 100%
rename from grype/matcher/java/maven_search.go
rename to grype/db/v5/matcher/java/maven_search.go
diff --git a/grype/matcher/javascript/matcher.go b/grype/db/v5/matcher/javascript/matcher.go
similarity index 77%
rename from grype/matcher/javascript/matcher.go
rename to grype/db/v5/matcher/javascript/matcher.go
index 9f8d596d..866429cf 100644
--- a/grype/matcher/javascript/matcher.go
+++ b/grype/db/v5/matcher/javascript/matcher.go
@@ -1,11 +1,11 @@
 package javascript
 
 import (
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/search"
-	"github.com/anchore/grype/grype/vulnerability"
 	syftPkg "github.com/anchore/syft/syft/pkg"
 )
 
@@ -31,7 +31,7 @@ func (m *Matcher) Type() match.MatcherType {
 	return match.JavascriptMatcher
 }
 
-func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) Match(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	criteria := search.CommonCriteria
 	if m.cfg.UseCPEs {
 		criteria = append(criteria, search.ByCPE)
diff --git a/grype/matcher/matcher.go b/grype/db/v5/matcher/matcher.go
similarity index 67%
rename from grype/matcher/matcher.go
rename to grype/db/v5/matcher/matcher.go
index a1af7868..c7377297 100644
--- a/grype/matcher/matcher.go
+++ b/grype/db/v5/matcher/matcher.go
@@ -1,15 +1,15 @@
 package matcher
 
 import (
+	v5 "github.com/anchore/grype/grype/db/v5"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/vulnerability"
 	syftPkg "github.com/anchore/syft/syft/pkg"
 )
 
 type Matcher interface {
 	PackageTypes() []syftPkg.Type
 	Type() match.MatcherType
-	Match(vulnerability.Provider, *distro.Distro, pkg.Package) ([]match.Match, error)
+	Match(v5.VulnerabilityProvider, *distro.Distro, pkg.Package) ([]match.Match, error)
 }
diff --git a/grype/matcher/matchers.go b/grype/db/v5/matcher/matchers.go
similarity index 55%
rename from grype/matcher/matchers.go
rename to grype/db/v5/matcher/matchers.go
index 72778eb6..966bbb8c 100644
--- a/grype/matcher/matchers.go
+++ b/grype/db/v5/matcher/matchers.go
@@ -1,19 +1,19 @@
 package matcher
 
 import (
-	"github.com/anchore/grype/grype/matcher/apk"
-	"github.com/anchore/grype/grype/matcher/dotnet"
-	"github.com/anchore/grype/grype/matcher/dpkg"
-	"github.com/anchore/grype/grype/matcher/golang"
-	"github.com/anchore/grype/grype/matcher/java"
-	"github.com/anchore/grype/grype/matcher/javascript"
-	"github.com/anchore/grype/grype/matcher/msrc"
-	"github.com/anchore/grype/grype/matcher/portage"
-	"github.com/anchore/grype/grype/matcher/python"
-	"github.com/anchore/grype/grype/matcher/rpm"
-	"github.com/anchore/grype/grype/matcher/ruby"
-	"github.com/anchore/grype/grype/matcher/rust"
-	"github.com/anchore/grype/grype/matcher/stock"
+	"github.com/anchore/grype/grype/db/v5/matcher/apk"
+	"github.com/anchore/grype/grype/db/v5/matcher/dotnet"
+	"github.com/anchore/grype/grype/db/v5/matcher/dpkg"
+	"github.com/anchore/grype/grype/db/v5/matcher/golang"
+	"github.com/anchore/grype/grype/db/v5/matcher/java"
+	"github.com/anchore/grype/grype/db/v5/matcher/javascript"
+	"github.com/anchore/grype/grype/db/v5/matcher/msrc"
+	"github.com/anchore/grype/grype/db/v5/matcher/portage"
+	"github.com/anchore/grype/grype/db/v5/matcher/python"
+	"github.com/anchore/grype/grype/db/v5/matcher/rpm"
+	"github.com/anchore/grype/grype/db/v5/matcher/ruby"
+	"github.com/anchore/grype/grype/db/v5/matcher/rust"
+	"github.com/anchore/grype/grype/db/v5/matcher/stock"
 )
 
 // Config contains values used by individual matcher structs for advanced configuration
diff --git a/grype/matcher/msrc/matcher.go b/grype/db/v5/matcher/msrc/matcher.go
similarity index 80%
rename from grype/matcher/msrc/matcher.go
rename to grype/db/v5/matcher/msrc/matcher.go
index 1fd95baa..6e84a2e9 100644
--- a/grype/matcher/msrc/matcher.go
+++ b/grype/db/v5/matcher/msrc/matcher.go
@@ -1,11 +1,11 @@
 package msrc
 
 import (
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/search"
-	"github.com/anchore/grype/grype/vulnerability"
 	syftPkg "github.com/anchore/syft/syft/pkg"
 )
 
@@ -23,7 +23,7 @@ func (m *Matcher) Type() match.MatcherType {
 	return match.MsrcMatcher
 }
 
-func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) Match(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	// find KB matches for the MSFT version given in the package and version.
 	// The "distro" holds the information about the Windows version, and its
 	// patch (KB)
diff --git a/grype/matcher/msrc/matcher_test.go b/grype/db/v5/matcher/msrc/matcher_test.go
similarity index 100%
rename from grype/matcher/msrc/matcher_test.go
rename to grype/db/v5/matcher/msrc/matcher_test.go
diff --git a/grype/matcher/portage/matcher.go b/grype/db/v5/matcher/portage/matcher.go
similarity index 73%
rename from grype/matcher/portage/matcher.go
rename to grype/db/v5/matcher/portage/matcher.go
index ddda5070..1e06f24c 100644
--- a/grype/matcher/portage/matcher.go
+++ b/grype/db/v5/matcher/portage/matcher.go
@@ -3,11 +3,11 @@ package portage
 import (
 	"fmt"
 
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/search"
-	"github.com/anchore/grype/grype/vulnerability"
 	syftPkg "github.com/anchore/syft/syft/pkg"
 )
 
@@ -22,7 +22,7 @@ func (m *Matcher) Type() match.MatcherType {
 	return match.PortageMatcher
 }
 
-func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) Match(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	matches, err := search.ByPackageDistro(store, d, p, m.Type())
 	if err != nil {
 		return nil, fmt.Errorf("failed to find vulnerabilities: %w", err)
diff --git a/grype/matcher/portage/matcher_test.go b/grype/db/v5/matcher/portage/matcher_test.go
similarity index 100%
rename from grype/matcher/portage/matcher_test.go
rename to grype/db/v5/matcher/portage/matcher_test.go
diff --git a/grype/matcher/python/matcher.go b/grype/db/v5/matcher/python/matcher.go
similarity index 77%
rename from grype/matcher/python/matcher.go
rename to grype/db/v5/matcher/python/matcher.go
index 64057636..e3b50cf3 100644
--- a/grype/matcher/python/matcher.go
+++ b/grype/db/v5/matcher/python/matcher.go
@@ -1,11 +1,11 @@
 package python
 
 import (
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/search"
-	"github.com/anchore/grype/grype/vulnerability"
 	syftPkg "github.com/anchore/syft/syft/pkg"
 )
 
@@ -31,7 +31,7 @@ func (m *Matcher) Type() match.MatcherType {
 	return match.PythonMatcher
 }
 
-func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) Match(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	criteria := search.CommonCriteria
 	if m.cfg.UseCPEs {
 		criteria = append(criteria, search.ByCPE)
diff --git a/grype/matcher/rpm/matcher.go b/grype/db/v5/matcher/rpm/matcher.go
similarity index 92%
rename from grype/matcher/rpm/matcher.go
rename to grype/db/v5/matcher/rpm/matcher.go
index 3003f582..9d2848bd 100644
--- a/grype/matcher/rpm/matcher.go
+++ b/grype/db/v5/matcher/rpm/matcher.go
@@ -4,11 +4,11 @@ import (
 	"fmt"
 	"strings"
 
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/search"
-	"github.com/anchore/grype/grype/vulnerability"
 	syftPkg "github.com/anchore/syft/syft/pkg"
 )
 
@@ -24,7 +24,7 @@ func (m *Matcher) Type() match.MatcherType {
 }
 
 //nolint:funlen
-func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) Match(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	matches := make([]match.Match, 0)
 
 	// let's match with a synthetic package that doesn't exist. We will create a new
@@ -104,7 +104,7 @@ func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Pa
 	return matches, nil
 }
 
-func (m *Matcher) matchUpstreamPackages(store vulnerability.ProviderByDistro, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) matchUpstreamPackages(store v5.ProviderByDistro, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	var matches []match.Match
 
 	for _, indirectPackage := range pkg.UpstreamPackages(p) {
@@ -122,7 +122,7 @@ func (m *Matcher) matchUpstreamPackages(store vulnerability.ProviderByDistro, d
 	return matches, nil
 }
 
-func (m *Matcher) matchPackage(store vulnerability.ProviderByDistro, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) matchPackage(store v5.ProviderByDistro, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	// we want to ensure that the version ALWAYS has an epoch specified...
 	originalPkg := p
 
diff --git a/grype/matcher/ruby/matcher.go b/grype/db/v5/matcher/ruby/matcher.go
similarity index 77%
rename from grype/matcher/ruby/matcher.go
rename to grype/db/v5/matcher/ruby/matcher.go
index 2a1840c1..ee7b3369 100644
--- a/grype/matcher/ruby/matcher.go
+++ b/grype/db/v5/matcher/ruby/matcher.go
@@ -1,11 +1,11 @@
 package ruby
 
 import (
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/search"
-	"github.com/anchore/grype/grype/vulnerability"
 	syftPkg "github.com/anchore/syft/syft/pkg"
 )
 
@@ -31,7 +31,7 @@ func (m *Matcher) Type() match.MatcherType {
 	return match.RubyGemMatcher
 }
 
-func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) Match(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	criteria := search.CommonCriteria
 	if m.cfg.UseCPEs {
 		criteria = append(criteria, search.ByCPE)
diff --git a/grype/matcher/rust/matcher.go b/grype/db/v5/matcher/rust/matcher.go
similarity index 77%
rename from grype/matcher/rust/matcher.go
rename to grype/db/v5/matcher/rust/matcher.go
index 6ce17449..59204df4 100644
--- a/grype/matcher/rust/matcher.go
+++ b/grype/db/v5/matcher/rust/matcher.go
@@ -1,11 +1,11 @@
 package rust
 
 import (
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/search"
-	"github.com/anchore/grype/grype/vulnerability"
 	syftPkg "github.com/anchore/syft/syft/pkg"
 )
 
@@ -31,7 +31,7 @@ func (m *Matcher) Type() match.MatcherType {
 	return match.RustMatcher
 }
 
-func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) Match(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	criteria := search.CommonCriteria
 	if m.cfg.UseCPEs {
 		criteria = append(criteria, search.ByCPE)
diff --git a/grype/matcher/stock/matcher.go b/grype/db/v5/matcher/stock/matcher.go
similarity index 76%
rename from grype/matcher/stock/matcher.go
rename to grype/db/v5/matcher/stock/matcher.go
index 7f30a52d..4277a632 100644
--- a/grype/matcher/stock/matcher.go
+++ b/grype/db/v5/matcher/stock/matcher.go
@@ -1,11 +1,11 @@
 package stock
 
 import (
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/search"
-	"github.com/anchore/grype/grype/vulnerability"
 	syftPkg "github.com/anchore/syft/syft/pkg"
 )
 
@@ -31,7 +31,7 @@ func (m *Matcher) Type() match.MatcherType {
 	return match.StockMatcher
 }
 
-func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
+func (m *Matcher) Match(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
 	criteria := search.CommonCriteria
 	if m.cfg.UseCPEs {
 		criteria = append(criteria, search.ByCPE)
diff --git a/grype/db/v5/provider.go b/grype/db/v5/provider.go
new file mode 100644
index 00000000..8f17c845
--- /dev/null
+++ b/grype/db/v5/provider.go
@@ -0,0 +1,33 @@
+package v5
+
+import (
+	"github.com/anchore/grype/grype/distro"
+	"github.com/anchore/grype/grype/pkg"
+	"github.com/anchore/grype/grype/vulnerability"
+	"github.com/anchore/syft/syft/cpe"
+	syftPkg "github.com/anchore/syft/syft/pkg"
+)
+
+type VulnerabilityProvider interface {
+	Get(id, namespace string) ([]vulnerability.Vulnerability, error)
+	ProviderByDistro
+	ProviderByLanguage
+	ProviderByCPE
+}
+
+type ProviderByDistro interface {
+	GetByDistro(*distro.Distro, pkg.Package) ([]vulnerability.Vulnerability, error)
+}
+
+type ProviderByLanguage interface {
+	GetByLanguage(syftPkg.Language, pkg.Package) ([]vulnerability.Vulnerability, error)
+}
+
+type ProviderByCPE interface {
+	GetByCPE(cpe.CPE) ([]vulnerability.Vulnerability, error)
+}
+
+type VulnerabilityMetadataProvider interface {
+	vulnerability.MetadataProvider
+	GetMetadata(id, namespace string) (*vulnerability.Metadata, error)
+}
diff --git a/grype/db/v5/provider_store.go b/grype/db/v5/provider_store.go
new file mode 100644
index 00000000..dd66da85
--- /dev/null
+++ b/grype/db/v5/provider_store.go
@@ -0,0 +1,14 @@
+package v5
+
+import (
+	"io"
+
+	"github.com/anchore/grype/grype/match"
+)
+
+type ProviderStore struct {
+	VulnerabilityProvider
+	VulnerabilityMetadataProvider
+	match.ExclusionProvider
+	io.Closer
+}
diff --git a/grype/search/cpe.go b/grype/db/v5/search/cpe.go
similarity index 98%
rename from grype/search/cpe.go
rename to grype/db/v5/search/cpe.go
index b709e7b7..e267ad69 100644
--- a/grype/search/cpe.go
+++ b/grype/db/v5/search/cpe.go
@@ -9,6 +9,7 @@ import (
 	"github.com/facebookincubator/nvdtools/wfn"
 	"github.com/scylladb/go-set/strset"
 
+	v5 "github.com/anchore/grype/grype/db/v5"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
@@ -86,7 +87,7 @@ func alpineCPEComparableVersion(version string) string {
 var ErrEmptyCPEMatch = errors.New("attempted CPE match against package with no CPEs")
 
 // ByPackageCPE retrieves all vulnerabilities that match the generated CPE
-func ByPackageCPE(store vulnerability.ProviderByCPE, d *distro.Distro, p pkg.Package, upstreamMatcher match.MatcherType) ([]match.Match, error) {
+func ByPackageCPE(store v5.ProviderByCPE, d *distro.Distro, p pkg.Package, upstreamMatcher match.MatcherType) ([]match.Match, error) {
 	// we attempt to merge match details within the same matcher when searching by CPEs, in this way there are fewer duplicated match
 	// objects (and fewer duplicated match details).
 
diff --git a/grype/search/criteria.go b/grype/db/v5/search/criteria.go
similarity index 86%
rename from grype/search/criteria.go
rename to grype/db/v5/search/criteria.go
index fc4cb974..fba23c87 100644
--- a/grype/search/criteria.go
+++ b/grype/db/v5/search/criteria.go
@@ -3,10 +3,10 @@ package search
 import (
 	"errors"
 
+	v5 "github.com/anchore/grype/grype/db/v5"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/vulnerability"
 	"github.com/anchore/grype/internal/log"
 )
 
@@ -21,7 +21,7 @@ var (
 
 type Criteria string
 
-func ByCriteria(store vulnerability.Provider, d *distro.Distro, p pkg.Package, upstreamMatcher match.MatcherType, criteria ...Criteria) ([]match.Match, error) {
+func ByCriteria(store v5.VulnerabilityProvider, d *distro.Distro, p pkg.Package, upstreamMatcher match.MatcherType, criteria ...Criteria) ([]match.Match, error) {
 	matches := make([]match.Match, 0)
 	for _, c := range criteria {
 		switch c {
diff --git a/grype/search/distro.go b/grype/db/v5/search/distro.go
similarity index 92%
rename from grype/search/distro.go
rename to grype/db/v5/search/distro.go
index ed59a919..57514332 100644
--- a/grype/search/distro.go
+++ b/grype/db/v5/search/distro.go
@@ -5,15 +5,15 @@ import (
 	"fmt"
 	"strings"
 
+	v5 "github.com/anchore/grype/grype/db/v5"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
 	"github.com/anchore/grype/grype/version"
-	"github.com/anchore/grype/grype/vulnerability"
 	"github.com/anchore/grype/internal/log"
 )
 
-func ByPackageDistro(store vulnerability.ProviderByDistro, d *distro.Distro, p pkg.Package, upstreamMatcher match.MatcherType) ([]match.Match, error) {
+func ByPackageDistro(store v5.ProviderByDistro, d *distro.Distro, p pkg.Package, upstreamMatcher match.MatcherType) ([]match.Match, error) {
 	if d == nil {
 		return nil, nil
 	}
diff --git a/grype/search/language.go b/grype/db/v5/search/language.go
similarity index 90%
rename from grype/search/language.go
rename to grype/db/v5/search/language.go
index e4034b52..2ab453ab 100644
--- a/grype/search/language.go
+++ b/grype/db/v5/search/language.go
@@ -4,15 +4,15 @@ import (
 	"errors"
 	"fmt"
 
+	v5 "github.com/anchore/grype/grype/db/v5"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
 	"github.com/anchore/grype/grype/version"
-	"github.com/anchore/grype/grype/vulnerability"
 	"github.com/anchore/grype/internal/log"
 )
 
-func ByPackageLanguage(store vulnerability.ProviderByLanguage, d *distro.Distro, p pkg.Package, upstreamMatcher match.MatcherType) ([]match.Match, error) {
+func ByPackageLanguage(store v5.ProviderByLanguage, d *distro.Distro, p pkg.Package, upstreamMatcher match.MatcherType) ([]match.Match, error) {
 	if isUnknownVersion(p.Version) {
 		log.WithFields("package", p.Name).Trace("skipping package with unknown version")
 
diff --git a/grype/db/v5/vulnerability.go b/grype/db/v5/vulnerability.go
index b3700aa0..8e4b59bb 100644
--- a/grype/db/v5/vulnerability.go
+++ b/grype/db/v5/vulnerability.go
@@ -148,11 +148,13 @@ func NewVulnerability(vuln Vulnerability) (*vulnerability.Vulnerability, error)
 	}
 
 	return &vulnerability.Vulnerability{
-		PackageName:       vuln.PackageName,
-		Constraint:        constraint,
-		ID:                vuln.ID,
+		PackageName: vuln.PackageName,
+		Constraint:  constraint,
+		Reference: vulnerability.Reference{
+			ID:        vuln.ID,
+			Namespace: vuln.Namespace,
+		},
 		CPEs:              make([]cpe.CPE, 0),
-		Namespace:         vuln.Namespace,
 		PackageQualifiers: pkgQualifiers,
 		Fix: vulnerability.Fix{
 			Versions: vuln.Fix.Versions,
diff --git a/grype/db/v5/vulnerability_metadata_provider.go b/grype/db/v5/vulnerability_metadata_provider.go
index 05c9af20..c58510de 100644
--- a/grype/db/v5/vulnerability_metadata_provider.go
+++ b/grype/db/v5/vulnerability_metadata_provider.go
@@ -6,19 +6,23 @@ import (
 	"github.com/anchore/grype/grype/vulnerability"
 )
 
-var _ vulnerability.MetadataProvider = (*VulnerabilityMetadataProvider)(nil)
+var _ VulnerabilityMetadataProvider = (*vulnerabilityMetadataProvider)(nil)
 
-type VulnerabilityMetadataProvider struct {
+type vulnerabilityMetadataProvider struct {
 	reader VulnerabilityMetadataStoreReader
 }
 
-func NewVulnerabilityMetadataProvider(reader VulnerabilityMetadataStoreReader) *VulnerabilityMetadataProvider {
-	return &VulnerabilityMetadataProvider{
+func NewVulnerabilityMetadataProvider(reader VulnerabilityMetadataStoreReader) VulnerabilityMetadataProvider {
+	return &vulnerabilityMetadataProvider{
 		reader: reader,
 	}
 }
 
-func (pr *VulnerabilityMetadataProvider) GetMetadata(id, namespace string) (*vulnerability.Metadata, error) {
+func (pr *vulnerabilityMetadataProvider) VulnerabilityMetadata(ref vulnerability.Reference) (*vulnerability.Metadata, error) {
+	return pr.GetMetadata(ref.ID, ref.Namespace)
+}
+
+func (pr *vulnerabilityMetadataProvider) GetMetadata(id, namespace string) (*vulnerability.Metadata, error) {
 	metadata, err := pr.reader.GetVulnerabilityMetadata(id, namespace)
 	if err != nil {
 		return nil, fmt.Errorf("metadata provider failed to fetch id='%s' recordsource='%s': %w", id, namespace, err)
diff --git a/grype/db/v5/vulnerability_provider.go b/grype/db/v5/vulnerability_provider.go
index 16c8392e..851aa3a1 100644
--- a/grype/db/v5/vulnerability_provider.go
+++ b/grype/db/v5/vulnerability_provider.go
@@ -15,14 +15,12 @@ import (
 	syftPkg "github.com/anchore/syft/syft/pkg"
 )
 
-var _ vulnerability.Provider = (*VulnerabilityProvider)(nil)
-
-type VulnerabilityProvider struct {
+type vulnerabilityProvider struct {
 	namespaceIndex *namespace.Index
 	reader         VulnerabilityStoreReader
 }
 
-func NewVulnerabilityProvider(reader VulnerabilityStoreReader) (*VulnerabilityProvider, error) {
+func NewVulnerabilityProvider(reader VulnerabilityStoreReader) (VulnerabilityProvider, error) {
 	namespaces, err := reader.GetVulnerabilityNamespaces()
 	if err != nil {
 		return nil, fmt.Errorf("unable to get namespaces from store: %w", err)
@@ -33,13 +31,13 @@ func NewVulnerabilityProvider(reader VulnerabilityStoreReader) (*VulnerabilityPr
 		return nil, fmt.Errorf("unable to parse namespaces from store: %w", err)
 	}
 
-	return &VulnerabilityProvider{
+	return &vulnerabilityProvider{
 		namespaceIndex: namespaceIndex,
 		reader:         reader,
 	}, nil
 }
 
-func (pr *VulnerabilityProvider) Get(id, namespace string) ([]vulnerability.Vulnerability, error) {
+func (pr *vulnerabilityProvider) Get(id, namespace string) ([]vulnerability.Vulnerability, error) {
 	// note: getting a vulnerability record by id doesn't necessarily return a single record
 	// since records are duplicated by the set of fixes they have.
 	vulns, err := pr.reader.GetVulnerability(namespace, id)
@@ -60,7 +58,7 @@ func (pr *VulnerabilityProvider) Get(id, namespace string) ([]vulnerability.Vuln
 	return results, nil
 }
 
-func (pr *VulnerabilityProvider) GetByDistro(d *distro.Distro, p pkg.Package) ([]vulnerability.Vulnerability, error) {
+func (pr *vulnerabilityProvider) GetByDistro(d *distro.Distro, p pkg.Package) ([]vulnerability.Vulnerability, error) {
 	if d == nil {
 		return nil, nil
 	}
@@ -99,7 +97,7 @@ func (pr *VulnerabilityProvider) GetByDistro(d *distro.Distro, p pkg.Package) ([
 	return vulnerabilities, nil
 }
 
-func (pr *VulnerabilityProvider) GetByLanguage(l syftPkg.Language, p pkg.Package) ([]vulnerability.Vulnerability, error) {
+func (pr *vulnerabilityProvider) GetByLanguage(l syftPkg.Language, p pkg.Package) ([]vulnerability.Vulnerability, error) {
 	var vulnerabilities []vulnerability.Vulnerability
 	namespaces := pr.namespaceIndex.NamespacesForLanguage(l)
 
@@ -134,7 +132,7 @@ func (pr *VulnerabilityProvider) GetByLanguage(l syftPkg.Language, p pkg.Package
 	return vulnerabilities, nil
 }
 
-func (pr *VulnerabilityProvider) GetByCPE(requestCPE cpe.CPE) ([]vulnerability.Vulnerability, error) {
+func (pr *vulnerabilityProvider) GetByCPE(requestCPE cpe.CPE) ([]vulnerability.Vulnerability, error) {
 	vulns := make([]vulnerability.Vulnerability, 0)
 	namespaces := pr.namespaceIndex.CPENamespaces()
 
diff --git a/grype/deprecated.go b/grype/deprecated.go
index e9e4d4eb..b96a2bdb 100644
--- a/grype/deprecated.go
+++ b/grype/deprecated.go
@@ -1,10 +1,10 @@
 package grype
 
 import (
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/matcher"
 	"github.com/anchore/grype/grype/match"
-	"github.com/anchore/grype/grype/matcher"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/store"
 	"github.com/anchore/grype/internal/log"
 	"github.com/anchore/stereoscope/pkg/image"
 	"github.com/anchore/syft/syft"
@@ -13,7 +13,7 @@ import (
 )
 
 // TODO: deprecated, will remove before v1.0.0
-func FindVulnerabilities(store store.Store, userImageStr string, scopeOpt source.Scope, registryOptions *image.RegistryOptions) (match.Matches, pkg.Context, []pkg.Package, error) {
+func FindVulnerabilities(store v5.ProviderStore, userImageStr string, scopeOpt source.Scope, registryOptions *image.RegistryOptions) (match.Matches, pkg.Context, []pkg.Package, error) {
 	providerConfig := pkg.ProviderConfig{
 		SyftProviderConfig: pkg.SyftProviderConfig{
 			RegistryOptions: registryOptions,
@@ -33,7 +33,7 @@ func FindVulnerabilities(store store.Store, userImageStr string, scopeOpt source
 }
 
 // TODO: deprecated, will remove before v1.0.0
-func FindVulnerabilitiesForPackage(store store.Store, d *linux.Release, matchers []matcher.Matcher, packages []pkg.Package) match.Matches {
+func FindVulnerabilitiesForPackage(store v5.ProviderStore, d *linux.Release, matchers []matcher.Matcher, packages []pkg.Package) match.Matches {
 	runner := VulnerabilityMatcher{
 		Store:          store,
 		Matchers:       matchers,
diff --git a/grype/load_vulnerability_db.go b/grype/load_vulnerability_db.go
index 52d15a10..fdbddd95 100644
--- a/grype/load_vulnerability_db.go
+++ b/grype/load_vulnerability_db.go
@@ -3,11 +3,10 @@ package grype
 import (
 	"github.com/anchore/grype/grype/db/legacy/distribution"
 	v5 "github.com/anchore/grype/grype/db/v5"
-	"github.com/anchore/grype/grype/store"
 	"github.com/anchore/grype/internal/log"
 )
 
-func LoadVulnerabilityDB(cfg distribution.Config, update bool) (*store.Store, *distribution.Status, error) {
+func LoadVulnerabilityDB(cfg distribution.Config, update bool) (*v5.ProviderStore, *distribution.Status, error) {
 	dbCurator, err := distribution.NewCurator(cfg)
 	if err != nil {
 		return nil, nil, err
@@ -33,11 +32,11 @@ func LoadVulnerabilityDB(cfg distribution.Config, update bool) (*store.Store, *d
 		return nil, &status, err
 	}
 
-	s := &store.Store{
-		Provider:          p,
-		MetadataProvider:  v5.NewVulnerabilityMetadataProvider(storeReader),
-		ExclusionProvider: v5.NewMatchExclusionProvider(storeReader),
-		Closer:            storeReader,
+	s := &v5.ProviderStore{
+		VulnerabilityProvider:         p,
+		VulnerabilityMetadataProvider: v5.NewVulnerabilityMetadataProvider(storeReader),
+		ExclusionProvider:             v5.NewMatchExclusionProvider(storeReader),
+		Closer:                        storeReader,
 	}
 
 	return s, &status, nil
diff --git a/grype/presenter/cyclonedx/presenter.go b/grype/presenter/cyclonedx/presenter.go
index 49d4cbe5..2ae63229 100644
--- a/grype/presenter/cyclonedx/presenter.go
+++ b/grype/presenter/cyclonedx/presenter.go
@@ -26,7 +26,7 @@ type Presenter struct {
 	sbom             *sbom.SBOM
 }
 
-// NewPresenter is a *Presenter constructor
+// NewJSONPresenter is a *Presenter constructor
 func NewJSONPresenter(pb models.PresenterConfig) *Presenter {
 	return &Presenter{
 		id:               pb.ID,
@@ -39,7 +39,7 @@ func NewJSONPresenter(pb models.PresenterConfig) *Presenter {
 	}
 }
 
-// NewPresenter is a *Presenter constructor
+// NewXMLPresenter is a *Presenter constructor
 func NewXMLPresenter(pb models.PresenterConfig) *Presenter {
 	return &Presenter{
 		id:               pb.ID,
diff --git a/grype/presenter/cyclonedx/vulnerability.go b/grype/presenter/cyclonedx/vulnerability.go
index 5e8f64e9..4e75d55d 100644
--- a/grype/presenter/cyclonedx/vulnerability.go
+++ b/grype/presenter/cyclonedx/vulnerability.go
@@ -18,7 +18,7 @@ import (
 
 // NewVulnerability creates a Vulnerability document from a match and the metadata provider
 func NewVulnerability(m match.Match, p vulnerability.MetadataProvider) (v cyclonedx.Vulnerability, err error) {
-	metadata, err := p.GetMetadata(m.Vulnerability.ID, m.Vulnerability.Namespace)
+	metadata, err := p.VulnerabilityMetadata(m.Vulnerability.Reference)
 	if err != nil {
 		return v, fmt.Errorf("unable to fetch vuln=%q metadata: %+v", m.Vulnerability.ID, err)
 	}
diff --git a/grype/presenter/models/match.go b/grype/presenter/models/match.go
index 333c8047..f98ed266 100644
--- a/grype/presenter/models/match.go
+++ b/grype/presenter/models/match.go
@@ -28,7 +28,7 @@ type MatchDetails struct {
 func newMatch(m match.Match, p pkg.Package, metadataProvider vulnerability.MetadataProvider) (*Match, error) {
 	relatedVulnerabilities := make([]VulnerabilityMetadata, 0)
 	for _, r := range m.Vulnerability.RelatedVulnerabilities {
-		relatedMetadata, err := metadataProvider.GetMetadata(r.ID, r.Namespace)
+		relatedMetadata, err := metadataProvider.VulnerabilityMetadata(r)
 		if err != nil {
 			return nil, fmt.Errorf("unable to fetch related vuln=%q metadata: %+v", r, err)
 		}
@@ -37,7 +37,7 @@ func newMatch(m match.Match, p pkg.Package, metadataProvider vulnerability.Metad
 		}
 	}
 
-	metadata, err := metadataProvider.GetMetadata(m.Vulnerability.ID, m.Vulnerability.Namespace)
+	metadata, err := metadataProvider.VulnerabilityMetadata(m.Vulnerability.Reference)
 	if err != nil {
 		return nil, fmt.Errorf("unable to fetch vuln=%q metadata: %+v", m.Vulnerability.ID, err)
 	}
diff --git a/grype/presenter/models/metadata_mock.go b/grype/presenter/models/metadata_mock.go
index cade2230..b648d3c8 100644
--- a/grype/presenter/models/metadata_mock.go
+++ b/grype/presenter/models/metadata_mock.go
@@ -1,10 +1,12 @@
 package models
 
-import "github.com/anchore/grype/grype/vulnerability"
+import (
+	"github.com/anchore/grype/grype/vulnerability"
+)
 
 var _ vulnerability.MetadataProvider = (*MetadataMock)(nil)
 
-// MetadataMock provides the behavior required for a vulnerability.MetadataProvider for the purpose of testing.
+// MetadataMock provides the behavior required for a vulnerability.Provider for the purpose of testing.
 type MetadataMock struct {
 	store map[string]map[string]vulnerability.Metadata
 }
@@ -85,8 +87,8 @@ func NewMetadataMock() *MetadataMock {
 	}
 }
 
-// GetMetadata returns vulnerability metadata for a given id and recordSource.
-func (m *MetadataMock) GetMetadata(id, namespace string) (*vulnerability.Metadata, error) {
-	value := m.store[id][namespace]
+// VulnerabilityMetadata returns vulnerability metadata for a given id and recordSource.
+func (m *MetadataMock) VulnerabilityMetadata(vuln vulnerability.Reference) (*vulnerability.Metadata, error) {
+	value := m.store[vuln.ID][vuln.Namespace]
 	return &value, nil
 }
diff --git a/grype/presenter/sarif/presenter.go b/grype/presenter/sarif/presenter.go
index 0d9b233b..9218c62a 100644
--- a/grype/presenter/sarif/presenter.go
+++ b/grype/presenter/sarif/presenter.go
@@ -288,13 +288,13 @@ func (pres *Presenter) severityText(m match.Match) string {
 func (pres *Presenter) cvssScore(v vulnerability.Vulnerability) float64 {
 	var all []*vulnerability.Metadata
 
-	meta, err := pres.metadataProvider.GetMetadata(v.ID, v.Namespace)
+	meta, err := pres.metadataProvider.VulnerabilityMetadata(v.Reference)
 	if err == nil && meta != nil {
 		all = append(all, meta)
 	}
 
 	for _, related := range v.RelatedVulnerabilities {
-		meta, err = pres.metadataProvider.GetMetadata(related.ID, related.Namespace)
+		meta, err = pres.metadataProvider.VulnerabilityMetadata(related)
 		if err == nil && meta != nil {
 			all = append(all, meta)
 		}
@@ -357,7 +357,7 @@ func (pres *Presenter) securitySeverityValue(m match.Match) string {
 
 // metadata returns the matching *vulnerability.Metadata from the provider or nil if not found / error
 func (pres *Presenter) metadata(m match.Match) *vulnerability.Metadata {
-	meta, _ := pres.metadataProvider.GetMetadata(m.Vulnerability.ID, m.Vulnerability.Namespace)
+	meta, _ := pres.metadataProvider.VulnerabilityMetadata(m.Vulnerability.Reference)
 	return meta
 }
 
diff --git a/grype/presenter/table/presenter.go b/grype/presenter/table/presenter.go
index bec37e39..9b1748ad 100644
--- a/grype/presenter/table/presenter.go
+++ b/grype/presenter/table/presenter.go
@@ -173,7 +173,7 @@ func removeDuplicateRows(items [][]string) [][]string {
 func createRow(m match.Match, metadataProvider vulnerability.MetadataProvider, severitySuffix string) ([]string, error) {
 	var severity string
 
-	metadata, err := metadataProvider.GetMetadata(m.Vulnerability.ID, m.Vulnerability.Namespace)
+	metadata, err := metadataProvider.VulnerabilityMetadata(m.Vulnerability.Reference)
 	if err != nil {
 		return nil, fmt.Errorf("unable to fetch vuln=%q metadata: %+v", m.Vulnerability.ID, err)
 	}
diff --git a/grype/store/store.go b/grype/store/store.go
deleted file mode 100644
index fc7c7219..00000000
--- a/grype/store/store.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package store
-
-import (
-	"io"
-
-	"github.com/anchore/grype/grype/match"
-	"github.com/anchore/grype/grype/vulnerability"
-)
-
-type Store struct {
-	vulnerability.Provider
-	vulnerability.MetadataProvider
-	match.ExclusionProvider
-	io.Closer
-}
diff --git a/grype/vulnerability/provider.go b/grype/vulnerability/provider.go
index eb516e39..0309d8e4 100644
--- a/grype/vulnerability/provider.go
+++ b/grype/vulnerability/provider.go
@@ -1,31 +1,6 @@
 package vulnerability
 
-import (
-	"github.com/anchore/grype/grype/distro"
-	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/syft/syft/cpe"
-	syftPkg "github.com/anchore/syft/syft/pkg"
-)
-
-type Provider interface {
-	Get(id, namespace string) ([]Vulnerability, error)
-	ProviderByDistro
-	ProviderByLanguage
-	ProviderByCPE
-}
-
-type ProviderByDistro interface {
-	GetByDistro(*distro.Distro, pkg.Package) ([]Vulnerability, error)
-}
-
-type ProviderByLanguage interface {
-	GetByLanguage(syftPkg.Language, pkg.Package) ([]Vulnerability, error)
-}
-
-type ProviderByCPE interface {
-	GetByCPE(cpe.CPE) ([]Vulnerability, error)
-}
-
 type MetadataProvider interface {
-	GetMetadata(id, namespace string) (*Metadata, error)
+	// VulnerabilityMetadata returns the metadata associated with a vulnerability
+	VulnerabilityMetadata(ref Reference) (*Metadata, error)
 }
diff --git a/grype/vulnerability/vulnerability.go b/grype/vulnerability/vulnerability.go
index 22bf943f..9c629de7 100644
--- a/grype/vulnerability/vulnerability.go
+++ b/grype/vulnerability/vulnerability.go
@@ -14,12 +14,11 @@ type Reference struct {
 }
 
 type Vulnerability struct {
+	Reference
 	PackageName            string
 	Constraint             version.Constraint
 	PackageQualifiers      []qualifier.Qualifier
 	CPEs                   []cpe.CPE
-	ID                     string
-	Namespace              string
 	Fix                    Fix
 	Advisories             []Advisory
 	RelatedVulnerabilities []Reference
diff --git a/grype/vulnerability_matcher.go b/grype/vulnerability_matcher.go
index 05b58ab3..387534a4 100644
--- a/grype/vulnerability_matcher.go
+++ b/grype/vulnerability_matcher.go
@@ -8,15 +8,15 @@ import (
 	"github.com/wagoodman/go-partybus"
 	"github.com/wagoodman/go-progress"
 
+	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/matcher"
+	"github.com/anchore/grype/grype/db/v5/matcher/stock"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/event"
 	"github.com/anchore/grype/grype/event/monitor"
 	"github.com/anchore/grype/grype/grypeerr"
 	"github.com/anchore/grype/grype/match"
-	"github.com/anchore/grype/grype/matcher"
-	"github.com/anchore/grype/grype/matcher/stock"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/store"
 	"github.com/anchore/grype/grype/vex"
 	"github.com/anchore/grype/grype/vulnerability"
 	"github.com/anchore/grype/internal/bus"
@@ -31,7 +31,7 @@ const (
 )
 
 type VulnerabilityMatcher struct {
-	Store          store.Store
+	Store          v5.ProviderStore
 	Matchers       []matcher.Matcher
 	IgnoreRules    []match.IgnoreRule
 	FailSeverity   *vulnerability.Severity
@@ -39,7 +39,7 @@ type VulnerabilityMatcher struct {
 	VexProcessor   *vex.Processor
 }
 
-func DefaultVulnerabilityMatcher(store store.Store) *VulnerabilityMatcher {
+func DefaultVulnerabilityMatcher(store v5.ProviderStore) *VulnerabilityMatcher {
 	return &VulnerabilityMatcher{
 		Store:    store,
 		Matchers: matcher.NewDefaultMatchers(matcher.Config{}),
@@ -209,7 +209,7 @@ func (m *VulnerabilityMatcher) searchDBForMatches(
 func indexFalsePositivesByLocation(
 	d *distro.Distro,
 	packages []pkg.Package,
-	s store.Store,
+	s v5.ProviderStore,
 ) (map[string][]string, error) {
 	distroFalsePositivesByLocationPath := make(map[string][]string)
 
@@ -226,7 +226,7 @@ func indexFalsePositivesByLocation(
 	return distroFalsePositivesByLocationPath, nil
 }
 
-func getDistroFalsePositivesByLocation(s store.Store, d *distro.Distro, p pkg.Package) (map[string][]string, error) {
+func getDistroFalsePositivesByLocation(s v5.ProviderStore, d *distro.Distro, p pkg.Package) (map[string][]string, error) {
 	result := make(map[string][]string)
 
 	if data, ok := p.Metadata.(pkg.ApkMetadata); ok {
@@ -432,7 +432,7 @@ func isCVE(id string) bool {
 	return strings.HasPrefix(strings.ToLower(id), "cve-")
 }
 
-func HasSeverityAtOrAbove(store vulnerability.MetadataProvider, severity vulnerability.Severity, matches match.Matches) bool {
+func HasSeverityAtOrAbove(store v5.VulnerabilityMetadataProvider, severity vulnerability.Severity, matches match.Matches) bool {
 	if severity == vulnerability.UnknownSeverity {
 		return false
 	}
@@ -469,7 +469,7 @@ func logListSummary(vl *monitorWriter) {
 	}
 }
 
-func updateVulnerabilityList(mon *monitorWriter, matches []match.Match, ignores []match.IgnoredMatch, dropped []match.IgnoredMatch, metadataProvider vulnerability.MetadataProvider) {
+func updateVulnerabilityList(mon *monitorWriter, matches []match.Match, ignores []match.IgnoredMatch, dropped []match.IgnoredMatch, metadataProvider v5.VulnerabilityMetadataProvider) {
 	for _, m := range matches {
 		metadata, err := metadataProvider.GetMetadata(m.Vulnerability.ID, m.Vulnerability.Namespace)
 		if err != nil || metadata == nil {


Test patch:
diff --git a/grype/matcher/apk/matcher_test.go b/grype/db/v5/matcher/apk/matcher_test.go
similarity index 99%
rename from grype/matcher/apk/matcher_test.go
rename to grype/db/v5/matcher/apk/matcher_test.go
index a8b7df06..25a2ac5f 100644
--- a/grype/matcher/apk/matcher_test.go
+++ b/grype/db/v5/matcher/apk/matcher_test.go
@@ -10,10 +10,10 @@ import (
 	"github.com/stretchr/testify/require"
 
 	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/search"
 	"github.com/anchore/grype/grype/vulnerability"
 	"github.com/anchore/syft/syft/cpe"
 	syftPkg "github.com/anchore/syft/syft/pkg"
diff --git a/grype/matcher/dpkg/matcher_mocks_test.go b/grype/db/v5/matcher/dpkg/matcher_mocks_test.go
similarity index 82%
rename from grype/matcher/dpkg/matcher_mocks_test.go
rename to grype/db/v5/matcher/dpkg/matcher_mocks_test.go
index a315ad0d..ebfbb566 100644
--- a/grype/matcher/dpkg/matcher_mocks_test.go
+++ b/grype/db/v5/matcher/dpkg/matcher_mocks_test.go
@@ -27,7 +27,7 @@ func (pr *mockProvider) stub() {
 		"neutron": {
 			{
 				Constraint: version.MustGetConstraint("< 2014.1.3-6", version.DebFormat),
-				ID:         "CVE-2014-fake-1",
+				Reference:  vulnerability.Reference{ID: "CVE-2014-fake-1"},
 			},
 		},
 		// indirect...
@@ -35,16 +35,16 @@ func (pr *mockProvider) stub() {
 			// expected...
 			{
 				Constraint: version.MustGetConstraint("< 2014.1.4-5", version.DebFormat),
-				ID:         "CVE-2014-fake-2",
+				Reference:  vulnerability.Reference{ID: "CVE-2014-fake-2"},
 			},
 			{
 				Constraint: version.MustGetConstraint("< 2015.0.0-1", version.DebFormat),
-				ID:         "CVE-2013-fake-3",
+				Reference:  vulnerability.Reference{ID: "CVE-2013-fake-3"},
 			},
 			// unexpected...
 			{
 				Constraint: version.MustGetConstraint("< 2014.0.4-1", version.DebFormat),
-				ID:         "CVE-2013-fake-BAD",
+				Reference:  vulnerability.Reference{ID: "CVE-2013-fake-BAD"},
 			},
 		},
 	}
diff --git a/grype/matcher/golang/matcher_test.go b/grype/db/v5/matcher/golang/matcher_test.go
similarity index 98%
rename from grype/matcher/golang/matcher_test.go
rename to grype/db/v5/matcher/golang/matcher_test.go
index e406888b..8bbd1960 100644
--- a/grype/matcher/golang/matcher_test.go
+++ b/grype/db/v5/matcher/golang/matcher_test.go
@@ -220,7 +220,7 @@ func (mp *mockProvider) populateData() {
 		"istio.io/istio": {
 			{
 				Constraint: version.MustGetConstraint("< 5.0.7", version.UnknownFormat),
-				ID:         "CVE-2013-fake-BAD",
+				Reference:  vulnerability.Reference{ID: "CVE-2013-fake-BAD"},
 			},
 		},
 	}
@@ -230,7 +230,7 @@ func (mp *mockProvider) populateData() {
 		"cpe:2.3:a:golang:go:1.18.3:-:*:*:*:*:*:*": {
 			{
 				Constraint: version.MustGetConstraint("< 1.18.6 || = 1.19.0", version.UnknownFormat),
-				ID:         "CVE-2022-27664",
+				Reference:  vulnerability.Reference{ID: "CVE-2022-27664"},
 			},
 		},
 	}
diff --git a/grype/matcher/java/matcher_mocks_test.go b/grype/db/v5/matcher/java/matcher_mocks_test.go
similarity index 90%
rename from grype/matcher/java/matcher_mocks_test.go
rename to grype/db/v5/matcher/java/matcher_mocks_test.go
index 4bdca780..64d75d9f 100644
--- a/grype/matcher/java/matcher_mocks_test.go
+++ b/grype/db/v5/matcher/java/matcher_mocks_test.go
@@ -23,16 +23,16 @@ func (mp *mockProvider) populateData() {
 		"org.springframework.spring-webmvc": {
 			{
 				Constraint: version.MustGetConstraint(">=5.0.0,<5.1.7", version.UnknownFormat),
-				ID:         "CVE-2014-fake-2",
+				Reference:  vulnerability.Reference{ID: "CVE-2014-fake-2"},
 			},
 			{
 				Constraint: version.MustGetConstraint(">=5.0.1,<5.1.7", version.UnknownFormat),
-				ID:         "CVE-2013-fake-3",
+				Reference:  vulnerability.Reference{ID: "CVE-2013-fake-3"},
 			},
 			// unexpected...
 			{
 				Constraint: version.MustGetConstraint(">=5.0.0,<5.0.7", version.UnknownFormat),
-				ID:         "CVE-2013-fake-BAD",
+				Reference:  vulnerability.Reference{ID: "CVE-2013-fake-BAD"},
 			},
 		},
 	}
diff --git a/grype/matcher/portage/matcher_mocks_test.go b/grype/db/v5/matcher/portage/matcher_mocks_test.go
similarity index 91%
rename from grype/matcher/portage/matcher_mocks_test.go
rename to grype/db/v5/matcher/portage/matcher_mocks_test.go
index e5919b7b..b71e5ecd 100644
--- a/grype/matcher/portage/matcher_mocks_test.go
+++ b/grype/db/v5/matcher/portage/matcher_mocks_test.go
@@ -34,11 +34,11 @@ func (pr *mockProvider) stub() {
 		"app-misc/neutron": {
 			{
 				Constraint: version.MustGetConstraint("< 2014.1.3", version.PortageFormat),
-				ID:         "CVE-2014-fake-1",
+				Reference:  vulnerability.Reference{ID: "CVE-2014-fake-1"},
 			},
 			{
 				Constraint: version.MustGetConstraint("< 2014.1.4", version.PortageFormat),
-				ID:         "CVE-2014-fake-2",
+				Reference:  vulnerability.Reference{ID: "CVE-2014-fake-2"},
 			},
 		},
 	}
diff --git a/grype/matcher/rpm/matcher_mocks_test.go b/grype/db/v5/matcher/rpm/matcher_mocks_test.go
similarity index 83%
rename from grype/matcher/rpm/matcher_mocks_test.go
rename to grype/db/v5/matcher/rpm/matcher_mocks_test.go
index 21889717..3f6bd393 100644
--- a/grype/matcher/rpm/matcher_mocks_test.go
+++ b/grype/db/v5/matcher/rpm/matcher_mocks_test.go
@@ -43,7 +43,7 @@ func (pr *mockProvider) stub(packageName, indirectName string) {
 		packageName: {
 			{
 				Constraint: version.MustGetConstraint("<= 7.1.3-6", version.RpmFormat),
-				ID:         "CVE-2014-fake-1",
+				Reference:  vulnerability.Reference{ID: "CVE-2014-fake-1"},
 			},
 		},
 		// indirect...
@@ -51,16 +51,16 @@ func (pr *mockProvider) stub(packageName, indirectName string) {
 			// expected...
 			{
 				Constraint: version.MustGetConstraint("< 7.1.4-5", version.RpmFormat),
-				ID:         "CVE-2014-fake-2",
+				Reference:  vulnerability.Reference{ID: "CVE-2014-fake-2"},
 			},
 			{
 				Constraint: version.MustGetConstraint("< 8.0.2-0", version.RpmFormat),
-				ID:         "CVE-2013-fake-3",
+				Reference:  vulnerability.Reference{ID: "CVE-2013-fake-3"},
 			},
 			// unexpected...
 			{
 				Constraint: version.MustGetConstraint("< 7.0.4-1", version.RpmFormat),
-				ID:         "CVE-2013-fake-BAD",
+				Reference:  vulnerability.Reference{ID: "CVE-2013-fake-BAD"},
 			},
 		},
 	}
@@ -72,23 +72,23 @@ func (pr *mockProvider) stubWithEpoch(packageName, indirectName string) {
 		packageName: {
 			{
 				Constraint: version.MustGetConstraint("<= 0:1.0-419.el8.", version.RpmFormat),
-				ID:         "CVE-2021-1",
+				Reference:  vulnerability.Reference{ID: "CVE-2021-1"},
 			},
 			{
 				Constraint: version.MustGetConstraint("<= 0:2.28-419.el8.", version.RpmFormat),
-				ID:         "CVE-2021-2",
+				Reference:  vulnerability.Reference{ID: "CVE-2021-2"},
 			},
 		},
 		// indirect...
 		indirectName: {
 			{
 				Constraint: version.MustGetConstraint("< 5.28.3-420.el8", version.RpmFormat),
-				ID:         "CVE-2021-3",
+				Reference:  vulnerability.Reference{ID: "CVE-2021-3"},
 			},
 			// unexpected...
 			{
 				Constraint: version.MustGetConstraint("< 4:5.26.3-419.el8", version.RpmFormat),
-				ID:         "CVE-2021-4",
+				Reference:  vulnerability.Reference{ID: "CVE-2021-4"},
 			},
 		},
 	}
@@ -100,25 +100,25 @@ func (pr *mockProvider) stubWithPackageQualifiers(packageName string) {
 		packageName: {
 			{
 				Constraint: version.MustGetConstraint("<= 0:1.0-419.el8.", version.RpmFormat),
-				ID:         "CVE-2021-1",
+				Reference:  vulnerability.Reference{ID: "CVE-2021-1"},
 				PackageQualifiers: []qualifier.Qualifier{
 					rpmmodularity.New("containertools:3"),
 				},
 			},
 			{
 				Constraint: version.MustGetConstraint("<= 0:1.0-419.el8.", version.RpmFormat),
-				ID:         "CVE-2021-2",
+				Reference:  vulnerability.Reference{ID: "CVE-2021-2"},
 				PackageQualifiers: []qualifier.Qualifier{
 					rpmmodularity.New(""),
 				},
 			},
 			{
 				Constraint: version.MustGetConstraint("<= 0:1.0-419.el8.", version.RpmFormat),
-				ID:         "CVE-2021-3",
+				Reference:  vulnerability.Reference{ID: "CVE-2021-3"},
 			},
 			{
 				Constraint: version.MustGetConstraint("<= 0:1.0-419.el8.", version.RpmFormat),
-				ID:         "CVE-2021-4",
+				Reference:  vulnerability.Reference{ID: "CVE-2021-4"},
 				PackageQualifiers: []qualifier.Qualifier{
 					rpmmodularity.New("containertools:4"),
 				},
diff --git a/grype/matcher/rpm/matcher_test.go b/grype/db/v5/matcher/rpm/matcher_test.go
similarity index 91%
rename from grype/matcher/rpm/matcher_test.go
rename to grype/db/v5/matcher/rpm/matcher_test.go
index ea101c42..6154770d 100644
--- a/grype/matcher/rpm/matcher_test.go
+++ b/grype/db/v5/matcher/rpm/matcher_test.go
@@ -7,10 +7,10 @@ import (
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
+	v5 "github.com/anchore/grype/grype/db/v5"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/vulnerability"
 	syftPkg "github.com/anchore/syft/syft/pkg"
 )
 
@@ -22,7 +22,7 @@ func TestMatcherRpm(t *testing.T) {
 	tests := []struct {
 		name            string
 		p               pkg.Package
-		setup           func() (vulnerability.Provider, *distro.Distro, Matcher)
+		setup           func() (v5.VulnerabilityProvider, *distro.Distro, Matcher)
 		expectedMatches map[string]match.Type
 		wantErr         bool
 	}{
@@ -40,7 +40,7 @@ func TestMatcherRpm(t *testing.T) {
 					},
 				},
 			},
-			setup: func() (vulnerability.Provider, *distro.Distro, Matcher) {
+			setup: func() (v5.VulnerabilityProvider, *distro.Distro, Matcher) {
 				matcher := Matcher{}
 				d, err := distro.New(distro.CentOS, "8", "")
 				if err != nil {
@@ -71,7 +71,7 @@ func TestMatcherRpm(t *testing.T) {
 					},
 				},
 			},
-			setup: func() (vulnerability.Provider, *distro.Distro, Matcher) {
+			setup: func() (v5.VulnerabilityProvider, *distro.Distro, Matcher) {
 				matcher := Matcher{}
 				d, err := distro.New(distro.CentOS, "8", "")
 				if err != nil {
@@ -101,7 +101,7 @@ func TestMatcherRpm(t *testing.T) {
 					},
 				},
 			},
-			setup: func() (vulnerability.Provider, *distro.Distro, Matcher) {
+			setup: func() (v5.VulnerabilityProvider, *distro.Distro, Matcher) {
 				matcher := Matcher{}
 				d, err := distro.New(distro.CentOS, "8", "")
 				if err != nil {
@@ -135,7 +135,7 @@ func TestMatcherRpm(t *testing.T) {
 					},
 				},
 			},
-			setup: func() (vulnerability.Provider, *distro.Distro, Matcher) {
+			setup: func() (v5.VulnerabilityProvider, *distro.Distro, Matcher) {
 				matcher := Matcher{}
 				d, err := distro.New(distro.CentOS, "8", "")
 				if err != nil {
@@ -160,7 +160,7 @@ func TestMatcherRpm(t *testing.T) {
 				Type:     syftPkg.RpmPkg,
 				Metadata: pkg.RpmMetadata{},
 			},
-			setup: func() (vulnerability.Provider, *distro.Distro, Matcher) {
+			setup: func() (v5.VulnerabilityProvider, *distro.Distro, Matcher) {
 				matcher := Matcher{}
 				d, err := distro.New(distro.CentOS, "8", "")
 				if err != nil {
@@ -184,7 +184,7 @@ func TestMatcherRpm(t *testing.T) {
 				Type:     syftPkg.RpmPkg,
 				Metadata: pkg.RpmMetadata{},
 			},
-			setup: func() (vulnerability.Provider, *distro.Distro, Matcher) {
+			setup: func() (v5.VulnerabilityProvider, *distro.Distro, Matcher) {
 				matcher := Matcher{}
 				d, err := distro.New(distro.CentOS, "8", "")
 				if err != nil {
@@ -208,7 +208,7 @@ func TestMatcherRpm(t *testing.T) {
 				Type:     syftPkg.RpmPkg,
 				Metadata: pkg.RpmMetadata{},
 			},
-			setup: func() (vulnerability.Provider, *distro.Distro, Matcher) {
+			setup: func() (v5.VulnerabilityProvider, *distro.Distro, Matcher) {
 				matcher := Matcher{}
 				d, err := distro.New(distro.CentOS, "8", "")
 				if err != nil {
@@ -232,7 +232,7 @@ func TestMatcherRpm(t *testing.T) {
 				Type:     syftPkg.RpmPkg,
 				Metadata: pkg.RpmMetadata{},
 			},
-			setup: func() (vulnerability.Provider, *distro.Distro, Matcher) {
+			setup: func() (v5.VulnerabilityProvider, *distro.Distro, Matcher) {
 				matcher := Matcher{}
 				d, err := distro.New(distro.CentOS, "8", "")
 				if err != nil {
@@ -256,7 +256,7 @@ func TestMatcherRpm(t *testing.T) {
 					ModularityLabel: strRef("containertools:3:1234:5678"),
 				},
 			},
-			setup: func() (vulnerability.Provider, *distro.Distro, Matcher) {
+			setup: func() (v5.VulnerabilityProvider, *distro.Distro, Matcher) {
 				matcher := Matcher{}
 				d, err := distro.New(distro.CentOS, "8", "")
 				if err != nil {
@@ -283,7 +283,7 @@ func TestMatcherRpm(t *testing.T) {
 					ModularityLabel: strRef("containertools:1:abc:123"),
 				},
 			},
-			setup: func() (vulnerability.Provider, *distro.Distro, Matcher) {
+			setup: func() (v5.VulnerabilityProvider, *distro.Distro, Matcher) {
 				matcher := Matcher{}
 				d, err := distro.New(distro.CentOS, "8", "")
 				if err != nil {
@@ -306,7 +306,7 @@ func TestMatcherRpm(t *testing.T) {
 				Version: "0.1",
 				Type:    syftPkg.RpmPkg,
 			},
-			setup: func() (vulnerability.Provider, *distro.Distro, Matcher) {
+			setup: func() (v5.VulnerabilityProvider, *distro.Distro, Matcher) {
 				matcher := Matcher{}
 				d, err := distro.New(distro.CentOS, "8", "")
 				if err != nil {
diff --git a/grype/matcher/stock/matcher_test.go b/grype/db/v5/matcher/stock/matcher_test.go
similarity index 89%
rename from grype/matcher/stock/matcher_test.go
rename to grype/db/v5/matcher/stock/matcher_test.go
index edd42c49..9680a3b9 100644
--- a/grype/matcher/stock/matcher_test.go
+++ b/grype/db/v5/matcher/stock/matcher_test.go
@@ -103,32 +103,32 @@ func (mp *mockProvider) populateData() {
 			{
 				// positive cases
 				Constraint: version.MustGetConstraint(hit, version.JVMFormat),
-				ID:         "CVE-2024-20919-real",
+				Reference:  vulnerability.Reference{ID: "CVE-2024-20919-real"},
 			},
 			{
 				// positive cases
 				Constraint: version.MustGetConstraint("< 22.22.22", version.UnknownFormat),
-				ID:         "CVE-2024-20919-bonkers-format",
+				Reference:  vulnerability.Reference{ID: "CVE-2024-20919-bonkers-format"},
 			},
 			{
 				// negative case
 				Constraint: version.MustGetConstraint("< 1.8.0_399 || >= 1.9-ea, < 8.0.399 || >= 9-ea", version.JVMFormat),
-				ID:         "CVE-FAKE-bad-update",
+				Reference:  vulnerability.Reference{ID: "CVE-FAKE-bad-update"},
 			},
 			{
 				// positive case
 				Constraint: version.MustGetConstraint("< 8.0.401", version.JVMFormat),
-				ID:         "CVE-2024-20919-post-jep223",
+				Reference:  vulnerability.Reference{ID: "CVE-2024-20919-post-jep223"},
 			},
 			{
 				// negative case
 				Constraint: version.MustGetConstraint("< 8.0.399", version.JVMFormat),
-				ID:         "CVE-FAKE-bad-range-post-jep223",
+				Reference:  vulnerability.Reference{ID: "CVE-FAKE-bad-range-post-jep223"},
 			},
 			{
 				// negative case
 				Constraint: version.MustGetConstraint("< 7.0.0", version.JVMFormat),
-				ID:         "CVE-FAKE-bad-range-post-jep223",
+				Reference:  vulnerability.Reference{ID: "CVE-FAKE-bad-range-post-jep223"},
 			},
 		},
 	}
diff --git a/grype/search/cpe_test.go b/grype/db/v5/search/cpe_test.go
similarity index 97%
rename from grype/search/cpe_test.go
rename to grype/db/v5/search/cpe_test.go
index 2ff5b1bb..189a7d3f 100644
--- a/grype/search/cpe_test.go
+++ b/grype/db/v5/search/cpe_test.go
@@ -179,7 +179,7 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
 				{
 
 					Vulnerability: vulnerability.Vulnerability{
-						ID: "CVE-2017-fake-1",
+						Reference: vulnerability.Reference{ID: "CVE-2017-fake-1"},
 					},
 					Package: pkg.Package{
 						CPEs: []cpe.CPE{
@@ -230,7 +230,7 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
 				{
 
 					Vulnerability: vulnerability.Vulnerability{
-						ID: "CVE-2017-fake-1",
+						Reference: vulnerability.Reference{ID: "CVE-2017-fake-1"},
 					},
 					Package: pkg.Package{
 						CPEs: []cpe.CPE{
@@ -295,7 +295,7 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
 				{
 
 					Vulnerability: vulnerability.Vulnerability{
-						ID: "CVE-2017-fake-1",
+						Reference: vulnerability.Reference{ID: "CVE-2017-fake-1"},
 					},
 					Package: pkg.Package{
 						CPEs: []cpe.CPE{
@@ -334,7 +334,7 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
 				{
 
 					Vulnerability: vulnerability.Vulnerability{
-						ID: "CVE-2017-fake-2",
+						Reference: vulnerability.Reference{ID: "CVE-2017-fake-2"},
 					},
 					Package: pkg.Package{
 						CPEs: []cpe.CPE{
@@ -385,7 +385,7 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
 				{
 
 					Vulnerability: vulnerability.Vulnerability{
-						ID: "CVE-2017-fake-3",
+						Reference: vulnerability.Reference{ID: "CVE-2017-fake-3"},
 					},
 					Package: pkg.Package{
 						CPEs: []cpe.CPE{
@@ -446,7 +446,7 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
 				{
 
 					Vulnerability: vulnerability.Vulnerability{
-						ID: "CVE-2017-fake-4",
+						Reference: vulnerability.Reference{ID: "CVE-2017-fake-4"},
 					},
 					Package: pkg.Package{
 						CPEs: []cpe.CPE{
@@ -494,7 +494,7 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
 				{
 
 					Vulnerability: vulnerability.Vulnerability{
-						ID: "CVE-2017-fake-5",
+						Reference: vulnerability.Reference{ID: "CVE-2017-fake-5"},
 					},
 					Package: pkg.Package{
 						CPEs: []cpe.CPE{
@@ -559,7 +559,7 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
 			expected: []match.Match{
 				{
 					Vulnerability: vulnerability.Vulnerability{
-						ID: "CVE-2017-fake-7",
+						Reference: vulnerability.Reference{ID: "CVE-2017-fake-7"},
 					},
 					Package: pkg.Package{
 						CPEs: []cpe.CPE{
@@ -612,7 +612,7 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
 			expected: []match.Match{
 				{
 					Vulnerability: vulnerability.Vulnerability{
-						ID: "CVE-2017-fake-6",
+						Reference: vulnerability.Reference{ID: "CVE-2017-fake-6"},
 					},
 					Package: pkg.Package{
 						CPEs: []cpe.CPE{
@@ -666,7 +666,7 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
 			expected: []match.Match{
 				{
 					Vulnerability: vulnerability.Vulnerability{
-						ID: "CVE-2021-23369",
+						Reference: vulnerability.Reference{ID: "CVE-2021-23369"},
 					},
 					Package: pkg.Package{
 						CPEs: []cpe.CPE{
@@ -716,7 +716,7 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
 			expected: []match.Match{
 				{
 					Vulnerability: vulnerability.Vulnerability{
-						ID: "CVE-2021-23369",
+						Reference: vulnerability.Reference{ID: "CVE-2021-23369"},
 					},
 					Package: pkg.Package{
 						CPEs: []cpe.CPE{
@@ -766,7 +766,7 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
 			expected: []match.Match{
 				{
 					Vulnerability: vulnerability.Vulnerability{
-						ID: "CVE-2021-23369",
+						Reference: vulnerability.Reference{ID: "CVE-2021-23369"},
 					},
 					Package: pkg.Package{
 						CPEs: []cpe.CPE{
@@ -829,7 +829,7 @@ func TestFindMatchesByPackageCPE(t *testing.T) {
 			expected: []match.Match{
 				{
 					Vulnerability: vulnerability.Vulnerability{
-						ID: "CVE-2021-23369",
+						Reference: vulnerability.Reference{ID: "CVE-2021-23369"},
 					},
 					Package: pkg.Package{
 						CPEs: []cpe.CPE{
diff --git a/grype/search/distro_test.go b/grype/db/v5/search/distro_test.go
similarity index 91%
rename from grype/search/distro_test.go
rename to grype/db/v5/search/distro_test.go
index b90f0e61..527d8463 100644
--- a/grype/search/distro_test.go
+++ b/grype/db/v5/search/distro_test.go
@@ -34,8 +34,10 @@ func (pr *mockDistroProvider) stub() {
 		"neutron": {
 			{
 				Constraint: version.MustGetConstraint("< 2014.1.5-6", version.DebFormat),
-				ID:         "CVE-2014-fake-1",
-				Namespace:  "debian:8",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-2014-fake-1",
+					Namespace: "debian:8",
+				},
 			},
 		},
 	}
@@ -44,8 +46,10 @@ func (pr *mockDistroProvider) stub() {
 		"sles_test_package": {
 			{
 				Constraint: version.MustGetConstraint("< 2014.1.5-6", version.RpmFormat),
-				ID:         "CVE-2014-fake-4",
-				Namespace:  "sles:12.5",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-2014-fake-4",
+					Namespace: "sles:12.5",
+				},
 			},
 		},
 	}
@@ -77,7 +81,9 @@ func TestFindMatchesByPackageDistro(t *testing.T) {
 		{
 
 			Vulnerability: vulnerability.Vulnerability{
-				ID: "CVE-2014-fake-1",
+				Reference: vulnerability.Reference{
+					ID: "CVE-2014-fake-1",
+				},
 			},
 			Package: p,
 			Details: []match.Detail{
@@ -140,7 +146,9 @@ func TestFindMatchesByPackageDistroSles(t *testing.T) {
 		{
 
 			Vulnerability: vulnerability.Vulnerability{
-				ID: "CVE-2014-fake-4",
+				Reference: vulnerability.Reference{
+					ID: "CVE-2014-fake-4",
+				},
 			},
 			Package: p,
 			Details: []match.Detail{
diff --git a/grype/search/language_test.go b/grype/db/v5/search/language_test.go
similarity index 86%
rename from grype/search/language_test.go
rename to grype/db/v5/search/language_test.go
index 5dfae0f8..6204a495 100644
--- a/grype/search/language_test.go
+++ b/grype/db/v5/search/language_test.go
@@ -34,26 +34,34 @@ func (pr *mockLanguageProvider) stub() {
 			{
 				// make sure we find it with semVer constraint
 				Constraint: version.MustGetConstraint("< 3.7.6", version.SemanticFormat),
-				ID:         "CVE-2017-fake-1",
-				Namespace:  "github:ruby",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-2017-fake-1",
+					Namespace: "github:ruby",
+				},
 			},
 			{
 				Constraint: version.MustGetConstraint("< 3.7.4", version.GemFormat),
-				ID:         "CVE-2017-fake-2",
-				Namespace:  "github:ruby",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-2017-fake-2",
+					Namespace: "github:ruby",
+				},
 			},
 		},
 		"nokogiri": {
 			{
 				// make sure we find it with gem version constraint
 				Constraint: version.MustGetConstraint("< 1.7.6", version.GemFormat),
-				ID:         "CVE-2017-fake-1",
-				Namespace:  "github:ruby",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-2017-fake-1",
+					Namespace: "github:ruby",
+				},
 			},
 			{
 				Constraint: version.MustGetConstraint("< 1.7.4", version.SemanticFormat),
-				ID:         "CVE-2017-fake-2",
-				Namespace:  "github:ruby",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-2017-fake-2",
+					Namespace: "github:ruby",
+				},
 			},
 		},
 	}
@@ -70,7 +78,9 @@ func expectedMatch(p pkg.Package, constraint string) []match.Match {
 	return []match.Match{
 		{
 			Vulnerability: vulnerability.Vulnerability{
-				ID: "CVE-2017-fake-1",
+				Reference: vulnerability.Reference{
+					ID: "CVE-2017-fake-1",
+				},
 			},
 			Package: p,
 			Details: []match.Detail{
diff --git a/grype/search/only_qualified_packages.go b/grype/db/v5/search/only_qualified_packages.go
similarity index 100%
rename from grype/search/only_qualified_packages.go
rename to grype/db/v5/search/only_qualified_packages.go
diff --git a/grype/search/only_vulnerable_targets.go b/grype/db/v5/search/only_vulnerable_targets.go
similarity index 100%
rename from grype/search/only_vulnerable_targets.go
rename to grype/db/v5/search/only_vulnerable_targets.go
diff --git a/grype/search/only_vulnerable_targets_test.go b/grype/db/v5/search/only_vulnerable_targets_test.go
similarity index 100%
rename from grype/search/only_vulnerable_targets_test.go
rename to grype/db/v5/search/only_vulnerable_targets_test.go
diff --git a/grype/search/only_vulnerable_versions.go b/grype/db/v5/search/only_vulnerable_versions.go
similarity index 100%
rename from grype/search/only_vulnerable_versions.go
rename to grype/db/v5/search/only_vulnerable_versions.go
diff --git a/grype/search/utils_test.go b/grype/db/v5/search/utils_test.go
similarity index 82%
rename from grype/search/utils_test.go
rename to grype/db/v5/search/utils_test.go
index d2104f11..11356795 100644
--- a/grype/search/utils_test.go
+++ b/grype/db/v5/search/utils_test.go
@@ -15,7 +15,7 @@ func assertMatchesUsingIDsForVulnerabilities(t testing.TB, expected, actual []ma
 	assert.Len(t, actual, len(expected))
 	for idx, a := range actual {
 		// only compare the vulnerability ID, nothing else
-		a.Vulnerability = vulnerability.Vulnerability{ID: a.Vulnerability.ID}
+		a.Vulnerability = vulnerability.Vulnerability{Reference: vulnerability.Reference{ID: a.Vulnerability.ID}}
 		for _, d := range deep.Equal(expected[idx], a) {
 			t.Errorf("diff idx=%d: %+v", idx, d)
 		}
diff --git a/grype/db/v5/vulnerability_provider_test.go b/grype/db/v5/vulnerability_provider_test.go
index 2f680d6f..e4347d4b 100644
--- a/grype/db/v5/vulnerability_provider_test.go
+++ b/grype/db/v5/vulnerability_provider_test.go
@@ -33,19 +33,23 @@ func Test_GetByDistro(t *testing.T) {
 
 	expected := []vulnerability.Vulnerability{
 		{
-			PackageName:       "neutron",
-			Constraint:        version.MustGetConstraint("< 2014.1.3-6", version.DebFormat),
-			ID:                "CVE-2014-fake-1",
-			Namespace:         "debian:distro:debian:8",
+			PackageName: "neutron",
+			Constraint:  version.MustGetConstraint("< 2014.1.3-6", version.DebFormat),
+			Reference: vulnerability.Reference{
+				ID:        "CVE-2014-fake-1",
+				Namespace: "debian:distro:debian:8",
+			},
 			PackageQualifiers: []qualifier.Qualifier{},
 			CPEs:              []cpe.CPE{},
 			Advisories:        []vulnerability.Advisory{},
 		},
 		{
-			PackageName:       "neutron",
-			Constraint:        version.MustGetConstraint("< 2013.0.2-1", version.DebFormat),
-			ID:                "CVE-2013-fake-2",
-			Namespace:         "debian:distro:debian:8",
+			PackageName: "neutron",
+			Constraint:  version.MustGetConstraint("< 2013.0.2-1", version.DebFormat),
+			Reference: vulnerability.Reference{
+				ID:        "CVE-2013-fake-2",
+				Namespace: "debian:distro:debian:8",
+			},
 			PackageQualifiers: []qualifier.Qualifier{},
 			CPEs:              []cpe.CPE{},
 			Advisories:        []vulnerability.Advisory{},
@@ -91,11 +95,13 @@ func Test_GetByCPE(t *testing.T) {
 				{
 					PackageName: "activerecord",
 					Constraint:  version.MustGetConstraint("< 3.7.4", version.UnknownFormat),
-					ID:          "CVE-2014-fake-4",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-2014-fake-4",
+						Namespace: "nvd:cpe",
+					},
 					CPEs: []cpe.CPE{
 						cpe.Must("cpe:2.3:*:activerecord:activerecord:*:*:something:*:*:ruby:*:*", ""),
 					},
-					Namespace:         "nvd:cpe",
 					PackageQualifiers: []qualifier.Qualifier{},
 					Advisories:        []vulnerability.Advisory{},
 				},
@@ -108,11 +114,13 @@ func Test_GetByCPE(t *testing.T) {
 				{
 					PackageName: "activerecord",
 					Constraint:  version.MustGetConstraint("< 3.7.4", version.UnknownFormat),
-					ID:          "CVE-2014-fake-4",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-2014-fake-4",
+						Namespace: "nvd:cpe",
+					},
 					CPEs: []cpe.CPE{
 						cpe.Must("cpe:2.3:*:activerecord:activerecord:*:*:something:*:*:ruby:*:*", ""),
 					},
-					Namespace:         "nvd:cpe",
 					PackageQualifiers: []qualifier.Qualifier{},
 					Advisories:        []vulnerability.Advisory{},
 				},
@@ -125,22 +133,26 @@ func Test_GetByCPE(t *testing.T) {
 				{
 					PackageName: "activerecord",
 					Constraint:  version.MustGetConstraint("< 3.7.6", version.UnknownFormat),
-					ID:          "CVE-2014-fake-3",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-2014-fake-3",
+						Namespace: "nvd:cpe",
+					},
 					CPEs: []cpe.CPE{
 						cpe.Must("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:rails:*:*", ""),
 					},
-					Namespace:         "nvd:cpe",
 					PackageQualifiers: []qualifier.Qualifier{},
 					Advisories:        []vulnerability.Advisory{},
 				},
 				{
 					PackageName: "activerecord",
 					Constraint:  version.MustGetConstraint("< 3.7.4", version.UnknownFormat),
-					ID:          "CVE-2014-fake-4",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-2014-fake-4",
+						Namespace: "nvd:cpe",
+					},
 					CPEs: []cpe.CPE{
 						cpe.Must("cpe:2.3:*:activerecord:activerecord:*:*:something:*:*:ruby:*:*", ""),
 					},
-					Namespace:         "nvd:cpe",
 					PackageQualifiers: []qualifier.Qualifier{},
 					Advisories:        []vulnerability.Advisory{},
 				},
@@ -188,10 +200,12 @@ func Test_Get(t *testing.T) {
 
 	expected := []vulnerability.Vulnerability{
 		{
-			Constraint:        version.MustGetConstraint("< 2014.1.3-6", version.DebFormat),
-			PackageName:       "neutron",
-			ID:                "CVE-2014-fake-1",
-			Namespace:         "debian:distro:debian:8",
+			Constraint:  version.MustGetConstraint("< 2014.1.3-6", version.DebFormat),
+			PackageName: "neutron",
+			Reference: vulnerability.Reference{
+				ID:        "CVE-2014-fake-1",
+				Namespace: "debian:distro:debian:8",
+			},
 			PackageQualifiers: []qualifier.Qualifier{},
 			CPEs:              []cpe.CPE{},
 			Advisories:        []vulnerability.Advisory{},
diff --git a/grype/match/explicit_ignores_test.go b/grype/match/explicit_ignores_test.go
index c95930de..abdc9c9d 100644
--- a/grype/match/explicit_ignores_test.go
+++ b/grype/match/explicit_ignores_test.go
@@ -117,7 +117,7 @@ func Test_ApplyExplicitIgnoreRules(t *testing.T) {
 						Type: test.typ,
 					},
 					Vulnerability: vulnerability.Vulnerability{
-						ID: cp.cve,
+						Reference: vulnerability.Reference{ID: cp.cve},
 					},
 				})
 			}
diff --git a/grype/match/ignore_test.go b/grype/match/ignore_test.go
index 1062d897..5b236599 100644
--- a/grype/match/ignore_test.go
+++ b/grype/match/ignore_test.go
@@ -16,8 +16,10 @@ var (
 	allMatches = []Match{
 		{
 			Vulnerability: vulnerability.Vulnerability{
-				ID:        "CVE-123",
-				Namespace: "debian-vulns",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-123",
+					Namespace: "debian-vulns",
+				},
 				Fix: vulnerability.Fix{
 					State: vulnerability.FixStateFixed,
 				},
@@ -32,8 +34,10 @@ var (
 		},
 		{
 			Vulnerability: vulnerability.Vulnerability{
-				ID:        "CVE-456",
-				Namespace: "ruby-vulns",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-456",
+					Namespace: "ruby-vulns",
+				},
 				Fix: vulnerability.Fix{
 					State: vulnerability.FixStateNotFixed,
 				},
@@ -50,8 +54,10 @@ var (
 		},
 		{
 			Vulnerability: vulnerability.Vulnerability{
-				ID:        "CVE-457",
-				Namespace: "ruby-vulns",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-457",
+					Namespace: "ruby-vulns",
+				},
 				Fix: vulnerability.Fix{
 					State: vulnerability.FixStateWontFix,
 				},
@@ -68,8 +74,10 @@ var (
 		},
 		{
 			Vulnerability: vulnerability.Vulnerability{
-				ID:        "CVE-458",
-				Namespace: "ruby-vulns",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-458",
+					Namespace: "ruby-vulns",
+				},
 				Fix: vulnerability.Fix{
 					State: vulnerability.FixStateUnknown,
 				},
@@ -91,8 +99,10 @@ var (
 		// Direct match, not like a normal kernel header match
 		{
 			Vulnerability: vulnerability.Vulnerability{
-				ID:        "CVE-1",
-				Namespace: "fake-redhat-vulns",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-1",
+					Namespace: "fake-redhat-vulns",
+				},
 				Fix: vulnerability.Fix{
 					State: vulnerability.FixStateUnknown,
 				},
@@ -114,8 +124,10 @@ var (
 		},
 		{
 			Vulnerability: vulnerability.Vulnerability{
-				ID:        "CVE-2",
-				Namespace: "fake-deb-vulns",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-2",
+					Namespace: "fake-deb-vulns",
+				},
 				Fix: vulnerability.Fix{
 					State: vulnerability.FixStateUnknown,
 				},
@@ -137,8 +149,10 @@ var (
 		},
 		{
 			Vulnerability: vulnerability.Vulnerability{
-				ID:        "CVE-1",
-				Namespace: "npm-vulns",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-1",
+					Namespace: "npm-vulns",
+				},
 				Fix: vulnerability.Fix{
 					State: vulnerability.FixStateUnknown,
 				},
@@ -162,8 +176,10 @@ var (
 		// RPM-like match similar to what we see from RedHat
 		{
 			Vulnerability: vulnerability.Vulnerability{
-				ID:        "CVE-2",
-				Namespace: "fake-redhat-vulns",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-2",
+					Namespace: "fake-redhat-vulns",
+				},
 				Fix: vulnerability.Fix{
 					State: vulnerability.FixStateUnknown,
 				},
@@ -186,8 +202,10 @@ var (
 		// debian-like match, showing the kernel header package name w/embedded version
 		{
 			Vulnerability: vulnerability.Vulnerability{
-				ID:        "CVE-2",
-				Namespace: "fake-debian-vulns",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-2",
+					Namespace: "fake-debian-vulns",
+				},
 				Fix: vulnerability.Fix{
 					State: vulnerability.FixStateUnknown,
 				},
@@ -213,8 +231,10 @@ var (
 	packageTypeMatches = []Match{
 		{
 			Vulnerability: vulnerability.Vulnerability{
-				ID:        "CVE-2",
-				Namespace: "fake-redhat-vulns",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-2",
+					Namespace: "fake-redhat-vulns",
+				},
 				Fix: vulnerability.Fix{
 					State: vulnerability.FixStateUnknown,
 				},
@@ -228,8 +248,10 @@ var (
 		},
 		{
 			Vulnerability: vulnerability.Vulnerability{
-				ID:        "CVE-2",
-				Namespace: "fake-debian-vulns",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-2",
+					Namespace: "fake-debian-vulns",
+				},
 				Fix: vulnerability.Fix{
 					State: vulnerability.FixStateUnknown,
 				},
@@ -691,7 +713,7 @@ func sliceToMatches(s []Match) Matches {
 var (
 	exampleMatch = Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2000-1234",
+			Reference: vulnerability.Reference{ID: "CVE-2000-1234"},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
diff --git a/grype/match/match_test.go b/grype/match/match_test.go
index bb9f9386..76e6e194 100644
--- a/grype/match/match_test.go
+++ b/grype/match/match_test.go
@@ -22,8 +22,10 @@ func TestMatch_Merge(t *testing.T) {
 			name: "error on fingerprint mismatch",
 			m1: Match{
 				Vulnerability: vulnerability.Vulnerability{
-					ID:        "CVE-2023-0001",
-					Namespace: "namespace1",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-2023-0001",
+						Namespace: "namespace1",
+					},
 				},
 				Package: pkg.Package{
 					ID: "pkg1",
@@ -31,8 +33,10 @@ func TestMatch_Merge(t *testing.T) {
 			},
 			m2: Match{
 				Vulnerability: vulnerability.Vulnerability{
-					ID:        "CVE-2023-0002",
-					Namespace: "namespace2",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-2023-0002",
+						Namespace: "namespace2",
+					},
 				},
 				Package: pkg.Package{
 					ID: "pkg2",
@@ -44,8 +48,10 @@ func TestMatch_Merge(t *testing.T) {
 			name: "merge with unique values",
 			m1: Match{
 				Vulnerability: vulnerability.Vulnerability{
-					ID:        "CVE-2023-0001",
-					Namespace: "namespace",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-2023-0001",
+						Namespace: "namespace",
+					},
 					RelatedVulnerabilities: []vulnerability.Reference{
 						{
 							Namespace: "ns1",
@@ -70,8 +76,10 @@ func TestMatch_Merge(t *testing.T) {
 			},
 			m2: Match{
 				Vulnerability: vulnerability.Vulnerability{
-					ID:        "CVE-2023-0001",
-					Namespace: "namespace",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-2023-0001",
+						Namespace: "namespace",
+					},
 					RelatedVulnerabilities: []vulnerability.Reference{
 						{
 							Namespace: "ns2",
@@ -97,8 +105,10 @@ func TestMatch_Merge(t *testing.T) {
 			expectedErr: nil,
 			expected: Match{
 				Vulnerability: vulnerability.Vulnerability{
-					ID:        "CVE-2023-0001",
-					Namespace: "namespace",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-2023-0001",
+						Namespace: "namespace",
+					},
 					RelatedVulnerabilities: []vulnerability.Reference{
 						{
 							Namespace: "ns1",
@@ -137,8 +147,10 @@ func TestMatch_Merge(t *testing.T) {
 			name: "merges with duplicate values",
 			m1: Match{
 				Vulnerability: vulnerability.Vulnerability{
-					ID:        "CVE-2023-0001",
-					Namespace: "namespace",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-2023-0001",
+						Namespace: "namespace",
+					},
 					RelatedVulnerabilities: []vulnerability.Reference{
 						{
 							Namespace: "ns1",
@@ -163,8 +175,10 @@ func TestMatch_Merge(t *testing.T) {
 			},
 			m2: Match{
 				Vulnerability: vulnerability.Vulnerability{
-					ID:        "CVE-2023-0001",
-					Namespace: "namespace",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-2023-0001",
+						Namespace: "namespace",
+					},
 					RelatedVulnerabilities: []vulnerability.Reference{
 						{
 							Namespace: "ns1",
@@ -190,8 +204,10 @@ func TestMatch_Merge(t *testing.T) {
 			expectedErr: nil,
 			expected: Match{
 				Vulnerability: vulnerability.Vulnerability{
-					ID:        "CVE-2023-0001",
-					Namespace: "namespace",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-2023-0001",
+						Namespace: "namespace",
+					},
 					RelatedVulnerabilities: []vulnerability.Reference{
 						{
 							Namespace: "ns1",
diff --git a/grype/match/matches_test.go b/grype/match/matches_test.go
index b0b869ff..ca1d4848 100644
--- a/grype/match/matches_test.go
+++ b/grype/match/matches_test.go
@@ -19,7 +19,9 @@ import (
 func TestMatchesSortMixedDimensions(t *testing.T) {
 	first := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0010",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0010",
+			},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
@@ -30,7 +32,9 @@ func TestMatchesSortMixedDimensions(t *testing.T) {
 	}
 	second := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0020",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0020",
+			},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
@@ -41,7 +45,9 @@ func TestMatchesSortMixedDimensions(t *testing.T) {
 	}
 	third := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0020",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0020",
+			},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
@@ -52,7 +58,9 @@ func TestMatchesSortMixedDimensions(t *testing.T) {
 	}
 	fourth := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0020",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0020",
+			},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
@@ -63,7 +71,9 @@ func TestMatchesSortMixedDimensions(t *testing.T) {
 	}
 	fifth := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0020",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0020",
+			},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
@@ -74,7 +84,9 @@ func TestMatchesSortMixedDimensions(t *testing.T) {
 	}
 	sixth := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0020",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0020",
+			},
 			Fix: vulnerability.Fix{
 				Versions: []string{"2.0.0", "1.0.0"},
 			},
@@ -88,7 +100,9 @@ func TestMatchesSortMixedDimensions(t *testing.T) {
 	}
 	seventh := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0020",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0020",
+			},
 			Fix: vulnerability.Fix{
 				Versions: []string{"2.0.1"},
 			},
@@ -102,7 +116,9 @@ func TestMatchesSortMixedDimensions(t *testing.T) {
 	}
 	eighth := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0020",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0020",
+			},
 			Fix: vulnerability.Fix{
 				Versions: []string{"3.0.0"},
 			},
@@ -117,7 +133,9 @@ func TestMatchesSortMixedDimensions(t *testing.T) {
 	}
 	ninth := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0020",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0020",
+			},
 			Fix: vulnerability.Fix{
 				Versions: []string{"3.0.0"},
 			},
@@ -144,7 +162,9 @@ func TestMatchesSortMixedDimensions(t *testing.T) {
 func TestMatchesSortByVulnerability(t *testing.T) {
 	first := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0010",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0010",
+			},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
@@ -155,7 +175,9 @@ func TestMatchesSortByVulnerability(t *testing.T) {
 	}
 	second := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0020",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0020",
+			},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
@@ -177,7 +199,9 @@ func TestMatchesSortByVulnerability(t *testing.T) {
 func TestMatches_AllByPkgID(t *testing.T) {
 	first := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0010",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0010",
+			},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
@@ -188,7 +212,9 @@ func TestMatches_AllByPkgID(t *testing.T) {
 	}
 	second := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0010",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0010",
+			},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
@@ -219,7 +245,9 @@ func TestMatches_AllByPkgID(t *testing.T) {
 func TestMatchesSortByPackage(t *testing.T) {
 	first := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0010",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0010",
+			},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
@@ -230,7 +258,9 @@ func TestMatchesSortByPackage(t *testing.T) {
 	}
 	second := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0010",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0010",
+			},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
@@ -252,7 +282,9 @@ func TestMatchesSortByPackage(t *testing.T) {
 func TestMatchesSortByPackageVersion(t *testing.T) {
 	first := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0010",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0010",
+			},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
@@ -263,7 +295,9 @@ func TestMatchesSortByPackageVersion(t *testing.T) {
 	}
 	second := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0010",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0010",
+			},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
@@ -285,7 +319,9 @@ func TestMatchesSortByPackageVersion(t *testing.T) {
 func TestMatchesSortByPackageType(t *testing.T) {
 	first := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0010",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0010",
+			},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
@@ -296,7 +332,9 @@ func TestMatchesSortByPackageType(t *testing.T) {
 	}
 	second := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-2020-0010",
+			Reference: vulnerability.Reference{
+				ID: "CVE-2020-0010",
+			},
 		},
 		Package: pkg.Package{
 			ID:      pkg.ID(uuid.NewString()),
@@ -356,8 +394,10 @@ func assertIgnoredMatchOrder(t *testing.T, expected, actual []IgnoredMatch) {
 func TestMatches_Diff(t *testing.T) {
 	a := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID:        "vuln-a",
-			Namespace: "name-a",
+			Reference: vulnerability.Reference{
+				ID:        "vuln-a",
+				Namespace: "name-a",
+			},
 		},
 		Package: pkg.Package{
 			ID: "package-a",
@@ -366,8 +406,10 @@ func TestMatches_Diff(t *testing.T) {
 
 	b := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID:        "vuln-b",
-			Namespace: "name-b",
+			Reference: vulnerability.Reference{
+				ID:        "vuln-b",
+				Namespace: "name-b",
+			},
 		},
 		Package: pkg.Package{
 			ID: "package-b",
@@ -376,8 +418,10 @@ func TestMatches_Diff(t *testing.T) {
 
 	c := Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID:        "vuln-c",
-			Namespace: "name-c",
+			Reference: vulnerability.Reference{
+				ID:        "vuln-c",
+				Namespace: "name-c",
+			},
 		},
 		Package: pkg.Package{
 			ID: "package-c",
@@ -421,8 +465,10 @@ func TestMatches_Add_Merge(t *testing.T) {
 	commonVuln := "CVE-2023-0001"
 	commonNamespace := "namespace1"
 	commonVulnerability := vulnerability.Vulnerability{
-		ID:        commonVuln,
-		Namespace: commonNamespace,
+		Reference: vulnerability.Reference{
+			ID:        commonVuln,
+			Namespace: commonNamespace,
+		},
 		Constraint: func() version.Constraint {
 			c, err := version.GetConstraint("< 1.0.0", version.SemanticFormat)
 			require.NoError(t, err)
@@ -522,8 +568,10 @@ func TestMatches_Add_Merge(t *testing.T) {
 			matches: []Match{
 				{
 					Vulnerability: vulnerability.Vulnerability{
-						ID:        commonVuln,
-						Namespace: commonNamespace,
+						Reference: vulnerability.Reference{
+							ID:        commonVuln,
+							Namespace: commonNamespace,
+						},
 						Constraint: func() version.Constraint { // different!
 							c, err := version.GetConstraint("< 3.2.12", version.SemanticFormat)
 							require.NoError(t, err)
@@ -568,8 +616,10 @@ func TestMatches_Add_Merge(t *testing.T) {
 			matches: []Match{
 				{
 					Vulnerability: vulnerability.Vulnerability{
-						ID:        commonVuln,
-						Namespace: commonNamespace,
+						Reference: vulnerability.Reference{
+							ID:        commonVuln,
+							Namespace: commonNamespace,
+						},
 						Constraint: func() version.Constraint { // different!
 							c, err := version.GetConstraint("< 3.2.12", version.SemanticFormat)
 							require.NoError(t, err)
@@ -595,8 +645,10 @@ func TestMatches_Add_Merge(t *testing.T) {
 				"pkg1": {
 					{
 						Vulnerability: vulnerability.Vulnerability{
-							ID:        commonVuln,
-							Namespace: commonNamespace,
+							Reference: vulnerability.Reference{
+								ID:        commonVuln,
+								Namespace: commonNamespace,
+							},
 							Constraint: func() version.Constraint { // different!
 								c, err := version.GetConstraint("< 3.2.12", version.SemanticFormat)
 								require.NoError(t, err)
diff --git a/grype/presenter/cyclonedx/vulnerability_test.go b/grype/presenter/cyclonedx/vulnerability_test.go
index 44f2b985..63f298f1 100644
--- a/grype/presenter/cyclonedx/vulnerability_test.go
+++ b/grype/presenter/cyclonedx/vulnerability_test.go
@@ -69,11 +69,11 @@ type metadataProvider struct {
 	cvss     []vulnerability.Cvss
 }
 
-func (m metadataProvider) GetMetadata(id, namespace string) (*vulnerability.Metadata, error) {
+func (m metadataProvider) VulnerabilityMetadata(ref vulnerability.Reference) (*vulnerability.Metadata, error) {
 	return &vulnerability.Metadata{
-		ID:          id,
+		ID:          ref.ID,
 		DataSource:  "",
-		Namespace:   namespace,
+		Namespace:   ref.Namespace,
 		Severity:    m.severity,
 		URLs:        nil,
 		Description: "",
diff --git a/grype/presenter/internal/test_helpers.go b/grype/presenter/internal/test_helpers.go
index 8052216d..0cd5f638 100644
--- a/grype/presenter/internal/test_helpers.go
+++ b/grype/presenter/internal/test_helpers.go
@@ -84,8 +84,10 @@ func generateMatches(t *testing.T, p1, p2 pkg.Package) match.Matches {
 		{
 
 			Vulnerability: vulnerability.Vulnerability{
-				ID:        "CVE-1999-0001",
-				Namespace: "source-1",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-1999-0001",
+					Namespace: "source-1",
+				},
 				Fix: vulnerability.Fix{
 					Versions: []string{"the-next-version"},
 					State:    vulnerability.FixStateFixed,
@@ -111,8 +113,10 @@ func generateMatches(t *testing.T, p1, p2 pkg.Package) match.Matches {
 		{
 
 			Vulnerability: vulnerability.Vulnerability{
-				ID:        "CVE-1999-0002",
-				Namespace: "source-2",
+				Reference: vulnerability.Reference{
+					ID:        "CVE-1999-0002",
+					Namespace: "source-2",
+				},
 			},
 			Package: p2,
 			Details: []match.Detail{
@@ -143,8 +147,10 @@ func generateIgnoredMatches(t *testing.T, p pkg.Package) []match.IgnoredMatch {
 		{
 			Match: match.Match{
 				Vulnerability: vulnerability.Vulnerability{
-					ID:        "CVE-1999-0001",
-					Namespace: "source-1",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-1999-0001",
+						Namespace: "source-1",
+					},
 				},
 				Package: p,
 				Details: []match.Detail{
@@ -168,8 +174,10 @@ func generateIgnoredMatches(t *testing.T, p pkg.Package) []match.IgnoredMatch {
 		{
 			Match: match.Match{
 				Vulnerability: vulnerability.Vulnerability{
-					ID:        "CVE-1999-0002",
-					Namespace: "source-2",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-1999-0002",
+						Namespace: "source-2",
+					},
 				},
 				Package: p,
 				Details: []match.Detail{
@@ -190,8 +198,10 @@ func generateIgnoredMatches(t *testing.T, p pkg.Package) []match.IgnoredMatch {
 		{
 			Match: match.Match{
 				Vulnerability: vulnerability.Vulnerability{
-					ID:        "CVE-1999-0004",
-					Namespace: "source-2",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-1999-0004",
+						Namespace: "source-2",
+					},
 				},
 				Package: p,
 				Details: []match.Detail{
diff --git a/grype/presenter/models/document_test.go b/grype/presenter/models/document_test.go
index 1cf48912..cedd73f4 100644
--- a/grype/presenter/models/document_test.go
+++ b/grype/presenter/models/document_test.go
@@ -33,7 +33,7 @@ func TestPackagesAreSorted(t *testing.T) {
 
 	var match1 = match.Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-1999-0003",
+			Reference: vulnerability.Reference{ID: "CVE-1999-0003"},
 		},
 		Package: pkg1,
 		Details: match.Details{
@@ -45,7 +45,7 @@ func TestPackagesAreSorted(t *testing.T) {
 
 	var match2 = match.Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-1999-0002",
+			Reference: vulnerability.Reference{ID: "CVE-1999-0002"},
 		},
 		Package: pkg1,
 		Details: match.Details{
@@ -57,7 +57,7 @@ func TestPackagesAreSorted(t *testing.T) {
 
 	var match3 = match.Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID: "CVE-1999-0001",
+			Reference: vulnerability.Reference{ID: "CVE-1999-0001"},
 		},
 		Package: pkg1,
 		Details: match.Details{
diff --git a/grype/presenter/sarif/presenter_test.go b/grype/presenter/sarif/presenter_test.go
index e2790fc9..3a682c47 100644
--- a/grype/presenter/sarif/presenter_test.go
+++ b/grype/presenter/sarif/presenter_test.go
@@ -347,13 +347,13 @@ func TestToSarifReport(t *testing.T) {
 
 type NilMetadataProvider struct{}
 
-func (m *NilMetadataProvider) GetMetadata(_, _ string) (*vulnerability.Metadata, error) {
+func (m *NilMetadataProvider) VulnerabilityMetadata(_ vulnerability.Reference) (*vulnerability.Metadata, error) {
 	return nil, nil
 }
 
 type MockMetadataProvider struct{}
 
-func (m *MockMetadataProvider) GetMetadata(id, namespace string) (*vulnerability.Metadata, error) {
+func (m *MockMetadataProvider) VulnerabilityMetadata(ref vulnerability.Reference) (*vulnerability.Metadata, error) {
 	cvss := func(id string, namespace string, scores ...float64) vulnerability.Metadata {
 		values := make([]vulnerability.Cvss, 0, len(scores))
 		for _, score := range scores {
@@ -375,7 +375,7 @@ func (m *MockMetadataProvider) GetMetadata(id, namespace string) (*vulnerability
 		cvss("2", "not-nvd", 3, 4),
 	}
 	for _, v := range values {
-		if v.ID == id && v.Namespace == namespace {
+		if v.ID == ref.ID && v.Namespace == ref.Namespace {
 			return &v, nil
 		}
 	}
@@ -387,8 +387,10 @@ func Test_cvssScoreWithNilMetadata(t *testing.T) {
 		metadataProvider: &NilMetadataProvider{},
 	}
 	score := pres.cvssScore(vulnerability.Vulnerability{
-		ID:        "id",
-		Namespace: "namespace",
+		Reference: vulnerability.Reference{
+			ID:        "id",
+			Namespace: "namespace",
+		},
 	})
 	assert.Equal(t, float64(-1), score)
 }
@@ -402,7 +404,9 @@ func Test_cvssScore(t *testing.T) {
 		{
 			name: "none",
 			vulnerability: vulnerability.Vulnerability{
-				ID: "4",
+				Reference: vulnerability.Reference{
+					ID: "4",
+				},
 				RelatedVulnerabilities: []vulnerability.Reference{
 					{
 						ID:        "7",
@@ -415,8 +419,10 @@ func Test_cvssScore(t *testing.T) {
 		{
 			name: "direct",
 			vulnerability: vulnerability.Vulnerability{
-				ID:        "2",
-				Namespace: "not-nvd",
+				Reference: vulnerability.Reference{
+					ID:        "2",
+					Namespace: "not-nvd",
+				},
 				RelatedVulnerabilities: []vulnerability.Reference{
 					{
 						ID:        "1",
@@ -429,8 +435,10 @@ func Test_cvssScore(t *testing.T) {
 		{
 			name: "related not nvd",
 			vulnerability: vulnerability.Vulnerability{
-				ID:        "1",
-				Namespace: "nvd:cpe",
+				Reference: vulnerability.Reference{
+					ID:        "1",
+					Namespace: "nvd:cpe",
+				},
 				RelatedVulnerabilities: []vulnerability.Reference{
 					{
 						ID:        "1",
@@ -447,8 +455,10 @@ func Test_cvssScore(t *testing.T) {
 		{
 			name: "related nvd",
 			vulnerability: vulnerability.Vulnerability{
-				ID:        "4",
-				Namespace: "not-nvd",
+				Reference: vulnerability.Reference{
+					ID:        "4",
+					Namespace: "not-nvd",
+				},
 				RelatedVulnerabilities: []vulnerability.Reference{
 					{
 						ID:        "1",
diff --git a/grype/presenter/table/presenter_test.go b/grype/presenter/table/presenter_test.go
index ab8b2692..6ec21530 100644
--- a/grype/presenter/table/presenter_test.go
+++ b/grype/presenter/table/presenter_test.go
@@ -27,8 +27,10 @@ func TestCreateRow(t *testing.T) {
 	}
 	match1 := match.Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID:        "CVE-1999-0001",
-			Namespace: "source-1",
+			Reference: vulnerability.Reference{
+				ID:        "CVE-1999-0001",
+				Namespace: "source-1",
+			},
 		},
 		Package: pkg1,
 		Details: []match.Detail{
diff --git a/grype/vex/processor_test.go b/grype/vex/processor_test.go
index 21cc8860..86a7d0d1 100644
--- a/grype/vex/processor_test.go
+++ b/grype/vex/processor_test.go
@@ -42,8 +42,10 @@ func TestProcessor_ApplyVEX(t *testing.T) {
 
 	libCryptoCVE_2023_3817 := match.Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID:        "CVE-2023-3817",
-			Namespace: "alpine:distro:alpine:3.17",
+			Reference: vulnerability.Reference{
+				ID:        "CVE-2023-3817",
+				Namespace: "alpine:distro:alpine:3.17",
+			},
 			Fix: vulnerability.Fix{
 				Versions: []string{"3.0.10-r0"},
 				State:    vulnerability.FixStateFixed,
@@ -54,8 +56,10 @@ func TestProcessor_ApplyVEX(t *testing.T) {
 
 	libCryptoCVE_2023_1255 := match.Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID:        "CVE-2023-1255",
-			Namespace: "alpine:distro:alpine:3.17",
+			Reference: vulnerability.Reference{
+				ID:        "CVE-2023-1255",
+				Namespace: "alpine:distro:alpine:3.17",
+			},
 			Fix: vulnerability.Fix{
 				Versions: []string{"3.0.8-r4"},
 				State:    vulnerability.FixStateFixed,
@@ -66,8 +70,10 @@ func TestProcessor_ApplyVEX(t *testing.T) {
 
 	libCryptoCVE_2023_2975 := match.Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID:        "CVE-2023-2975",
-			Namespace: "alpine:distro:alpine:3.17",
+			Reference: vulnerability.Reference{
+				ID:        "CVE-2023-2975",
+				Namespace: "alpine:distro:alpine:3.17",
+			},
 			Fix: vulnerability.Fix{
 				Versions: []string{"3.0.9-r2"},
 				State:    vulnerability.FixStateFixed,
diff --git a/grype/vulnerability_matcher_test.go b/grype/vulnerability_matcher_test.go
index 54608b26..d63fb728 100644
--- a/grype/vulnerability_matcher_test.go
+++ b/grype/vulnerability_matcher_test.go
@@ -11,17 +11,16 @@ import (
 	"github.com/wagoodman/go-partybus"
 
 	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/matcher"
+	"github.com/anchore/grype/grype/db/v5/matcher/ruby"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/distro"
 	"github.com/anchore/grype/grype/event"
 	"github.com/anchore/grype/grype/event/monitor"
 	"github.com/anchore/grype/grype/grypeerr"
 	"github.com/anchore/grype/grype/match"
-	"github.com/anchore/grype/grype/matcher"
-	"github.com/anchore/grype/grype/matcher/ruby"
 	"github.com/anchore/grype/grype/pkg"
 	"github.com/anchore/grype/grype/pkg/qualifier"
-	"github.com/anchore/grype/grype/search"
-	"github.com/anchore/grype/grype/store"
 	"github.com/anchore/grype/grype/version"
 	"github.com/anchore/grype/grype/vex"
 	"github.com/anchore/grype/grype/vulnerability"
@@ -225,8 +224,10 @@ func Test_HasSeverityAtOrAbove(t *testing.T) {
 	matches := match.NewMatches()
 	matches.Add(match.Match{
 		Vulnerability: vulnerability.Vulnerability{
-			ID:        "CVE-2014-fake-1",
-			Namespace: "debian:distro:debian:8",
+			Reference: vulnerability.Reference{
+				ID:        "CVE-2014-fake-1",
+				Namespace: "debian:distro:debian:8",
+			},
 		},
 		Package: thePkg,
 		Details: match.Details{
@@ -294,10 +295,10 @@ func TestVulnerabilityMatcher_FindMatches(t *testing.T) {
 	mkStr := newMockStore(defaultStubFn)
 	vp, err := v5.NewVulnerabilityProvider(mkStr)
 	require.NoError(t, err)
-	str := store.Store{
-		Provider:          vp,
-		MetadataProvider:  v5.NewVulnerabilityMetadataProvider(mkStr),
-		ExclusionProvider: v5.NewMatchExclusionProvider(mkStr),
+	str := v5.ProviderStore{
+		VulnerabilityProvider:         vp,
+		VulnerabilityMetadataProvider: v5.NewVulnerabilityMetadataProvider(mkStr),
+		ExclusionProvider:             v5.NewMatchExclusionProvider(mkStr),
 	}
 
 	neutron2013Pkg := pkg.Package{
@@ -327,7 +328,7 @@ func TestVulnerabilityMatcher_FindMatches(t *testing.T) {
 	}
 
 	type fields struct {
-		Store          store.Store
+		Store          v5.ProviderStore
 		Matchers       []matcher.Matcher
 		IgnoreRules    []match.IgnoreRule
 		FailSeverity   *vulnerability.Severity
@@ -390,10 +391,12 @@ func TestVulnerabilityMatcher_FindMatches(t *testing.T) {
 			wantMatches: match.NewMatches(
 				match.Match{
 					Vulnerability: vulnerability.Vulnerability{
-						PackageName:       "neutron",
-						Constraint:        version.MustGetConstraint("< 2014.1.3-6", version.DebFormat),
-						ID:                "CVE-2014-fake-1",
-						Namespace:         "debian:distro:debian:8",
+						PackageName: "neutron",
+						Constraint:  version.MustGetConstraint("< 2014.1.3-6", version.DebFormat),
+						Reference: vulnerability.Reference{
+							ID:        "CVE-2014-fake-1",
+							Namespace: "debian:distro:debian:8",
+						},
 						PackageQualifiers: []qualifier.Qualifier{},
 						CPEs:              []cpe.CPE{},
 						Advisories:        []vulnerability.Advisory{},
@@ -444,10 +447,12 @@ func TestVulnerabilityMatcher_FindMatches(t *testing.T) {
 			wantMatches: match.NewMatches(
 				match.Match{
 					Vulnerability: vulnerability.Vulnerability{
-						PackageName:       "neutron",
-						Constraint:        version.MustGetConstraint("< 2014.1.3-6", version.DebFormat),
-						ID:                "CVE-2014-fake-1",
-						Namespace:         "debian:distro:debian:8",
+						PackageName: "neutron",
+						Constraint:  version.MustGetConstraint("< 2014.1.3-6", version.DebFormat),
+						Reference: vulnerability.Reference{
+							ID:        "CVE-2014-fake-1",
+							Namespace: "debian:distro:debian:8",
+						},
 						PackageQualifiers: []qualifier.Qualifier{},
 						CPEs:              []cpe.CPE{},
 						Advisories:        []vulnerability.Advisory{},
@@ -525,10 +530,12 @@ func TestVulnerabilityMatcher_FindMatches(t *testing.T) {
 					},
 					Match: match.Match{
 						Vulnerability: vulnerability.Vulnerability{
-							PackageName:       "neutron",
-							Constraint:        version.MustGetConstraint("< 2014.1.3-6", version.DebFormat),
-							ID:                "CVE-2014-fake-1",
-							Namespace:         "debian:distro:debian:8",
+							PackageName: "neutron",
+							Constraint:  version.MustGetConstraint("< 2014.1.3-6", version.DebFormat),
+							Reference: vulnerability.Reference{
+								ID:        "CVE-2014-fake-1",
+								Namespace: "debian:distro:debian:8",
+							},
 							PackageQualifiers: []qualifier.Qualifier{},
 							CPEs:              []cpe.CPE{},
 							Advisories:        []vulnerability.Advisory{},
@@ -576,8 +583,10 @@ func TestVulnerabilityMatcher_FindMatches(t *testing.T) {
 					Vulnerability: vulnerability.Vulnerability{
 						PackageName: "activerecord",
 						Constraint:  version.MustGetConstraint("< 3.7.6", version.UnknownFormat),
-						ID:          "CVE-2014-fake-3",
-						Namespace:   "nvd:cpe",
+						Reference: vulnerability.Reference{
+							ID:        "CVE-2014-fake-3",
+							Namespace: "nvd:cpe",
+						},
 						CPEs: []cpe.CPE{
 							mustCPE("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:rails:*:*"),
 						},
@@ -614,8 +623,10 @@ func TestVulnerabilityMatcher_FindMatches(t *testing.T) {
 					Vulnerability: vulnerability.Vulnerability{
 						PackageName: "activerecord",
 						Constraint:  version.MustGetConstraint("< 3.7.6", version.UnknownFormat),
-						ID:          "GHSA-2014-fake-3",
-						Namespace:   "github:language:ruby",
+						Reference: vulnerability.Reference{
+							ID:        "GHSA-2014-fake-3",
+							Namespace: "github:language:ruby",
+						},
 						RelatedVulnerabilities: []vulnerability.Reference{
 							{
 								ID:        "CVE-2014-fake-3",
@@ -672,8 +683,10 @@ func TestVulnerabilityMatcher_FindMatches(t *testing.T) {
 					Vulnerability: vulnerability.Vulnerability{
 						PackageName: "activerecord",
 						Constraint:  version.MustGetConstraint("< 3.7.6", version.UnknownFormat),
-						ID:          "CVE-2014-fake-3",
-						Namespace:   "nvd:cpe",
+						Reference: vulnerability.Reference{
+							ID:        "CVE-2014-fake-3",
+							Namespace: "nvd:cpe",
+						},
 						CPEs: []cpe.CPE{
 							mustCPE("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:rails:*:*"),
 						},
@@ -759,8 +772,10 @@ func TestVulnerabilityMatcher_FindMatches(t *testing.T) {
 					Vulnerability: vulnerability.Vulnerability{
 						PackageName: "activerecord",
 						Constraint:  version.MustGetConstraint("< 3.7.6", version.UnknownFormat),
-						ID:          "CVE-2014-fake-3",
-						Namespace:   "nvd:cpe",
+						Reference: vulnerability.Reference{
+							ID:        "CVE-2014-fake-3",
+							Namespace: "nvd:cpe",
+						},
 						CPEs: []cpe.CPE{
 							mustCPE("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:rails:*:*"),
 						},
@@ -799,10 +814,12 @@ func TestVulnerabilityMatcher_FindMatches(t *testing.T) {
 				{
 					Match: match.Match{
 						Vulnerability: vulnerability.Vulnerability{
-							PackageName:       "activerecord",
-							Constraint:        version.MustGetConstraint("< 3.7.6", version.UnknownFormat),
-							ID:                "CVE-2014-fake-3",
-							Namespace:         "nvd:cpe",
+							PackageName: "activerecord",
+							Constraint:  version.MustGetConstraint("< 3.7.6", version.UnknownFormat),
+							Reference: vulnerability.Reference{
+								ID:        "CVE-2014-fake-3",
+								Namespace: "nvd:cpe",
+							},
 							CPEs:              []cpe.CPE{},
 							PackageQualifiers: []qualifier.Qualifier{},
 							Advisories:        []vulnerability.Advisory{},
@@ -870,8 +887,10 @@ func TestVulnerabilityMatcher_FindMatches(t *testing.T) {
 						Vulnerability: vulnerability.Vulnerability{
 							PackageName: "activerecord",
 							Constraint:  version.MustGetConstraint("< 3.7.6", version.UnknownFormat),
-							ID:          "CVE-2014-fake-3",
-							Namespace:   "nvd:cpe",
+							Reference: vulnerability.Reference{
+								ID:        "CVE-2014-fake-3",
+								Namespace: "nvd:cpe",
+							},
 							CPEs: []cpe.CPE{
 								mustCPE("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:rails:*:*"),
 							},
@@ -919,10 +938,12 @@ func TestVulnerabilityMatcher_FindMatches(t *testing.T) {
 					},
 					Match: match.Match{
 						Vulnerability: vulnerability.Vulnerability{
-							PackageName:       "activerecord",
-							Constraint:        version.MustGetConstraint("< 3.7.6", version.UnknownFormat),
-							ID:                "CVE-2014-fake-3",
-							Namespace:         "nvd:cpe",
+							PackageName: "activerecord",
+							Constraint:  version.MustGetConstraint("< 3.7.6", version.UnknownFormat),
+							Reference: vulnerability.Reference{
+								ID:        "CVE-2014-fake-3",
+								Namespace: "nvd:cpe",
+							},
 							CPEs:              []cpe.CPE{},
 							PackageQualifiers: []qualifier.Qualifier{},
 							Advisories:        []vulnerability.Advisory{},
@@ -980,8 +1001,10 @@ func TestVulnerabilityMatcher_FindMatches(t *testing.T) {
 					Vulnerability: vulnerability.Vulnerability{
 						PackageName: "activerecord",
 						Constraint:  version.MustGetConstraint("< 3.7.6", version.UnknownFormat),
-						ID:          "GHSA-2014-fake-3",
-						Namespace:   "github:language:ruby",
+						Reference: vulnerability.Reference{
+							ID:        "GHSA-2014-fake-3",
+							Namespace: "github:language:ruby",
+						},
 						RelatedVulnerabilities: []vulnerability.Reference{
 							{
 								ID:        "CVE-2014-fake-3",
@@ -1022,8 +1045,10 @@ func TestVulnerabilityMatcher_FindMatches(t *testing.T) {
 						Vulnerability: vulnerability.Vulnerability{
 							PackageName: "activerecord",
 							Constraint:  version.MustGetConstraint("< 3.7.6", version.UnknownFormat),
-							ID:          "CVE-2014-fake-3",
-							Namespace:   "nvd:cpe",
+							Reference: vulnerability.Reference{
+								ID:        "CVE-2014-fake-3",
+								Namespace: "nvd:cpe",
+							},
 							CPEs: []cpe.CPE{
 								mustCPE("cpe:2.3:*:activerecord:activerecord:*:*:*:*:*:rails:*:*"),
 							},
@@ -1267,17 +1292,17 @@ func Test_indexFalsePositivesByLocation(t *testing.T) {
 	}
 }
 
-func createMockStore(t *testing.T, fn mockStoreStubFn) store.Store {
+func createMockStore(t *testing.T, fn mockStoreStubFn) v5.ProviderStore {
 	t.Helper()
 
 	mkStr := newMockStore(fn)
 	vp, err := v5.NewVulnerabilityProvider(mkStr)
 	require.NoError(t, err)
 
-	return store.Store{
-		Provider:          vp,
-		MetadataProvider:  v5.NewVulnerabilityMetadataProvider(mkStr),
-		ExclusionProvider: v5.NewMatchExclusionProvider(mkStr),
+	return v5.ProviderStore{
+		VulnerabilityProvider:         vp,
+		VulnerabilityMetadataProvider: v5.NewVulnerabilityMetadataProvider(mkStr),
+		ExclusionProvider:             v5.NewMatchExclusionProvider(mkStr),
 	}
 }
 
@@ -1304,7 +1329,7 @@ func Test_filterMatchesUsingDistroFalsePositives(t *testing.T) {
 						Name:      "crane",
 						Locations: file.NewLocationSet(file.NewLocation("/usr/bin/crane")),
 					},
-					Vulnerability: vulnerability.Vulnerability{ID: "CVE-2014-fake-3"},
+					Vulnerability: vulnerability.Vulnerability{Reference: vulnerability.Reference{ID: "CVE-2014-fake-3"}},
 				},
 			},
 			fpIndex: map[string][]string{
@@ -1320,7 +1345,7 @@ func Test_filterMatchesUsingDistroFalsePositives(t *testing.T) {
 						Name:      "crane",
 						Locations: file.NewLocationSet(file.NewLocation("/usr/bin/crane")),
 					},
-					Vulnerability: vulnerability.Vulnerability{ID: "CVE-2014-fake-3"},
+					Vulnerability: vulnerability.Vulnerability{Reference: vulnerability.Reference{ID: "CVE-2014-fake-3"}},
 				},
 			},
 			fpIndex: map[string][]string{
@@ -1332,7 +1357,7 @@ func Test_filterMatchesUsingDistroFalsePositives(t *testing.T) {
 						Name:      "crane",
 						Locations: file.NewLocationSet(file.NewLocation("/usr/bin/crane")),
 					},
-					Vulnerability: vulnerability.Vulnerability{ID: "CVE-2014-fake-3"},
+					Vulnerability: vulnerability.Vulnerability{Reference: vulnerability.Reference{ID: "CVE-2014-fake-3"}},
 				},
 			},
 		},
@@ -1344,7 +1369,7 @@ func Test_filterMatchesUsingDistroFalsePositives(t *testing.T) {
 						Name:      "crane",
 						Locations: file.NewLocationSet(file.NewLocation("/usr/bin/crane")),
 					},
-					Vulnerability: vulnerability.Vulnerability{ID: "CVE-2014-fake-3"},
+					Vulnerability: vulnerability.Vulnerability{Reference: vulnerability.Reference{ID: "CVE-2014-fake-3"}},
 				},
 			},
 			fpIndex: map[string][]string{
@@ -1356,7 +1381,7 @@ func Test_filterMatchesUsingDistroFalsePositives(t *testing.T) {
 						Name:      "crane",
 						Locations: file.NewLocationSet(file.NewLocation("/usr/bin/crane")),
 					},
-					Vulnerability: vulnerability.Vulnerability{ID: "CVE-2014-fake-3"},
+					Vulnerability: vulnerability.Vulnerability{Reference: vulnerability.Reference{ID: "CVE-2014-fake-3"}},
 				},
 			},
 		},
@@ -1368,7 +1393,7 @@ func Test_filterMatchesUsingDistroFalsePositives(t *testing.T) {
 						Name:      "crane",
 						Locations: file.NewLocationSet(file.NewLocation("/usr/bin/crane")),
 					},
-					Vulnerability: vulnerability.Vulnerability{ID: "CVE-2014-fake-3"},
+					Vulnerability: vulnerability.Vulnerability{Reference: vulnerability.Reference{ID: "CVE-2014-fake-3"}},
 				},
 			},
 			fpIndex: map[string][]string{},
@@ -1378,7 +1403,7 @@ func Test_filterMatchesUsingDistroFalsePositives(t *testing.T) {
 						Name:      "crane",
 						Locations: file.NewLocationSet(file.NewLocation("/usr/bin/crane")),
 					},
-					Vulnerability: vulnerability.Vulnerability{ID: "CVE-2014-fake-3"},
+					Vulnerability: vulnerability.Vulnerability{Reference: vulnerability.Reference{ID: "CVE-2014-fake-3"}},
 				},
 			},
 		},
diff --git a/test/integration/match_by_image_test.go b/test/integration/match_by_image_test.go
index 463de48b..d6dd9934 100644
--- a/test/integration/match_by_image_test.go
+++ b/test/integration/match_by_image_test.go
@@ -12,19 +12,18 @@ import (
 
 	"github.com/anchore/grype/grype"
 	v5 "github.com/anchore/grype/grype/db/v5"
+	"github.com/anchore/grype/grype/db/v5/matcher"
+	"github.com/anchore/grype/grype/db/v5/matcher/dotnet"
+	"github.com/anchore/grype/grype/db/v5/matcher/golang"
+	"github.com/anchore/grype/grype/db/v5/matcher/java"
+	"github.com/anchore/grype/grype/db/v5/matcher/javascript"
+	"github.com/anchore/grype/grype/db/v5/matcher/python"
+	"github.com/anchore/grype/grype/db/v5/matcher/ruby"
+	"github.com/anchore/grype/grype/db/v5/matcher/rust"
+	"github.com/anchore/grype/grype/db/v5/matcher/stock"
+	"github.com/anchore/grype/grype/db/v5/search"
 	"github.com/anchore/grype/grype/match"
-	"github.com/anchore/grype/grype/matcher"
-	"github.com/anchore/grype/grype/matcher/dotnet"
-	"github.com/anchore/grype/grype/matcher/golang"
-	"github.com/anchore/grype/grype/matcher/java"
-	"github.com/anchore/grype/grype/matcher/javascript"
-	"github.com/anchore/grype/grype/matcher/python"
-	"github.com/anchore/grype/grype/matcher/ruby"
-	"github.com/anchore/grype/grype/matcher/rust"
-	"github.com/anchore/grype/grype/matcher/stock"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/search"
-	"github.com/anchore/grype/grype/store"
 	"github.com/anchore/grype/grype/vex"
 	"github.com/anchore/grype/grype/vulnerability"
 	"github.com/anchore/grype/internal/stringutil"
@@ -765,10 +764,10 @@ func TestMatchByImage(t *testing.T) {
 			require.NoError(t, err)
 			mp := v5.NewVulnerabilityMetadataProvider(theStore)
 			ep := v5.NewMatchExclusionProvider(theStore)
-			str := store.Store{
-				Provider:          vp,
-				MetadataProvider:  mp,
-				ExclusionProvider: ep,
+			str := v5.ProviderStore{
+				VulnerabilityProvider:         vp,
+				VulnerabilityMetadataProvider: mp,
+				ExclusionProvider:             ep,
 			}
 
 			actualResults := grype.FindVulnerabilitiesForPackage(str, s.Artifacts.LinuxDistribution, matchers, pkg.FromCollection(s.Artifacts.Packages, pkg.SynthesisConfig{}))
@@ -852,8 +851,10 @@ func testIgnoredMatches() []match.IgnoredMatch {
 		{
 			Match: match.Match{
 				Vulnerability: vulnerability.Vulnerability{
-					ID:        "CVE-alpine-libvncserver",
-					Namespace: "alpine:distro:alpine:3.12",
+					Reference: vulnerability.Reference{
+						ID:        "CVE-alpine-libvncserver",
+						Namespace: "alpine:distro:alpine:3.12",
+					},
 				},
 				Package: pkg.Package{
 					ID:       "44fa3691ae360cac",
diff --git a/test/integration/match_by_sbom_document_test.go b/test/integration/match_by_sbom_document_test.go
index 79eff543..cdffe976 100644
--- a/test/integration/match_by_sbom_document_test.go
+++ b/test/integration/match_by_sbom_document_test.go
@@ -14,7 +14,6 @@ import (
 	v5 "github.com/anchore/grype/grype/db/v5"
 	"github.com/anchore/grype/grype/match"
 	"github.com/anchore/grype/grype/pkg"
-	"github.com/anchore/grype/grype/store"
 	"github.com/anchore/syft/syft/source"
 )
 
@@ -82,10 +81,10 @@ func TestMatchBySBOMDocument(t *testing.T) {
 			require.NoError(t, err)
 			mp := v5.NewVulnerabilityMetadataProvider(mkStr)
 			ep := v5.NewMatchExclusionProvider(mkStr)
-			str := store.Store{
-				Provider:          vp,
-				MetadataProvider:  mp,
-				ExclusionProvider: ep,
+			str := v5.ProviderStore{
+				VulnerabilityProvider:         vp,
+				VulnerabilityMetadataProvider: mp,
+				ExclusionProvider:             ep,
 			}
 			matches, _, _, err := grype.FindVulnerabilities(str, fmt.Sprintf("sbom:%s", test.fixture), source.SquashedScope, nil)
 			assert.NoError(t, err)