ant_quic/compliance_validator/
mod.rs1use std::collections::HashMap;
7use std::fmt;
8use std::path::Path;
9
10pub mod endpoint_tester;
11pub mod report_generator;
12pub mod rfc_parser;
13pub mod spec_validator;
14
15#[cfg(test)]
16mod tests;
17
18#[derive(Debug, Clone, PartialEq)]
20pub struct ComplianceRequirement {
21 pub spec_id: String,
23 pub section: String,
25 pub level: RequirementLevel,
27 pub description: String,
29 pub category: RequirementCategory,
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Hash)]
35pub enum RequirementLevel {
36 Must,
38 MustNot,
40 Should,
42 ShouldNot,
44 May,
46}
47
48impl fmt::Display for RequirementLevel {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 match self {
51 Self::Must => write!(f, "MUST"),
52 Self::MustNot => write!(f, "MUST NOT"),
53 Self::Should => write!(f, "SHOULD"),
54 Self::ShouldNot => write!(f, "SHOULD NOT"),
55 Self::May => write!(f, "MAY"),
56 }
57 }
58}
59
60#[derive(Debug, Clone, PartialEq, Eq, Hash)]
62pub enum RequirementCategory {
63 Transport,
65 FrameFormat,
67 TransportParameters,
69 ConnectionEstablishment,
71 NatTraversal,
73 AddressDiscovery,
75 ErrorHandling,
77 Security,
79 Performance,
81}
82
83#[derive(Debug, Clone)]
85pub struct ComplianceResult {
86 pub requirement: ComplianceRequirement,
88 pub compliant: bool,
90 pub details: String,
92 pub evidence: Vec<Evidence>,
94}
95
96#[derive(Debug, Clone)]
98pub enum Evidence {
99 TestResult {
101 test_name: String,
102 passed: bool,
103 output: String,
104 },
105 PacketCapture {
107 description: String,
108 packets: Vec<u8>,
109 },
110 CodeReference {
112 file: String,
113 line: usize,
114 snippet: String,
115 },
116 EndpointTest { endpoint: String, result: String },
118}
119
120pub struct ComplianceValidator {
122 requirements: Vec<ComplianceRequirement>,
124 validators: HashMap<String, Box<dyn SpecValidator>>,
126 test_endpoints: Vec<String>,
128}
129
130impl Default for ComplianceValidator {
131 fn default() -> Self {
132 Self::new()
133 }
134}
135
136impl ComplianceValidator {
137 pub fn new() -> Self {
139 Self {
140 requirements: Vec::new(),
141 validators: HashMap::new(),
142 test_endpoints: Vec::new(),
143 }
144 }
145
146 pub fn load_requirements(&mut self, rfc_path: &Path) -> Result<(), ValidationError> {
148 let parser = rfc_parser::RfcParser::new();
149 let requirements = parser.parse_file(rfc_path)?;
150 self.requirements.extend(requirements);
151 Ok(())
152 }
153
154 pub fn register_validator(&mut self, spec_id: String, validator: Box<dyn SpecValidator>) {
156 self.validators.insert(spec_id, validator);
157 }
158
159 pub fn add_test_endpoint(&mut self, endpoint: String) {
161 self.test_endpoints.push(endpoint);
162 }
163
164 pub fn validate_all(&self) -> ComplianceReport {
166 let mut results = Vec::new();
167
168 for requirement in &self.requirements {
169 if let Some(validator) = self.validators.get(&requirement.spec_id) {
170 let result = validator.validate(requirement);
171 results.push(result);
172 } else {
173 results.push(ComplianceResult {
174 requirement: requirement.clone(),
175 compliant: false,
176 details: format!("No validator registered for {}", requirement.spec_id),
177 evidence: vec![],
178 });
179 }
180 }
181
182 ComplianceReport::new(results)
183 }
184
185 pub async fn validate_endpoints(&self) -> EndpointValidationReport {
187 let mut tester = endpoint_tester::EndpointTester::new();
188 for endpoint in &self.test_endpoints {
189 tester.add_endpoint(endpoint.clone());
190 }
191 tester.test_all_endpoints().await
192 }
193}
194
195pub trait SpecValidator: Send + Sync {
197 fn validate(&self, requirement: &ComplianceRequirement) -> ComplianceResult;
199
200 fn spec_id(&self) -> &str;
202}
203
204#[derive(Debug)]
206pub struct ComplianceReport {
207 pub results: Vec<ComplianceResult>,
209 pub summary: ComplianceSummary,
211 pub timestamp: std::time::SystemTime,
213}
214
215impl ComplianceReport {
216 fn new(results: Vec<ComplianceResult>) -> Self {
217 let summary = ComplianceSummary::from_results(&results);
218 Self {
219 results,
220 summary,
221 timestamp: std::time::SystemTime::now(),
222 }
223 }
224
225 pub fn to_html(&self) -> String {
227 report_generator::generate_html_report(self)
228 }
229
230 pub fn to_json(&self) -> serde_json::Value {
232 report_generator::generate_json_report(self)
233 }
234}
235
236#[derive(Debug)]
238pub struct ComplianceSummary {
239 pub total_requirements: usize,
241 pub passed: usize,
243 pub failed: usize,
245 pub pass_rate_by_level: HashMap<RequirementLevel, f64>,
247 pub pass_rate_by_category: HashMap<RequirementCategory, f64>,
249}
250
251impl ComplianceSummary {
252 fn from_results(results: &[ComplianceResult]) -> Self {
253 let total_requirements = results.len();
254 let passed = results.iter().filter(|r| r.compliant).count();
255 let failed = total_requirements - passed;
256
257 let mut pass_rate_by_level = HashMap::new();
258 let mut pass_rate_by_category = HashMap::new();
259
260 for level in &[
262 RequirementLevel::Must,
263 RequirementLevel::MustNot,
264 RequirementLevel::Should,
265 RequirementLevel::ShouldNot,
266 RequirementLevel::May,
267 ] {
268 let level_results: Vec<_> = results
269 .iter()
270 .filter(|r| &r.requirement.level == level)
271 .collect();
272
273 if !level_results.is_empty() {
274 let level_passed = level_results.iter().filter(|r| r.compliant).count();
275 let pass_rate = level_passed as f64 / level_results.len() as f64;
276 pass_rate_by_level.insert(level.clone(), pass_rate);
277 }
278 }
279
280 for category in &[
282 RequirementCategory::Transport,
283 RequirementCategory::FrameFormat,
284 RequirementCategory::TransportParameters,
285 RequirementCategory::ConnectionEstablishment,
286 RequirementCategory::NatTraversal,
287 RequirementCategory::AddressDiscovery,
288 RequirementCategory::ErrorHandling,
289 RequirementCategory::Security,
290 RequirementCategory::Performance,
291 ] {
292 let category_results: Vec<_> = results
293 .iter()
294 .filter(|r| &r.requirement.category == category)
295 .collect();
296
297 if !category_results.is_empty() {
298 let category_passed = category_results.iter().filter(|r| r.compliant).count();
299 let pass_rate = category_passed as f64 / category_results.len() as f64;
300 pass_rate_by_category.insert(category.clone(), pass_rate);
301 }
302 }
303
304 Self {
305 total_requirements,
306 passed,
307 failed,
308 pass_rate_by_level,
309 pass_rate_by_category,
310 }
311 }
312
313 pub fn compliance_percentage(&self) -> f64 {
315 if self.total_requirements == 0 {
316 0.0
317 } else {
318 (self.passed as f64 / self.total_requirements as f64) * 100.0
319 }
320 }
321
322 pub fn must_requirements_met(&self) -> bool {
324 self.pass_rate_by_level
325 .get(&RequirementLevel::Must)
326 .map(|&rate| rate == 1.0)
327 .unwrap_or(true)
328 }
329}
330
331#[derive(Debug)]
333pub struct EndpointValidationReport {
334 pub endpoint_results: HashMap<String, EndpointResult>,
336 pub success_rate: f64,
338 pub common_issues: Vec<String>,
340}
341
342#[derive(Debug)]
344pub struct EndpointResult {
345 pub endpoint: String,
347 pub connected: bool,
349 pub quic_versions: Vec<u32>,
351 pub extensions: Vec<String>,
353 pub issues: Vec<String>,
355}
356
357#[derive(Debug)]
359pub enum ValidationError {
360 RfcParseError(String),
362 SpecLoadError(String),
364 ValidationError(String),
366 IoError(std::io::Error),
368}
369
370impl fmt::Display for ValidationError {
371 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
372 match self {
373 Self::RfcParseError(e) => write!(f, "RFC parse error: {e}"),
374 Self::SpecLoadError(e) => write!(f, "Specification load error: {e}"),
375 Self::ValidationError(e) => write!(f, "Validation error: {e}"),
376 Self::IoError(e) => write!(f, "IO error: {e}"),
377 }
378 }
379}
380
381impl std::error::Error for ValidationError {}
382
383impl From<std::io::Error> for ValidationError {
384 fn from(err: std::io::Error) -> Self {
385 Self::IoError(err)
386 }
387}