forked from mirrors/kingfisher
176 lines
5 KiB
Rust
176 lines
5 KiB
Rust
use std::fs;
|
|
|
|
use assert_cmd::Command;
|
|
use predicates::prelude::*;
|
|
use tempfile::tempdir;
|
|
use clap::Parser;
|
|
|
|
const GH_PAT: &str = "ghp_1wuHFikBKQtCcH3EB2FBUkyn8krXhP2qLqPa";
|
|
|
|
#[test]
|
|
fn manage_baseline_enables_no_dedup() -> anyhow::Result<()> {
|
|
use kingfisher::cli::{
|
|
commands::scan::ScanOperation,
|
|
global::{Command, CommandLineArgs},
|
|
};
|
|
|
|
let dir = tempdir()?;
|
|
|
|
let args = CommandLineArgs::try_parse_from([
|
|
"kingfisher",
|
|
"scan",
|
|
dir.path().to_str().unwrap(),
|
|
"--manage-baseline",
|
|
"--no-update-check",
|
|
])?;
|
|
|
|
let command = match args.command {
|
|
Command::Scan(scan_args) => scan_args,
|
|
other => panic!("unexpected command parsed: {:?}", other),
|
|
};
|
|
|
|
let scan_args = match command.into_operation()? {
|
|
ScanOperation::Scan(scan_args) => scan_args,
|
|
op => panic!("expected scan operation, got {:?}", op),
|
|
};
|
|
|
|
assert!(scan_args.manage_baseline);
|
|
assert!(scan_args.no_dedup);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn baseline_create_and_filter() -> anyhow::Result<()> {
|
|
let dir = tempdir()?;
|
|
let file = dir.path().join("leak.txt");
|
|
fs::write(&file, format!("token = \"{}\"\n", GH_PAT))?;
|
|
let baseline = dir.path().join("baseline.yaml");
|
|
|
|
// Create baseline with manage flag
|
|
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
|
|
.args([
|
|
"scan",
|
|
dir.path().to_str().unwrap(),
|
|
"--no-binary",
|
|
"--confidence=low",
|
|
"--no-validate",
|
|
"--format",
|
|
"json",
|
|
"--manage-baseline",
|
|
"--baseline-file",
|
|
baseline.to_str().unwrap(),
|
|
"--git-history=none",
|
|
"--no-update-check",
|
|
])
|
|
.assert()
|
|
.code(200)
|
|
.stdout(predicate::str::contains(GH_PAT));
|
|
|
|
assert!(baseline.exists(), "baseline file created");
|
|
|
|
let initial_baseline = fs::read_to_string(&baseline)?;
|
|
|
|
// Scanning with the baseline should suppress the existing finding and leave
|
|
// the baseline untouched.
|
|
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
|
|
.args([
|
|
"scan",
|
|
dir.path().to_str().unwrap(),
|
|
"--no-binary",
|
|
"--confidence=low",
|
|
"--no-validate",
|
|
"--format",
|
|
"json",
|
|
"--baseline-file",
|
|
baseline.to_str().unwrap(),
|
|
"--git-history=none",
|
|
"--no-update-check",
|
|
])
|
|
.assert()
|
|
.code(0)
|
|
.stdout(predicate::str::contains(GH_PAT).not());
|
|
|
|
let baseline_after_scan = fs::read_to_string(&baseline)?;
|
|
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::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
|
|
.args([
|
|
"scan",
|
|
dir.path().to_str().unwrap(),
|
|
"--no-binary",
|
|
"--confidence=low",
|
|
"--no-validate",
|
|
"--format",
|
|
"json",
|
|
"--manage-baseline",
|
|
"--baseline-file",
|
|
baseline.to_str().unwrap(),
|
|
"--git-history=none",
|
|
"--no-update-check",
|
|
])
|
|
.assert()
|
|
.code(0)
|
|
.stdout(predicate::str::contains(GH_PAT).not());
|
|
|
|
let rerun_baseline = fs::read_to_string(&baseline)?;
|
|
assert_eq!(initial_baseline, rerun_baseline, "baseline remains stable");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn baseline_exclude_prunes_entries() -> anyhow::Result<()> {
|
|
let dir = tempdir()?;
|
|
let git_dir = dir.path().join(".git");
|
|
std::fs::create_dir(&git_dir)?;
|
|
let secret_file = git_dir.join("secret.txt");
|
|
fs::write(&secret_file, format!("token = \"{}\"\n", GH_PAT))?;
|
|
let baseline = dir.path().join("baseline.yaml");
|
|
|
|
// Initial baseline includes the .git secret
|
|
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
|
|
.args([
|
|
"scan",
|
|
dir.path().to_str().unwrap(),
|
|
"--no-binary",
|
|
"--confidence=low",
|
|
"--no-validate",
|
|
"--format",
|
|
"json",
|
|
"--manage-baseline",
|
|
"--baseline-file",
|
|
baseline.to_str().unwrap(),
|
|
"--no-update-check",
|
|
])
|
|
.assert()
|
|
.code(200);
|
|
|
|
let content = fs::read_to_string(&baseline)?;
|
|
assert!(content.contains(".git/secret.txt"));
|
|
|
|
// Rescan with exclusion, which should prune the .git entry
|
|
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
|
|
.args([
|
|
"scan",
|
|
dir.path().to_str().unwrap(),
|
|
"--no-binary",
|
|
"--confidence=low",
|
|
"--no-validate",
|
|
"--format",
|
|
"json",
|
|
"--manage-baseline",
|
|
"--baseline-file",
|
|
baseline.to_str().unwrap(),
|
|
"--exclude=.git",
|
|
"--no-update-check",
|
|
])
|
|
.assert()
|
|
.code(0);
|
|
|
|
let content = fs::read_to_string(&baseline)?;
|
|
assert!(!content.contains(".git/secret.txt"));
|
|
|
|
Ok(())
|
|
}
|