diff --git a/convert.go b/convert.go index ac27448..6c53145 100644 --- a/convert.go +++ b/convert.go @@ -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) @@ -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) { diff --git a/convert_test.go b/convert_test.go index 251a7a2..f071258 100644 --- a/convert_test.go +++ b/convert_test.go @@ -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) + }) +} diff --git a/cyclonedx.go b/cyclonedx.go index f530bb7..378f878 100644 --- a/cyclonedx.go +++ b/cyclonedx.go @@ -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 { @@ -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 { diff --git a/testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-component-authors.json b/testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-component-authors.json new file mode 100644 index 0000000..e2f8bff --- /dev/null +++ b/testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-component-authors.json @@ -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" + } + ] +} + diff --git a/testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-component-manufacturer.json b/testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-component-manufacturer.json new file mode 100644 index 0000000..881a63c --- /dev/null +++ b/testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-component-manufacturer.json @@ -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" + } + ] +} + diff --git a/testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-manufacturer.json b/testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-manufacturer.json new file mode 100644 index 0000000..f1eb8c0 --- /dev/null +++ b/testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-manufacturer.json @@ -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": [] +} + diff --git a/testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-component-authors.xml b/testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-component-authors.xml new file mode 100644 index 0000000..73a5759 --- /dev/null +++ b/testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-component-authors.xml @@ -0,0 +1,20 @@ + + + + + + + Anthony Edward Stark + ironman@example.org + 555-212-970-4133 + + + Peter Benjamin Parker + spiderman@example.org + + + Acme Application + 9.1.1 + + + diff --git a/testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-component-manufacturer.xml b/testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-component-manufacturer.xml new file mode 100644 index 0000000..6d05a1a --- /dev/null +++ b/testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-component-manufacturer.xml @@ -0,0 +1,17 @@ + + + + + + Acme, Inc. + https://example.com + + Acme Professional Services + professional.services@example.com + + + Acme Application + 9.1.1 + + + diff --git a/testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-metadata-manufacturer.xml b/testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-metadata-manufacturer.xml new file mode 100644 index 0000000..2050638 --- /dev/null +++ b/testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-metadata-manufacturer.xml @@ -0,0 +1,13 @@ + + + + + Acme, Inc. + https://example.com + + Acme Professional Services + professional.services@example.com + + + + diff --git a/testdata/valid-component-authors.json b/testdata/valid-component-authors.json new file mode 100644 index 0000000..1d9c3fc --- /dev/null +++ b/testdata/valid-component-authors.json @@ -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" + } + ] + } + ] +} diff --git a/testdata/valid-component-authors.xml b/testdata/valid-component-authors.xml new file mode 100644 index 0000000..49e6b96 --- /dev/null +++ b/testdata/valid-component-authors.xml @@ -0,0 +1,20 @@ + + + + + + + Anthony Edward Stark + ironman@example.org + 555-212-970-4133 + + + Peter Benjamin Parker + spiderman@example.org + + + Acme Application + 9.1.1 + + + diff --git a/testdata/valid-component-manufacturer.json b/testdata/valid-component-manufacturer.json new file mode 100644 index 0000000..9653fc0 --- /dev/null +++ b/testdata/valid-component-manufacturer.json @@ -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" + } + ] + } + } + ] +} diff --git a/testdata/valid-component-manufacturer.xml b/testdata/valid-component-manufacturer.xml new file mode 100644 index 0000000..f9b4d44 --- /dev/null +++ b/testdata/valid-component-manufacturer.xml @@ -0,0 +1,17 @@ + + + + + + Acme, Inc. + https://example.com + + Acme Professional Services + professional.services@example.com + + + Acme Application + 9.1.1 + + + diff --git a/testdata/valid-metadata-manufacturer.json b/testdata/valid-metadata-manufacturer.json new file mode 100644 index 0000000..838213f --- /dev/null +++ b/testdata/valid-metadata-manufacturer.json @@ -0,0 +1,21 @@ +{ + "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": [] +} diff --git a/testdata/valid-metadata-manufacturer.xml b/testdata/valid-metadata-manufacturer.xml new file mode 100644 index 0000000..294e4e5 --- /dev/null +++ b/testdata/valid-metadata-manufacturer.xml @@ -0,0 +1,14 @@ + + + + + Acme, Inc. + https://example.com + + Acme Professional Services + professional.services@example.com + + + + +