Skip to content

Commit eb024ab

Browse files
committed
Validate policies configuration file
* Be strict during deserialization: error when something unknown is found * Validate policy names: ensure they do not contain the `/` symbol Signed-off-by: Flavio Castelli <fcastelli@suse.com>
1 parent c99f7d2 commit eb024ab

File tree

1 file changed

+90
-7
lines changed

1 file changed

+90
-7
lines changed

src/config.rs

+90-7
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ lazy_static! {
2525
std::env::var("HOSTNAME").unwrap_or_else(|_| String::from("unknown"));
2626
}
2727

28-
// TODO: be more strict when parsing the configuration file:
29-
// - error when unknown data is found
30-
// - validate the names of the policies and sub-policies: they cannot have `/` symbols
3128
pub struct Config {
3229
pub addr: SocketAddr,
3330
pub sources: Option<Sources>,
@@ -195,13 +192,43 @@ fn tls_files(matches: &clap::ArgMatches) -> Result<(String, String)> {
195192

196193
fn policies(matches: &clap::ArgMatches) -> Result<HashMap<String, PolicyOrPolicyGroup>> {
197194
let policies_file = Path::new(matches.get_one::<String>("policies").unwrap());
198-
read_policies_file(policies_file).map_err(|e| {
195+
let policies = read_policies_file(policies_file).map_err(|e| {
199196
anyhow!(
200197
"error while loading policies from {:?}: {}",
201198
policies_file,
202199
e
203200
)
204-
})
201+
})?;
202+
203+
validate_policies(&policies)?;
204+
205+
Ok(policies)
206+
}
207+
208+
// Validate the policies and policy groups:
209+
// - ensure policy names do not contain a '/' character
210+
// - ensure names of policy group members do not contain a '/' character
211+
fn validate_policies(policies: &HashMap<String, PolicyOrPolicyGroup>) -> Result<()> {
212+
for (name, policy) in policies.iter() {
213+
if name.contains('/') {
214+
return Err(anyhow!("policy name '{}' contains a '/' character", name));
215+
}
216+
if let PolicyOrPolicyGroup::PolicyGroup { members, .. } = policy {
217+
let members_with_invalid_name: Vec<String> = members
218+
.iter()
219+
.filter_map(|(id, _)| if id.contains('/') { Some(id) } else { None })
220+
.cloned()
221+
.collect();
222+
if !members_with_invalid_name.is_empty() {
223+
return Err(anyhow!(
224+
"policy group '{}' contains members with invalid names: {:?}",
225+
name,
226+
members_with_invalid_name
227+
));
228+
}
229+
}
230+
}
231+
Ok(())
205232
}
206233

207234
fn verification_config(matches: &clap::ArgMatches) -> Result<Option<LatestVerificationConfig>> {
@@ -286,7 +313,7 @@ pub enum PolicyOrPolicyGroupSettings {
286313

287314
/// `PolicyGroupMember` represents a single policy that is part of a policy group.
288315
#[derive(Deserialize, Debug, Clone)]
289-
#[serde(rename_all = "camelCase")]
316+
#[serde(deny_unknown_fields, rename_all = "camelCase")]
290317
pub struct PolicyGroupMember {
291318
/// Thge URL where the policy is located
292319
pub url: String,
@@ -306,7 +333,7 @@ impl PolicyGroupMember {
306333

307334
/// Describes a policy that can be either an individual policy or a group policy.
308335
#[derive(Deserialize, Debug, Clone)]
309-
#[serde(untagged, rename_all = "camelCase")]
336+
#[serde(deny_unknown_fields, untagged, rename_all = "camelCase")]
310337
pub enum PolicyOrPolicyGroup {
311338
/// An individual policy
312339
Policy {
@@ -491,4 +518,60 @@ example:
491518
assert_eq!(provide_flag, config.metrics_enabled);
492519
}
493520
}
521+
522+
#[rstest]
523+
#[case::all_good(
524+
r#"
525+
---
526+
example:
527+
url: file:///tmp/namespace-validate-policy.wasm
528+
settings: {}
529+
group_policy:
530+
expression: "true"
531+
message: "group policy message"
532+
members:
533+
policy1:
534+
url: file:///tmp/namespace-validate-policy.wasm
535+
settings: {}
536+
policy2:
537+
url: file:///tmp/namespace-validate-policy.wasm
538+
settings: {}
539+
"#,
540+
true
541+
)]
542+
#[case::policy_with_invalid_name(
543+
r#"
544+
---
545+
example/invalid:
546+
url: file:///tmp/namespace-validate-policy.wasm
547+
settings: {}
548+
"#,
549+
false
550+
)]
551+
#[case::policy_group_member_with_invalid_name(
552+
r#"
553+
---
554+
example:
555+
url: file:///tmp/namespace-validate-policy.wasm
556+
settings: {}
557+
group_policy:
558+
expression: "true"
559+
message: "group policy message"
560+
members:
561+
policy1/a:
562+
url: file:///tmp/namespace-validate-policy.wasm
563+
settings: {}
564+
policy2:
565+
url: file:///tmp/namespace-validate-policy.wasm
566+
settings: {}
567+
"#,
568+
false
569+
)]
570+
fn policy_validation(#[case] policies_yaml: &str, #[case] is_valid: bool) {
571+
let policies: HashMap<String, PolicyOrPolicyGroup> =
572+
serde_yaml::from_str(policies_yaml).unwrap();
573+
574+
let validation_result = validate_policies(&policies);
575+
assert_eq!(is_valid, validation_result.is_ok());
576+
}
494577
}

0 commit comments

Comments
 (0)