Trait Validate

Source
pub trait Validate {
    // Required method
    fn validate(&self, context: &mut ValidationContext) -> ValidationResult;

    // Provided methods
    fn is_valid(&self) -> bool { ... }
    fn validate_result(&self) -> ValidationResult { ... }
}
Expand description

Trait for validating IAM policy components All validation is strict and enforces high quality standards

Required Methods§

Provided Methods§

Source

fn is_valid(&self) -> bool

Convenience method for basic validation

Examples found in repository?
examples/validation_demo.rs (line 26)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8    println!("=== IAM Policy Validation Demo ===\n");
9
10    // Example 1: Valid Policy
11    println!("1. Valid Policy Validation:");
12    let valid_policy = IAMPolicy::new()
13        .with_id("550e8400-e29b-41d4-a716-446655440000")
14        .add_statement(
15            IAMStatement::new(Effect::Allow)
16                .with_sid("AllowS3Read")
17                .with_action(Action::Single("s3:GetObject".to_string()))
18                .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string()))
19                .with_condition(
20                    Operator::StringEquals,
21                    "aws:PrincipalTag/department".to_string(),
22                    json!("engineering"),
23                ),
24        );
25
26    if valid_policy.is_valid() {
27        println!("✓ Policy is valid!");
28    } else {
29        println!("✗ Policy is invalid");
30    }
31
32    match valid_policy.validate_result() {
33        Ok(()) => println!("✓ Policy passes validation"),
34        Err(e) => println!("✗ Policy fails validation: {}", e),
35    }
36
37    println!();
38
39    // Example 2: Invalid Policy - Missing Required Fields
40    println!("2. Invalid Policy - Missing Required Fields:");
41    let invalid_policy = IAMPolicy::new().add_statement(IAMStatement::new(Effect::Allow)); // Missing action and resource
42
43    if !invalid_policy.is_valid() {
44        println!("✗ Policy is invalid (as expected)");
45        match invalid_policy.validate_result() {
46            Err(e) => println!("   Validation errors: {}", e),
47            Ok(()) => println!("   Unexpected: validation passed"),
48        }
49    }
50
51    println!();
52
53    // Example 3: Policy with Multiple Validation Errors
54    println!("3. Policy with Multiple Validation Errors:");
55    let multi_error_policy = IAMPolicy::new()
56        .with_id("") // Empty ID
57        .add_statement(
58            IAMStatement::new(Effect::Allow)
59                .with_action(Action::Single("invalid-action".to_string())) // Invalid action format
60                .with_resource(Resource::Single("invalid-resource".to_string())), // Invalid resource
61        )
62        .add_statement(
63            IAMStatement::new(Effect::Allow)
64                .with_sid("DuplicateId")
65                .with_action(Action::Single("s3:GetObject".to_string()))
66                .with_resource(Resource::Single("*".to_string())),
67        )
68        .add_statement(
69            IAMStatement::new(Effect::Deny)
70                .with_sid("DuplicateId") // Duplicate SID
71                .with_action(Action::Single("s3:DeleteObject".to_string()))
72                .with_resource(Resource::Single("*".to_string())),
73        );
74
75    match multi_error_policy.validate_result() {
76        Err(ValidationError::Multiple(errors)) => {
77            println!("✗ Found {} validation errors:", errors.len());
78            for (i, error) in errors.iter().enumerate() {
79                println!("   {}. {}", i + 1, error);
80            }
81        }
82        Err(e) => {
83            println!("✗ Single validation error: {}", e);
84        }
85        Ok(()) => {
86            println!("✓ Unexpected: validation passed");
87        }
88    }
89
90    println!();
91
92    // Example 4: Comprehensive Validation
93    println!("4. Comprehensive Validation:");
94    let comprehensive_policy = IAMPolicy::new()
95        .with_id("short") // Short ID - will fail validation
96        .add_statement(
97            IAMStatement::new(Effect::Allow)
98                .with_action(Action::Single("s3:GetObject".to_string()))
99                .with_resource(Resource::Single("*".to_string()))
100                .with_condition(
101                    Operator::NumericEquals,
102                    "aws:RequestedRegion".to_string(),
103                    json!("not-a-number"), // Numeric operator with string value - will fail
104                ),
105        );
106
107    match comprehensive_policy.validate_result() {
108        Ok(()) => println!("✓ Policy passes validation"),
109        Err(e) => println!("✗ Policy fails validation: {}", e),
110    }
111
112    println!();
113
114    // Example 5: Logical Policy Errors
115    println!("5. Logical Policy Errors:");
116
117    // NotPrincipal with Allow effect (invalid)
118    let mut logical_error_policy = IAMStatement::new(Effect::Allow);
119    logical_error_policy.action = Some(Action::Single("s3:GetObject".to_string()));
120    logical_error_policy.resource = Some(Resource::Single("*".to_string()));
121    let mut principal_map = std::collections::HashMap::new();
122    principal_map.insert(
123        PrincipalType::Aws,
124        serde_json::json!("arn:aws:iam::123456789012:user/test"),
125    );
126    logical_error_policy.not_principal = Some(Principal::Mapped(principal_map));
127
128    match logical_error_policy.validate_result() {
129        Err(e) => println!("✗ Logical error detected: {}", e),
130        Ok(()) => println!("✓ Unexpected: validation passed"),
131    }
132
133    // Both Action and NotAction (invalid)
134    let mut conflicting_statement = IAMStatement::new(Effect::Allow);
135    conflicting_statement.action = Some(Action::Single("s3:GetObject".to_string()));
136    conflicting_statement.not_action = Some(Action::Single("s3:PutObject".to_string()));
137    conflicting_statement.resource = Some(Resource::Single("*".to_string()));
138
139    match conflicting_statement.validate_result() {
140        Err(e) => println!("✗ Logical error detected: {}", e),
141        Ok(()) => println!("✓ Unexpected: validation passed"),
142    }
143
144    println!();
145
146    // Example 6: Component Validation
147    println!("6. Individual Component Validation:");
148
149    // Invalid action
150    let invalid_action = Action::Single("invalid-action".to_string());
151    match invalid_action.validate_result() {
152        Err(e) => println!("✗ Invalid action: {}", e),
153        Ok(()) => println!("✓ Action is valid"),
154    }
155
156    // Invalid principal
157    let mut invalid_map = std::collections::HashMap::new();
158    invalid_map.insert(PrincipalType::Aws, serde_json::json!("invalid-principal"));
159    let invalid_principal = Principal::Mapped(invalid_map);
160    match invalid_principal.validate_result() {
161        Err(e) => println!("✗ Invalid principal: {}", e),
162        Ok(()) => println!("✓ Principal is valid"),
163    }
164
165    // Valid service principal
166    let service_principal = Principal::Mapped(
167        [(PrincipalType::Service, json!("lambda.amazonaws.com"))]
168            .iter()
169            .cloned()
170            .collect(),
171    );
172    if service_principal.is_valid() {
173        println!("✓ Service principal is valid");
174    } else {
175        println!("✗ Service principal is invalid");
176    }
177
178    println!("\n=== Validation Demo Complete ===");
179
180    Ok(())
181}
Source

