#[macro_export]
macro_rules! impl_scanner_builder {
($scanner:ty) => {
#[allow(dead_code)]
impl $scanner {
pub fn new() -> Self {
Self {
config: $crate::scanner::ScannerConfig::new(),
}
}
pub fn with_skip_comments(mut self, skip: bool) -> Self {
self.config = self.config.with_skip_comments(skip);
self
}
pub fn with_dynamic_rules(mut self, rules: Vec<$crate::rules::DynamicRule>) -> Self {
self.config = self.config.with_dynamic_rules(rules);
self
}
pub fn with_strict_secrets(mut self, strict: bool) -> Self {
self.config = self.config.with_strict_secrets(strict);
self
}
pub fn with_recursive(mut self, recursive: bool) -> Self {
self.config = self.config.with_recursive(recursive);
self
}
pub fn with_max_file_size(mut self, max_file_size: u64) -> Self {
self.config = self.config.with_max_file_size(max_file_size);
self
}
pub fn with_progress_callback(
mut self,
callback: $crate::engine::scanner::ProgressCallback,
) -> Self {
self.config = self.config.with_progress_callback(callback);
self
}
}
impl Default for $scanner {
fn default() -> Self {
Self::new()
}
}
};
}
#[macro_export]
macro_rules! impl_content_scanner {
($scanner:ty) => {
impl $crate::engine::scanner::ContentScanner for $scanner {
fn config(&self) -> &$crate::engine::scanner::ScannerConfig {
&self.config
}
}
};
}
#[macro_export]
macro_rules! impl_simple_file_scanner {
($scanner:ty, $file_patterns:expr) => {
impl $crate::scanner::Scanner for $scanner {
fn scan_file(
&self,
path: &std::path::Path,
) -> $crate::error::Result<Vec<$crate::rules::Finding>> {
let content = self.config.read_file(path)?;
let path_str = path.display().to_string();
Ok(self.config.check_content(&content, &path_str))
}
fn scan_directory(
&self,
dir: &std::path::Path,
) -> $crate::error::Result<Vec<$crate::rules::Finding>> {
let mut findings = Vec::new();
let patterns_fn: fn(&std::path::Path) -> Vec<std::path::PathBuf> = $file_patterns;
let patterns = patterns_fn(dir);
for pattern in patterns {
if pattern.exists() {
findings.extend(self.scan_file(&pattern)?);
}
}
Ok(findings)
}
}
};
}
#[cfg(test)]
mod tests {
use crate::engine::scanner::ScannerConfig;
pub struct TestScanner {
config: ScannerConfig,
}
impl_scanner_builder!(TestScanner);
#[test]
fn test_new_scanner() {
let scanner = TestScanner::new();
assert!(!scanner.config.skip_comments());
}
#[test]
fn test_with_skip_comments() {
let scanner = TestScanner::new().with_skip_comments(true);
assert!(scanner.config.skip_comments());
}
#[test]
fn test_with_dynamic_rules() {
let scanner = TestScanner::new().with_dynamic_rules(vec![]);
assert!(!scanner.config.skip_comments());
}
#[test]
fn test_with_strict_secrets() {
let scanner = TestScanner::new().with_strict_secrets(true);
assert!(scanner.config.strict_secrets());
}
#[test]
fn test_default_trait() {
let scanner = TestScanner::default();
assert!(!scanner.config.skip_comments());
}
#[allow(dead_code)]
pub struct TestContentScanner {
config: ScannerConfig,
}
impl_scanner_builder!(TestContentScanner);
impl crate::scanner::Scanner for TestContentScanner {
fn scan_file(
&self,
_path: &std::path::Path,
) -> crate::error::Result<Vec<crate::rules::Finding>> {
Ok(vec![])
}
fn scan_directory(
&self,
_dir: &std::path::Path,
) -> crate::error::Result<Vec<crate::rules::Finding>> {
Ok(vec![])
}
}
impl_content_scanner!(TestContentScanner);
#[test]
fn test_content_scanner_config_access() {
use crate::engine::scanner::ContentScanner;
let scanner = TestContentScanner::new();
let _config = scanner.config();
}
}