mirror of
https://github.com/anchore/syft.git
synced 2025-11-18 08:53:15 +01:00
feat: support multiple known CPEs in index (#2813)
It is possible that a given package has multiple known "official" CPEs active in the dictionary at once, so the index should support a slice of CPE strings per package Signed-off-by: Weston Steimel <commits@weston.slmail.me>
This commit is contained in:
parent
f2fc10aa86
commit
9604e3dc9c
@ -111,10 +111,10 @@ func NewPackageTask(cfg CatalogingFactoryConfig, c pkg.Cataloger, tags ...string
|
|||||||
if cfg.DataGenerationConfig.GenerateCPEs {
|
if cfg.DataGenerationConfig.GenerateCPEs {
|
||||||
// generate CPEs (note: this is excluded from package ID, so is safe to mutate)
|
// generate CPEs (note: this is excluded from package ID, so is safe to mutate)
|
||||||
// we might have binary classified CPE already with the package so we want to append here
|
// we might have binary classified CPE already with the package so we want to append here
|
||||||
dictionaryCPE, ok := cpe.DictionaryFind(p)
|
dictionaryCPEs, ok := cpe.DictionaryFind(p)
|
||||||
if ok {
|
if ok {
|
||||||
log.Tracef("used CPE dictionary to find CPE for %s package %q: %s", p.Type, p.Name, dictionaryCPE.Attributes.BindToFmtString())
|
log.Tracef("used CPE dictionary to find CPEs for %s package %q: %s", p.Type, p.Name, dictionaryCPEs)
|
||||||
p.CPEs = append(p.CPEs, dictionaryCPE)
|
p.CPEs = append(p.CPEs, dictionaryCPEs...)
|
||||||
} else {
|
} else {
|
||||||
p.CPEs = append(p.CPEs, cpe.Generate(p)...)
|
p.CPEs = append(p.CPEs, cpe.Generate(p)...)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,6 @@ func Generate(p pkg.Package) []cpe.CPE {
|
|||||||
return cpegenerate.FromPackageAttributes(p)
|
return cpegenerate.FromPackageAttributes(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DictionaryFind(p pkg.Package) (cpe.CPE, bool) {
|
func DictionaryFind(p pkg.Package) ([]cpe.CPE, bool) {
|
||||||
return cpegenerate.FromDictionaryFind(p)
|
return cpegenerate.FromDictionaryFind(p)
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -167,16 +167,24 @@ func indexCPEList(list CpeList) *dictionary.Indexed {
|
|||||||
return indexed
|
return indexed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateIndex(indexed *dictionary.Indexed, ecosystem string, pkgName string, cpe string) {
|
||||||
|
if _, exists := indexed.EcosystemPackages[ecosystem]; !exists {
|
||||||
|
indexed.EcosystemPackages[ecosystem] = make(dictionary.Packages)
|
||||||
|
}
|
||||||
|
|
||||||
|
if indexed.EcosystemPackages[ecosystem][pkgName] == nil {
|
||||||
|
indexed.EcosystemPackages[ecosystem][pkgName] = dictionary.NewSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
indexed.EcosystemPackages[ecosystem][pkgName].Add(cpe)
|
||||||
|
}
|
||||||
|
|
||||||
func addEntryForRustCrate(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
func addEntryForRustCrate(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||||
// Prune off the non-package-name parts of the URL
|
// Prune off the non-package-name parts of the URL
|
||||||
ref = strings.TrimPrefix(ref, prefixForRustCrates)
|
ref = strings.TrimPrefix(ref, prefixForRustCrates)
|
||||||
ref = strings.Split(ref, "/")[0]
|
ref = strings.Split(ref, "/")[0]
|
||||||
|
|
||||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemRustCrates]; !ok {
|
updateIndex(indexed, dictionary.EcosystemRustCrates, ref, cpeItemName)
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemRustCrates] = make(dictionary.Packages)
|
|
||||||
}
|
|
||||||
|
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemRustCrates][ref] = cpeItemName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addEntryForJenkinsPluginGitHub(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
func addEntryForJenkinsPluginGitHub(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||||
@ -190,12 +198,7 @@ func addEntryForJenkinsPluginGitHub(indexed *dictionary.Indexed, ref string, cpe
|
|||||||
}
|
}
|
||||||
|
|
||||||
ref = strings.TrimSuffix(ref, "-plugin")
|
ref = strings.TrimSuffix(ref, "-plugin")
|
||||||
|
updateIndex(indexed, dictionary.EcosystemJenkinsPlugins, ref, cpeItemName)
|
||||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins]; !ok {
|
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins] = make(dictionary.Packages)
|
|
||||||
}
|
|
||||||
|
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins][ref] = cpeItemName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addEntryForJenkinsPlugin(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
func addEntryForJenkinsPlugin(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||||
@ -207,11 +210,7 @@ func addEntryForJenkinsPlugin(indexed *dictionary.Indexed, ref string, cpeItemNa
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins]; !ok {
|
updateIndex(indexed, dictionary.EcosystemJenkinsPlugins, ref, cpeItemName)
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins] = make(dictionary.Packages)
|
|
||||||
}
|
|
||||||
|
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins][ref] = cpeItemName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addEntryForPyPIPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
func addEntryForPyPIPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||||
@ -219,11 +218,7 @@ func addEntryForPyPIPackage(indexed *dictionary.Indexed, ref string, cpeItemName
|
|||||||
ref = strings.TrimPrefix(ref, prefixForPyPIPackages)
|
ref = strings.TrimPrefix(ref, prefixForPyPIPackages)
|
||||||
ref = strings.Split(ref, "/")[0]
|
ref = strings.Split(ref, "/")[0]
|
||||||
|
|
||||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemPyPI]; !ok {
|
updateIndex(indexed, dictionary.EcosystemPyPI, ref, cpeItemName)
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemPyPI] = make(dictionary.Packages)
|
|
||||||
}
|
|
||||||
|
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemPyPI][ref] = cpeItemName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addEntryForNativeRubyGem(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
func addEntryForNativeRubyGem(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||||
@ -231,11 +226,7 @@ func addEntryForNativeRubyGem(indexed *dictionary.Indexed, ref string, cpeItemNa
|
|||||||
ref = strings.TrimPrefix(ref, prefixForNativeRubyGems)
|
ref = strings.TrimPrefix(ref, prefixForNativeRubyGems)
|
||||||
ref = strings.Split(ref, "/")[0]
|
ref = strings.Split(ref, "/")[0]
|
||||||
|
|
||||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemRubyGems]; !ok {
|
updateIndex(indexed, dictionary.EcosystemRubyGems, ref, cpeItemName)
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems] = make(dictionary.Packages)
|
|
||||||
}
|
|
||||||
|
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems][ref] = cpeItemName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addEntryForRubyGem(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
func addEntryForRubyGem(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||||
@ -244,11 +235,7 @@ func addEntryForRubyGem(indexed *dictionary.Indexed, ref string, cpeItemName str
|
|||||||
ref = strings.TrimPrefix(ref, prefixForRubyGemsHTTP)
|
ref = strings.TrimPrefix(ref, prefixForRubyGemsHTTP)
|
||||||
ref = strings.Split(ref, "/")[0]
|
ref = strings.Split(ref, "/")[0]
|
||||||
|
|
||||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemRubyGems]; !ok {
|
updateIndex(indexed, dictionary.EcosystemRubyGems, ref, cpeItemName)
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems] = make(dictionary.Packages)
|
|
||||||
}
|
|
||||||
|
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems][ref] = cpeItemName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addEntryForNPMPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
func addEntryForNPMPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||||
@ -257,11 +244,7 @@ func addEntryForNPMPackage(indexed *dictionary.Indexed, ref string, cpeItemName
|
|||||||
ref = strings.Split(ref, "?")[0]
|
ref = strings.Split(ref, "?")[0]
|
||||||
ref = strings.TrimPrefix(ref, prefixForNPMPackages)
|
ref = strings.TrimPrefix(ref, prefixForNPMPackages)
|
||||||
|
|
||||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemNPM]; !ok {
|
updateIndex(indexed, dictionary.EcosystemNPM, ref, cpeItemName)
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemNPM] = make(dictionary.Packages)
|
|
||||||
}
|
|
||||||
|
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemNPM][ref] = cpeItemName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func phpExtensionPackageFromURLFragment(ref string) string {
|
func phpExtensionPackageFromURLFragment(ref string) string {
|
||||||
@ -301,11 +284,7 @@ func addEntryForPHPPearPackage(indexed *dictionary.Indexed, ref string, cpeItemN
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemPHPPear]; !ok {
|
updateIndex(indexed, dictionary.EcosystemPHPPear, ref, cpeItemName)
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemPHPPear] = make(dictionary.Packages)
|
|
||||||
}
|
|
||||||
|
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemPHPPear][ref] = cpeItemName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addEntryForPHPPeclPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
func addEntryForPHPPeclPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||||
@ -317,11 +296,7 @@ func addEntryForPHPPeclPackage(indexed *dictionary.Indexed, ref string, cpeItemN
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemPHPPecl]; !ok {
|
updateIndex(indexed, dictionary.EcosystemPHPPecl, ref, cpeItemName)
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemPHPPecl] = make(dictionary.Packages)
|
|
||||||
}
|
|
||||||
|
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemPHPPecl][ref] = cpeItemName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addEntryForPHPComposerPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
func addEntryForPHPComposerPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||||
@ -335,9 +310,5 @@ func addEntryForPHPComposerPackage(indexed *dictionary.Indexed, ref string, cpeI
|
|||||||
|
|
||||||
ref = components[0] + "/" + components[1]
|
ref = components[0] + "/" + components[1]
|
||||||
|
|
||||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemPHPComposer]; !ok {
|
updateIndex(indexed, dictionary.EcosystemPHPComposer, ref, cpeItemName)
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemPHPComposer] = make(dictionary.Packages)
|
|
||||||
}
|
|
||||||
|
|
||||||
indexed.EcosystemPackages[dictionary.EcosystemPHPComposer][ref] = cpeItemName
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/scylladb/go-set/strset"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
@ -59,7 +60,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
|||||||
expectedIndexed: dictionary.Indexed{
|
expectedIndexed: dictionary.Indexed{
|
||||||
EcosystemPackages: map[string]dictionary.Packages{
|
EcosystemPackages: map[string]dictionary.Packages{
|
||||||
dictionary.EcosystemRustCrates: {
|
dictionary.EcosystemRustCrates: {
|
||||||
"unicycle": "cpe:2.3:a:unicycle_project:unicycle:*:*:*:*:*:rust:*:*",
|
"unicycle": dictionary.NewSet("cpe:2.3:a:unicycle_project:unicycle:*:*:*:*:*:rust:*:*"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -72,7 +73,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
|||||||
expectedIndexed: dictionary.Indexed{
|
expectedIndexed: dictionary.Indexed{
|
||||||
EcosystemPackages: map[string]dictionary.Packages{
|
EcosystemPackages: map[string]dictionary.Packages{
|
||||||
dictionary.EcosystemJenkinsPlugins: {
|
dictionary.EcosystemJenkinsPlugins: {
|
||||||
"sonarqube": "cpe:2.3:a:sonarsource:sonarqube_scanner:2.7:*:*:*:*:jenkins:*:*",
|
"sonarqube": dictionary.NewSet("cpe:2.3:a:sonarsource:sonarqube_scanner:2.7:*:*:*:*:jenkins:*:*"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -94,7 +95,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
|||||||
expectedIndexed: dictionary.Indexed{
|
expectedIndexed: dictionary.Indexed{
|
||||||
EcosystemPackages: map[string]dictionary.Packages{
|
EcosystemPackages: map[string]dictionary.Packages{
|
||||||
dictionary.EcosystemJenkinsPlugins: {
|
dictionary.EcosystemJenkinsPlugins: {
|
||||||
"svn-partial-release-mgr": "cpe:2.3:a:jenkins:subversion_partial_release_manager:1.0.1:*:*:*:*:jenkins:*:*",
|
"svn-partial-release-mgr": dictionary.NewSet("cpe:2.3:a:jenkins:subversion_partial_release_manager:1.0.1:*:*:*:*:jenkins:*:*"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -107,7 +108,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
|||||||
expectedIndexed: dictionary.Indexed{
|
expectedIndexed: dictionary.Indexed{
|
||||||
EcosystemPackages: map[string]dictionary.Packages{
|
EcosystemPackages: map[string]dictionary.Packages{
|
||||||
dictionary.EcosystemPyPI: {
|
dictionary.EcosystemPyPI: {
|
||||||
"vault-cli": "cpe:2.3:a:vault-cli_project:vault-cli:*:*:*:*:*:python:*:*",
|
"vault-cli": dictionary.NewSet("cpe:2.3:a:vault-cli_project:vault-cli:*:*:*:*:*:python:*:*"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -120,7 +121,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
|||||||
expectedIndexed: dictionary.Indexed{
|
expectedIndexed: dictionary.Indexed{
|
||||||
EcosystemPackages: map[string]dictionary.Packages{
|
EcosystemPackages: map[string]dictionary.Packages{
|
||||||
dictionary.EcosystemRubyGems: {
|
dictionary.EcosystemRubyGems: {
|
||||||
"openssl": "cpe:2.3:a:ruby-lang:openssl:-:*:*:*:*:ruby:*:*",
|
"openssl": dictionary.NewSet("cpe:2.3:a:ruby-lang:openssl:-:*:*:*:*:ruby:*:*"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -133,7 +134,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
|||||||
expectedIndexed: dictionary.Indexed{
|
expectedIndexed: dictionary.Indexed{
|
||||||
EcosystemPackages: map[string]dictionary.Packages{
|
EcosystemPackages: map[string]dictionary.Packages{
|
||||||
dictionary.EcosystemRubyGems: {
|
dictionary.EcosystemRubyGems: {
|
||||||
"actionview": "cpe:2.3:a:action_view_project:action_view:*:*:*:*:*:ruby:*:*",
|
"actionview": dictionary.NewSet("cpe:2.3:a:action_view_project:action_view:*:*:*:*:*:ruby:*:*"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -146,7 +147,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
|||||||
expectedIndexed: dictionary.Indexed{
|
expectedIndexed: dictionary.Indexed{
|
||||||
EcosystemPackages: map[string]dictionary.Packages{
|
EcosystemPackages: map[string]dictionary.Packages{
|
||||||
dictionary.EcosystemRubyGems: {
|
dictionary.EcosystemRubyGems: {
|
||||||
"rbovirt": "cpe:2.3:a:amos_benari:rbovirt:*:*:*:*:*:ruby:*:*",
|
"rbovirt": dictionary.NewSet("cpe:2.3:a:amos_benari:rbovirt:*:*:*:*:*:ruby:*:*"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -159,7 +160,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
|||||||
expectedIndexed: dictionary.Indexed{
|
expectedIndexed: dictionary.Indexed{
|
||||||
EcosystemPackages: map[string]dictionary.Packages{
|
EcosystemPackages: map[string]dictionary.Packages{
|
||||||
dictionary.EcosystemNPM: {
|
dictionary.EcosystemNPM: {
|
||||||
"@nubosoftware/node-static": "cpe:2.3:a:\\@nubosoftware\\/node-static_project:\\@nubosoftware\\/node-static:-:*:*:*:*:node.js:*:*",
|
"@nubosoftware/node-static": dictionary.NewSet("cpe:2.3:a:\\@nubosoftware\\/node-static_project:\\@nubosoftware\\/node-static:-:*:*:*:*:node.js:*:*"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -172,7 +173,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
|||||||
expectedIndexed: dictionary.Indexed{
|
expectedIndexed: dictionary.Indexed{
|
||||||
EcosystemPackages: map[string]dictionary.Packages{
|
EcosystemPackages: map[string]dictionary.Packages{
|
||||||
dictionary.EcosystemPHPPecl: {
|
dictionary.EcosystemPHPPecl: {
|
||||||
"imagick": "cpe:2.3:a:php:imagick:*:*:*:*:*:*:*:*",
|
"imagick": dictionary.NewSet("cpe:2.3:a:php:imagick:*:*:*:*:*:*:*:*"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -185,7 +186,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
|||||||
expectedIndexed: dictionary.Indexed{
|
expectedIndexed: dictionary.Indexed{
|
||||||
EcosystemPackages: map[string]dictionary.Packages{
|
EcosystemPackages: map[string]dictionary.Packages{
|
||||||
dictionary.EcosystemPHPPecl: {
|
dictionary.EcosystemPHPPecl: {
|
||||||
"memcached": "cpe:2.3:a:php:memcached:*:*:*:*:*:*:*:*",
|
"memcached": dictionary.NewSet("cpe:2.3:a:php:memcached:*:*:*:*:*:*:*:*"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -198,7 +199,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
|||||||
expectedIndexed: dictionary.Indexed{
|
expectedIndexed: dictionary.Indexed{
|
||||||
EcosystemPackages: map[string]dictionary.Packages{
|
EcosystemPackages: map[string]dictionary.Packages{
|
||||||
dictionary.EcosystemPHPPear: {
|
dictionary.EcosystemPHPPear: {
|
||||||
"PEAR": "cpe:2.3:a:php:pear:*:*:*:*:*:*:*:*",
|
"PEAR": dictionary.NewSet("cpe:2.3:a:php:pear:*:*:*:*:*:*:*:*"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -211,7 +212,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
|||||||
expectedIndexed: dictionary.Indexed{
|
expectedIndexed: dictionary.Indexed{
|
||||||
EcosystemPackages: map[string]dictionary.Packages{
|
EcosystemPackages: map[string]dictionary.Packages{
|
||||||
dictionary.EcosystemPHPPear: {
|
dictionary.EcosystemPHPPear: {
|
||||||
"abcdefg": "cpe:2.3:a:php:abcdefg:*:*:*:*:*:*:*:*",
|
"abcdefg": dictionary.NewSet("cpe:2.3:a:php:abcdefg:*:*:*:*:*:*:*:*"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -224,7 +225,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
|||||||
expectedIndexed: dictionary.Indexed{
|
expectedIndexed: dictionary.Indexed{
|
||||||
EcosystemPackages: map[string]dictionary.Packages{
|
EcosystemPackages: map[string]dictionary.Packages{
|
||||||
dictionary.EcosystemPHPComposer: {
|
dictionary.EcosystemPHPComposer: {
|
||||||
"frappant/frp-form-answers": "cpe:2.3:a:frappant:forms_export:*:*:*:*:*:*:*:*",
|
"frappant/frp-form-answers": dictionary.NewSet("cpe:2.3:a:frappant:forms_export:*:*:*:*:*:*:*:*"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -239,7 +240,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
|||||||
|
|
||||||
tt.addEntryFunc(indexed, tt.inputRef, tt.inputCpeItemName)
|
tt.addEntryFunc(indexed, tt.inputRef, tt.inputCpeItemName)
|
||||||
|
|
||||||
if diff := cmp.Diff(tt.expectedIndexed, *indexed); diff != "" {
|
if diff := cmp.Diff(tt.expectedIndexed, *indexed, cmp.AllowUnexported(strset.Set{})); diff != "" {
|
||||||
t.Errorf("addEntry* mismatch (-want +got):\n%s", diff)
|
t.Errorf("addEntry* mismatch (-want +got):\n%s", diff)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,44 +1,97 @@
|
|||||||
{
|
{
|
||||||
"ecosystems": {
|
"ecosystems": {
|
||||||
"jenkins_plugins": {
|
"jenkins_plugins": {
|
||||||
"fireline": "cpe:2.3:a:jenkins:360_fireline:*:*:*:*:*:jenkins:*:*",
|
"anchore-container-scanner": [
|
||||||
"sonarqube": "cpe:2.3:a:sonarsource:sonarqube_scanner:*:*:*:*:*:jenkins:*:*",
|
"cpe:2.3:a:anchore:container_image_scanner:*:*:*:*:*:jenkins:*:*",
|
||||||
"svn-partial-release-mgr": "cpe:2.3:a:jenkins:subversion_partial_release_manager:*:*:*:*:*:jenkins:*:*"
|
"cpe:2.3:a:jenkins:anchore_container_image_scanner:*:*:*:*:*:jenkins:*:*"
|
||||||
|
],
|
||||||
|
"fireline": [
|
||||||
|
"cpe:2.3:a:jenkins:360_fireline:*:*:*:*:*:jenkins:*:*"
|
||||||
|
],
|
||||||
|
"sonarqube": [
|
||||||
|
"cpe:2.3:a:sonarsource:sonarqube_scanner:*:*:*:*:*:jenkins:*:*"
|
||||||
|
],
|
||||||
|
"svn-partial-release-mgr": [
|
||||||
|
"cpe:2.3:a:jenkins:subversion_partial_release_manager:*:*:*:*:*:jenkins:*:*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"npm": {
|
"npm": {
|
||||||
"merge-recursive": "cpe:2.3:a:umbraengineering:merge-recursive:*:*:*:*:*:node.js:*:*",
|
"merge-recursive": [
|
||||||
"ps": "cpe:2.3:a:umbraengineering:ps:*:*:*:*:*:node.js:*:*",
|
"cpe:2.3:a:umbraengineering:merge-recursive:*:*:*:*:*:node.js:*:*"
|
||||||
"static-dev-server": "cpe:2.3:a:static-dev-server_project:static-dev-server:*:*:*:*:*:node.js:*:*",
|
],
|
||||||
"umount": "cpe:2.3:a:umount_project:umount:*:*:*:*:*:node.js:*:*",
|
"ps": [
|
||||||
"undefsafe": "cpe:2.3:a:undefsafe_project:undefsafe:*:*:*:*:*:node.js:*:*",
|
"cpe:2.3:a:umbraengineering:ps:*:*:*:*:*:node.js:*:*"
|
||||||
"underscore": "cpe:2.3:a:underscorejs:underscore:*:*:*:*:*:node.js:*:*",
|
],
|
||||||
"underscore-99xp": "cpe:2.3:a:underscore-99xp_project:underscore-99xp:*:*:*:*:*:node.js:*:*",
|
"static-dev-server": [
|
||||||
"ungit": "cpe:2.3:a:ungit_project:ungit:*:*:*:*:*:node.js:*:*",
|
"cpe:2.3:a:static-dev-server_project:static-dev-server:*:*:*:*:*:node.js:*:*"
|
||||||
"unicode": "cpe:2.3:a:unicode_project:unicode:*:*:*:*:*:node.js:*:*",
|
],
|
||||||
"unicode-json": "cpe:2.3:a:unicode:unicode-json:*:*:*:*:*:node.js:*:*",
|
"umount": [
|
||||||
"unicorn-list": "cpe:2.3:a:unicorn-list_project:unicorn-list:*:*:*:*:*:node.js:*:*"
|
"cpe:2.3:a:umount_project:umount:*:*:*:*:*:node.js:*:*"
|
||||||
|
],
|
||||||
|
"undefsafe": [
|
||||||
|
"cpe:2.3:a:undefsafe_project:undefsafe:*:*:*:*:*:node.js:*:*"
|
||||||
|
],
|
||||||
|
"underscore": [
|
||||||
|
"cpe:2.3:a:underscorejs:underscore:*:*:*:*:*:node.js:*:*"
|
||||||
|
],
|
||||||
|
"underscore-99xp": [
|
||||||
|
"cpe:2.3:a:underscore-99xp_project:underscore-99xp:*:*:*:*:*:node.js:*:*"
|
||||||
|
],
|
||||||
|
"ungit": [
|
||||||
|
"cpe:2.3:a:ungit_project:ungit:*:*:*:*:*:node.js:*:*"
|
||||||
|
],
|
||||||
|
"unicode": [
|
||||||
|
"cpe:2.3:a:unicode_project:unicode:*:*:*:*:*:node.js:*:*"
|
||||||
|
],
|
||||||
|
"unicode-json": [
|
||||||
|
"cpe:2.3:a:unicode:unicode-json:*:*:*:*:*:node.js:*:*"
|
||||||
|
],
|
||||||
|
"unicorn-list": [
|
||||||
|
"cpe:2.3:a:unicorn-list_project:unicorn-list:*:*:*:*:*:node.js:*:*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"php_composer": {
|
"php_composer": {
|
||||||
"frappant/frp-form-answers": "cpe:2.3:a:frappant:forms_export:*:*:*:*:*:typo3:*:*"
|
"frappant/frp-form-answers": [
|
||||||
|
"cpe:2.3:a:frappant:forms_export:*:*:*:*:*:typo3:*:*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"php_pear": {
|
"php_pear": {
|
||||||
"HTML_QuickForm": "cpe:2.3:a:html_quickform_project:html_quickform:*:*:*:*:*:*:*:*",
|
"HTML_QuickForm": [
|
||||||
"PEAR": "cpe:2.3:a:php:pear:*:*:*:*:*:*:*:*",
|
"cpe:2.3:a:html_quickform_project:html_quickform:*:*:*:*:*:*:*:*"
|
||||||
"XML_RPC": "cpe:2.3:a:php:xml_rpc:*:*:*:*:*:pear:*:*"
|
],
|
||||||
|
"PEAR": [
|
||||||
|
"cpe:2.3:a:php:pear:*:*:*:*:*:*:*:*"
|
||||||
|
],
|
||||||
|
"XML_RPC": [
|
||||||
|
"cpe:2.3:a:php:xml_rpc:*:*:*:*:*:pear:*:*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"php_pecl": {
|
"php_pecl": {
|
||||||
"imagick": "cpe:2.3:a:php:imagick:*:*:*:*:*:*:*:*",
|
"imagick": [
|
||||||
"memcached": "cpe:2.3:a:php:memcached:*:*:*:*:*:*:*:*",
|
"cpe:2.3:a:php:imagick:*:*:*:*:*:*:*:*"
|
||||||
"xhprof": "cpe:2.3:a:php:xhprof:*:*:*:*:*:*:*:*"
|
],
|
||||||
|
"memcached": [
|
||||||
|
"cpe:2.3:a:php:memcached:*:*:*:*:*:*:*:*"
|
||||||
|
],
|
||||||
|
"xhprof": [
|
||||||
|
"cpe:2.3:a:php:xhprof:*:*:*:*:*:*:*:*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"pypi": {
|
"pypi": {
|
||||||
"vault-cli": "cpe:2.3:a:vault-cli_project:vault-cli:*:*:*:*:*:python:*:*"
|
"vault-cli": [
|
||||||
|
"cpe:2.3:a:vault-cli_project:vault-cli:*:*:*:*:*:python:*:*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"rubygems": {
|
"rubygems": {
|
||||||
"openssl": "cpe:2.3:a:ruby-lang:openssl:*:*:*:*:*:*:*:*"
|
"openssl": [
|
||||||
|
"cpe:2.3:a:ruby-lang:openssl:*:*:*:*:*:*:*:*",
|
||||||
|
"cpe:2.3:a:ruby-lang:openssl:*:*:*:*:*:ruby:*:*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"rust_crates": {
|
"rust_crates": {
|
||||||
"unicycle": "cpe:2.3:a:unicycle_project:unicycle:*:*:*:*:*:rust:*:*"
|
"unicycle": [
|
||||||
|
"cpe:2.3:a:unicycle_project:unicycle:*:*:*:*:*:rust:*:*"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -25014,6 +25014,40 @@
|
|||||||
</references>
|
</references>
|
||||||
<cpe-23:cpe23-item name="cpe:2.3:a:jenkins:360_fireline:1.0:*:*:*:*:jenkins:*:*"/>
|
<cpe-23:cpe23-item name="cpe:2.3:a:jenkins:360_fireline:1.0:*:*:*:*:jenkins:*:*"/>
|
||||||
</cpe-item>
|
</cpe-item>
|
||||||
|
<cpe-item name="cpe:/a:anchore:container_image_scanner:-::~~~jenkins~~">
|
||||||
|
<title xml:lang="en-US">Anchore Container Image Scanner for Jenkins</title>
|
||||||
|
<references>
|
||||||
|
<reference href="https://jenkins.io/security/advisory/2018-07-30/#SECURITY-1039">Advisory</reference>
|
||||||
|
<reference href="https://github.com/jenkinsci/anchore-container-scanner-plugin/releases">Version</reference>
|
||||||
|
<reference href="https://plugins.jenkins.io/anchore-container-scanner">Product</reference>
|
||||||
|
</references>
|
||||||
|
<cpe-23:cpe23-item name="cpe:2.3:a:anchore:container_image_scanner:-:*:*:*:*:jenkins:*:*"/>
|
||||||
|
</cpe-item>
|
||||||
|
<cpe-item name="cpe:/a:anchore:container_image_scanner:1.0.0::~~~jenkins~~">
|
||||||
|
<title xml:lang="en-US">Anchore Container Image Scanner 1.0.0 for Jenkins</title>
|
||||||
|
<references>
|
||||||
|
<reference href="https://jenkins.io/security/advisory/2018-07-30/#SECURITY-1039">Advisory</reference>
|
||||||
|
<reference href="https://github.com/jenkinsci/anchore-container-scanner-plugin/releases">Version</reference>
|
||||||
|
<reference href="https://plugins.jenkins.io/anchore-container-scanner">Product</reference>
|
||||||
|
</references>
|
||||||
|
<cpe-23:cpe23-item name="cpe:2.3:a:anchore:container_image_scanner:1.0.0:*:*:*:*:jenkins:*:*"/>
|
||||||
|
</cpe-item>
|
||||||
|
<cpe-item name="cpe:/a:jenkins:anchore_container_image_scanner:1.0.0::~~~jenkins~~">
|
||||||
|
<title xml:lang="en-US">Jenkins Anchore Container Image Scanner 1.0.0 for Jenkins</title>
|
||||||
|
<references>
|
||||||
|
<reference href="https://plugins.jenkins.io/anchore-container-scanner">Product</reference>
|
||||||
|
<reference href="https://github.com/jenkinsci/anchore-container-scanner-plugin">Version</reference>
|
||||||
|
</references>
|
||||||
|
<cpe-23:cpe23-item name="cpe:2.3:a:jenkins:anchore_container_image_scanner:1.0.0:*:*:*:*:jenkins:*:*"/>
|
||||||
|
</cpe-item>
|
||||||
|
<cpe-item name="cpe:/a:jenkins:anchore_container_image_scanner:1.0.1::~~~jenkins~~">
|
||||||
|
<title xml:lang="en-US">Jenkins Anchore Container Image Scanner 1.0.1 for Jenkins</title>
|
||||||
|
<references>
|
||||||
|
<reference href="https://plugins.jenkins.io/anchore-container-scanner">Product</reference>
|
||||||
|
<reference href="https://github.com/jenkinsci/anchore-container-scanner-plugin">Version</reference>
|
||||||
|
</references>
|
||||||
|
<cpe-23:cpe23-item name="cpe:2.3:a:jenkins:anchore_container_image_scanner:1.0.1:*:*:*:*:jenkins:*:*"/>
|
||||||
|
</cpe-item>
|
||||||
</cpe-list>
|
</cpe-list>
|
||||||
</cpe-list>
|
</cpe-list>
|
||||||
</cpe-list>
|
</cpe-list>
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
package dictionary
|
package dictionary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
"github.com/scylladb/go-set/strset"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
EcosystemNPM = "npm"
|
EcosystemNPM = "npm"
|
||||||
EcosystemRubyGems = "rubygems"
|
EcosystemRubyGems = "rubygems"
|
||||||
@ -15,4 +22,29 @@ type Indexed struct {
|
|||||||
EcosystemPackages map[string]Packages `json:"ecosystems"`
|
EcosystemPackages map[string]Packages `json:"ecosystems"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Packages map[string]string
|
type Set struct {
|
||||||
|
*strset.Set
|
||||||
|
}
|
||||||
|
|
||||||
|
type Packages map[string]*Set
|
||||||
|
|
||||||
|
func NewSet(ts ...string) *Set {
|
||||||
|
return &Set{strset.New(ts...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Set) MarshalJSON() ([]byte, error) {
|
||||||
|
l := s.List()
|
||||||
|
slices.Sort(l)
|
||||||
|
return json.Marshal(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Set) UnmarshalJSON(data []byte) error {
|
||||||
|
var strSlice []string
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &strSlice); err == nil {
|
||||||
|
*s = *NewSet(strSlice...)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@ -58,58 +58,66 @@ func GetIndexedDictionary() (_ *dictionary.Indexed, err error) {
|
|||||||
return indexedCPEDictionary, err
|
return indexedCPEDictionary, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromDictionaryFind(p pkg.Package) (cpe.CPE, bool) {
|
func FromDictionaryFind(p pkg.Package) ([]cpe.CPE, bool) {
|
||||||
dict, err := GetIndexedDictionary()
|
dict, err := GetIndexedDictionary()
|
||||||
|
parsedCPEs := []cpe.CPE{}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("CPE dictionary lookup not available: %+v", err)
|
log.Debugf("CPE dictionary lookup not available: %+v", err)
|
||||||
return cpe.CPE{}, false
|
return parsedCPEs, false
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
cpeString string
|
cpes *dictionary.Set
|
||||||
ok bool
|
ok bool
|
||||||
)
|
)
|
||||||
|
|
||||||
switch p.Type {
|
switch p.Type {
|
||||||
case pkg.NpmPkg:
|
case pkg.NpmPkg:
|
||||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemNPM][p.Name]
|
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemNPM][p.Name]
|
||||||
|
|
||||||
case pkg.GemPkg:
|
case pkg.GemPkg:
|
||||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemRubyGems][p.Name]
|
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemRubyGems][p.Name]
|
||||||
|
|
||||||
case pkg.PythonPkg:
|
case pkg.PythonPkg:
|
||||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemPyPI][p.Name]
|
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemPyPI][p.Name]
|
||||||
|
|
||||||
case pkg.JenkinsPluginPkg:
|
case pkg.JenkinsPluginPkg:
|
||||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemJenkinsPlugins][p.Name]
|
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemJenkinsPlugins][p.Name]
|
||||||
|
|
||||||
case pkg.RustPkg:
|
case pkg.RustPkg:
|
||||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemRustCrates][p.Name]
|
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemRustCrates][p.Name]
|
||||||
|
|
||||||
case pkg.PhpComposerPkg:
|
case pkg.PhpComposerPkg:
|
||||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemPHPComposer][p.Name]
|
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemPHPComposer][p.Name]
|
||||||
|
|
||||||
case pkg.PhpPeclPkg:
|
case pkg.PhpPeclPkg:
|
||||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemPHPPecl][p.Name]
|
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemPHPPecl][p.Name]
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// The dictionary doesn't support this package type yet.
|
// The dictionary doesn't support this package type yet.
|
||||||
return cpe.CPE{}, false
|
return parsedCPEs, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
// The dictionary doesn't have a CPE for this package.
|
// The dictionary doesn't have a CPE for this package.
|
||||||
return cpe.CPE{}, false
|
return parsedCPEs, false
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedCPE, err := cpe.New(cpeString, cpe.NVDDictionaryLookupSource)
|
for _, c := range cpes.List() {
|
||||||
if err != nil {
|
parsedCPE, err := cpe.New(c, cpe.NVDDictionaryLookupSource)
|
||||||
return cpe.CPE{}, false
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedCPE.Attributes.Version = p.Version
|
||||||
|
parsedCPEs = append(parsedCPEs, parsedCPE)
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedCPE.Attributes.Version = p.Version
|
if len(parsedCPEs) == 0 {
|
||||||
|
return []cpe.CPE{}, false
|
||||||
|
}
|
||||||
|
|
||||||
return parsedCPE, true
|
return parsedCPEs, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromPackageAttributes Create a list of CPEs for a given package, trying to guess the vendor, product tuple. We should be trying to
|
// FromPackageAttributes Create a list of CPEs for a given package, trying to guess the vendor, product tuple. We should be trying to
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/scylladb/go-set/strset"
|
"github.com/scylladb/go-set/strset"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/cpe"
|
||||||
"github.com/anchore/syft/syft/pkg"
|
"github.com/anchore/syft/syft/pkg"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -991,7 +992,7 @@ func TestDictionaryFindIsWired(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
pkg pkg.Package
|
pkg pkg.Package
|
||||||
want string
|
want []cpe.CPE
|
||||||
wantExists bool
|
wantExists bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@ -1001,7 +1002,10 @@ func TestDictionaryFindIsWired(t *testing.T) {
|
|||||||
Version: "1.0.2k",
|
Version: "1.0.2k",
|
||||||
Type: pkg.GemPkg,
|
Type: pkg.GemPkg,
|
||||||
},
|
},
|
||||||
want: "cpe:2.3:a:ruby-lang:openssl:1.0.2k:*:*:*:*:*:*:*",
|
want: []cpe.CPE{
|
||||||
|
cpe.Must("cpe:2.3:a:ruby-lang:openssl:1.0.2k:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
|
||||||
|
cpe.Must("cpe:2.3:a:ruby-lang:openssl:1.0.2k:*:*:*:*:ruby:*:*", cpe.NVDDictionaryLookupSource),
|
||||||
|
},
|
||||||
// without the cpe data wired up, this would be empty (generation also creates cpe:2.3:a:openssl:openssl:1.0.2k:*:*:*:*:*:*:*)
|
// without the cpe data wired up, this would be empty (generation also creates cpe:2.3:a:openssl:openssl:1.0.2k:*:*:*:*:*:*:*)
|
||||||
wantExists: true,
|
wantExists: true,
|
||||||
},
|
},
|
||||||
@ -1009,8 +1013,7 @@ func TestDictionaryFindIsWired(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got, gotExists := FromDictionaryFind(tt.pkg)
|
got, gotExists := FromDictionaryFind(tt.pkg)
|
||||||
|
assert.ElementsMatch(t, tt.want, got)
|
||||||
assert.Equal(t, tt.want, got.Attributes.BindToFmtString())
|
|
||||||
assert.Equal(t, tt.wantExists, gotExists)
|
assert.Equal(t, tt.wantExists, gotExists)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user