Skip to content

Commit

Permalink
feat: add manufacturer and authors
Browse files Browse the repository at this point in the history
- adds manufacturer field to Metadata and Component
- adds authors field to Component
- adds roundtrip testdata for above

Signed-off-by: Tim Pickles <tim.pickles@snyk.io>
  • Loading branch information
snyk-tim committed May 29, 2024
1 parent 1586f07 commit b5d3595
Show file tree
Hide file tree
Showing 15 changed files with 335 additions and 38 deletions.
6 changes: 6 additions & 0 deletions convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ func (b *BOM) convert(specVersion SpecVersion) {
b.Metadata.Lifecycles = nil
}

if specVersion < SpecVersion1_6 {
b.Metadata.Manufacturer = nil
}

recurseComponent(b.Metadata.Component, componentConverter(specVersion))
convertLicenses(b.Metadata.Licenses, specVersion)
convertTools(b.Metadata.Tools, specVersion)
Expand Down Expand Up @@ -147,6 +151,8 @@ func componentConverter(specVersion SpecVersion) func(*Component) {
if specVersion < SpecVersion1_6 {
c.SWHID = nil
c.OmniborID = nil
c.Manufacturer = nil
c.Authors = nil
}

if !specVersion.supportsComponentType(c.Type) {
Expand Down
44 changes: 44 additions & 0 deletions convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,47 @@ func Test_convertModelCard(t *testing.T) {
assert.Nil(t, bom.Metadata.Component.ModelCard.Considerations.EnvironmentalConsiderations)
})
}

func Test_convertManufacturer(t *testing.T) {
t.Run("spec 1.5 and lower", func(t *testing.T) {
bom := NewBOM()
bom.Metadata = &Metadata{
Manufacturer: &OrganizationalEntity{
Name: "Acme, Inc.",
},
}
bom.Components = &[]Component{
{
Name: "foo",
Manufacturer: &OrganizationalEntity{
Name: "Acme, Inc.",
},
},
}

bom.convert(SpecVersion1_5)

assert.Nil(t, bom.Metadata.Manufacturer)
assert.Nil(t, (*bom.Components)[0].Manufacturer)
})
}

func Test_convertAuthors(t *testing.T) {
t.Run("spec 1.5 and lower", func(t *testing.T) {
bom := NewBOM()
bom.Components = &[]Component{
{
Name: "foo",
Authors: &[]OrganizationalContact{
{
Name: "Acme Professional Services",
},
},
},
}

bom.convert(SpecVersion1_5)

assert.Nil(t, (*bom.Components)[0].Authors)
})
}
79 changes: 41 additions & 38 deletions cyclonedx.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,35 +221,37 @@ type Commit struct {
}

