use crate::compliance::{Rule, Severity};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComplianceFramework {
pub id: String,
pub name: String,
pub version: String,
pub description: String,
pub organization: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub effective_date: Option<String>,
pub requirements: Vec<Requirement>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Requirement {
pub id: String,
pub name: String,
pub description: String,
pub category: String,
pub severity: Severity,
#[serde(default)]
pub remediation: String,
pub rules: Vec<Rule>,
}
impl ComplianceFramework {
pub fn get_requirement(&self, id: &str) -> Option<&Requirement> {
self.requirements.iter().find(|r| r.id == id)
}
pub fn requirements_by_category(&self, category: &str) -> Vec<&Requirement> {
self.requirements
.iter()
.filter(|r| r.category == category)
.collect()
}
pub fn requirements_by_severity(&self, severity: Severity) -> Vec<&Requirement> {
self.requirements
.iter()
.filter(|r| r.severity == severity)
.collect()
}
pub fn categories(&self) -> Vec<String> {
let mut categories: Vec<String> = self
.requirements
.iter()
.map(|r| r.category.clone())
.collect();
categories.sort();
categories.dedup();
categories
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_framework_get_requirement() {
let framework = ComplianceFramework {
id: "test".to_string(),
name: "Test".to_string(),
version: "1.0".to_string(),
description: "Test framework".to_string(),
organization: "Test Org".to_string(),
effective_date: None,
requirements: vec![Requirement {
id: "TEST-1".to_string(),
name: "Test Requirement".to_string(),
description: "".to_string(),
category: "Security".to_string(),
severity: Severity::High,
remediation: "".to_string(),
rules: vec![],
}],
};
assert!(framework.get_requirement("TEST-1").is_some());
assert!(framework.get_requirement("TEST-2").is_none());
}
#[test]
fn test_framework_categories() {
let framework = ComplianceFramework {
id: "test".to_string(),
name: "Test".to_string(),
version: "1.0".to_string(),
description: "Test framework".to_string(),
organization: "Test Org".to_string(),
effective_date: None,
requirements: vec![
Requirement {
id: "TEST-1".to_string(),
name: "Test 1".to_string(),
description: "".to_string(),
category: "Protocol Security".to_string(),
severity: Severity::High,
remediation: "".to_string(),
rules: vec![],
},
Requirement {
id: "TEST-2".to_string(),
name: "Test 2".to_string(),
description: "".to_string(),
category: "Cipher Security".to_string(),
severity: Severity::High,
remediation: "".to_string(),
rules: vec![],
},
Requirement {
id: "TEST-3".to_string(),
name: "Test 3".to_string(),
description: "".to_string(),
category: "Protocol Security".to_string(),
severity: Severity::Medium,
remediation: "".to_string(),
rules: vec![],
},
],
};
let categories = framework.categories();
assert_eq!(categories.len(), 2);
assert!(categories.contains(&"Protocol Security".to_string()));
assert!(categories.contains(&"Cipher Security".to_string()));
}
}