diff --git a/cyclonedx-bom/src/models/metadata.rs b/cyclonedx-bom/src/models/metadata.rs index 8d141eeb..7d0154e7 100644 --- a/cyclonedx-bom/src/models/metadata.rs +++ b/cyclonedx-bom/src/models/metadata.rs @@ -125,6 +125,7 @@ mod test { name: None, version: None, hashes: None, + external_references: None, }])), authors: Some(vec![OrganizationalContact { bom_ref: None, @@ -195,6 +196,7 @@ mod test { name: None, version: None, hashes: None, + external_references: None, }])), authors: Some(vec![OrganizationalContact { bom_ref: None, diff --git a/cyclonedx-bom/src/models/tool.rs b/cyclonedx-bom/src/models/tool.rs index 50e95adc..648f82ea 100644 --- a/cyclonedx-bom/src/models/tool.rs +++ b/cyclonedx-bom/src/models/tool.rs @@ -22,6 +22,7 @@ use crate::validation::{Validate, ValidationContext, ValidationResult}; use super::bom::SpecVersion; use super::component::Components; +use super::external_reference::ExternalReferences; use super::service::Services; /// Defines the creation tool(s) @@ -80,6 +81,8 @@ pub struct Tool { pub name: Option, pub version: Option, pub hashes: Option, + /// Added in spec version 1.4 + pub external_references: Option, } impl Tool { @@ -95,6 +98,7 @@ impl Tool { name: Some(NormalizedString::new(name)), version: Some(NormalizedString::new(version)), hashes: None, + external_references: None, } } } @@ -108,6 +112,11 @@ impl Validate for Tool { .add_list("hashes", &self.hashes, |hashes| { hashes.validate_version(version) }) + .add_struct_option( + "external_references", + self.external_references.as_ref(), + version, + ) .into() } } @@ -134,6 +143,7 @@ mod test { name: None, version: None, hashes: None, + external_references: None, }]) .validate(); @@ -147,6 +157,7 @@ mod test { name: None, version: None, hashes: None, + external_references: None, }]) .validate(); @@ -173,18 +184,21 @@ mod test { name: None, version: None, hashes: None, + external_references: None, }, Tool { vendor: Some(NormalizedString("spaces and\ttabs".to_string())), name: None, version: None, hashes: None, + external_references: None, }, Tool { vendor: None, name: Some(NormalizedString("spaces and\ttabs".to_string())), version: None, hashes: None, + external_references: None, }, ]) .validate(); diff --git a/cyclonedx-bom/src/specs/common/bom.rs b/cyclonedx-bom/src/specs/common/bom.rs index 830566d3..62b1e438 100644 --- a/cyclonedx-bom/src/specs/common/bom.rs +++ b/cyclonedx-bom/src/specs/common/bom.rs @@ -1023,6 +1023,15 @@ pub(crate) mod base { hash value + + + url + comment + + hash value + + + @@ -1414,6 +1423,15 @@ pub(crate) mod base { hash value + + + url + comment + + hash value + + + @@ -1467,6 +1485,15 @@ pub(crate) mod base { hash value + + + url + comment + + hash value + + + @@ -2091,6 +2118,15 @@ pub(crate) mod base { hash value + + + url + comment + + hash value + + + diff --git a/cyclonedx-bom/src/specs/common/metadata.rs b/cyclonedx-bom/src/specs/common/metadata.rs index 37348575..0992d9c7 100644 --- a/cyclonedx-bom/src/specs/common/metadata.rs +++ b/cyclonedx-bom/src/specs/common/metadata.rs @@ -546,6 +546,15 @@ pub(crate) mod base { hash value + + + url + comment + + hash value + + + @@ -695,6 +704,15 @@ pub(crate) mod base { hash value + + + url + comment + + hash value + + + diff --git a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_4__test__it_should_serialize_a_complex_example_to_json.snap b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_4__test__it_should_serialize_a_complex_example_to_json.snap index c71fe4be..5888bea3 100644 --- a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_4__test__it_should_serialize_a_complex_example_to_json.snap +++ b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_4__test__it_should_serialize_a_complex_example_to_json.snap @@ -1,6 +1,6 @@ --- source: cyclonedx-bom/src/specs/common/bom.rs -assertion_line: 606 +assertion_line: 654 expression: actual --- { @@ -20,6 +20,19 @@ expression: actual "alg": "algorithm", "content": "hash value" } + ], + "externalReferences": [ + { + "type": "external reference type", + "url": "url", + "comment": "comment", + "hashes": [ + { + "alg": "algorithm", + "content": "hash value" + } + ] + } ] } ], @@ -529,6 +542,19 @@ expression: actual "alg": "algorithm", "content": "hash value" } + ], + "externalReferences": [ + { + "type": "external reference type", + "url": "url", + "comment": "comment", + "hashes": [ + { + "alg": "algorithm", + "content": "hash value" + } + ] + } ] } ], diff --git a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_4__test__it_should_serialize_a_complex_example_to_xml.snap b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_4__test__it_should_serialize_a_complex_example_to_xml.snap index 381b92ff..bd4f4c38 100644 --- a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_4__test__it_should_serialize_a_complex_example_to_xml.snap +++ b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_4__test__it_should_serialize_a_complex_example_to_xml.snap @@ -1,6 +1,6 @@ --- source: cyclonedx-bom/src/specs/common/bom.rs -assertion_line: 598 +assertion_line: 660 expression: xml_output --- @@ -15,6 +15,15 @@ expression: xml_output hash value + + + url + comment + + hash value + + + @@ -403,6 +412,15 @@ expression: xml_output hash value + + + url + comment + + hash value + + + diff --git a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_5__test__it_should_serialize_a_complex_example_to_json.snap b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_5__test__it_should_serialize_a_complex_example_to_json.snap index bcaa9b40..dc8bb5bc 100644 --- a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_5__test__it_should_serialize_a_complex_example_to_json.snap +++ b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_5__test__it_should_serialize_a_complex_example_to_json.snap @@ -1,5 +1,6 @@ --- source: cyclonedx-bom/src/specs/common/bom.rs +assertion_line: 654 expression: actual --- { @@ -19,6 +20,19 @@ expression: actual "alg": "algorithm", "content": "hash value" } + ], + "externalReferences": [ + { + "type": "external reference type", + "url": "url", + "comment": "comment", + "hashes": [ + { + "alg": "algorithm", + "content": "hash value" + } + ] + } ] } ], @@ -782,6 +796,19 @@ expression: actual "alg": "algorithm", "content": "hash value" } + ], + "externalReferences": [ + { + "type": "external reference type", + "url": "url", + "comment": "comment", + "hashes": [ + { + "alg": "algorithm", + "content": "hash value" + } + ] + } ] } ], diff --git a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_5__test__it_should_serialize_a_complex_example_to_xml.snap b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_5__test__it_should_serialize_a_complex_example_to_xml.snap index 37703b1b..fff5dbde 100644 --- a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_5__test__it_should_serialize_a_complex_example_to_xml.snap +++ b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__bom__v1_5__test__it_should_serialize_a_complex_example_to_xml.snap @@ -1,5 +1,6 @@ --- source: cyclonedx-bom/src/specs/common/bom.rs +assertion_line: 660 expression: xml_output --- @@ -14,6 +15,15 @@ expression: xml_output hash value + + + url + comment + + hash value + + + @@ -568,6 +578,15 @@ expression: xml_output hash value + + + url + comment + + hash value + + + diff --git a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__metadata__v1_4__test__it_should_write_xml_full.snap b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__metadata__v1_4__test__it_should_write_xml_full.snap index 5fe42519..ca638f76 100644 --- a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__metadata__v1_4__test__it_should_write_xml_full.snap +++ b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__metadata__v1_4__test__it_should_write_xml_full.snap @@ -1,5 +1,6 @@ --- source: cyclonedx-bom/src/specs/common/metadata.rs +assertion_line: 387 expression: xml_output --- @@ -13,6 +14,15 @@ expression: xml_output hash value + + + url + comment + + hash value + + + diff --git a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__metadata__v1_5__test__it_should_write_xml_full.snap b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__metadata__v1_5__test__it_should_write_xml_full.snap index 11aaf50c..219df6cb 100644 --- a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__metadata__v1_5__test__it_should_write_xml_full.snap +++ b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__metadata__v1_5__test__it_should_write_xml_full.snap @@ -1,5 +1,6 @@ --- source: cyclonedx-bom/src/specs/common/metadata.rs +assertion_line: 387 expression: xml_output --- @@ -13,6 +14,15 @@ expression: xml_output hash value + + + url + comment + + hash value + + + diff --git a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__tool__v1_4__test__it_should_write_xml_full.snap b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__tool__v1_4__test__it_should_write_xml_full.snap index ca503655..2a96f6b4 100644 --- a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__tool__v1_4__test__it_should_write_xml_full.snap +++ b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__tool__v1_4__test__it_should_write_xml_full.snap @@ -1,5 +1,6 @@ --- source: cyclonedx-bom/src/specs/common/tool.rs +assertion_line: 474 expression: xml_output --- @@ -11,5 +12,14 @@ expression: xml_output hash value + + + url + comment + + hash value + + + diff --git a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__tool__v1_5__test__it_should_write_xml_full.snap b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__tool__v1_5__test__it_should_write_xml_full.snap index ca503655..2a96f6b4 100644 --- a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__tool__v1_5__test__it_should_write_xml_full.snap +++ b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__tool__v1_5__test__it_should_write_xml_full.snap @@ -1,5 +1,6 @@ --- source: cyclonedx-bom/src/specs/common/tool.rs +assertion_line: 474 expression: xml_output --- @@ -11,5 +12,14 @@ expression: xml_output hash value + + + url + comment + + hash value + + + diff --git a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__vulnerability__v1_4__test__it_should_write_xml_full.snap b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__vulnerability__v1_4__test__it_should_write_xml_full.snap index 7141dd8c..bf0cf662 100644 --- a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__vulnerability__v1_4__test__it_should_write_xml_full.snap +++ b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__vulnerability__v1_4__test__it_should_write_xml_full.snap @@ -1,5 +1,6 @@ --- source: cyclonedx-bom/src/specs/common/vulnerability.rs +assertion_line: 758 expression: xml_output --- @@ -77,6 +78,15 @@ expression: xml_output hash value + + + url + comment + + hash value + + + diff --git a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__vulnerability__v1_5__test__it_should_write_xml_full.snap b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__vulnerability__v1_5__test__it_should_write_xml_full.snap index b19cefb4..c7e76d5e 100644 --- a/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__vulnerability__v1_5__test__it_should_write_xml_full.snap +++ b/cyclonedx-bom/src/specs/common/snapshots/cyclonedx_bom__specs__common__vulnerability__v1_5__test__it_should_write_xml_full.snap @@ -79,6 +79,15 @@ expression: xml_output hash value + + + url + comment + + hash value + + + diff --git a/cyclonedx-bom/src/specs/common/tool.rs b/cyclonedx-bom/src/specs/common/tool.rs index 9de72020..9a15c6df 100644 --- a/cyclonedx-bom/src/specs/common/tool.rs +++ b/cyclonedx-bom/src/specs/common/tool.rs @@ -20,8 +20,12 @@ use cyclonedx_bom_macros::versioned; #[versioned("1.3", "1.4", "1.5")] pub(crate) mod base { + #[versioned("1.4")] + use crate::specs::v1_4::external_reference::ExternalReferences; #[versioned("1.5")] - use crate::specs::v1_5::{component::Components, service::Services}; + use crate::specs::v1_5::{ + component::Components, external_reference::ExternalReferences, service::Services, + }; use crate::{ errors::{BomError, XmlReadError}, @@ -225,6 +229,9 @@ pub(crate) mod base { version: Option, #[serde(skip_serializing_if = "Option::is_none")] hashes: Option, + #[versioned("1.4", "1.5")] + #[serde(skip_serializing_if = "Option::is_none")] + external_references: Option, } impl From for Tool { @@ -234,6 +241,8 @@ pub(crate) mod base { name: other.name.map(|n| n.to_string()), version: other.version.map(|v| v.to_string()), hashes: convert_optional(other.hashes), + #[versioned("1.4", "1.5")] + external_references: convert_optional(other.external_references), } } } @@ -245,6 +254,10 @@ pub(crate) mod base { name: other.name.map(NormalizedString::new_unchecked), version: other.version.map(NormalizedString::new_unchecked), hashes: convert_optional(other.hashes), + #[versioned("1.3")] + external_references: None, + #[versioned("1.4", "1.5")] + external_references: convert_optional(other.external_references), } } } @@ -281,6 +294,11 @@ pub(crate) mod base { } } + #[versioned("1.4", "1.5")] + if let Some(external_references) = &self.external_references { + external_references.write_xml_element(writer)?; + } + writer .write(writer::XmlEvent::end_element()) .map_err(to_xml_write_error(TOOL_TAG))?; @@ -297,6 +315,8 @@ pub(crate) mod base { } const HASHES_TAG: &str = "hashes"; + #[versioned("1.4", "1.5")] + const EXTERNAL_REFERENCES_TAG: &str = "externalReferences"; impl FromXml for Tool { fn read_xml_element( @@ -311,6 +331,8 @@ pub(crate) mod base { let mut tool_name: Option = None; let mut version: Option = None; let mut hashes: Option = None; + #[versioned("1.4", "1.5")] + let mut external_references: Option = None; let mut got_end_tag = false; while !got_end_tag { @@ -334,6 +356,16 @@ pub(crate) mod base { } if name.local_name == HASHES_TAG => { hashes = Some(Hashes::read_xml_element(event_reader, &name, &attributes)?) } + #[versioned("1.4", "1.5")] + reader::XmlEvent::StartElement { + name, attributes, .. + } if name.local_name == EXTERNAL_REFERENCES_TAG => { + external_references = Some(ExternalReferences::read_xml_element( + event_reader, + &name, + &attributes, + )?) + } // lax validation of any elements from a different schema reader::XmlEvent::StartElement { name, .. } => { read_lax_validation_tag(event_reader, &name)? @@ -350,15 +382,24 @@ pub(crate) mod base { name: tool_name, version, hashes, + #[versioned("1.4", "1.5")] + external_references, }) } } #[cfg(test)] pub(crate) mod test { + #[versioned("1.4")] + use crate::specs::common::external_reference::v1_4::test::{ + corresponding_external_references, example_external_references, + }; #[versioned("1.5")] use crate::specs::{ common::{ + external_reference::v1_5::test::{ + corresponding_external_references, example_external_references, + }, hash::{Hash, HashValue}, organization::OrganizationalEntity, }, @@ -384,21 +425,46 @@ pub(crate) mod base { models::tool::Tools::List(vec![corresponding_tool()]) } + #[versioned("1.3")] + pub(crate) fn example_tool() -> Tool { + Tool { + vendor: Some("vendor".to_string()), + name: Some("name".to_string()), + version: Some("version".to_string()), + hashes: Some(example_hashes()), + } + } + + #[versioned("1.3")] + pub(crate) fn corresponding_tool() -> models::tool::Tool { + models::tool::Tool { + vendor: Some(NormalizedString::new_unchecked("vendor".to_string())), + name: Some(NormalizedString::new_unchecked("name".to_string())), + version: Some(NormalizedString::new_unchecked("version".to_string())), + hashes: Some(corresponding_hashes()), + external_references: None, + } + } + + #[versioned("1.4", "1.5")] pub(crate) fn example_tool() -> Tool { Tool { vendor: Some("vendor".to_string()), name: Some("name".to_string()), version: Some("version".to_string()), hashes: Some(example_hashes()), + external_references: Some(example_external_references()), } } + #[versioned("1.4", "1.5")] pub(crate) fn corresponding_tool() -> models::tool::Tool { models::tool::Tool { vendor: Some(NormalizedString::new_unchecked("vendor".to_string())), name: Some(NormalizedString::new_unchecked("name".to_string())), version: Some(NormalizedString::new_unchecked("version".to_string())), hashes: Some(corresponding_hashes()), + external_references: Some(corresponding_external_references()), } } @@ -419,6 +485,15 @@ pub(crate) mod base { hash value + + + url + comment + + hash value + + + "#; diff --git a/cyclonedx-bom/src/specs/common/vulnerability.rs b/cyclonedx-bom/src/specs/common/vulnerability.rs index 75316201..ef119dea 100644 --- a/cyclonedx-bom/src/specs/common/vulnerability.rs +++ b/cyclonedx-bom/src/specs/common/vulnerability.rs @@ -836,6 +836,15 @@ pub(crate) mod base { hash value + + + url + comment + + hash value + + + @@ -959,6 +968,15 @@ pub(crate) mod base { hash value + + + url + comment + + hash value + + +