Skip to content

Commit

Permalink
fix(sbom): use group field for pom.xml and nodejs files for Cyclone…
Browse files Browse the repository at this point in the history
…DX reports (aquasecurity#5922)
  • Loading branch information
DmitriyLewen authored Jan 15, 2024
1 parent a3fac90 commit c75143f
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 15 deletions.
6 changes: 4 additions & 2 deletions integration/testdata/pom-cyclonedx.json.golden
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
{
"bom-ref": "pkg:maven/com.example/log4shell@1.0-SNAPSHOT",
"type": "library",
"name": "com.example:log4shell",
"group": "com.example",
"name": "log4shell",
"version": "1.0-SNAPSHOT",
"purl": "pkg:maven/com.example/log4shell@1.0-SNAPSHOT",
"properties": [
Expand All @@ -61,7 +62,8 @@
{
"bom-ref": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.1",
"type": "library",
"name": "com.fasterxml.jackson.core:jackson-databind",
"group": "com.fasterxml.jackson.core",
"name": "jackson-databind",
"version": "2.9.1",
"purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.1",
"properties": [
Expand Down
8 changes: 6 additions & 2 deletions pkg/sbom/cyclonedx/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"

cdx "github.com/CycloneDX/cyclonedx-go"
"github.com/package-url/packageurl-go"
"github.com/samber/lo"
"golang.org/x/xerrors"

Expand Down Expand Up @@ -323,8 +324,11 @@ func pkgComponent(pkg Package) (*core.Component, error) {
// e.g. local Go packages
if pu := pkg.Identifier.PURL; pu != nil {
version = pu.Version
// use `group` field for GroupID and `name` for ArtifactID for jar files
if pkg.Type == ftypes.Jar {
// Use `group` field for GroupID and `name` for ArtifactID for java files
// https://github.com/aquasecurity/trivy/issues/4675
// Use `group` field for npm scopes
// https://github.com/aquasecurity/trivy/issues/5908
if pu.Type == packageurl.TypeMaven || pu.Type == packageurl.TypeNPM {
name = pu.Name
group = pu.Namespace
}
Expand Down
64 changes: 64 additions & 0 deletions pkg/sbom/cyclonedx/marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,26 @@ func TestMarshaler_Marshal(t *testing.T) {
},
},
},
{
Target: "yarn.lock",
Class: types.ClassLangPkg,
Type: ftypes.Yarn,
Packages: []ftypes.Package{
{
ID: "@babel/helper-string-parser@7.23.4",
Name: "@babel/helper-string-parser",
Version: "7.23.4",
Identifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeNPM,
Namespace: "@babel",
Name: "helper-string-parser",
Version: "7.23.4",
},
},
},
},
},
},
},
want: &cdx.BOM{
Expand Down Expand Up @@ -1270,6 +1290,21 @@ func TestMarshaler_Marshal(t *testing.T) {
},
},
},
{
BOMRef: "3ff14136-e09f-4df9-80ea-000000000004",
Type: cdx.ComponentTypeApplication,
Name: "yarn.lock",
Properties: &[]cdx.Property{
{
Name: "aquasecurity:trivy:Class",
Value: "lang-pkgs",
},
{
Name: "aquasecurity:trivy:Type",
Value: "yarn",
},
},
},
{
BOMRef: "pkg:gem/actioncable@6.1.4.1",
Type: "library",
Expand Down Expand Up @@ -1301,13 +1336,32 @@ func TestMarshaler_Marshal(t *testing.T) {
},
},
},
{
BOMRef: "pkg:npm/%40babel/helper-string-parser@7.23.4",
Type: "library",
Name: "helper-string-parser",
Group: "@babel",
Version: "7.23.4",
PackageURL: "pkg:npm/%40babel/helper-string-parser@7.23.4",
Properties: &[]cdx.Property{
{
Name: "aquasecurity:trivy:PkgID",
Value: "@babel/helper-string-parser@7.23.4",
},
{
Name: "aquasecurity:trivy:PkgType",
Value: "yarn",
},
},
},
},
Vulnerabilities: &[]cdx.Vulnerability{},
Dependencies: &[]cdx.Dependency{
{
Ref: "3ff14136-e09f-4df9-80ea-000000000002",
Dependencies: &[]string{
"3ff14136-e09f-4df9-80ea-000000000003",
"3ff14136-e09f-4df9-80ea-000000000004",
"pkg:maven/org.springframework/spring-web@5.3.22?file_path=spring-web-5.3.22.jar",
},
},
Expand All @@ -1317,6 +1371,12 @@ func TestMarshaler_Marshal(t *testing.T) {
"pkg:gem/actioncable@6.1.4.1",
},
},
{
Ref: "3ff14136-e09f-4df9-80ea-000000000004",
Dependencies: &[]string{
"pkg:npm/%40babel/helper-string-parser@7.23.4",
},
},
{
Ref: "pkg:gem/actioncable@6.1.4.1",
Dependencies: lo.ToPtr([]string{}),
Expand All @@ -1325,6 +1385,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Ref: "pkg:maven/org.springframework/spring-web@5.3.22?file_path=spring-web-5.3.22.jar",
Dependencies: lo.ToPtr([]string{}),
},
{
Ref: "pkg:npm/%40babel/helper-string-parser@7.23.4",
Dependencies: lo.ToPtr([]string{}),
},
},
},
},
Expand Down
7 changes: 4 additions & 3 deletions pkg/sbom/cyclonedx/testdata/happy/bom.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,9 @@
]
},
{
"bom-ref": "pkg:npm/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json",
"bom-ref": "pkg:npm/@example/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json",
"type": "library",
"group": "@example",
"name": "bootstrap",
"version": "5.0.2",
"licenses": [
Expand All @@ -132,7 +133,7 @@
}
}
],
"purl": "pkg:npm/bootstrap@5.0.2",
"purl": "pkg:npm/@example/bootstrap@5.0.2",
"properties": [
{
"name": "aquasecurity:trivy:FilePath",
Expand Down Expand Up @@ -265,7 +266,7 @@
"60e9f57b-d4a6-4f71-ad14-0893ac609182",
"pkg:maven/org.codehaus.mojo/child-project@1.0?file_path=app%2Fmaven%2Ftarget%2Fchild-project-1.0.jar",
"pkg:maven/com.example/example@0.0.1",
"pkg:npm/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json",
"pkg:npm/@example/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json",
"100925ff-7c0a-470f-a725-8fb973b40e7b",
"1a111e6b-a682-470e-8b0e-aaa49d93cd39"
]
Expand Down
15 changes: 12 additions & 3 deletions pkg/sbom/cyclonedx/unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,10 +419,11 @@ func toTrivyCdxComponent(component cdx.Component) ftypes.Component {
}

func packageName(typ, pkgNameFromPurl string, component cdx.Component) string {
if typ == packageurl.TypeMaven {
// Jar uses `Group` field for `GroupID`
if typ == packageurl.TypeMaven || typ == packageurl.TypeNPM {
// Maven uses `Group` field for `GroupID`
// Npm uses `Group` field for `Scope`
if component.Group != "" {
return fmt.Sprintf("%s:%s", component.Group, component.Name)
return fmt.Sprintf("%s%s%s", component.Group, packageNameSeparator(typ), component.Name)
} else {
// use name derived from purl if `Group` doesn't exist
return pkgNameFromPurl
Expand All @@ -431,6 +432,14 @@ func packageName(typ, pkgNameFromPurl string, component cdx.Component) string {
return component.Name
}

// packageNameSeparator selects separator to join `group` and `name` fields of the component
func packageNameSeparator(typ string) string {
if typ == packageurl.TypeMaven {
return ":"
}
return "/"
}

// parsePackageLicenses checks all supported license fields and returns a list of licenses.
// https://cyclonedx.org/docs/1.5/json/#components_items_licenses
func parsePackageLicenses(l *cdx.Licenses) []string {
Expand Down
11 changes: 6 additions & 5 deletions pkg/sbom/cyclonedx/unmarshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,15 +172,16 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
FilePath: "",
Libraries: ftypes.Packages{
{
Name: "bootstrap",
Name: "@example/bootstrap",
Version: "5.0.2",
Identifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeNPM,
Name: "bootstrap",
Version: "5.0.2",
Type: packageurl.TypeNPM,
Namespace: "@example",
Name: "bootstrap",
Version: "5.0.2",
},
BOMRef: "pkg:npm/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json",
BOMRef: "pkg:npm/@example/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json",
},
Licenses: []string{"MIT"},
Layer: ftypes.Layer{
Expand Down

0 comments on commit c75143f

Please sign in to comment.