1use chrono::{DateTime, Utc};
2use url::Url;
3
4#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
5pub struct Distribution {
6 #[serde(default, skip_serializing_if = "Option::is_none")]
7 pub directory_url: Option<Url>,
8 #[serde(default, skip_serializing_if = "Option::is_none")]
9 pub rolie: Option<Rolie>,
10}
11
12#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
13pub struct Rolie {
14 #[serde(default)]
15 pub categories: Vec<Url>,
16 #[serde(default, skip_serializing_if = "Vec::is_empty")]
17 pub feeds: Vec<Feed>,
18 #[serde(default)]
19 pub services: Vec<Url>,
20}
21
22#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
23pub struct Feed {
24 #[serde(default, skip_serializing_if = "Option::is_none")]
25 pub summary: Option<String>,
26 pub tlp_label: TlpLabel,
27 pub url: Url,
28}
29
30#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
31#[serde(rename_all = "UPPERCASE")]
32pub enum TlpLabel {
33 Unlabeled,
34 White,
35 Green,
36 Amber,
37 Red,
38}
39
40#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
41pub struct Key {
42 #[serde(default, skip_serializing_if = "Option::is_none")]
43 pub fingerprint: Option<String>,
44 pub url: Url,
45}
46
47impl<'a> From<&'a Key> for walker_common::validate::source::Key<'a> {
48 fn from(value: &'a Key) -> Self {
49 walker_common::validate::source::Key {
50 fingerprint: value.fingerprint.as_deref(),
51 url: &value.url,
52 }
53 }
54}
55
56#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
57pub struct Publisher {
58 pub category: PublisherCategory,
59 #[serde(default, skip_serializing_if = "Option::is_none")]
60 pub contact_details: Option<String>,
61 #[serde(default, skip_serializing_if = "Option::is_none")]
62 pub issuing_authority: Option<String>,
63 pub name: String,
64 pub namespace: String,
65}
66
67#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize)]
68#[serde(rename_all = "snake_case")]
69pub enum PublisherCategory {
70 Coordinator,
71 Discoverer,
72 Other,
73 Translator,
74 User,
75 Vendor,
76 #[serde(untagged)]
77 Unknown(String),
78}
79
80#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize)]
81pub enum MetadataVersion {
82 #[serde(rename = "2.0")]
83 V2_0,
84 #[serde(untagged)]
85 Unknown(String),
86}
87
88#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
89pub struct ProviderMetadata {
90 pub canonical_url: Url,
91
92 #[serde(default)]
93 pub distributions: Vec<Distribution>,
94
95 pub last_updated: DateTime<Utc>,
96
97 #[serde(rename = "list_on_CSAF_aggregators")]
98 #[serde(default)]
99 pub list_on_csaf_aggregators: bool,
100
101 pub metadata_version: MetadataVersion,
102
103 #[serde(rename = "mirror_on_CSAF_aggregators")]
104 #[serde(default)]
105 pub mirror_on_csaf_aggregators: bool,
106
107 #[serde(default)]
108 pub public_openpgp_keys: Vec<Key>,
109
110 pub publisher: Publisher,
111
112 #[serde(default = "default_role")]
114 pub role: Role,
115}
116
117const fn default_role() -> Role {
118 Role::Provider
119}
120
121#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize)]
122pub enum Role {
123 #[serde(rename = "csaf_publisher")]
124 Publisher,
125 #[serde(rename = "csaf_provider")]
126 Provider,
127 #[serde(rename = "csaf_trusted_provider")]
128 TrustedProvider,
129}