agent_kernel/
validation.rs

1//! Input validation for MXP messages.
2
3use thiserror::Error;
4
5/// Configuration for message validation.
6#[derive(Debug, Clone)]
7pub struct ValidationConfig {
8    /// Maximum allowed message payload size in bytes.
9    pub max_payload_size: usize,
10    /// Maximum allowed message header size in bytes.
11    pub max_header_size: usize,
12}
13
14impl ValidationConfig {
15    /// Create a new validation configuration.
16    #[must_use]
17    pub fn new(max_payload_size: usize, max_header_size: usize) -> Self {
18        Self {
19            max_payload_size,
20            max_header_size,
21        }
22    }
23}
24
25impl Default for ValidationConfig {
26    fn default() -> Self {
27        Self {
28            max_payload_size: 10 * 1024 * 1024, // 10 MB
29            max_header_size: 64 * 1024,         // 64 KB
30        }
31    }
32}
33
34/// Errors that can occur during message validation.
35#[derive(Debug, Error, PartialEq, Eq)]
36pub enum ValidationError {
37    /// Message payload exceeds the configured size limit.
38    #[error("message payload size {size} exceeds limit {limit}")]
39    PayloadTooLarge {
40        /// The actual payload size.
41        size: usize,
42        /// The configured limit.
43        limit: usize,
44    },
45
46    /// Message header exceeds the configured size limit.
47    #[error("message header size {size} exceeds limit {limit}")]
48    HeaderTooLarge {
49        /// The actual header size.
50        size: usize,
51        /// The configured limit.
52        limit: usize,
53    },
54}
55
56/// Result alias for validation operations.
57pub type ValidationResult<T = ()> = Result<T, ValidationError>;
58
59/// Validates an MXP message against configured limits.
60///
61/// # Errors
62///
63/// Returns `ValidationError::PayloadTooLarge` if the payload exceeds the configured limit.
64/// Returns `ValidationError::HeaderTooLarge` if the header exceeds the configured limit.
65pub fn validate_message(
66    payload_size: usize,
67    header_size: usize,
68    config: &ValidationConfig,
69) -> ValidationResult {
70    if payload_size > config.max_payload_size {
71        return Err(ValidationError::PayloadTooLarge {
72            size: payload_size,
73            limit: config.max_payload_size,
74        });
75    }
76
77    if header_size > config.max_header_size {
78        return Err(ValidationError::HeaderTooLarge {
79            size: header_size,
80            limit: config.max_header_size,
81        });
82    }
83
84    Ok(())
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn validation_config_default() {
93        let config = ValidationConfig::default();
94        assert_eq!(config.max_payload_size, 10 * 1024 * 1024);
95        assert_eq!(config.max_header_size, 64 * 1024);
96    }
97
98    #[test]
99    fn validate_message_within_limits() {
100        let config = ValidationConfig::new(1000, 100);
101        let result = validate_message(500, 50, &config);
102        assert!(result.is_ok());
103    }
104
105    #[test]
106    fn validate_message_payload_too_large() {
107        let config = ValidationConfig::new(1000, 100);
108        let result = validate_message(1500, 50, &config);
109        assert!(matches!(
110            result,
111            Err(ValidationError::PayloadTooLarge {
112                size: 1500,
113                limit: 1000
114            })
115        ));
116    }
117
118    #[test]
119    fn validate_message_header_too_large() {
120        let config = ValidationConfig::new(1000, 100);
121        let result = validate_message(500, 150, &config);
122        assert!(matches!(
123            result,
124            Err(ValidationError::HeaderTooLarge {
125                size: 150,
126                limit: 100
127            })
128        ));
129    }
130
131    #[test]
132    fn validate_message_at_exact_limits() {
133        let config = ValidationConfig::new(1000, 100);
134        let result = validate_message(1000, 100, &config);
135        assert!(result.is_ok());
136    }
137
138    #[test]
139    fn validate_message_just_over_payload_limit() {
140        let config = ValidationConfig::new(1000, 100);
141        let result = validate_message(1001, 100, &config);
142        assert!(matches!(
143            result,
144            Err(ValidationError::PayloadTooLarge {
145                size: 1001,
146                limit: 1000
147            })
148        ));
149    }
150
151    #[test]
152    fn validate_message_just_over_header_limit() {
153        let config = ValidationConfig::new(1000, 100);
154        let result = validate_message(1000, 101, &config);
155        assert!(matches!(
156            result,
157            Err(ValidationError::HeaderTooLarge {
158                size: 101,
159                limit: 100
160            })
161        ));
162    }
163}