feat: disable cpe vendor wildcards to reduce false positives (#1647)

* improved parsing of vendor from github url

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* stop generating wildcard vendors

Add logic for parsing javascript and ruby package vendor candidates from
url and author fields and stop generating wildcard vendor candidates

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

---------

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
This commit is contained in:
Weston Steimel 2023-03-03 17:26:46 +00:00 committed by GitHub
parent 01230aa766
commit c4cbe211a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 68 additions and 16 deletions

View File

@ -93,13 +93,6 @@ func candidateVendors(p pkg.Package) []string {
}
}
// some ecosystems do not have enough metadata to determine the vendor accurately, in which case we selectively
// allow * as a candidate. Note: do NOT allow Java packages to have * vendors.
switch p.Language {
case pkg.Ruby, pkg.JavaScript:
vendors.addValue(wfn.Any)
}
switch p.MetadataType {
case pkg.RpmMetadataType:
vendors.union(candidateVendorsForRPM(p))
@ -111,8 +104,15 @@ func candidateVendors(p pkg.Package) []string {
vendors.union(candidateVendorsForJava(p))
case pkg.ApkMetadataType:
vendors.union(candidateVendorsForAPK(p))
case pkg.NpmPackageJSONMetadataType:
vendors.union(candidateVendorsForJavascript(p))
}
// 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)

View File

@ -121,11 +121,16 @@ func TestGeneratePackageCPEs(t *testing.T) {
Version: "3.2",
FoundBy: "some-analyzer",
Language: pkg.JavaScript,
Type: pkg.DebPkg,
MetadataType: pkg.NpmPackageJSONMetadataType,
Metadata: pkg.NpmPackageJSONMetadata{
Author: "jon",
URL: "https://github.com/bob/npm-name",
},
},
expected: []string{
"cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*",
"cpe:2.3:a:*:name:3.2:*:*:*:*:*:*:*",
"cpe:2.3:a:jon:name:3.2:*:*:*:*:*:*:*",
"cpe:2.3:a:bob:name:3.2:*:*:*:*:*:*:*",
},
},
{
@ -142,10 +147,10 @@ func TestGeneratePackageCPEs(t *testing.T) {
"someones name",
"someones.elses.name@gmail.com",
},
Homepage: "https://github.com/tom/ruby-name",
},
},
expected: []string{
"cpe:2.3:a:*:name:3.2:*:*:*:*:*:*:*",
"cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*",
"cpe:2.3:a:ruby-lang:name:3.2:*:*:*:*:*:*:*",
"cpe:2.3:a:ruby:name:3.2:*:*:*:*:*:*:*",
@ -154,6 +159,7 @@ func TestGeneratePackageCPEs(t *testing.T) {
"cpe:2.3:a:someones-name:name:3.2:*:*:*:*:*:*:*",
"cpe:2.3:a:someones_elses_name:name:3.2:*:*:*:*:*:*:*",
"cpe:2.3:a:someones_name:name:3.2:*:*:*:*:*:*:*",
"cpe:2.3:a:tom:name:3.2:*:*:*:*:*:*:*",
},
},
{
@ -641,7 +647,6 @@ func TestGeneratePackageCPEs(t *testing.T) {
},
},
expected: []string{
"cpe:2.3:a:*:bundler:2.1.4:*:*:*:*:*:*:*",
"cpe:2.3:a:bundler:bundler:2.1.4:*:*:*:*:*:*:*",
"cpe:2.3:a:ruby-lang:bundler:2.1.4:*:*:*:*:*:*:*",
"cpe:2.3:a:ruby:bundler:2.1.4:*:*:*:*:*:*:*",

View File

@ -0,0 +1,32 @@
package cpe
import "github.com/anchore/syft/syft/pkg"
func candidateVendorsForJavascript(p pkg.Package) fieldCandidateSet {
if p.MetadataType != pkg.NpmPackageJSONMetadataType {
return nil
}
vendors := newFieldCandidateSet()
metadata, ok := p.Metadata.(pkg.NpmPackageJSONMetadata)
if !ok {
return nil
}
if metadata.Author != "" {
vendors.add(fieldCandidate{
value: normalizePersonName(stripEmailSuffix(metadata.Author)),
disallowSubSelections: true,
})
}
if metadata.URL != "" {
vendors.union(candidateVendorsFromURL(metadata.URL))
}
if metadata.Homepage != "" {
vendors.union(candidateVendorsFromURL(metadata.Homepage))
}
return vendors
}

View File

@ -17,5 +17,10 @@ func candidateVendorsForRuby(p pkg.Package) fieldCandidateSet {
disallowSubSelections: true,
})
}
if metadata.Homepage != "" {
vendors.union(candidateVendorsFromURL(metadata.Homepage))
}
return vendors
}

View File

@ -21,7 +21,7 @@ var (
}
vendorExtractionPatterns = []*regexp.Regexp{
regexp.MustCompile(`^https://(?:github|gitlab)\.com/(?P<vendor>[\w\-]*?)/.*$`),
regexp.MustCompile(`^(?:https|http|git)://(?:github|gitlab)\.com/(?P<vendor>[\w\-]*?)/.*$`),
}
)

View File

@ -52,6 +52,16 @@ func Test_candidateVendorsFromURL(t *testing.T) {
url: "https://github.com/armadillo/abcxyz-12345/a/b/c/d/e/f/g",
expected: []string{"armadillo"},
},
{
name: "github username from git://",
url: "git://github.com/abc/xyz.git",
expected: []string{"abc"},
},
{
name: "github username from http://",
url: "http://github.com/abc/xyz.git",
expected: []string{"abc"},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {