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 { switch p.MetadataType {
case pkg.RpmMetadataType: case pkg.RpmMetadataType:
vendors.union(candidateVendorsForRPM(p)) vendors.union(candidateVendorsForRPM(p))
@ -111,8 +104,15 @@ func candidateVendors(p pkg.Package) []string {
vendors.union(candidateVendorsForJava(p)) vendors.union(candidateVendorsForJava(p))
case pkg.ApkMetadataType: case pkg.ApkMetadataType:
vendors.union(candidateVendorsForAPK(p)) 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 // try swapping hyphens for underscores, vice versa, and removing separators altogether
addDelimiterVariations(vendors) addDelimiterVariations(vendors)

View File

@ -121,11 +121,16 @@ func TestGeneratePackageCPEs(t *testing.T) {
Version: "3.2", Version: "3.2",
FoundBy: "some-analyzer", FoundBy: "some-analyzer",
Language: pkg.JavaScript, Language: pkg.JavaScript,
Type: pkg.DebPkg, MetadataType: pkg.NpmPackageJSONMetadataType,
Metadata: pkg.NpmPackageJSONMetadata{
Author: "jon",
URL: "https://github.com/bob/npm-name",
},
}, },
expected: []string{ expected: []string{
"cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*", "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 name",
"someones.elses.name@gmail.com", "someones.elses.name@gmail.com",
}, },
Homepage: "https://github.com/tom/ruby-name",
}, },
}, },
expected: []string{ expected: []string{
"cpe:2.3:a:*:name:3.2:*:*:*:*:*:*:*",
"cpe:2.3:a:name: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-lang:name:3.2:*:*:*:*:*:*:*",
"cpe:2.3:a:ruby: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-name:name:3.2:*:*:*:*:*:*:*",
"cpe:2.3:a:someones_elses_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:someones_name:name:3.2:*:*:*:*:*:*:*",
"cpe:2.3:a:tom:name:3.2:*:*:*:*:*:*:*",
}, },
}, },
{ {
@ -641,7 +647,6 @@ func TestGeneratePackageCPEs(t *testing.T) {
}, },
}, },
expected: []string{ expected: []string{
"cpe:2.3:a:*:bundler:2.1.4:*:*:*:*:*:*:*",
"cpe:2.3:a:bundler: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-lang:bundler:2.1.4:*:*:*:*:*:*:*",
"cpe:2.3:a:ruby: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, disallowSubSelections: true,
}) })
} }
if metadata.Homepage != "" {
vendors.union(candidateVendorsFromURL(metadata.Homepage))
}
return vendors return vendors
} }

View File

@ -21,7 +21,7 @@ var (
} }
vendorExtractionPatterns = []*regexp.Regexp{ 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", url: "https://github.com/armadillo/abcxyz-12345/a/b/c/d/e/f/g",
expected: []string{"armadillo"}, 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 { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {