Skip to main content

cc_audit/parser/
yaml.rs

1//! YAML content parser.
2
3use super::traits::{ContentParser, ContentType, ParsedContent};
4use crate::error::Result;
5
6/// Parser for YAML files (docker-compose.yml, subagent configs, etc.).
7pub struct YamlParser;
8
9impl YamlParser {
10    /// Create a new YAML parser.
11    pub fn new() -> Self {
12        Self
13    }
14
15    /// Parse YAML content to a serde_json::Value.
16    pub fn parse_value(content: &str) -> Option<serde_json::Value> {
17        serde_yaml::from_str(content).ok()
18    }
19
20    /// Parse YAML content to a serde_yaml::Value.
21    pub fn parse_yaml_value(content: &str) -> Option<serde_yaml::Value> {
22        serde_yaml::from_str(content).ok()
23    }
24}
25
26impl Default for YamlParser {
27    fn default() -> Self {
28        Self::new()
29    }
30}
31
32impl ContentParser for YamlParser {
33    fn parse(&self, content: &str, path: &str) -> Result<ParsedContent> {
34        let mut parsed =
35            ParsedContent::new(ContentType::Yaml, content.to_string(), path.to_string());
36
37        // Try to parse as structured YAML (convert to JSON Value for uniformity)
38        if let Some(value) = Self::parse_value(content) {
39            parsed = parsed.with_structured_data(value);
40        }
41
42        Ok(parsed)
43    }
44
45    fn supported_extensions(&self) -> &[&str] {
46        &[".yml", ".yaml"]
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn test_parse_valid_yaml() {
56        let parser = YamlParser::new();
57        let content = "name: test\nversion: 1.0";
58        let result = parser.parse(content, "config.yml").unwrap();
59
60        assert_eq!(result.content_type, ContentType::Yaml);
61        assert!(result.structured_data.is_some());
62        let data = result.structured_data.unwrap();
63        assert_eq!(data["name"].as_str(), Some("test"));
64    }
65
66    #[test]
67    fn test_parse_invalid_yaml() {
68        let parser = YamlParser::new();
69        let content = "invalid: yaml: content: [";
70        let result = parser.parse(content, "config.yml").unwrap();
71
72        // Parser still returns content, just without structured_data
73        assert_eq!(result.content_type, ContentType::Yaml);
74    }
75
76    #[test]
77    fn test_supported_extensions() {
78        let parser = YamlParser::new();
79        assert!(parser.can_parse("config.yml"));
80        assert!(parser.can_parse("config.yaml"));
81        assert!(!parser.can_parse("config.json"));
82    }
83
84    #[test]
85    fn test_parse_docker_compose() {
86        let parser = YamlParser::new();
87        let content = r#"
88version: '3.8'
89services:
90  app:
91    image: myapp:latest
92    ports:
93      - "8080:80"
94"#;
95        let result = parser.parse(content, "docker-compose.yml").unwrap();
96
97        assert!(result.structured_data.is_some());
98        let data = result.structured_data.unwrap();
99        assert!(data["services"]["app"]["image"].is_string());
100    }
101}