Skip to main content

cc_audit/runtime/
hook.rs

1//! Hook mode runner.
2//!
3//! This module provides integration with hook_mode for CI/CD.
4
5use crate::hook_mode::HookAnalyzer;
6
7/// Runner for hook mode operations.
8///
9/// Provides a unified interface for running hook mode and
10/// analyzing different types of inputs.
11pub struct HookRunner;
12
13impl HookRunner {
14    /// Create a new hook runner.
15    pub fn new() -> Self {
16        Self
17    }
18
19    /// Analyze bash command input.
20    pub fn analyze_bash(
21        input: &crate::hook_mode::BashInput,
22    ) -> Vec<crate::hook_mode::types::HookFinding> {
23        HookAnalyzer::analyze_bash(input)
24    }
25
26    /// Analyze write input.
27    pub fn analyze_write(
28        input: &crate::hook_mode::WriteInput,
29    ) -> Vec<crate::hook_mode::types::HookFinding> {
30        HookAnalyzer::analyze_write(input)
31    }
32
33    /// Analyze edit input.
34    pub fn analyze_edit(
35        input: &crate::hook_mode::EditInput,
36    ) -> Vec<crate::hook_mode::types::HookFinding> {
37        HookAnalyzer::analyze_edit(input)
38    }
39
40    /// Run hook mode (blocking).
41    ///
42    /// This reads events from stdin and writes responses to stdout.
43    pub fn run() -> i32 {
44        crate::hook_mode::run_hook_mode()
45    }
46}
47
48impl Default for HookRunner {
49    fn default() -> Self {
50        Self::new()
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57    use crate::hook_mode::{BashInput, EditInput, WriteInput};
58
59    #[test]
60    fn test_hook_runner_creation() {
61        let _runner = HookRunner::new();
62    }
63
64    #[test]
65    fn test_hook_runner_default() {
66        let runner = HookRunner;
67        // Just verify it creates successfully
68        let _ = runner;
69    }
70
71    #[test]
72    fn test_hook_runner_analyze_bash_safe() {
73        let input = BashInput {
74            command: "ls -la".to_string(),
75            description: None,
76            timeout: None,
77        };
78        let findings = HookRunner::analyze_bash(&input);
79        assert!(findings.is_empty());
80    }
81
82    #[test]
83    fn test_hook_runner_analyze_bash_dangerous() {
84        let input = BashInput {
85            command: "sudo rm -rf /".to_string(),
86            description: None,
87            timeout: None,
88        };
89        let findings = HookRunner::analyze_bash(&input);
90        assert!(!findings.is_empty());
91    }
92
93    #[test]
94    fn test_hook_runner_analyze_write_safe() {
95        let input = WriteInput {
96            file_path: "/tmp/test.txt".to_string(),
97            content: "Hello, world!".to_string(),
98        };
99        let findings = HookRunner::analyze_write(&input);
100        assert!(findings.is_empty());
101    }
102
103    #[test]
104    fn test_hook_runner_analyze_write_dangerous() {
105        let input = WriteInput {
106            file_path: "/etc/passwd".to_string(),
107            content: "root::0:0::/root:/bin/bash".to_string(),
108        };
109        let findings = HookRunner::analyze_write(&input);
110        assert!(!findings.is_empty());
111    }
112
113    #[test]
114    fn test_hook_runner_analyze_edit_safe() {
115        let input = EditInput {
116            file_path: "/tmp/test.txt".to_string(),
117            old_string: "old".to_string(),
118            new_string: "new".to_string(),
119        };
120        let findings = HookRunner::analyze_edit(&input);
121        assert!(findings.is_empty());
122    }
123
124    #[test]
125    fn test_hook_runner_analyze_edit_dangerous() {
126        let input = EditInput {
127            file_path: "/etc/sudoers".to_string(),
128            old_string: "old".to_string(),
129            new_string: "ALL=(ALL) NOPASSWD: ALL".to_string(),
130        };
131        let findings = HookRunner::analyze_edit(&input);
132        assert!(!findings.is_empty());
133    }
134}