Added an optional exclude_words list to PatternRequirements so matches containing case-insensitive placeholder words are filtered out, with accompanying tests to cover the new behavior.

This commit is contained in:
Mick Grove 2025-11-04 13:07:24 -08:00
commit 6a5a62a5b5
17 changed files with 113 additions and 168 deletions

View file

@ -81,6 +81,10 @@ rules:
mongodb(?:\+srv)?://[\S]{3,50}:(?:[\S]{3,88})@[-.%\w/:]+
)
\b
pattern_requirements:
exclude_words:
- "@localhost"
- "@127.0.0.1"
min_entropy: 3
examples:
- client = mongoc_client_new ("mongodb+srv://someuser:hunter2@my-atlas-rd941.mongodb.net/test?retryWrites=true&w=majority");

View file

@ -1171,13 +1171,22 @@ mod test {
let mut matcher =
Matcher::new(&rules_db, scanner_pool, &seen_blobs, None, false, None, &[], false)?;
matcher.scan_bytes_raw(input, "fname")?;
let blob = Blob::from_bytes(input.to_vec());
let origin = OriginSet::from(Origin::from_file(PathBuf::from("exclude.txt")));
let matches = match matcher.scan_blob(&blob, &origin, None, false, false, false)? {
ScanResult::New(matches) => matches,
ScanResult::SeenWithMatches => {
panic!("unexpected scan result: blob should not be considered previously seen with matches")
}
ScanResult::SeenSansMatches => {
panic!("unexpected scan result: blob should not be considered previously seen without matches")
}
};
let matches = &matcher.user_data.raw_matches_scratch;
assert_eq!(matches.len(), 1, "exclude_words should drop filtered matches");
let RawMatch { start_idx, end_idx, .. } = matches[0];
assert_eq!(
&input[start_idx as usize..end_idx as usize],
matches[0].matching_input,
b"prefixgood",
"remaining match should be the non-excluded token",
);
@ -1185,6 +1194,7 @@ mod test {
Ok(())
}
// ---------------------------------------------------------------------
// additional deterministic unit-tests
// ---------------------------------------------------------------------

View file

@ -6,8 +6,7 @@ mod test {
use super::*;
#[test]
fn cli_lists_rules_pretty() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["rules", "list", "--format", "pretty", "--no-update-check"])
.assert()
.success()
@ -15,8 +14,7 @@ mod test {
}
#[test]
fn cli_lists_rules_json() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["rules", "list", "--format", "json", "--no-update-check"])
.assert()
.success()
@ -25,8 +23,7 @@ mod test {
#[test]
fn cli_version_flag() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.arg("--version")
.assert()
.success()

View file

@ -8,8 +8,7 @@ use tempfile::TempDir;
/// 1. Path-does-not-exist ⇒ run_async_scan bails with “Invalid input”
#[test]
fn scan_fails_for_missing_path() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "no/such/path/here", "--no-update-check"])
.assert()
.failure() // exit-code ≠ 0
@ -22,8 +21,7 @@ fn scan_fails_for_bad_rule_yaml() {
let tmp = TempDir::new().unwrap();
fs::write(tmp.path().join("broken.yml"), "this: is: : not yaml").unwrap();
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
tmp.path().to_str().unwrap(), // dummy input dir (exists)
@ -68,8 +66,7 @@ rules:
// Create a dummy input file that matches the rule
fs::write(tmp.path().join("input.txt"), "dummy_dead").unwrap();
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
tmp.path().join("input.txt").to_str().unwrap(),

View file

@ -19,8 +19,7 @@ mod github {
#[test]
fn scan_github_help() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "github", "--help"])
.assert()
.success()
@ -29,8 +28,7 @@ mod github {
#[test]
fn scan_github_list_only_help() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "github", "--help"])
.assert()
.success()
@ -42,8 +40,7 @@ mod github {
#[test]
fn scan_github_requires_specifier() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "github", "--no-update-check"])
.assert()
.failure()
@ -52,8 +49,7 @@ mod github {
#[test]
fn scan_github_with_user() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "github", "--user", "testuser", "--list-only", "--no-update-check"])
.assert()
.code(predicates::function::function(|code: &i32| {
@ -64,8 +60,7 @@ mod github {
#[test]
fn scan_github_with_organization() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"github",
@ -80,8 +75,7 @@ mod github {
#[test]
fn scan_github_multiple_users() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"github",
@ -98,8 +92,7 @@ mod github {
#[test]
fn scan_github_with_exclude() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"github",
@ -116,8 +109,7 @@ mod github {
#[test]
fn scan_github_with_repo_type_fork() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"github",
@ -134,8 +126,7 @@ mod github {
#[test]
fn scan_github_with_repo_type_source() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"github",
@ -152,8 +143,7 @@ mod github {
#[test]
fn scan_github_custom_api_url() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"github",
@ -170,8 +160,7 @@ mod github {
#[test]
fn scan_github_all_organizations() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"github",
@ -187,8 +176,7 @@ mod github {
#[test]
fn scan_github_invalid_repo_type() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"github",
@ -205,8 +193,7 @@ mod github {
#[test]
fn scan_github_mixed_user_and_org() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"github",
@ -231,8 +218,7 @@ mod gitlab {
#[test]
fn scan_gitlab_help() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "gitlab", "--help"])
.assert()
.success()
@ -241,8 +227,7 @@ mod gitlab {
#[test]
fn scan_gitlab_list_only_flag() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "gitlab", "--help"])
.assert()
.success()
@ -251,8 +236,7 @@ mod gitlab {
#[test]
fn scan_gitlab_requires_specifier() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "gitlab", "--no-update-check"])
.assert()
.failure()
@ -261,8 +245,7 @@ mod gitlab {
#[test]
fn scan_gitlab_with_user() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "gitlab", "--user", "testuser", "--list-only", "--no-update-check"])
.assert()
.code(predicates::function::function(|code: &i32| *code == 0 || *code == 1));
@ -270,8 +253,7 @@ mod gitlab {
#[test]
fn scan_gitlab_with_group() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "gitlab", "--group", "testgroup", "--list-only", "--no-update-check"])
.assert()
.code(predicates::function::function(|code: &i32| *code == 0 || *code == 1));
@ -279,8 +261,7 @@ mod gitlab {
#[test]
fn scan_gitlab_with_include_subgroups() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"gitlab",
@ -296,8 +277,7 @@ mod gitlab {
#[test]
fn scan_gitlab_with_repo_type() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"gitlab",
@ -314,8 +294,7 @@ mod gitlab {
#[test]
fn scan_gitlab_with_exclude() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"gitlab",
@ -332,8 +311,7 @@ mod gitlab {
#[test]
fn scan_gitlab_custom_api_url() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"gitlab",
@ -350,8 +328,7 @@ mod gitlab {
#[test]
fn scan_gitlab_all_groups() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"gitlab",
@ -375,8 +352,7 @@ mod azure {
#[test]
fn scan_azure_help() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "azure", "--help"])
.assert()
.success()
@ -385,8 +361,7 @@ mod azure {
#[test]
fn scan_azure_list_only_flag() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "azure", "--help"])
.assert()
.success()
@ -395,8 +370,7 @@ mod azure {
#[test]
fn scan_azure_requires_specifier() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "azure", "--no-update-check"])
.assert()
.failure()
@ -405,8 +379,7 @@ mod azure {
#[test]
fn scan_azure_with_organization() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"azure",
@ -421,8 +394,7 @@ mod azure {
#[test]
fn scan_azure_with_project() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"azure",
@ -437,8 +409,7 @@ mod azure {
#[test]
fn scan_azure_all_projects() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"azure",
@ -454,8 +425,7 @@ mod azure {
#[test]
fn scan_azure_with_exclude() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"azure",
@ -472,8 +442,7 @@ mod azure {
#[test]
fn scan_azure_with_repo_type() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"azure",
@ -498,8 +467,7 @@ mod bitbucket {
#[test]
fn scan_bitbucket_help() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "bitbucket", "--help"])
.assert()
.stdout(is_match(r"kingfisher(\.exe)? scan bitbucket \[OPTIONS\]").unwrap());
@ -507,8 +475,7 @@ mod bitbucket {
#[test]
fn scan_bitbucket_list_only_flag() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "bitbucket", "--help"])
.assert()
.success()
@ -517,8 +484,7 @@ mod bitbucket {
#[test]
fn scan_bitbucket_requires_specifier() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "bitbucket", "--no-update-check"])
.assert()
.failure()
@ -527,8 +493,7 @@ mod bitbucket {
#[test]
fn scan_bitbucket_with_workspace() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"bitbucket",
@ -543,8 +508,7 @@ mod bitbucket {
#[test]
fn scan_bitbucket_with_user() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "bitbucket", "--user", "testuser", "--list-only", "--no-update-check"])
.assert()
.code(predicates::function::function(|code: &i32| *code == 0 || *code == 1));
@ -552,8 +516,7 @@ mod bitbucket {
#[test]
fn scan_bitbucket_with_project() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"bitbucket",
@ -568,8 +531,7 @@ mod bitbucket {
#[test]
fn scan_bitbucket_all_workspaces() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"bitbucket",
@ -585,8 +547,7 @@ mod bitbucket {
#[test]
fn scan_bitbucket_with_exclude() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"bitbucket",
@ -603,8 +564,7 @@ mod bitbucket {
#[test]
fn scan_bitbucket_with_repo_type() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"bitbucket",
@ -629,8 +589,7 @@ mod gitea {
#[test]
fn scan_gitea_help() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "gitea", "--help"])
.assert()
.success()
@ -639,8 +598,7 @@ mod gitea {
#[test]
fn scan_gitea_requires_specifier() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "gitea", "--no-update-check"])
.assert()
.failure()
@ -649,8 +607,7 @@ mod gitea {
#[test]
fn scan_gitea_with_organization() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"gitea",
@ -665,8 +622,7 @@ mod gitea {
#[test]
fn scan_gitea_with_user() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "gitea", "--user", "testuser", "--list-only", "--no-update-check"])
.assert()
.code(predicates::function::function(|code: &i32| *code == 0 || *code == 1));
@ -674,8 +630,7 @@ mod gitea {
#[test]
fn scan_gitea_all_organizations() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"gitea",
@ -689,8 +644,7 @@ mod gitea {
#[test]
fn scan_gitea_with_exclude() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"gitea",
@ -707,8 +661,7 @@ mod gitea {
#[test]
fn scan_gitea_with_repo_type() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"gitea",
@ -725,8 +678,7 @@ mod gitea {
#[test]
fn scan_gitea_custom_api_url() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"gitea",
@ -751,8 +703,7 @@ mod huggingface {
#[test]
fn scan_huggingface_help() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "huggingface", "--help"])
.assert()
.success()
@ -761,8 +712,7 @@ mod huggingface {
#[test]
fn scan_huggingface_requires_specifier() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "huggingface", "--no-update-check"])
.assert()
.failure()
@ -771,8 +721,7 @@ mod huggingface {
#[test]
fn scan_huggingface_with_user() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"huggingface",
@ -787,8 +736,7 @@ mod huggingface {
#[test]
fn scan_huggingface_with_organization() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"huggingface",
@ -803,8 +751,7 @@ mod huggingface {
#[test]
fn scan_huggingface_with_model() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"huggingface",
@ -819,8 +766,7 @@ mod huggingface {
#[test]
fn scan_huggingface_with_dataset() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"huggingface",
@ -835,8 +781,7 @@ mod huggingface {
#[test]
fn scan_huggingface_with_space() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"huggingface",
@ -851,8 +796,7 @@ mod huggingface {
#[test]
fn scan_huggingface_with_exclude() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
"huggingface",
@ -888,8 +832,7 @@ mod cross_platform {
for mut platform_args in platforms {
platform_args.extend_from_slice(&["--list-only", "--no-update-check"]);
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(&platform_args)
.assert()
.code(predicates::function::function(|code: &i32| *code == 0 || *code == 1));
@ -898,8 +841,7 @@ mod cross_platform {
#[test]
fn scan_requires_subcommand_or_path() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "--no-update-check"])
.assert()
.failure()
@ -908,8 +850,7 @@ mod cross_platform {
#[test]
fn scan_invalid_platform_subcommand() {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "invalid-platform", "--no-update-check"])
.assert()
.failure()
@ -919,8 +860,7 @@ mod cross_platform {
#[test]
fn scan_github_without_scanning_no_paths() {
// list-only should work without providing actual scan paths
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "github", "--user", "testuser", "--list-only", "--no-update-check"])
.assert()
.code(predicates::function::function(|code: &i32| *code == 0 || *code == 1));
@ -941,8 +881,7 @@ mod legacy_compatibility {
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let test_file = root.join("testdata").join("generic_secrets.py");
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
test_file.to_str().expect("REASON"),
@ -962,8 +901,7 @@ mod legacy_compatibility {
// This just validates the CLI parsing works
// New syntax
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "github", "--user", "test", "--list-only", "--no-update-check"])
.assert()
.code(predicates::function::function(|code: &i32| *code == 0 || *code == 1));

View file

@ -12,7 +12,7 @@ fn detects_base64_encoded_secret() -> anyhow::Result<()> {
let encoded = "Z2hwXzF3dUhGaWtCS1F0Q2NIM0VCMkZCVWt5bjhrclhoUDJxTHFQYQ==";
fs::write(&file_path, encoded)?;
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
dir.path().to_str().unwrap(),
@ -42,7 +42,7 @@ fn skips_base64_when_disabled() -> anyhow::Result<()> {
let encoded = "Z2hwXzF3dUhGaWtCS1F0Q2NIM0VCMkZCVWt5bjhrclhoUDJxTHFQYQ==";
fs::write(&file_path, encoded)?;
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
dir.path().to_str().unwrap(),
@ -68,7 +68,7 @@ fn no_base64_skips_empty_files() -> anyhow::Result<()> {
let file_path = dir.path().join("empty.py");
fs::write(&file_path, "")?;
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
dir.path().to_str().unwrap(),
@ -96,7 +96,7 @@ fn detects_base64_in_code_with_tree_sitter() -> anyhow::Result<()> {
let encoded = "Z2hwXzF3dUhGaWtCS1F0Q2NIM0VCMkZCVWt5bjhrclhoUDJxTHFQYQ==";
fs::write(&file_path, format!("token = \"{}\"\n", encoded))?;
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
dir.path().to_str().unwrap(),

View file

@ -10,8 +10,7 @@ fn contains_bytes(haystack: &[u8], needle: &[u8]) -> bool {
#[test]
fn scan_quiet_suppresses_summary() {
for format in FORMATS {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.env("NO_COLOR", "1")
.args([
"scan",
@ -35,8 +34,7 @@ fn scan_quiet_suppresses_summary() {
#[test]
fn scan_quiet_with_rule_stats_prints_rule_stats() {
for format in FORMATS {
Command::cargo_bin("kingfisher")
.unwrap()
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.env("NO_COLOR", "1")
.args([
"scan",

View file

@ -4,7 +4,7 @@ use serde_json::Value;
#[test]
fn scan_rules_has_no_validated_findings() -> Result<()> {
let output = Command::cargo_bin("kingfisher")?
let output = Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "data/rules", "--format", "json", "--no-update-check", "--only-valid"])
.output()?;

View file

@ -29,7 +29,7 @@ fn smoke_scan_tar_gz_archive() -> anyhow::Result<()> {
let findings_code = 200;
// ── 1) extraction ENABLED -- secret should be found ─────────────────────────
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
tar_gz.to_str().unwrap(),
@ -43,7 +43,7 @@ fn smoke_scan_tar_gz_archive() -> anyhow::Result<()> {
.stdout(predicates::str::contains(github_pat));
// ── 2) extraction DISABLED -- secret *not* found ────────────────────────────
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
tar_gz.to_str().unwrap(),

View file

@ -3,6 +3,7 @@ use std::fs;
use assert_cmd::Command;
use predicates::prelude::*;
use tempfile::tempdir;
use clap::Parser;
const GH_PAT: &str = "ghp_1wuHFikBKQtCcH3EB2FBUkyn8krXhP2qLqPa";
@ -47,7 +48,7 @@ fn baseline_create_and_filter() -> anyhow::Result<()> {
let baseline = dir.path().join("baseline.yaml");
// Create baseline with manage flag
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
dir.path().to_str().unwrap(),
@ -72,7 +73,7 @@ fn baseline_create_and_filter() -> anyhow::Result<()> {
// Scanning with the baseline should suppress the existing finding and leave
// the baseline untouched.
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
dir.path().to_str().unwrap(),
@ -94,7 +95,7 @@ fn baseline_create_and_filter() -> anyhow::Result<()> {
assert_eq!(initial_baseline, baseline_after_scan, "baseline remains stable after reuse");
// Managing the baseline again should not churn entries or report the secret
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
dir.path().to_str().unwrap(),
@ -129,7 +130,7 @@ fn baseline_exclude_prunes_entries() -> anyhow::Result<()> {
let baseline = dir.path().join("baseline.yaml");
// Initial baseline includes the .git secret
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
dir.path().to_str().unwrap(),
@ -150,7 +151,7 @@ fn baseline_exclude_prunes_entries() -> anyhow::Result<()> {
assert!(content.contains(".git/secret.txt"));
// Rescan with exclusion, which should prune the .git entry
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
dir.path().to_str().unwrap(),

View file

@ -94,7 +94,7 @@ aws_secret_access_key = efnegoUp/WXc3XwlL77dXu1aKIICzvz+n+7Sz88i
)?;
// ── scan the repository by commit hash ───────────────────────────────────
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
repo_dir.to_str().unwrap(),
@ -112,7 +112,7 @@ aws_secret_access_key = efnegoUp/WXc3XwlL77dXu1aKIICzvz+n+7Sz88i
);
// ── scan only the diff between feature-1 and the merge base ─────────────
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
repo_dir.to_str().unwrap(),
@ -196,7 +196,7 @@ fn scan_specific_commit_reports_only_that_commit() -> Result<()> {
let c1_hex = commits[0].to_string(); // first commit (AWS only)
// Scan exactly the initial commit via --branch <commit>
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
repo_dir.to_str().unwrap(),
@ -225,7 +225,7 @@ fn scan_with_branch_root_includes_descendants() -> Result<()> {
let c1_hex = commits[0].to_string(); // start from first commit
// Using --branch-root should include the selected commit and remaining history up to HEAD
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
repo_dir.to_str().unwrap(),
@ -256,7 +256,7 @@ fn scan_branch_tip_with_branch_root_commit() -> Result<()> {
// Passing --branch-root-commit should implicitly enable inclusive scanning even
// without the legacy --branch-root flag when targeting a named branch tip.
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
repo_dir.to_str().unwrap(),

View file

@ -7,7 +7,7 @@ use predicates::prelude::*;
#[test]
fn check_rules() -> anyhow::Result<()> {
// ── run kingfisher ────────────────────────────────────────────────
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"rules",
"check",

View file

@ -3,7 +3,7 @@ use std::process::Command;
#[test]
fn smoke_scan_docker_image() -> anyhow::Result<()> {
let mut cmd = Command::cargo_bin("kingfisher")?;
let mut cmd = Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"));
let output = cmd
.args([
"scan",

View file

@ -14,7 +14,7 @@ fn exclude_pattern_hides_matches() -> anyhow::Result<()> {
fs::write(&py, format!("token = \"{}\"\n", SECRET))?;
fs::write(&txt, format!("token = \"{}\"\n", SECRET))?;
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
dir.path().to_str().unwrap(),
@ -41,7 +41,7 @@ fn exclude_git_directory_hides_matches() -> anyhow::Result<()> {
fs::write(git_dir.join("config"), format!("token = \"{}\"\n", SECRET))?;
fs::write(dir.path().join("bar.txt"), format!("token = \"{}\"\n", SECRET))?;
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
dir.path().to_str().unwrap(),

View file

@ -18,7 +18,7 @@ fn smoke_scan_filesystem_text_and_binary() -> anyhow::Result<()> {
fs::write(&bin_path, [0x89, 0x50, 0x4E, 0x47])?; // tiny PNG header
// ── run kingfisher ────────────────────────────────────────────────
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
dir.path().to_str().unwrap(),

View file

@ -31,7 +31,7 @@ fn smoke_scan_git_history() -> anyhow::Result<()> {
repo.commit(Some("HEAD"), &sig, &sig, "update", &tree2, &[&head])?;
// ── run kingfisher with git-history mode FULL ─────────────────────
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args([
"scan",
repo_dir.to_str().unwrap(),

View file

@ -3,7 +3,7 @@ use predicates::str::contains;
#[test]
fn scan_homebrew_github_no_findings() -> anyhow::Result<()> {
Command::cargo_bin("kingfisher")?
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
.args(["scan", "--git-url", "https://github.com/homebrew/.github", "--no-update-check"])
.assert()
.success()