Internalize CPE generation logic (#2541)

* migrate CPE generation logic to internal

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* remove create function

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
Alex Goodman 2024-01-26 12:16:05 -05:00 committed by GitHub
parent 7f90b8f1eb
commit b6cbf82389
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 63 additions and 49 deletions

View file

@ -8,6 +8,8 @@ import (
"github.com/facebookincubator/nvdtools/wfn"
)
const Any = ""
type CPE struct {
Part string
Vendor string
@ -123,7 +125,7 @@ func normalizeField(field string) string {
// keep dashes and forward slashes unescaped
if field == "*" {
return wfn.Any
return Any
}
return stripSlashes(field)
}

View file

@ -0,0 +1,15 @@
package cpe
import (
"github.com/anchore/syft/syft/cpe"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/internal/cpegenerate"
)
func Generate(p pkg.Package) []cpe.CPE {
return cpegenerate.FromPackageAttributes(p)
}
func DictionaryFind(p pkg.Package) (cpe.CPE, bool) {
return cpegenerate.FromDictionaryFind(p)
}

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import (
"fmt"

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import (
"testing"

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import (
"github.com/anchore/syft/syft/pkg"

View file

@ -12,7 +12,7 @@ import (
"github.com/facebookincubator/nvdtools/wfn"
"github.com/anchore/syft/syft/pkg/cataloger/common/cpe/dictionary"
"github.com/anchore/syft/syft/pkg/cataloger/internal/cpegenerate/dictionary"
)
func generateIndexedDictionaryJSON(rawGzipData io.Reader) ([]byte, error) {

View file

@ -11,7 +11,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/syft/pkg/cataloger/common/cpe/dictionary"
"github.com/anchore/syft/syft/pkg/cataloger/internal/cpegenerate/dictionary"
)
func Test_generateIndexedDictionaryJSON(t *testing.T) {

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import (
"strconv"

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
// A fieldCandidateCondition returns true if the condition is true for a given fieldCandidate.
type fieldCandidateCondition func(fieldCandidate) bool

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import (
"strings"

View file

@ -1,10 +1,8 @@
package cpe
package cpegenerate
import (
"strings"
"github.com/facebookincubator/nvdtools/wfn"
"github.com/anchore/syft/syft/cpe"
"github.com/anchore/syft/syft/pkg"
)
@ -45,18 +43,18 @@ func disallowNonParseableCPEs(c cpe.CPE, _ pkg.Package) bool {
}
// jenkins plugins should not match against jenkins
func disallowJenkinsServerCPEForPluginPackage(cpe cpe.CPE, p pkg.Package) bool {
if p.Type == pkg.JenkinsPluginPkg && cpe.Product == jenkinsName {
func disallowJenkinsServerCPEForPluginPackage(c cpe.CPE, p pkg.Package) bool {
if p.Type == pkg.JenkinsPluginPkg && c.Product == jenkinsName {
return true
}
return false
}
// filter to account that packages that are not for jenkins but have a CPE generated that will match against jenkins
func disallowJenkinsCPEsNotAssociatedWithJenkins(cpe cpe.CPE, p pkg.Package) bool {
func disallowJenkinsCPEsNotAssociatedWithJenkins(c cpe.CPE, p pkg.Package) bool {
// jenkins server should only match against a product with the name jenkins
if cpe.Product == jenkinsName && !strings.Contains(strings.ToLower(p.Name), jenkinsName) {
if cpe.Vendor == wfn.Any || cpe.Vendor == jenkinsName || cpe.Vendor == "cloudbees" {
if c.Product == jenkinsName && !strings.Contains(strings.ToLower(p.Name), jenkinsName) {
if c.Vendor == cpe.Any || c.Vendor == jenkinsName || c.Vendor == "cloudbees" {
return true
}
}
@ -64,10 +62,10 @@ func disallowJenkinsCPEsNotAssociatedWithJenkins(cpe cpe.CPE, p pkg.Package) boo
}
// filter to account for packages which are jira client packages but have a CPE that will match against jira
func disallowJiraClientServerMismatch(cpe cpe.CPE, p pkg.Package) bool {
func disallowJiraClientServerMismatch(c cpe.CPE, p pkg.Package) bool {
// jira / atlassian should not apply to clients
if cpe.Product == "jira" && strings.Contains(strings.ToLower(p.Name), "client") {
if cpe.Vendor == wfn.Any || cpe.Vendor == "jira" || cpe.Vendor == "atlassian" {
if c.Product == "jira" && strings.Contains(strings.ToLower(p.Name), "client") {
if c.Vendor == cpe.Any || c.Vendor == "jira" || c.Vendor == "atlassian" {
return true
}
}

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import (
"testing"

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import (
"bufio"
@ -10,13 +10,12 @@ import (
"strings"
"sync"
"github.com/facebookincubator/nvdtools/wfn"
"github.com/scylladb/go-set/strset"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/cpe"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/common/cpe/dictionary"
"github.com/anchore/syft/syft/pkg/cataloger/internal/cpegenerate/dictionary"
)
// knownVendors contains vendor strings that are known to exist in
@ -59,7 +58,7 @@ func GetIndexedDictionary() (_ *dictionary.Indexed, err error) {
return indexedCPEDictionary, err
}
func DictionaryFind(p pkg.Package) (cpe.CPE, bool) {
func FromDictionaryFind(p pkg.Package) (cpe.CPE, bool) {
dict, err := GetIndexedDictionary()
if err != nil {
log.Debugf("dictionary CPE lookup not available: %+v", err)
@ -107,10 +106,10 @@ func DictionaryFind(p pkg.Package) (cpe.CPE, bool) {
return parsedCPE, true
}
// Generate 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
// generate the minimal set of representative CPEs, which implies that optional fields should not be included
// (such as target SW).
func Generate(p pkg.Package) []cpe.CPE {
func FromPackageAttributes(p pkg.Package) []cpe.CPE {
vendors := candidateVendors(p)
products := candidateProducts(p)
if len(products) == 0 {
@ -128,7 +127,7 @@ func Generate(p pkg.Package) []cpe.CPE {
}
keys.Add(key)
// add a new entry...
if c := newCPE(product, vendor, p.Version, wfn.Any); c != nil {
if c := newCPE(product, vendor, p.Version, cpe.Any); c != nil {
cpes = append(cpes, *c)
}
}

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import (
"fmt"
@ -711,7 +711,7 @@ func TestGeneratePackageCPEs(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := Generate(test.p)
actual := FromPackageAttributes(test.p)
expectedCpeSet := set.NewStringSet(test.expected...)
actualCpeSet := set.NewStringSet()
@ -994,7 +994,7 @@ func TestDictionaryFindIsWired(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, gotExists := DictionaryFind(tt.pkg)
got, gotExists := FromDictionaryFind(tt.pkg)
assert.Equal(t, tt.want, got.BindToFmtString())
assert.Equal(t, tt.wantExists, gotExists)

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import (
"net/url"

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import (
"testing"

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import (
"sort"

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
var DefaultArtifactIDToGroupID = map[string]string{
"ant": "org.apache.ant",

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import (
"strings"

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import "github.com/anchore/syft/syft/pkg"

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import (
"fmt"

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import "github.com/anchore/syft/syft/pkg"

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import "github.com/anchore/syft/syft/pkg"

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import "strings"

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import (
"testing"

View file

@ -1,4 +1,4 @@
package cpe
package cpegenerate
import (
"regexp"

View file

@ -5,7 +5,7 @@ import (
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/common/cpe"
"github.com/anchore/syft/syft/pkg/cataloger/internal/cpegenerate"
)
// PackageURL returns the PURL for the specific java package (see https://github.com/package-url/purl-spec)
@ -53,7 +53,7 @@ func groupIDFromJavaMetadata(pkgName string, metadata pkg.JavaArchive) (groupID
}
func groupIDFromKnownPackageList(pkgName string) (groupID string) {
if groupID, ok := cpe.DefaultArtifactIDToGroupID[pkgName]; ok {
if groupID, ok := cpegenerate.DefaultArtifactIDToGroupID[pkgName]; ok {
return groupID
}
return groupID
@ -64,13 +64,13 @@ func groupIDFromJavaManifest(manifest *pkg.JavaManifest) (groupID string) {
return groupID
}
groupIDS := cpe.GetManifestFieldGroupIDs(manifest, cpe.PrimaryJavaManifestGroupIDFields)
groupIDS := cpegenerate.GetManifestFieldGroupIDs(manifest, cpegenerate.PrimaryJavaManifestGroupIDFields)
// assumes that primaryJavaManifestNameFields are ordered by priority
if len(groupIDS) != 0 {
return groupIDS[0]
}
groupIDS = cpe.GetManifestFieldGroupIDs(manifest, cpe.SecondaryJavaManifestGroupIDFields)
groupIDS = cpegenerate.GetManifestFieldGroupIDs(manifest, cpegenerate.SecondaryJavaManifestGroupIDFields)
if len(groupIDS) != 0 {
return groupIDS[0]