Skip to main content

kya_validator/
policy.rs

1use crate::types::{Manifest, PolicyContext};
2
3pub trait PolicyRule {
4    fn evaluate(&self, manifest: &Manifest, context: &PolicyContext) -> Result<(), String>;
5}
6
7pub struct AllowedRegionRule;
8
9impl PolicyRule for AllowedRegionRule {
10    fn evaluate(&self, manifest: &Manifest, context: &PolicyContext) -> Result<(), String> {
11        let region = match context.requested_region.as_ref() {
12            Some(region) => region,
13            None => return Ok(()),
14        };
15
16        if let Some(permitted) = manifest.permitted_regions.as_ref() {
17            if !permitted
18                .iter()
19                .any(|item| item.eq_ignore_ascii_case(region))
20            {
21                return Err(format!("Region {} is not permitted", region));
22            }
23        }
24
25        if let Some(forbidden) = manifest.forbidden_regions.as_ref() {
26            if forbidden
27                .iter()
28                .any(|item| item.eq_ignore_ascii_case(region))
29            {
30                return Err(format!("Region {} is explicitly forbidden", region));
31            }
32        }
33
34        Ok(())
35    }
36}
37
38pub struct MaxTransactionValueRule;
39
40impl PolicyRule for MaxTransactionValueRule {
41    fn evaluate(&self, manifest: &Manifest, context: &PolicyContext) -> Result<(), String> {
42        let value = match context.transaction_value {
43            Some(value) => value,
44            None => return Ok(()),
45        };
46
47        if let Some(max) = manifest.max_transaction_value {
48            if value > max {
49                return Err(format!("Transaction value {} exceeds max {}", value, max));
50            }
51        }
52
53        Ok(())
54    }
55}
56
57pub fn apply_policy(
58    manifest: &Manifest,
59    context: &PolicyContext,
60    rules: &[Box<dyn PolicyRule>],
61) -> (bool, Vec<String>) {
62    let mut errors = Vec::new();
63    for rule in rules {
64        if let Err(err) = rule.evaluate(manifest, context) {
65            errors.push(err);
66        }
67    }
68
69    (errors.is_empty(), errors)
70}