fn validate_result(&self) -> ValidationResult

Validate with detailed errors (same as regular validation)

Examples found in repository?
examples/validation_demo.rs (line 32)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8    println!("=== IAM Policy Validation Demo ===\n");
9
10    // Example 1: Valid Policy
11    println!("1. Valid Policy Validation:");
12    let valid_policy = IAMPolicy::new()
13        .with_id("550e8400-e29b-41d4-a716-446655440000")
14        .add_statement(
15            IAMStatement::new(Effect::Allow)
16                .with_sid("AllowS3Read")
17                .with_action(Action::Single("s3:GetObject".to_string()))
18                .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string()))
19                .with_condition(
20                    Operator::StringEquals,
21                    "aws:PrincipalTag/department".to_string(),
22                    json!("engineering"),
23                ),
24        );
25
26    if valid_policy.is_valid() {
27        println!("✓ Policy is valid!");
28    } else {
29        println!("✗ Policy is invalid");
30    }
31
32    match valid_policy.validate_result() {
33        Ok(()) => println!("✓ Policy passes validation"),
34        Err(e) => println!("✗ Policy fails validation: {}", e),
35    }
36
37    println!();
38
39    // Example 2: Invalid Policy - Missing Required Fields
40    println!("2. Invalid Policy - Missing Required Fields:");
41    let invalid_policy = IAMPolicy::new().add_statement(IAMStatement::new(Effect::Allow)); // Missing action and resource
42
43    if !invalid_policy.is_valid() {
44        println!("✗ Policy is invalid (as expected)");
45        match invalid_policy.validate_result() {
46            Err(e) => println!("   Validation errors: {}", e),
47            Ok(()) => println!("   Unexpected: validation passed"),
48        }
49    }
50
51    println!();
52
53    // Example 3: Policy with Multiple Validation Errors
54    println!("3. Policy with Multiple Validation Errors:");
55    let multi_error_policy = IAMPolicy::new()
56        .with_id("") // Empty ID
57        .add_statement(
58            IAMStatement::new(Effect::Allow)
59                .with_action(Action::Single("invalid-action".to_string())) // Invalid action format
60                .with_resource(Resource::Single("invalid-resource".to_string())), // Invalid resource
61        )
62        .add_statement(
63            IAMStatement::new(Effect::Allow)
64                .with_sid("DuplicateId")
65                .with_action(Action::Single("s3:GetObject".to_string()))
66                .with_resource(Resource::Single("*".to_string())),
67        )
68        .add_statement(
69            IAMStatement::new(Effect::Deny)
70                .with_sid("DuplicateId") // Duplicate SID
71                .with_action(Action::Single("s3:DeleteObject".to_string()))
72                .with_resource(Resource::Single("*".to_string())),
73        );
74
75    match multi_error_policy.validate_result() {
76        Err(ValidationError::Multiple(errors)) => {
77            println!("✗ Found {} validation errors:", errors.len());
78            for (i, error) in errors.iter().enumerate() {
79                println!("   {}. {}", i + 1, error);
80            }
81        }
82        Err(e) => {
83            println!("✗ Single validation error: {}", e);
84        }
85        Ok(()) => {
86            println!("✓ Unexpected: validation passed");
87        }
88    }
89
90    println!();
91
92    // Example 4: Comprehensive Validation
93    println!("4. Comprehensive Validation:");
94    let comprehensive_policy = IAMPolicy::new()
95        .with_id("short") // Short ID - will fail validation
96        .add_statement(
97            IAMStatement::new(Effect::Allow)
98                .with_action(Action::Single("s3:GetObject".to_string()))
99                .with_resource(Resource::Single("*".to_string()))
100                .with_condition(
101                    Operator::NumericEquals,
102                    "aws:RequestedRegion".to_string(),
103                    json!("not-a-number"), // Numeric operator with string value - will fail
104                ),
105        );
106
107    match comprehensive_policy.validate_result() {
108        Ok(()) => println!("✓ Policy passes validation"),
109        Err(e) => println!("✗ Policy fails validation: {}", e),
110    }
111
112    println!();
113
114    // Example 5: Logical Policy Errors
115    println!("5. Logical Policy Errors:");
116
117    // NotPrincipal with Allow effect (invalid)
118    let mut logical_error_policy = IAMStatement::new(Effect::Allow);
119    logical_error_policy.action = Some(Action::Single("s3:GetObject".to_string()));
120    logical_error_policy.resource = Some(Resource::Single("*".to_string()));
121    let mut principal_map = std::collections::HashMap::new();
122    principal_map.insert(
123        PrincipalType::Aws,
124        serde_json::json!("arn:aws:iam::123456789012:user/test"),
125    );
126    logical_error_policy.not_principal = Some(Principal::Mapped(principal_map));
127
128    match logical_error_policy.validate_result() {
129        Err(e) => println!("✗ Logical error detected: {}", e),
130        Ok(()) => println!("✓ Unexpected: validation passed"),
131    }
132
133    // Both Action and NotAction (invalid)
134    let mut conflicting_statement = IAMStatement::new(Effect::Allow);
135    conflicting_statement.action = Some(Action::Single("s3:GetObject".to_string()));
136    conflicting_statement.not_action = Some(Action::Single("s3:PutObject".to_string()));
137    conflicting_statement.resource = Some(Resource::Single("*".to_string()));
138
139    match conflicting_statement.validate_result() {
140        Err(e) => println!("✗ Logical error detected: {}", e),
141        Ok(()) => println!("✓ Unexpected: validation passed"),
142    }
143
144    println!();
145
146    // Example 6: Component Validation
147    println!("6. Individual Component Validation:");
148
149    // Invalid action
150    let invalid_action = Action::Single("invalid-action".to_string());
151    match invalid_action.validate_result() {
152        Err(e) => println!("✗ Invalid action: {}", e),
153        Ok(()) => println!("✓ Action is valid"),
154    }
155
156    // Invalid principal
157    let mut invalid_map = std::collections::HashMap::new();
158    invalid_map.insert(PrincipalType::Aws, serde_json::json!("invalid-principal"));
159    let invalid_principal = Principal::Mapped(invalid_map);
160    match invalid_principal.validate_result() {
161        Err(e) => println!("✗ Invalid principal: {}", e),
162        Ok(()) => println!("✓ Principal is valid"),
163    }
164
165    // Valid service principal
166    let service_principal = Principal::Mapped(
167        [(PrincipalType::Service, json!("lambda.amazonaws.com"))]
168            .iter()
169            .cloned()
170            .collect(),
171    );
172    if service_principal.is_valid() {
173        println!("✓ Service principal is valid");
174    } else {
175        println!("✗ Service principal is invalid");
176    }
177
178    println!("\n=== Validation Demo Complete ===");
179
180    Ok(())
181}

Implementors§