diff --git a/syft/pkg/cataloger/internal/cpegenerate/generate.go b/syft/pkg/cataloger/internal/cpegenerate/generate.go index 44f3606bd..097cf4e32 100644 --- a/syft/pkg/cataloger/internal/cpegenerate/generate.go +++ b/syft/pkg/cataloger/internal/cpegenerate/generate.go @@ -184,9 +184,13 @@ func FromPackageAttributes(p pkg.Package) []cpe.CPE { } func candidateTargetSw(p pkg.Package) []string { - if p.Type == pkg.WordpressPluginPkg { + switch p.Type { + case pkg.WordpressPluginPkg: return []string{"wordpress"} + case pkg.RustPkg: + return []string{"rust"} } + return []string{cpe.Any} } @@ -217,6 +221,50 @@ func candidateVendors(p pkg.Package) []string { } } + vendors = candidateVendorsByType(p, vendors) + + if p.Type == pkg.BinaryPkg && endsWithNumber(p.Name) { + // add binary package digit-suffix variations (e.g. Qt5 -> Qt) + addBinaryPackageDigitVariations(vendors) + } + + // We should no longer be generating vendor candidates with these values ["" and "*"] + // (since CPEs will match any other value) + vendors.removeByValue("") + vendors.removeByValue("*") + + // try swapping hyphens for underscores, vice versa, and removing separators altogether + addDelimiterVariations(vendors) + + // rust vendor name needs to be added after the `addDelimiterVariations` call as `-project` suffix is used otherwise + if p.Language == pkg.Rust { + vendors.addValue(p.Name + "_project") + } + + // generate sub-selections of each candidate based on separators (e.g. jenkins-ci -> [jenkins, jenkins-ci]) + addAllSubSelections(vendors) + + // add more candidates based on the package info for each vendor candidate + for _, vendor := range vendors.uniqueValues() { + vendors.addValue(findAdditionalVendors(defaultCandidateAdditions, p.Type, p.Name, vendor)...) + } + + // remove known mis + vendors.removeByValue(findVendorsToRemove(defaultCandidateRemovals, p.Type, p.Name)...) + + uniqueVendors := vendors.uniqueValues() + + // if any known vendor was detected, pick that one. + for _, vendor := range uniqueVendors { + if knownVendors.Has(vendor) { + return []string{vendor} + } + } + + return uniqueVendors +} + +func candidateVendorsByType(p pkg.Package, vendors fieldCandidateSet) fieldCandidateSet { switch p.Metadata.(type) { case pkg.DotnetDepsEntry, pkg.DotnetPackagesLockEntry, pkg.DotnetPortableExecutableEntry: vendors.clear() @@ -240,41 +288,7 @@ func candidateVendors(p pkg.Package) []string { vendors.clear() vendors.union(candidateVendorsForWordpressPlugin(p)) } - - if p.Type == pkg.BinaryPkg && endsWithNumber(p.Name) { - // add binary package digit-suffix variations (e.g. Qt5 -> Qt) - addBinaryPackageDigitVariations(vendors) - } - - // We should no longer be generating vendor candidates with these values ["" and "*"] - // (since CPEs will match any other value) - vendors.removeByValue("") - vendors.removeByValue("*") - - // try swapping hyphens for underscores, vice versa, and removing separators altogether - addDelimiterVariations(vendors) - - // generate sub-selections of each candidate based on separators (e.g. jenkins-ci -> [jenkins, jenkins-ci]) - addAllSubSelections(vendors) - - // add more candidates based on the package info for each vendor candidate - for _, vendor := range vendors.uniqueValues() { - vendors.addValue(findAdditionalVendors(defaultCandidateAdditions, p.Type, p.Name, vendor)...) - } - - // remove known mis - vendors.removeByValue(findVendorsToRemove(defaultCandidateRemovals, p.Type, p.Name)...) - - uniqueVendors := vendors.uniqueValues() - - // if any known vendor was detected, pick that one. - for _, vendor := range uniqueVendors { - if knownVendors.Has(vendor) { - return []string{vendor} - } - } - - return uniqueVendors + return vendors } func candidateProducts(p pkg.Package) []string { diff --git a/syft/pkg/cataloger/internal/cpegenerate/generate_test.go b/syft/pkg/cataloger/internal/cpegenerate/generate_test.go index 890d60170..704468780 100644 --- a/syft/pkg/cataloger/internal/cpegenerate/generate_test.go +++ b/syft/pkg/cataloger/internal/cpegenerate/generate_test.go @@ -855,6 +855,25 @@ func TestGeneratePackageCPEs(t *testing.T) { }, expected: []string{}, }, + { + name: "rust package", + p: pkg.Package{ + Name: "rust-package", + Version: "0.5.0", + Type: pkg.RustPkg, + Language: pkg.Rust, + }, + expected: []string{ + "cpe:2.3:a:rust-package_project:rust-package:0.5.0:*:*:*:*:rust:*:*", + "cpe:2.3:a:rust-package_project:rust_package:0.5.0:*:*:*:*:rust:*:*", + "cpe:2.3:a:rust-package:rust-package:0.5.0:*:*:*:*:rust:*:*", + "cpe:2.3:a:rust-package:rust_package:0.5.0:*:*:*:*:rust:*:*", + "cpe:2.3:a:rust:rust-package:0.5.0:*:*:*:*:rust:*:*", + "cpe:2.3:a:rust:rust_package:0.5.0:*:*:*:*:rust:*:*", + "cpe:2.3:a:rust_package:rust-package:0.5.0:*:*:*:*:rust:*:*", + "cpe:2.3:a:rust_package:rust_package:0.5.0:*:*:*:*:rust:*:*", + }, + }, } for _, test := range tests {