mirror of
https://github.com/anchore/syft.git
synced 2025-11-18 00:43:20 +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 {
|
||||
// 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
|
||||
dictionaryCPE, ok := cpe.DictionaryFind(p)
|
||||
dictionaryCPEs, ok := cpe.DictionaryFind(p)
|
||||
if ok {
|
||||
log.Tracef("used CPE dictionary to find CPE for %s package %q: %s", p.Type, p.Name, dictionaryCPE.Attributes.BindToFmtString())
|
||||
p.CPEs = append(p.CPEs, dictionaryCPE)
|
||||
log.Tracef("used CPE dictionary to find CPEs for %s package %q: %s", p.Type, p.Name, dictionaryCPEs)
|
||||
p.CPEs = append(p.CPEs, dictionaryCPEs...)
|
||||
} else {
|
||||
p.CPEs = append(p.CPEs, cpe.Generate(p)...)
|
||||
}
|
||||
|
||||
@ -10,6 +10,6 @@ func Generate(p pkg.Package) []cpe.CPE {
|
||||
return cpegenerate.FromPackageAttributes(p)
|
||||
}
|
||||
|
||||
func DictionaryFind(p pkg.Package) (cpe.CPE, bool) {
|
||||
func DictionaryFind(p pkg.Package) ([]cpe.CPE, bool) {
|
||||
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
|
||||
}
|
||||
|
||||
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) {
|
||||
// Prune off the non-package-name parts of the URL
|
||||
ref = strings.TrimPrefix(ref, prefixForRustCrates)
|
||||
ref = strings.Split(ref, "/")[0]
|
||||
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemRustCrates]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRustCrates] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRustCrates][ref] = cpeItemName
|
||||
updateIndex(indexed, dictionary.EcosystemRustCrates, ref, cpeItemName)
|
||||
}
|
||||
|
||||
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")
|
||||
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins][ref] = cpeItemName
|
||||
updateIndex(indexed, dictionary.EcosystemJenkinsPlugins, ref, cpeItemName)
|
||||
}
|
||||
|
||||
func addEntryForJenkinsPlugin(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
@ -207,11 +210,7 @@ func addEntryForJenkinsPlugin(indexed *dictionary.Indexed, ref string, cpeItemNa
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins][ref] = cpeItemName
|
||||
updateIndex(indexed, dictionary.EcosystemJenkinsPlugins, ref, cpeItemName)
|
||||
}
|
||||
|
||||
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.Split(ref, "/")[0]
|
||||
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemPyPI]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemPyPI] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemPyPI][ref] = cpeItemName
|
||||
updateIndex(indexed, dictionary.EcosystemPyPI, ref, cpeItemName)
|
||||
}
|
||||
|
||||
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.Split(ref, "/")[0]
|
||||
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemRubyGems]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems][ref] = cpeItemName
|
||||
updateIndex(indexed, dictionary.EcosystemRubyGems, ref, cpeItemName)
|
||||
}
|
||||
|
||||
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.Split(ref, "/")[0]
|
||||
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemRubyGems]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems][ref] = cpeItemName
|
||||
updateIndex(indexed, dictionary.EcosystemRubyGems, ref, cpeItemName)
|
||||
}
|
||||
|
||||
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.TrimPrefix(ref, prefixForNPMPackages)
|
||||
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemNPM]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemNPM] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemNPM][ref] = cpeItemName
|
||||
updateIndex(indexed, dictionary.EcosystemNPM, ref, cpeItemName)
|
||||
}
|
||||
|
||||
func phpExtensionPackageFromURLFragment(ref string) string {
|
||||
@ -301,11 +284,7 @@ func addEntryForPHPPearPackage(indexed *dictionary.Indexed, ref string, cpeItemN
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemPHPPear]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemPHPPear] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemPHPPear][ref] = cpeItemName
|
||||
updateIndex(indexed, dictionary.EcosystemPHPPear, ref, cpeItemName)
|
||||
}
|
||||
|
||||
func addEntryForPHPPeclPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
@ -317,11 +296,7 @@ func addEntryForPHPPeclPackage(indexed *dictionary.Indexed, ref string, cpeItemN
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemPHPPecl]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemPHPPecl] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemPHPPecl][ref] = cpeItemName
|
||||
updateIndex(indexed, dictionary.EcosystemPHPPecl, ref, cpeItemName)
|
||||
}
|
||||
|
||||
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]
|
||||
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemPHPComposer]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemPHPComposer] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemPHPComposer][ref] = cpeItemName
|
||||
updateIndex(indexed, dictionary.EcosystemPHPComposer, ref, cpeItemName)
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/scylladb/go-set/strset"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@ -59,7 +60,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
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{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
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{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
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{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
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{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
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{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
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{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
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{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
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{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
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{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
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{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
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{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
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{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
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)
|
||||
|
||||
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)
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,44 +1,97 @@
|
||||
{
|
||||
"ecosystems": {
|
||||
"jenkins_plugins": {
|
||||
"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:*:*"
|
||||
"anchore-container-scanner": [
|
||||
"cpe:2.3:a:anchore:container_image_scanner:*:*:*:*:*: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": {
|
||||
"merge-recursive": "cpe:2.3:a:umbraengineering:merge-recursive:*:*:*:*:*:node.js:*:*",
|
||||
"ps": "cpe:2.3:a:umbraengineering:ps:*:*:*:*:*: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:*:*",
|
||||
"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:*:*"
|
||||
"merge-recursive": [
|
||||
"cpe:2.3:a:umbraengineering:merge-recursive:*:*:*:*:*:node.js:*:*"
|
||||
],
|
||||
"ps": [
|
||||
"cpe:2.3:a:umbraengineering:ps:*:*:*:*:*: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:*:*"
|
||||
],
|
||||
"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": {
|
||||
"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": {
|
||||
"HTML_QuickForm": "cpe:2.3:a:html_quickform_project:html_quickform:*:*:*:*:*:*:*:*",
|
||||
"PEAR": "cpe:2.3:a:php:pear:*:*:*:*:*:*:*:*",
|
||||
"XML_RPC": "cpe:2.3:a:php:xml_rpc:*:*:*:*:*:pear:*:*"
|
||||
"HTML_QuickForm": [
|
||||
"cpe:2.3:a:html_quickform_project:html_quickform:*:*:*:*:*:*:*:*"
|
||||
],
|
||||
"PEAR": [
|
||||
"cpe:2.3:a:php:pear:*:*:*:*:*:*:*:*"
|
||||
],
|
||||
"XML_RPC": [
|
||||
"cpe:2.3:a:php:xml_rpc:*:*:*:*:*:pear:*:*"
|
||||
]
|
||||
},
|
||||
"php_pecl": {
|
||||
"imagick": "cpe:2.3:a:php:imagick:*:*:*:*:*:*:*:*",
|
||||
"memcached": "cpe:2.3:a:php:memcached:*:*:*:*:*:*:*:*",
|
||||
"xhprof": "cpe:2.3:a:php:xhprof:*:*:*:*:*:*:*:*"
|
||||
"imagick": [
|
||||
"cpe:2.3:a:php:imagick:*:*:*:*:*:*:*:*"
|
||||
],
|
||||
"memcached": [
|
||||
"cpe:2.3:a:php:memcached:*:*:*:*:*:*:*:*"
|
||||
],
|
||||
"xhprof": [
|
||||
"cpe:2.3:a:php:xhprof:*:*:*:*:*:*:*:*"
|
||||
]
|
||||
},
|
||||
"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": {
|
||||
"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": {
|
||||
"unicycle": "cpe:2.3:a:unicycle_project:unicycle:*:*:*:*:*:rust:*:*"
|
||||
"unicycle": [
|
||||
"cpe:2.3:a:unicycle_project:unicycle:*:*:*:*:*:rust:*:*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -25014,6 +25014,40 @@
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:jenkins:360_fireline:1.0:*:*:*:*:jenkins:*:*"/>
|
||||
</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>
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
package dictionary
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"slices"
|
||||
|
||||
"github.com/scylladb/go-set/strset"
|
||||
)
|
||||
|
||||
const (
|
||||
EcosystemNPM = "npm"
|
||||
EcosystemRubyGems = "rubygems"
|
||||
@ -15,4 +22,29 @@ type Indexed struct {
|
||||
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
|
||||
}
|
||||
|
||||
func FromDictionaryFind(p pkg.Package) (cpe.CPE, bool) {
|
||||
func FromDictionaryFind(p pkg.Package) ([]cpe.CPE, bool) {
|
||||
dict, err := GetIndexedDictionary()
|
||||
parsedCPEs := []cpe.CPE{}
|
||||
if err != nil {
|
||||
log.Debugf("CPE dictionary lookup not available: %+v", err)
|
||||
return cpe.CPE{}, false
|
||||
return parsedCPEs, false
|
||||
}
|
||||
|
||||
var (
|
||||
cpeString string
|
||||
ok bool
|
||||
cpes *dictionary.Set
|
||||
ok bool
|
||||
)
|
||||
|
||||
switch p.Type {
|
||||
case pkg.NpmPkg:
|
||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemNPM][p.Name]
|
||||
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemNPM][p.Name]
|
||||
|
||||
case pkg.GemPkg:
|
||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemRubyGems][p.Name]
|
||||
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemRubyGems][p.Name]
|
||||
|
||||
case pkg.PythonPkg:
|
||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemPyPI][p.Name]
|
||||
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemPyPI][p.Name]
|
||||
|
||||
case pkg.JenkinsPluginPkg:
|
||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemJenkinsPlugins][p.Name]
|
||||
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemJenkinsPlugins][p.Name]
|
||||
|
||||
case pkg.RustPkg:
|
||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemRustCrates][p.Name]
|
||||
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemRustCrates][p.Name]
|
||||
|
||||
case pkg.PhpComposerPkg:
|
||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemPHPComposer][p.Name]
|
||||
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemPHPComposer][p.Name]
|
||||
|
||||
case pkg.PhpPeclPkg:
|
||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemPHPPecl][p.Name]
|
||||
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemPHPPecl][p.Name]
|
||||
|
||||
default:
|
||||
// The dictionary doesn't support this package type yet.
|
||||
return cpe.CPE{}, false
|
||||
return parsedCPEs, false
|
||||
}
|
||||
|
||||
if !ok {
|
||||
// The dictionary doesn't have a CPE for this package.
|
||||
return cpe.CPE{}, false
|
||||
return parsedCPEs, false
|
||||
}
|
||||
|
||||
parsedCPE, err := cpe.New(cpeString, cpe.NVDDictionaryLookupSource)
|
||||
if err != nil {
|
||||
return cpe.CPE{}, false
|
||||
for _, c := range cpes.List() {
|
||||
parsedCPE, err := cpe.New(c, cpe.NVDDictionaryLookupSource)
|
||||
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
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"github.com/scylladb/go-set/strset"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
@ -991,7 +992,7 @@ func TestDictionaryFindIsWired(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pkg pkg.Package
|
||||
want string
|
||||
want []cpe.CPE
|
||||
wantExists bool
|
||||
}{
|
||||
{
|
||||
@ -1001,7 +1002,10 @@ func TestDictionaryFindIsWired(t *testing.T) {
|
||||
Version: "1.0.2k",
|
||||
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:*:*:*:*:*:*:*)
|
||||
wantExists: true,
|
||||
},
|
||||
@ -1009,8 +1013,7 @@ func TestDictionaryFindIsWired(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, gotExists := FromDictionaryFind(tt.pkg)
|
||||
|
||||
assert.Equal(t, tt.want, got.Attributes.BindToFmtString())
|
||||
assert.ElementsMatch(t, tt.want, got)
|
||||
assert.Equal(t, tt.wantExists, gotExists)
|
||||
})
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user