type Component struct {
BOMRef string `json:"bom-ref,omitempty" xml:"bom-ref,attr,omitempty"`
MIMEType string `json:"mime-type,omitempty" xml:"mime-type,attr,omitempty"`
Type ComponentType `json:"type" xml:"type,attr"`
Supplier *OrganizationalEntity `json:"supplier,omitempty" xml:"supplier,omitempty"`
Author string `json:"author,omitempty" xml:"author,omitempty"`
Publisher string `json:"publisher,omitempty" xml:"publisher,omitempty"`
Group string `json:"group,omitempty" xml:"group,omitempty"`
Name string `json:"name" xml:"name"`
Version string `json:"version,omitempty" xml:"version,omitempty"`
Description string `json:"description,omitempty" xml:"description,omitempty"`
Scope Scope `json:"scope,omitempty" xml:"scope,omitempty"`
Hashes *[]Hash `json:"hashes,omitempty" xml:"hashes>hash,omitempty"`
Licenses *Licenses `json:"licenses,omitempty" xml:"licenses,omitempty"`
Copyright string `json:"copyright,omitempty" xml:"copyright,omitempty"`
CPE string `json:"cpe,omitempty" xml:"cpe,omitempty"`
PackageURL string `json:"purl,omitempty" xml:"purl,omitempty"`
OmniborID *[]string `json:"omniborId,omitempty" xml:"omniborId,omitempty"`
SWHID *[]string `json:"swhid,omitempty" xml:"swhid,omitempty"`
SWID *SWID `json:"swid,omitempty" xml:"swid,omitempty"`
Modified *bool `json:"modified,omitempty" xml:"modified,omitempty"`
Pedigree *Pedigree `json:"pedigree,omitempty" xml:"pedigree,omitempty"`
ExternalReferences *[]ExternalReference `json:"externalReferences,omitempty" xml:"externalReferences>reference,omitempty"`
Properties *[]Property `json:"properties,omitempty" xml:"properties>property,omitempty"`
Components *[]Component `json:"components,omitempty" xml:"components>component,omitempty"`
Evidence *Evidence `json:"evidence,omitempty" xml:"evidence,omitempty"`
ReleaseNotes *ReleaseNotes `json:"releaseNotes,omitempty" xml:"releaseNotes,omitempty"`
ModelCard *MLModelCard `json:"modelCard,omitempty" xml:"modelCard,omitempty"`
Data *ComponentData `json:"data,omitempty" xml:"data,omitempty"`
CryptoProperties *CryptoProperties `json:"cryptoProperties,omitempty" xml:"cryptoProperties,omitempty"`
BOMRef string `json:"bom-ref,omitempty" xml:"bom-ref,attr,omitempty"`
MIMEType string `json:"mime-type,omitempty" xml:"mime-type,attr,omitempty"`
Type ComponentType `json:"type" xml:"type,attr"`
Supplier *OrganizationalEntity `json:"supplier,omitempty" xml:"supplier,omitempty"`
Manufacturer *OrganizationalEntity `json:"manufacturer,omitempty" xml:"manufacturer,omitempty"`
Author string `json:"author,omitempty" xml:"author,omitempty"` // Deprecated: Use authors or manufacturer instead.
Authors *[]OrganizationalContact `json:"authors,omitempty" xml:"authors>author,omitempty"`
Publisher string `json:"publisher,omitempty" xml:"publisher,omitempty"`
Group string `json:"group,omitempty" xml:"group,omitempty"`
Name string `json:"name" xml:"name"`
Version string `json:"version,omitempty" xml:"version,omitempty"`
Description string `json:"description,omitempty" xml:"description,omitempty"`
Scope Scope `json:"scope,omitempty" xml:"scope,omitempty"`
Hashes *[]Hash `json:"hashes,omitempty" xml:"hashes>hash,omitempty"`
Licenses *Licenses `json:"licenses,omitempty" xml:"licenses,omitempty"`
Copyright string `json:"copyright,omitempty" xml:"copyright,omitempty"`
CPE string `json:"cpe,omitempty" xml:"cpe,omitempty"`
PackageURL string `json:"purl,omitempty" xml:"purl,omitempty"`
OmniborID *[]string `json:"omniborId,omitempty" xml:"omniborId,omitempty"`
SWHID *[]string `json:"swhid,omitempty" xml:"swhid,omitempty"`
SWID *SWID `json:"swid,omitempty" xml:"swid,omitempty"`
Modified *bool `json:"modified,omitempty" xml:"modified,omitempty"`
Pedigree *Pedigree `json:"pedigree,omitempty" xml:"pedigree,omitempty"`
ExternalReferences *[]ExternalReference `json:"externalReferences,omitempty" xml:"externalReferences>reference,omitempty"`
Properties *[]Property `json:"properties,omitempty" xml:"properties>property,omitempty"`
Components *[]Component `json:"components,omitempty" xml:"components>component,omitempty"`
Evidence *Evidence `json:"evidence,omitempty" xml:"evidence,omitempty"`
ReleaseNotes *ReleaseNotes `json:"releaseNotes,omitempty" xml:"releaseNotes,omitempty"`
ModelCard *MLModelCard `json:"modelCard,omitempty" xml:"modelCard,omitempty"`
Data *ComponentData `json:"data,omitempty" xml:"data,omitempty"`
CryptoProperties *CryptoProperties `json:"cryptoProperties,omitempty" xml:"cryptoProperties,omitempty"`
}

