feat: Record where CPEs come from (#2552)

Syft can get CPEs from several source, including generating them based on
package data, finding them in the NVD CPE dictionary, or finding them declared
in a manifest or existing SBOM. Record where Syft got CPEs so that consumers of
SBOMs can reason about how trustworthy they are.

Signed-off-by: Will Murphy <will.murphy@anchore.com>
This commit is contained in:
William Murphy
2024-02-02 16:17:52 +00:00
committed by GitHub
parent 4fe50f4169
commit b7a6d5e946
47 changed files with 2674 additions and 287 deletions
@@ -12,7 +12,7 @@ func encodeSingleCPE(p pkg.Package) string {
// Since the CPEs in a package are sorted by specificity
// we can extract the first CPE as the one to output in cyclonedx
if len(p.CPEs) > 0 {
return p.CPEs[0].String()
return p.CPEs[0].Attributes.String()
}
return ""
}
@@ -25,7 +25,7 @@ func encodeCPEs(p pkg.Package) (out []cyclonedx.Property) {
}
out = append(out, cyclonedx.Property{
Name: "syft:cpe23",
Value: c.String(),
Value: c.Attributes.String(),
})
}
return
@@ -33,7 +33,7 @@ func encodeCPEs(p pkg.Package) (out []cyclonedx.Property) {
func decodeCPEs(c *cyclonedx.Component) (out []cpe.CPE) {
if c.CPE != "" {
cp, err := cpe.New(c.CPE)
cp, err := cpe.New(c.CPE, cpe.DeclaredSource)
if err != nil {
log.Warnf("invalid CPE: %s", c.CPE)
} else {
@@ -44,7 +44,7 @@ func decodeCPEs(c *cyclonedx.Component) (out []cpe.CPE) {
if c.Properties != nil {
for _, p := range *c.Properties {
if p.Name == "syft:cpe23" {
cp, err := cpe.New(p.Value)
cp, err := cpe.New(p.Value, cpe.DeclaredSource)
if err != nil {
log.Warnf("invalid CPE: %s", p.Value)
} else {
@@ -10,8 +10,8 @@ import (
)
func Test_encodeCPE(t *testing.T) {
testCPE := cpe.Must("cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*")
testCPE2 := cpe.Must("cpe:2.3:a:name:name2:3.2:*:*:*:*:*:*:*")
testCPE := cpe.Must("cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*", "test-source")
testCPE2 := cpe.Must("cpe:2.3:a:name:name2:3.2:*:*:*:*:*:*:*", "test-source-2")
tests := []struct {
name string
input pkg.Package
@@ -26,7 +26,7 @@ func Test_encodeCPE(t *testing.T) {
expected: "",
},
{
name: "single CPE",
name: "single Attributes",
input: pkg.Package{
CPEs: []cpe.CPE{
testCPE,
@@ -222,7 +222,7 @@ func Test_decode(t *testing.T) {
if e.cpe != "" {
foundCPE := false
for _, c := range p.CPEs {
cstr := c.BindToFmtString()
cstr := c.Attributes.BindToFmtString()
if e.cpe == cstr {
foundCPE = true
break
@@ -10,7 +10,7 @@ func ExternalRefs(p pkg.Package) (externalRefs []ExternalRef) {
for _, c := range p.CPEs {
externalRefs = append(externalRefs, ExternalRef{
ReferenceCategory: SecurityReferenceCategory,
ReferenceLocator: c.String(),
ReferenceLocator: c.Attributes.String(),
ReferenceType: Cpe23ExternalRefType,
})
}
@@ -10,7 +10,7 @@ import (
)
func Test_ExternalRefs(t *testing.T) {
testCPE := cpe.Must("cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*")
testCPE := cpe.Must("cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*", cpe.Source(""))
tests := []struct {
name string
input pkg.Package
@@ -27,7 +27,7 @@ func Test_ExternalRefs(t *testing.T) {
expected: []ExternalRef{
{
ReferenceCategory: SecurityReferenceCategory,
ReferenceLocator: testCPE.String(),
ReferenceLocator: testCPE.Attributes.String(),
ReferenceType: Cpe23ExternalRefType,
},
{
@@ -123,7 +123,7 @@ func newDirectoryCatalog() *pkg.Collection {
},
PURL: "a-purl-2", // intentionally a bad pURL for test fixtures
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"),
cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*", cpe.Source("")),
},
})
catalog.Add(pkg.Package{
@@ -140,7 +140,7 @@ func newDirectoryCatalog() *pkg.Collection {
},
PURL: "pkg:deb/debian/package-2@2.0.1",
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"),
cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*", cpe.Source("")),
},
})
@@ -175,7 +175,7 @@ func newDirectoryCatalogWithAuthorField() *pkg.Collection {
},
PURL: "a-purl-2", // intentionally a bad pURL for test fixtures
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"),
cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*", cpe.GeneratedSource),
},
})
catalog.Add(pkg.Package{
@@ -192,7 +192,7 @@ func newDirectoryCatalogWithAuthorField() *pkg.Collection {
},
PURL: "pkg:deb/debian/package-2@2.0.1",
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"),
cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*", "another-test-source"),
},
})
+2 -2
View File
@@ -119,7 +119,7 @@ func populateImageCatalog(catalog *pkg.Collection, img *image.Image) {
},
PURL: "a-purl-1", // intentionally a bad pURL for test fixtures
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:*:some:package:1:*:*:*:*:*:*:*"),
cpe.Must("cpe:2.3:*:some:package:1:*:*:*:*:*:*:*", cpe.GeneratedSource),
},
})
}
@@ -139,7 +139,7 @@ func populateImageCatalog(catalog *pkg.Collection, img *image.Image) {
},
PURL: "pkg:deb/debian/package-2@2.0.1",
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"),
cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
})
}