kellnr_settings/
filter.rs1#![allow(clippy::struct_field_names)]
3
4use std::fmt::Display;
5
6use clap::ValueEnum;
7use provcfg::{ClapArgs, Configurable};
8use serde::{Deserialize, Deserializer, Serialize};
9
10#[derive(Debug, Default, Deserialize, Serialize, Eq, PartialEq, Clone, Configurable, ClapArgs)]
15#[serde(default)]
16#[configurable(clap_prefix = "cratesio-filter")]
17pub struct CratesioFilter {
18 pub license_enabled: bool,
20
21 #[configurable(env_list)]
23 #[arg(value_delimiter = ',')]
24 pub license_allowed: Vec<String>,
25
26 #[arg(value_enum)]
28 pub license_unknown: LicenseUnknown,
29
30 #[configurable(env_list)]
32 #[arg(value_delimiter = ',')]
33 pub license_exempt_crates: Vec<String>,
34}
35
36#[derive(Debug, Default, Deserialize, Serialize, Eq, PartialEq, Clone, Configurable, ClapArgs)]
40#[serde(default)]
41#[configurable(clap_prefix = "registry-filter")]
42pub struct RegistryFilter {
43 pub license_enabled: bool,
45
46 #[configurable(env_list)]
48 #[arg(value_delimiter = ',')]
49 pub license_allowed: Vec<String>,
50
51 #[arg(value_enum)]
53 pub license_unknown: LicenseUnknown,
54
55 #[configurable(env_list)]
57 #[arg(value_delimiter = ',')]
58 pub license_exempt_crates: Vec<String>,
59}
60
61#[derive(Debug, PartialEq, Eq, Clone, Copy, ValueEnum, Default)]
64pub enum LicenseUnknown {
65 #[default]
66 Deny,
67 Allow,
68}
69
70impl<'de> Deserialize<'de> for LicenseUnknown {
71 fn deserialize<D>(de: D) -> Result<Self, D::Error>
72 where
73 D: Deserializer<'de>,
74 {
75 match String::deserialize(de)?.to_lowercase().as_str() {
76 "deny" => Ok(Self::Deny),
77 "allow" => Ok(Self::Allow),
78 other => Err(serde::de::Error::custom(format!(
79 "unknown license_unknown value {other:?}; expected \"deny\" or \"allow\""
80 ))),
81 }
82 }
83}
84
85impl Serialize for LicenseUnknown {
86 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
87 where
88 S: serde::Serializer,
89 {
90 serializer.serialize_str(&self.to_string())
91 }
92}
93
94impl Display for LicenseUnknown {
95 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96 match self {
97 LicenseUnknown::Deny => write!(f, "deny"),
98 LicenseUnknown::Allow => write!(f, "allow"),
99 }
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use provcfg::Config;
106
107 use crate::settings::SettingsProv;
108 use crate::{CratesioFilter, LicenseUnknown, RegistryFilter, Settings};
109
110 fn from_toml(toml: &str) -> Result<Settings, provcfg::Error> {
111 Config::new()
112 .add_toml_str("test.toml", toml)
113 .build::<SettingsProv>()
114 .map(|prov| Settings::from(&prov))
115 }
116
117 #[test]
118 fn filters_are_disabled_by_default() {
119 let settings = Settings::default();
120
121 assert_eq!(CratesioFilter::default(), settings.cratesio_filter);
122 assert_eq!(RegistryFilter::default(), settings.registry_filter);
123 assert!(!settings.cratesio_filter.license_enabled);
124 assert!(settings.cratesio_filter.license_allowed.is_empty());
125 assert_eq!(
126 LicenseUnknown::Deny,
127 settings.cratesio_filter.license_unknown
128 );
129 assert!(settings.cratesio_filter.license_exempt_crates.is_empty());
130 }
131
132 #[test]
133 fn both_sections_read_from_toml() {
134 let settings = from_toml(
135 r#"
136 [cratesio_filter]
137 license_enabled = true
138 license_allowed = ["MIT", "Apache-2.0"]
139 license_unknown = "allow"
140 license_exempt_crates = ["ring"]
141
142 [registry_filter]
143 license_enabled = true
144 license_allowed = ["MIT"]
145 "#,
146 )
147 .unwrap();
148
149 assert_eq!(
150 CratesioFilter {
151 license_enabled: true,
152 license_allowed: vec!["MIT".to_string(), "Apache-2.0".to_string()],
153 license_unknown: LicenseUnknown::Allow,
154 license_exempt_crates: vec!["ring".to_string()],
155 },
156 settings.cratesio_filter
157 );
158 assert_eq!(
159 RegistryFilter {
160 license_enabled: true,
161 license_allowed: vec!["MIT".to_string()],
162 license_unknown: LicenseUnknown::Deny,
163 license_exempt_crates: vec![],
164 },
165 settings.registry_filter
166 );
167 }
168
169 #[test]
170 fn invalid_license_unknown_fails() {
171 let result = from_toml("[cratesio_filter]\nlicense_unknown = \"deneay\"\n");
172
173 assert!(result.is_err());
174 }
175
176 #[test]
177 fn list_settings_are_env_list_keys() {
178 let keys = crate::settings::env_list_keys();
179
180 for key in [
181 "cratesio_filter.license_allowed",
182 "cratesio_filter.license_exempt_crates",
183 "registry_filter.license_allowed",
184 "registry_filter.license_exempt_crates",
185 ] {
186 assert!(keys.contains(&key), "{key} must be an env list key");
187 }
188 }
189}