cyclonedx_rust/component/
pedigree_type.rs

1use crate::common::attached_text::AttachedTextType;
2use crate::component::Component;
3use derive_builder::Builder;
4use serde::{Deserialize, Serialize};
5use yaserde_derive::{YaDeserialize, YaSerialize};
6
7#[derive(
8    Clone, Default, Builder, PartialEq, Debug, Serialize, Deserialize, YaSerialize, YaDeserialize,
9)]
10#[yaserde(
11    prefix = "ns",
12    default_namespace = "ns",
13    namespace = "ns: http://cyclonedx.org/schema/bom/1.2"
14)]
15pub struct PedigreeType {
16    ancestors: Vec<Component>,
17    descendants: Vec<Component>,
18    variants: Vec<Component>,
19    commits: Vec<CommitType>,
20    patches: Vec<PatchType>,
21    #[yaserde(prefix = "ns")]
22    notes: Option<String>,
23}
24
25#[derive(
26    Clone, Default, Builder, PartialEq, Debug, Serialize, Deserialize, YaSerialize, YaDeserialize,
27)]
28pub struct PatchType {
29    #[serde(rename = "type")]
30    #[yaserde(rename = "type", attribute)]
31    patchtype_type: BomPatchClassification,
32
33    diff: Option<DiffType>,
34    resolves: Vec<IssueType>,
35}
36
37#[derive(
38    Clone, Default, Builder, PartialEq, Debug, Serialize, Deserialize, YaSerialize, YaDeserialize,
39)]
40pub struct DiffType {
41    text: Option<AttachedTextType>,
42    url: Option<String>,
43}
44
45impl DiffType {
46    pub fn new(text: Option<AttachedTextType>, url: Option<String>) {
47        DiffType { text, url };
48    }
49}
50
51#[derive(
52    Clone, Default, Builder, Debug, PartialEq, Serialize, Deserialize, YaSerialize, YaDeserialize,
53)]
54pub struct IssueType {
55    #[serde(rename = "type")]
56    #[yaserde(rename = "type", attribute)]
57    issue_type: BomIssueClassification,
58
59    id: Option<String>,
60    name: Option<String>,
61    description: Option<String>,
62    source: Option<Source>,
63    references: Vec<String>,
64}
65
66#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, YaSerialize, YaDeserialize)]
67pub struct Source {
68    name: Option<String>,
69    url: Option<String>,
70}
71
72#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, YaSerialize, YaDeserialize)]
73pub enum BomIssueClassification {
74    Detect,
75    Enhancement,
76    Security,
77}
78
79impl Default for BomIssueClassification {
80    fn default() -> Self {
81        BomIssueClassification::Detect
82    }
83}
84
85#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, YaSerialize, YaDeserialize)]
86pub enum BomPatchClassification {
87    Unofficial,
88    Monkey,
89    Backport,
90    CherryPick,
91}
92
93impl Default for BomPatchClassification {
94    fn default() -> Self {
95        BomPatchClassification::Backport
96    }
97}
98
99#[derive(
100    Default, Clone, Builder, PartialEq, Debug, Serialize, Deserialize, YaSerialize, YaDeserialize,
101)]
102#[yaserde(
103    prefix = "ns",
104    default_namespace = "ns",
105    namespace = "ns: http://cyclonedx.org/schema/bom/1.2"
106)]
107pub struct CommitType {
108    #[yaserde(prefix = "ns")]
109    uid: Option<String>,
110    #[yaserde(prefix = "ns")]
111    url: Option<String>,
112    #[yaserde(prefix = "ns")]
113    author: Option<IdentifiableActionType>,
114    #[yaserde(prefix = "ns")]
115    committer: Option<IdentifiableActionType>,
116    #[yaserde(prefix = "ns")]
117    message: Option<String>,
118}
119
120#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize, YaSerialize, YaDeserialize)]
121#[yaserde(
122    prefix = "ns",
123    default_namespace = "ns",
124    namespace = "ns: http://cyclonedx.org/schema/bom/1.2"
125)]
126pub struct IdentifiableActionType {
127    #[yaserde(prefix = "ns")]
128    timestamp: Option<String>,
129    #[yaserde(prefix = "ns")]
130    name: Option<String>,
131    #[yaserde(prefix = "ns")]
132    email: Option<String>,
133}
134
135impl IdentifiableActionType {
136    pub fn new(
137        timestamp: Option<String>,
138        name: Option<String>,
139        email: Option<String>,
140    ) -> IdentifiableActionType {
141        IdentifiableActionType {
142            timestamp,
143            name,
144            email,
145        }
146    }
147}
148
149#[cfg(test)]
150pub mod tests {
151    use super::*;
152    use crate::common::license::*;
153    use crate::component::classification::Classification;
154    use crate::component::pedigree_type::PedigreeType;
155    use crate::component::*;
156    use yaserde::ser::Config;
157
158    #[test]
159    pub fn print_xml() {
160        let expected: PedigreeType = PedigreeTypeBuilder::default()
161            .ancestors(vec![ComponentBuilder::default()
162                .component_type(Classification::Application)
163                .mime_type(None)
164                .bom_ref(None)
165                .supplier(None)
166                .author(None)
167                .publisher(Option::from("Apache".to_string()))
168                .group(Option::from("org.apache.tomcat".to_string()))
169                .name(Option::from("tomcat-catalina".to_string()))
170                .version(Option::from("9.0.14".to_string()))
171                .description(Option::from("Apache Catalina".to_string()))
172                .scope(None)
173                .hashes(Vec::new())
174                .licenses(vec![LicensesBuilder::default()
175                    .license(vec![LicenseTypeBuilder::default()
176                        .id(Option::from("Apache-2.0".to_string()))
177                        .name(None)
178                        .text(None)
179                        .url(None)
180                        .build()
181                        .unwrap()])
182                    .expression(None)
183                    .build()
184                    .unwrap()])
185                .copyright(None)
186                .purl(Option::from(
187                    "pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar".to_string(),
188                ))
189                .swid(None)
190                .modified(None)
191                .pedigree(None)
192                .external_references(Vec::new())
193                .components(Vec::new())
194                .build()
195                .unwrap()])
196            .descendants(Vec::new())
197            .variants(Vec::new())
198            .commits(vec![CommitTypeBuilder::default()
199                .uid(Option::from(
200                    "7638417db6d59f3c431d3e1f261cc637155684cd".to_string(),
201                ))
202                .url(Option::from(
203                    "https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd".to_string(),
204                ))
205                .author(Option::from(IdentifiableActionType::new(
206                    Option::from("2018-11-07T22:01:45Z".to_string()),
207                    Option::from("John Doe".to_string()),
208                    Option::from("john.doe@example.com".to_string()),
209                )))
210                .committer(None)
211                .message(None)
212                .build()
213                .unwrap()])
214            .patches(Vec::new())
215            .notes(Option::from("Commentary here".to_string()))
216            .build()
217            .unwrap();
218
219        let parsed = yaserde::ser::to_string_with_config(
220            &expected,
221            &Config {
222                perform_indent: false,
223                write_document_declaration: false,
224                indent_string: None,
225            },
226        )
227        .unwrap();
228
229        let actual: PedigreeType = yaserde::de::from_str(parsed.as_str()).unwrap();
230
231        assert_eq!(expected, actual);
232    }
233}