Skip to content

Commit bf70764

Browse files
cursoragentscript3r
andcommitted
Test: Add filtering tests for include_globs and max_file_size
Co-authored-by: script3r <[email protected]>
1 parent e1814d8 commit bf70764

File tree

1 file changed

+182
-0
lines changed

1 file changed

+182
-0
lines changed

crates/cli/tests/filtering.rs

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
use scanner_core::*;
2+
use std::fs;
3+
use std::path::PathBuf;
4+
use std::sync::Arc;
5+
use std::time::{SystemTime, UNIX_EPOCH};
6+
7+
fn write_file(dir: &PathBuf, rel: &str, contents: &str) {
8+
let path = dir.join(rel);
9+
if let Some(parent) = path.parent() {
10+
fs::create_dir_all(parent).unwrap();
11+
}
12+
fs::write(path, contents).unwrap();
13+
}
14+
15+
fn tmp_dir(prefix: &str) -> PathBuf {
16+
let mut base = std::env::temp_dir();
17+
let ts = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_nanos();
18+
let pid = std::process::id();
19+
base.push(format!("cipherscope_test_{}_{}_{}", prefix, pid, ts));
20+
fs::create_dir_all(&base).unwrap();
21+
base
22+
}
23+
24+
fn load_registry() -> Arc<PatternRegistry> {
25+
let workspace = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..");
26+
let patterns_path = workspace.join("patterns.toml");
27+
let patterns = fs::read_to_string(patterns_path).unwrap();
28+
Arc::new(PatternRegistry::load(&patterns).unwrap())
29+
}
30+
31+
#[test]
32+
fn commented_import_does_not_trigger_anchor_java() {
33+
let reg = load_registry();
34+
let dets: Vec<Box<dyn Detector>> = vec![Box::new(PatternDetector::new(
35+
"detector-java",
36+
&[Language::Java],
37+
reg.clone(),
38+
))];
39+
let cfg = Config::default();
40+
let scanner = Scanner::new(&reg, dets, cfg);
41+
42+
let dir = tmp_dir("commented_import_java");
43+
write_file(
44+
&dir,
45+
"src/Main.java",
46+
r#"package test;
47+
// import javax.crypto.Cipher; // commented anchor
48+
public class Main {
49+
public static void main(String[] args) throws Exception {
50+
javax.crypto.Cipher.getInstance("AES/GCM/NoPadding"); // API present
51+
}
52+
}
53+
"#,
54+
);
55+
let findings = scanner.run(std::slice::from_ref(&dir)).unwrap();
56+
assert!(
57+
!findings
58+
.iter()
59+
.any(|f| f.library == "Java JCA/JCE"),
60+
"JCA/JCE should not be reported when import is commented"
61+
);
62+
}
63+
64+
#[test]
65+
fn php_api_only_reports_openssl() {
66+
let reg = load_registry();
67+
let dets: Vec<Box<dyn Detector>> = vec![Box::new(PatternDetector::new(
68+
"detector-php",
69+
&[Language::Php],
70+
reg.clone(),
71+
))];
72+
let cfg = Config::default();
73+
let scanner = Scanner::new(&reg, dets, cfg);
74+
75+
let dir = tmp_dir("php_openssl_api_only");
76+
write_file(
77+
&dir,
78+
"web/index.php",
79+
r#"<?php
80+
// No imports for PHP OpenSSL detector; API use is enough
81+
$ciphertext = openssl_encrypt("data", "aes-256-cbc", "key", 0, "1234567890123456");
82+
echo $ciphertext;
83+
"#,
84+
);
85+
let findings = scanner.run(std::slice::from_ref(&dir)).unwrap();
86+
assert!(
87+
findings.iter().any(|f| f.library == "OpenSSL (PHP)"),
88+
"OpenSSL (PHP) should be reported on API use only"
89+
);
90+
}
91+
92+
#[test]
93+
fn include_glob_filters_file_types() {
94+
let reg = load_registry();
95+
let dets_java: Vec<Box<dyn Detector>> = vec![
96+
Box::new(PatternDetector::new("detector-java", &[Language::Java], reg.clone())),
97+
Box::new(PatternDetector::new("detector-php", &[Language::Php], reg.clone())),
98+
];
99+
100+
let dir = tmp_dir("include_glob_filters");
101+
// Java file with anchor+API
102+
write_file(
103+
&dir,
104+
"src/Main.java",
105+
r#"package test;
106+
import java.security.MessageDigest;
107+
public class Main {
108+
public static void main(String[] args) throws Exception {
109+
java.security.KeyFactory.getInstance("RSA");
110+
}
111+
}
112+
"#,
113+
);
114+
// PHP file with API
115+
write_file(
116+
&dir,
117+
"web/index.php",
118+
r#"<?php
119+
echo openssl_encrypt("data", "aes-256-cbc", "key", 0, "1234567890123456");
120+
"#,
121+
);
122+
123+
// Only Java
124+
let cfg_java_only = Config {
125+
include_globs: vec!["**/*.java".to_string()],
126+
..Default::default()
127+
};
128+
let scanner_java = Scanner::new(&reg, dets_java, cfg_java_only);
129+
let findings_java = scanner_java.run(std::slice::from_ref(&dir)).unwrap();
130+
assert!(findings_java.iter().any(|f| f.library == "Java JCA/JCE"));
131+
assert!(
132+
!findings_java.iter().any(|f| f.library == "OpenSSL (PHP)"),
133+
"PHP findings should be excluded by include_glob"
134+
);
135+
136+
// Only PHP
137+
let cfg_php_only = Config {
138+
include_globs: vec!["**/*.php".to_string()],
139+
..Default::default()
140+
};
141+
let dets_php: Vec<Box<dyn Detector>> = vec![
142+
Box::new(PatternDetector::new("detector-java", &[Language::Java], reg.clone())),
143+
Box::new(PatternDetector::new("detector-php", &[Language::Php], reg.clone())),
144+
];
145+
let scanner_php = Scanner::new(&reg, dets_php, cfg_php_only);
146+
let findings_php = scanner_php.run(std::slice::from_ref(&dir)).unwrap();
147+
assert!(findings_php.iter().any(|f| f.library == "OpenSSL (PHP)"));
148+
assert!(
149+
!findings_php.iter().any(|f| f.library == "Java JCA/JCE"),
150+
"Java findings should be excluded by include_glob"
151+
);
152+
}
153+
154+
#[test]
155+
fn max_file_size_skips_large_files() {
156+
let reg = load_registry();
157+
let dets: Vec<Box<dyn Detector>> = vec![Box::new(PatternDetector::new(
158+
"detector-java",
159+
&[Language::Java],
160+
reg.clone(),
161+
))];
162+
163+
let dir = tmp_dir("max_file_size");
164+
// Create a large Java file that would otherwise match JCA
165+
let mut content = String::from(
166+
"package test;\nimport javax.crypto.Cipher;\npublic class Big { public static void main(String[] a){ } }\n",
167+
);
168+
// Append enough data to exceed threshold
169+
for _ in 0..5000 {
170+
content.push_str("// padding padding padding padding padding padding\n");
171+
}
172+
write_file(&dir, "src/Big.java", &content);
173+
174+
let cfg_small_limit = Config {
175+
max_file_size: 512, // bytes
176+
..Default::default()
177+
};
178+
let scanner = Scanner::new(&reg, dets, cfg_small_limit);
179+
let findings = scanner.run(std::slice::from_ref(&dir)).unwrap();
180+
assert!(findings.is_empty(), "Large file should be skipped by max_file_size");
181+
}
182+

0 commit comments

Comments
 (0)