1pub mod command;
2pub mod common;
3pub mod dependency;
4pub mod dockerfile;
5pub mod hook;
6pub mod mcp;
7pub mod plugin;
8pub mod rules_dir;
9pub mod skill;
10pub mod subagent;
11
12use crate::error::{AuditError, Result};
13use crate::rules::Finding;
14use std::path::Path;
15
16pub use command::CommandScanner;
17pub use common::ScannerConfig;
18pub use dependency::DependencyScanner;
19pub use dockerfile::DockerScanner;
20pub use hook::HookScanner;
21pub use mcp::McpScanner;
22pub use plugin::PluginScanner;
23pub use rules_dir::RulesDirScanner;
24pub use skill::{FrontmatterParser, SkillFileFilter, SkillScanner};
25pub use subagent::SubagentScanner;
26
27pub trait Scanner {
29 fn scan_file(&self, path: &Path) -> Result<Vec<Finding>>;
30 fn scan_directory(&self, dir: &Path) -> Result<Vec<Finding>>;
31
32 fn scan_path(&self, path: &Path) -> Result<Vec<Finding>> {
33 if !path.exists() {
34 return Err(AuditError::FileNotFound(path.display().to_string()));
35 }
36
37 if path.is_file() {
38 return self.scan_file(path);
39 }
40
41 if !path.is_dir() {
42 return Err(AuditError::NotADirectory(path.display().to_string()));
43 }
44
45 self.scan_directory(path)
46 }
47}
48
49pub trait ContentScanner: Scanner {
55 fn config(&self) -> &ScannerConfig;
57
58 fn scan_content(&self, content: &str, file_path: &str) -> Result<Vec<Finding>> {
64 Ok(self.config().check_content(content, file_path))
65 }
66}