syft icon indicating copy to clipboard operation
syft copied to clipboard

Support accessing individual CPE fields from templates

Open abderrahim opened this issue 2 years ago • 1 comments

What would you like to be added:

I'd like to be able to use individual fields from the CPE when providing a custom template.

Why is this needed: I am investigating syft to assess whether we can migrate to using it. One of the requirements is to be able to generate a SBOM in a proprietary json format. This format requires the CPE information (vendor, product and version) to be in separate fields.

Additional context:

The following patch allows me to get what I want, but it breaks other parts. I think we can do it this way, but have pkg.CPEString be the default formatting function for a pkg.CPE

diff --git a/syft/formats/syftjson/model/package.go b/syft/formats/syftjson/model/package.go
index 12ef3c3..f3a8294 100644
--- a/syft/formats/syftjson/model/package.go
+++ b/syft/formats/syftjson/model/package.go
@@ -29,7 +29,7 @@ type PackageBasicData struct {
 	Locations []source.Coordinates `json:"locations"`
 	Licenses  []string             `json:"licenses"`
 	Language  pkg.Language         `json:"language"`
-	CPEs      []string             `json:"cpes"`
+	CPEs      []pkg.CPE            `json:"cpes"`
 	PURL      string               `json:"purl"`
 }
 
diff --git a/syft/formats/syftjson/to_format_model.go b/syft/formats/syftjson/to_format_model.go
index 58e4dbb..e72f09c 100644
--- a/syft/formats/syftjson/to_format_model.go
+++ b/syft/formats/syftjson/to_format_model.go
@@ -169,11 +169,6 @@ func toPackageModels(catalog *pkg.Catalog) []model.Package {
 
 // toPackageModel crates a new Package from the given pkg.Package.
 func toPackageModel(p pkg.Package) model.Package {
-	var cpes = make([]string, len(p.CPEs))
-	for i, c := range p.CPEs {
-		cpes[i] = pkg.CPEString(c)
-	}
-
 	var licenses = make([]string, 0)
 	if p.Licenses != nil {
 		licenses = p.Licenses
@@ -195,7 +190,7 @@ func toPackageModel(p pkg.Package) model.Package {
 			Locations: coordinates,
 			Licenses:  licenses,
 			Language:  p.Language,
-			CPEs:      cpes,
+			CPEs:      p.CPEs,
 			PURL:      p.PURL,
 		},
 		PackageCustomData: model.PackageCustomData{
diff --git a/syft/formats/syftjson/to_syft_model.go b/syft/formats/syftjson/to_syft_model.go
index 9c27604..f5f6600 100644
--- a/syft/formats/syftjson/to_syft_model.go
+++ b/syft/formats/syftjson/to_syft_model.go
@@ -153,13 +153,7 @@ func toSyftCatalog(pkgs []model.Package, idAliases map[string]string) *pkg.Catal
 func toSyftPackage(p model.Package, idAliases map[string]string) pkg.Package {
 	var cpes []pkg.CPE
 	for _, c := range p.CPEs {
-		value, err := pkg.NewCPE(c)
-		if err != nil {
-			log.Warnf("excluding invalid CPE %q: %v", c, err)
-			continue
-		}
-
-		cpes = append(cpes, value)
+		cpes = append(cpes, c)
 	}
 
 	var locations = make([]source.Location, len(p.Locations))

abderrahim avatar Sep 15 '22 15:09 abderrahim

I wonder if we could surface some helper functions in the template instead for this, what do you think?

kzantow avatar Sep 15 '22 16:09 kzantow

That would be possible indeed. I just feel that it would be cleaner to allow direct access as they are already stored with separated fields internally.

abderrahim avatar Oct 25 '22 11:10 abderrahim