From e0595644b634478001bfd0f417deb2a3ed24e303 Mon Sep 17 00:00:00 2001 From: Will Murphy Date: Fri, 25 Apr 2025 08:04:08 -0400 Subject: [PATCH 1/2] fix: only fallback to language if language is non-blank Signed-off-by: Will Murphy --- grype/db/v6/vulnerability_provider.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/grype/db/v6/vulnerability_provider.go b/grype/db/v6/vulnerability_provider.go index a655155d7bb..6e012daac38 100644 --- a/grype/db/v6/vulnerability_provider.go +++ b/grype/db/v6/vulnerability_provider.go @@ -222,11 +222,20 @@ func (vp vulnerabilityProvider) FindVulnerabilities(criteria ...vulnerability.Cr pkgSpec = &PackageSpecifier{} } // the v6 store normalizes ecosystems around the syft package type, so that field is preferred - if c.PackageType != "" && c.PackageType != syftPkg.UnknownPkg { - pkgSpec.Ecosystem = string(c.PackageType) + switch { + case c.PackageType != "" && c.PackageType != syftPkg.UnknownPkg: + // prefer to match by a non-blank, known package type pkgType = c.PackageType - } else { + pkgSpec.Ecosystem = string(c.PackageType) + case c.Language != "": + // if there's no known package type, but there is a non-blank language + // try that. pkgSpec.Ecosystem = string(c.Language) + case c.PackageType == syftPkg.UnknownPkg: + // if language is blank, and package type is explicitly "UnknownPkg" and not + // just blank, use that. + pkgType = c.PackageType + pkgSpec.Ecosystem = string(c.PackageType) } applied = true case *search.IDCriteria: From b9f4432b7a86d0935b1d9b978485401aba59edd4 Mon Sep 17 00:00:00 2001 From: Will Murphy Date: Fri, 25 Apr 2025 09:45:33 -0400 Subject: [PATCH 2/2] test: add units for known pkg, unknown language, etc Signed-off-by: Will Murphy --- grype/db/v6/vulnerability_provider_test.go | 53 ++++++++++++++++++++-- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/grype/db/v6/vulnerability_provider_test.go b/grype/db/v6/vulnerability_provider_test.go index 3b5ebfbf313..73b451ced82 100644 --- a/grype/db/v6/vulnerability_provider_test.go +++ b/grype/db/v6/vulnerability_provider_test.go @@ -305,11 +305,56 @@ func Test_FindVulnerabilitiesByByID(t *testing.T) { } func Test_FindVulnerabilitiesByEcosystem_UnknownPackageType(t *testing.T) { + tests := []struct { + name string + packageName string + packageType syftPkg.Type + language syftPkg.Language + expectedIDs []string + }{ + { + name: "known package type", + packageName: "Newtonsoft.Json", + packageType: syftPkg.DotnetPkg, + language: syftPkg.Java, // deliberately wrong to prove we're using package type + expectedIDs: []string{"GHSA-5crp-9r3c-p9vr"}, + }, + { + name: "unknown package type, known language", + packageName: "Newtonsoft.Json", + packageType: syftPkg.UnknownPkg, + language: syftPkg.Dotnet, + expectedIDs: []string{"GHSA-5crp-9r3c-p9vr"}, + }, + { + name: "unknown package type, unknown language", + packageName: "Newtonsoft.Json", + packageType: syftPkg.UnknownPkg, + language: syftPkg.UnknownLanguage, + // The vuln GHSA-5crp-9r3c-p9vr is specifically associated + // with the dotnet ecosystem, so it should not be returned here. + // In a real search for UnknownPkg + UnknownLanguage, there should + // be a separate search.ByCPE run that _does_ return it. + expectedIDs: []string{}, + }, + } provider := testVulnerabilityProvider(t) - actual, err := provider.FindVulnerabilities(search.ByEcosystem(syftPkg.Dotnet, syftPkg.UnknownPkg)) - require.NoError(t, err) - require.NotEmpty(t, actual) - require.Equal(t, actual[0].Reference.ID, "GHSA-5crp-9r3c-p9vr") + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + actual, err := provider.FindVulnerabilities( + search.ByEcosystem(test.language, test.packageType), + search.ByPackageName(test.packageName), + ) + require.NoError(t, err) + actualIDs := make([]string, len(actual)) + for idx, vuln := range actual { + actualIDs[idx] = vuln.ID + } + if d := cmp.Diff(test.expectedIDs, actualIDs); d != "" { + t.Errorf("diff: %+v", d) + } + }) + } } func Test_DataSource(t *testing.T) {