Skip to content

Commit a813506

Browse files
authored
fix(cyclonedx): move root component from scanned cyclonedx file to output cyclonedx file (aquasecurity#6113)
1 parent 14adbb4 commit a813506

File tree

4 files changed

+255
-0
lines changed

4 files changed

+255
-0
lines changed

pkg/fanal/types/sbom.go

+7
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,15 @@ type Component struct {
2626
MIMEType string `json:"mime-type,omitempty" xml:"mime-type,attr,omitempty"`
2727
Type ComponentType `json:"type" xml:"type,attr"`
2828
Name string `json:"name" xml:"name"`
29+
Group string `json:"group" xml:"group"`
2930
Version string `json:"version,omitempty" xml:"version,omitempty"`
3031
PackageURL string `json:"purl,omitempty" xml:"purl,omitempty"`
32+
Properties []Property `json:"properties,omitempty" xml:"properties>property,omitempty"`
33+
}
34+
35+
type Property struct {
36+
Name string `json:"name" xml:"name,attr"`
37+
Value string `json:"value" xml:",chardata"`
3138
}
3239

3340
type (

pkg/sbom/cyclonedx/marshal.go

+36
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ func (e *Marshaler) rootComponent(r types.Report) (*core.Component, error) {
250250
root.Type = cdx.ComponentTypeContainer
251251
case ftypes.ArtifactFilesystem, ftypes.ArtifactRepository:
252252
root.Type = cdx.ComponentTypeApplication
253+
case ftypes.ArtifactCycloneDX:
254+
return toCoreComponent(r.CycloneDX.Metadata.Component)
253255
}
254256

255257
if r.Metadata.Size != 0 {
@@ -396,3 +398,37 @@ func filterProperties(props []core.Property) []core.Property {
396398
return !(property.Value == "" || (property.Name == PropertySrcEpoch && property.Value == "0"))
397399
})
398400
}
401+
402+
func toCoreComponent(c ftypes.Component) (*core.Component, error) {
403+
var props []core.Property
404+
for _, prop := range c.Properties {
405+
var namespace string
406+
name := prop.Name
407+
// Separate the Trivy namespace to avoid double spelling of namespaces.
408+
if strings.HasPrefix(name, core.Namespace) {
409+
name = strings.TrimPrefix(name, core.Namespace)
410+
namespace = core.Namespace
411+
}
412+
props = append(props, core.Property{
413+
Namespace: namespace,
414+
Name: name,
415+
Value: prop.Value,
416+
})
417+
}
418+
var p *purl.PackageURL
419+
if c.PackageURL != "" {
420+
var err error
421+
p, err = purl.FromString(c.PackageURL)
422+
if err != nil {
423+
return nil, xerrors.Errorf("failed to parse purl: %w", err)
424+
}
425+
}
426+
427+
return &core.Component{
428+
Name: c.Name,
429+
Group: c.Group,
430+
PackageURL: p,
431+
Type: cdx.ComponentType(c.Type),
432+
Properties: props,
433+
}, nil
434+
}

pkg/sbom/cyclonedx/marshal_test.go

+203
Original file line numberDiff line numberDiff line change
@@ -1401,6 +1401,209 @@ func TestMarshaler_Marshal(t *testing.T) {
14011401
},
14021402
},
14031403
},
1404+
{
1405+
name: "happy path for sbom (cyclonedx) scan",
1406+
inputReport: types.Report{
1407+
SchemaVersion: report.SchemaVersion,
1408+
ArtifactName: "./report.cdx.json",
1409+
ArtifactType: ftypes.ArtifactCycloneDX,
1410+
CycloneDX: &ftypes.CycloneDX{
1411+
BOMFormat: "CycloneDX",
1412+
SpecVersion: 6,
1413+
SerialNumber: "urn:uuid:ea7360be-19a5-4f61-98dd-d4e170eb6737",
1414+
Version: 1,
1415+
Metadata: ftypes.Metadata{
1416+
Timestamp: "2024-02-16T06:05:53+00:00",
1417+
Component: ftypes.Component{
1418+
BOMRef: "aff65b54-6009-4c32-968d-748949ef46e8",
1419+
Type: "application",
1420+
Name: "jackson-databind-2.13.4.1.jar",
1421+
Properties: []ftypes.Property{
1422+
{
1423+
Name: "aquasecurity:trivy:SchemaVersion",
1424+
Value: "2",
1425+
},
1426+
},
1427+
},
1428+
},
1429+
},
1430+
Results: types.Results{
1431+
{
1432+
Target: "Java",
1433+
Class: types.ClassLangPkg,
1434+
Type: ftypes.Jar,
1435+
Packages: []ftypes.Package{
1436+
{
1437+
Name: "com.fasterxml.jackson.core:jackson-databind",
1438+
Version: "2.13.4.1",
1439+
Identifier: ftypes.PkgIdentifier{
1440+
BOMRef: "pkg:maven/com.fasterxml.jackson.core/[email protected]?file_path=jackson-databind-2.13.4.1.jar",
1441+
PURL: &packageurl.PackageURL{
1442+
Type: packageurl.TypeMaven,
1443+
Namespace: "com.fasterxml.jackson.core",
1444+
Name: "jackson-databind",
1445+
Version: "2.13.4.1",
1446+
},
1447+
},
1448+
FilePath: "jackson-databind-2.13.4.1.jar",
1449+
},
1450+
},
1451+
Vulnerabilities: []types.DetectedVulnerability{
1452+
{
1453+
VulnerabilityID: "CVE-2022-42003",
1454+
PkgName: "com.fasterxml.jackson.core:jackson-databind",
1455+
PkgPath: "jackson-databind-2.13.4.1.jar",
1456+
PkgIdentifier: ftypes.PkgIdentifier{
1457+
BOMRef: "pkg:maven/com.fasterxml.jackson.core/[email protected]?file_path=jackson-databind-2.13.4.1.jar",
1458+
PURL: &packageurl.PackageURL{
1459+
Type: packageurl.TypeMaven,
1460+
Namespace: "com.fasterxml.jackson.core",
1461+
Name: "jackson-databind",
1462+
Version: "2.13.4.1",
1463+
},
1464+
},
1465+
InstalledVersion: "2.13.4.1",
1466+
FixedVersion: "2.12.7.1, 2.13.4.2",
1467+
Status: dtypes.StatusFixed,
1468+
SeveritySource: "ghsa",
1469+
PrimaryURL: "https://avd.aquasec.com/nvd/cve-2022-42003",
1470+
DataSource: &dtypes.DataSource{
1471+
ID: vulnerability.GHSA,
1472+
Name: "GitHub Security Advisory Maven",
1473+
URL: "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Amaven",
1474+
},
1475+
Vulnerability: dtypes.Vulnerability{
1476+
Title: "jackson-databind: deep wrapper array nesting wrt UNWRAP_SINGLE_VALUE_ARRAYS",
1477+
Description: "In FasterXML jackson-databind before versions 2.13.4.1 and 2.12.17.1, resource exhaustion can occur because of a lack of a check in primitive value deserializers to avoid deep wrapper array nesting, when the UNWRAP_SINGLE_VALUE_ARRAYS feature is enabled.",
1478+
Severity: dtypes.SeverityHigh.String(),
1479+
VendorSeverity: dtypes.VendorSeverity{
1480+
vulnerability.GHSA: dtypes.SeverityHigh,
1481+
},
1482+
CVSS: dtypes.VendorCVSS{
1483+
vulnerability.GHSA: dtypes.CVSS{
1484+
V3Vector: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
1485+
V3Score: 7.5,
1486+
},
1487+
},
1488+
References: []string{
1489+
"https://access.redhat.com/security/cve/CVE-2022-42003",
1490+
},
1491+
PublishedDate: lo.ToPtr(time.Date(2022, 10, 02, 05, 15, 0, 0, time.UTC)),
1492+
LastModifiedDate: lo.ToPtr(time.Date(2022, 12, 20, 10, 15, 0, 0, time.UTC)),
1493+
},
1494+
},
1495+
},
1496+
},
1497+
},
1498+
},
1499+
want: &cdx.BOM{
1500+
XMLNS: "http://cyclonedx.org/schema/bom/1.5",
1501+
BOMFormat: "CycloneDX",
1502+
SpecVersion: cdx.SpecVersion1_5,
1503+
JSONSchema: "http://cyclonedx.org/schema/bom-1.5.schema.json",
1504+
SerialNumber: "urn:uuid:3ff14136-e09f-4df9-80ea-000000000001",
1505+
Version: 1,
1506+
Metadata: &cdx.Metadata{
1507+
Timestamp: "2021-08-25T12:20:30+00:00",
1508+
Tools: &cdx.ToolsChoice{
1509+
Components: &[]cdx.Component{
1510+
{
1511+
Type: cdx.ComponentTypeApplication,
1512+
Name: "trivy",
1513+
Group: "aquasecurity",
1514+
Version: "dev",
1515+
},
1516+
},
1517+
},
1518+
Component: &cdx.Component{
1519+
BOMRef: "3ff14136-e09f-4df9-80ea-000000000002",
1520+
Type: cdx.ComponentTypeApplication,
1521+
Name: "jackson-databind-2.13.4.1.jar",
1522+
Properties: &[]cdx.Property{
1523+
{
1524+
Name: "aquasecurity:trivy:SchemaVersion",
1525+
Value: "2",
1526+
},
1527+
},
1528+
},
1529+
},
1530+
Components: &[]cdx.Component{
1531+
{
1532+
BOMRef: "pkg:maven/com.fasterxml.jackson.core/[email protected]?file_path=jackson-databind-2.13.4.1.jar",
1533+
Type: cdx.ComponentTypeLibrary,
1534+
Group: "com.fasterxml.jackson.core",
1535+
Name: "jackson-databind",
1536+
Version: "2.13.4.1",
1537+
PackageURL: "pkg:maven/com.fasterxml.jackson.core/[email protected]",
1538+
Properties: &[]cdx.Property{
1539+
{
1540+
Name: "aquasecurity:trivy:FilePath",
1541+
Value: "jackson-databind-2.13.4.1.jar",
1542+
},
1543+
{
1544+
Name: "aquasecurity:trivy:PkgType",
1545+
Value: "jar",
1546+
},
1547+
},
1548+
},
1549+
},
1550+
Vulnerabilities: &[]cdx.Vulnerability{
1551+
{
1552+
ID: "CVE-2022-42003",
1553+
Source: &cdx.Source{
1554+
Name: string(vulnerability.GHSA),
1555+
URL: "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Amaven",
1556+
},
1557+
Recommendation: "Upgrade com.fasterxml.jackson.core:jackson-databind to version 2.12.7.1, 2.13.4.2",
1558+
Ratings: &[]cdx.VulnerabilityRating{
1559+
{
1560+
Source: &cdx.Source{
1561+
Name: string(vulnerability.GHSA),
1562+
},
1563+
Score: lo.ToPtr(7.5),
1564+
Severity: cdx.SeverityHigh,
1565+
Method: cdx.ScoringMethodCVSSv31,
1566+
Vector: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
1567+
},
1568+
},
1569+
Description: "In FasterXML jackson-databind before versions 2.13.4.1 and 2.12.17.1, resource exhaustion can occur because of a lack of a check in primitive value deserializers to avoid deep wrapper array nesting, when the UNWRAP_SINGLE_VALUE_ARRAYS feature is enabled.",
1570+
Advisories: &[]cdx.Advisory{
1571+
{
1572+
URL: "https://avd.aquasec.com/nvd/cve-2022-42003",
1573+
},
1574+
{
1575+
URL: "https://access.redhat.com/security/cve/CVE-2022-42003",
1576+
},
1577+
},
1578+
Published: "2022-10-02T05:15:00+00:00",
1579+
Updated: "2022-12-20T10:15:00+00:00",
1580+
Affects: &[]cdx.Affects{
1581+
{
1582+
Ref: "pkg:maven/com.fasterxml.jackson.core/[email protected]?file_path=jackson-databind-2.13.4.1.jar",
1583+
Range: &[]cdx.AffectedVersions{
1584+
{
1585+
Version: "2.13.4.1",
1586+
Status: cdx.VulnerabilityStatusAffected,
1587+
},
1588+
},
1589+
},
1590+
},
1591+
},
1592+
},
1593+
Dependencies: &[]cdx.Dependency{
1594+
{
1595+
Ref: "3ff14136-e09f-4df9-80ea-000000000002",
1596+
Dependencies: &[]string{
1597+
"pkg:maven/com.fasterxml.jackson.core/[email protected]?file_path=jackson-databind-2.13.4.1.jar",
1598+
},
1599+
},
1600+
{
1601+
Ref: "pkg:maven/com.fasterxml.jackson.core/[email protected]?file_path=jackson-databind-2.13.4.1.jar",
1602+
Dependencies: lo.ToPtr([]string{}),
1603+
},
1604+
},
1605+
},
1606+
},
14041607
{
14051608
name: "happy path. 2 packages for 1 CVE",
14061609
inputReport: types.Report{

pkg/sbom/cyclonedx/unmarshal.go

+9
Original file line numberDiff line numberDiff line change
@@ -408,13 +408,22 @@ func fillSrcPkg(pkg *ftypes.Package) {
408408
}
409409

410410
func toTrivyCdxComponent(component cdx.Component) ftypes.Component {
411+
var props []ftypes.Property
412+
for _, prop := range lo.FromPtr(component.Properties) {
413+
props = append(props, ftypes.Property{
414+
Name: prop.Name,
415+
Value: prop.Value,
416+
})
417+
}
411418
return ftypes.Component{
412419
BOMRef: component.BOMRef,
413420
MIMEType: component.MIMEType,
414421
Type: ftypes.ComponentType(component.Type),
415422
Name: component.Name,
423+
Group: component.Group,
416424
Version: component.Version,
417425
PackageURL: component.PackageURL,
426+
Properties: props,
418427
}
419428
}
420429

0 commit comments

Comments
 (0)