1use crate::validation::{Validate, ValidationContext, ValidationResult, helpers};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(untagged)]
7#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
8pub enum IAMResource {
9 Single(String),
11 Multiple(Vec<String>),
13}
14
15impl Validate for IAMResource {
16 fn validate(&self, context: &mut ValidationContext) -> ValidationResult {
17 context.with_segment("Resource", |ctx| match self {
18 IAMResource::Single(resource) => helpers::validate_resource(resource, ctx),
19 IAMResource::Multiple(resources) => {
20 if resources.is_empty() {
21 return Err(crate::validation::ValidationError::InvalidValue {
22 field: "Resource".to_string(),
23 value: "[]".to_string(),
24 reason: "Resource list cannot be empty".to_string(),
25 });
26 }
27
28 let results: Vec<ValidationResult> = resources
29 .iter()
30 .enumerate()
31 .map(|(i, resource)| {
32 ctx.with_segment(&format!("[{i}]"), |nested_ctx| {
33 helpers::validate_resource(resource, nested_ctx)
34 })
35 })
36 .collect();
37
38 helpers::collect_errors(results)
39 }
40 })
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47
48 #[test]
49 fn test_resource_validation() {
50 let valid_single = IAMResource::Single("arn:aws:s3:::bucket/*".to_string());
51 assert!(valid_single.is_valid());
52
53 let valid_wildcard = IAMResource::Single("*".to_string());
54 assert!(valid_wildcard.is_valid());
55
56 let valid_multiple = IAMResource::Multiple(vec![
57 "arn:aws:s3:::bucket/*".to_string(),
58 "arn:aws:s3:::other-bucket/*".to_string(),
59 ]);
60 assert!(valid_multiple.is_valid());
61
62 let invalid_single = IAMResource::Single("invalid-resource".to_string());
63 assert!(!invalid_single.is_valid());
64
65 let empty_multiple = IAMResource::Multiple(vec![]);
66 assert!(!empty_multiple.is_valid());
67
68 let invalid_multiple = IAMResource::Multiple(vec![
69 "arn:aws:s3:::bucket/*".to_string(),
70 "invalid-resource".to_string(),
71 ]);
72 assert!(!invalid_multiple.is_valid());
73 }
74
75 #[test]
76 fn test_resource_with_wildcards() {
77 let wildcard_resource = IAMResource::Single("arn:aws:s3:::*/*".to_string());
78 assert!(wildcard_resource.is_valid());
79
80 let complex_wildcard =
81 IAMResource::Single("arn:aws:s3:::bucket/folder/*/file.txt".to_string());
82 assert!(complex_wildcard.is_valid());
83 }
84}