type ComponentData struct {
Expand Down Expand Up @@ -957,15 +959,16 @@ func (mt MediaType) WithVersion(specVersion SpecVersion) (string, error) {
}

type Metadata struct {
Timestamp string `json:"timestamp,omitempty" xml:"timestamp,omitempty"`
Lifecycles *[]Lifecycle `json:"lifecycles,omitempty" xml:"lifecycles>lifecycle,omitempty"`
Tools *ToolsChoice `json:"tools,omitempty" xml:"tools,omitempty"`
Authors *[]OrganizationalContact `json:"authors,omitempty" xml:"authors>author,omitempty"`
Component *Component `json:"component,omitempty" xml:"component,omitempty"`
Manufacture *OrganizationalEntity `json:"manufacture,omitempty" xml:"manufacture,omitempty"`
Supplier *OrganizationalEntity `json:"supplier,omitempty" xml:"supplier,omitempty"`
Licenses *Licenses `json:"licenses,omitempty" xml:"licenses,omitempty"`
Properties *[]Property `json:"properties,omitempty" xml:"properties>property,omitempty"`
Timestamp string `json:"timestamp,omitempty" xml:"timestamp,omitempty"`
Lifecycles *[]Lifecycle `json:"lifecycles,omitempty" xml:"lifecycles>lifecycle,omitempty"`
Tools *ToolsChoice `json:"tools,omitempty" xml:"tools,omitempty"`
Authors *[]OrganizationalContact `json:"authors,omitempty" xml:"authors>author,omitempty"`
Component *Component `json:"component,omitempty" xml:"component,omitempty"`
Manufacture *OrganizationalEntity `json:"manufacture,omitempty" xml:"manufacture,omitempty"` // Deprecated: Use Component Manufacturer instead.
Manufacturer *OrganizationalEntity `json:"manufacturer,omitempty" xml:"manufacturer,omitempty"`
Supplier *OrganizationalEntity `json:"supplier,omitempty" xml:"supplier,omitempty"`
Licenses *Licenses `json:"licenses,omitempty" xml:"licenses,omitempty"`
Properties *[]Property `json:"properties,omitempty" xml:"properties>property,omitempty"`
}

type MLDatasetChoice struct {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
"version": 1,
"components": [
{
"type": "application",
"authors": [
{
"name": "Anthony Edward Stark",
"email": "ironman@example.org",
"phone": "555-212-970-4133"
},
{
"name": "Peter Benjamin Parker",
"email": "spiderman@example.org"
}
],
"name": "Acme Application",
"version": "9.1.1"
}
]
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
"version": 1,
"components": [
{
"type": "application",
"manufacturer": {
"name": "Acme, Inc.",
"url": [
"https://example.com"
],
"contact": [
{
"name": "Acme Professional Services",
"email": "professional.services@example.com"
}
]
},
"name": "Acme Application",
"version": "9.1.1"
}
]
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
"version": 1,
"metadata": {
"manufacturer": {
"name": "Acme, Inc.",
"url": [
"https://example.com"
],
"contact": [
{
"name": "Acme Professional Services",
"email": "professional.services@example.com"
}
]
}
},
"components": []
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.6" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1">
<components>
<component type="application">
<authors>
<author>
<name>Anthony Edward Stark</name>
<email>ironman@example.org</email>
<phone>555-212-970-4133</phone>
</author>
<author>
<name>Peter Benjamin Parker</name>
<email>spiderman@example.org</email>
</author>
</authors>
<name>Acme Application</name>
<version>9.1.1</version>
</component>
</components>
</bom>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.6" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1">
<components>
<component type="application">
<manufacturer>
<name>Acme, Inc.</name>
<url>https://example.com</url>
<contact>
<name>Acme Professional Services</name>
<email>professional.services@example.com</email>
</contact>
</manufacturer>
<name>Acme Application</name>
<version>9.1.1</version>
</component>
</components>
</bom>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.6" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1">
<metadata>
<manufacturer>
<name>Acme, Inc.</name>
<url>https://example.com</url>
<contact>
<name>Acme Professional Services</name>
<email>professional.services@example.com</email>
</contact>
</manufacturer>
</metadata>
</bom>
24 changes: 24 additions & 0 deletions testdata/valid-component-authors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
"version": 1,
"components": [
{
"type": "application",
"name": "Acme Application",
"version": "9.1.1",
"authors": [
{
"name": "Anthony Edward Stark",
"phone": "555-212-970-4133",
"email": "ironman@example.org"
},
{
"name": "Peter Benjamin Parker",
"email": "spiderman@example.org"
}
]
}
]
}
20 changes: 20 additions & 0 deletions testdata/valid-component-authors.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0"?>
<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.6">
<components>
<component type="application">
<authors>
<author>
<name>Anthony Edward Stark</name>
<email>ironman@example.org</email>
<phone>555-212-970-4133</phone>
</author>
<author>
<name>Peter Benjamin Parker</name>
<email>spiderman@example.org</email>
</author>
</authors>
<name>Acme Application</name>
<version>9.1.1</version>
</component>
</components>
</bom>
25 changes: 25 additions & 0 deletions testdata/valid-component-manufacturer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
"version": 1,
"components": [
{
"type": "application",
"name": "Acme Application",
"version": "9.1.1",
"manufacturer": {
"name": "Acme, Inc.",
"url": [
"https://example.com"
],
"contact": [
{
"name": "Acme Professional Services",
"email": "professional.services@example.com"
}
]
}
}
]
}
17 changes: 17 additions & 0 deletions testdata/valid-component-manufacturer.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0"?>
<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.6">
<components>
<component type="application">
<manufacturer>
<name>Acme, Inc.</name>
<url>https://example.com</url>
<contact>
<name>Acme Professional Services</name>
<email>professional.services@example.com</email>
</contact>
</manufacturer>
<name>Acme Application</name>
<version>9.1.1</version>
</component>
</components>
</bom>
Loading

0 comments on commit b5d3595

Please sign in to comment.