added '--fast' mode which sets maximum scan speed. Omits git commit context and will not base64 decode

This commit is contained in:
Mick Grove 2026-02-23 22:34:23 -07:00
commit aa29ee0e99
16 changed files with 34 additions and 0 deletions

View file

@ -3,6 +3,7 @@
All notable changes to this project will be documented in this file.
## [v1.85.0]
- Added `--fast` mode: sets `--commit-metadata=false` and `--no-base64` for maximum scan speed. Findings will omit Git commit context (author, date, commit hash) and will not include Base64-decoded secrets.
- SQLite database scanning: kingfisher now detects and extracts SQLite files (`.db`, `.sqlite`, `.sqlite3`, etc.), dumping each table as SQL text with named columns so secrets stored in database rows are scannable. Controlled by the existing `--extract-archives` flag.
- Python bytecode (.pyc) scanning: extracts string constants from compiled Python (`.pyc`, `.pyo`) files via marshal parsing so secrets embedded in bytecode are scannable. Controlled by `--extract-archives`.
- Performance: pipelined ODB enumeration — scanning now begins while blob OIDs are still being discovered, overlapping I/O with pattern matching.

View file

@ -312,6 +312,10 @@ kingfisher scan /path/to/code
# Scan without validation
kingfisher scan ~/src/myrepo --no-validate
# Fast mode: run as fast as possible by disabling Git commit metadata and Base64 decoding
# (findings omit commit context and Base64-encoded secrets)
kingfisher scan ~/src/myrepo --fast
# Display only secrets confirmed active by thirdparty APIs
kingfisher scan /path/to/repo --only-valid
@ -394,6 +398,10 @@ cat /path/to/file.py | kingfisher scan -
# Limit maximum file size scanned (default: 256 MB)
kingfisher scan /some/file --max-file-size 500
# Fast mode: equivalent to --commit-metadata=false --no-base64 for maximum speed
# No Git commit metadata (author, date, hash) or Base64 decoding in findings
kingfisher scan /path/to/repo --fast
# Scan using a rule family
kingfisher scan /path/to/repo --rule kingfisher.aws

View file

@ -151,6 +151,10 @@ pub struct ScanArgs {
#[arg(global = true, long, default_value_t = false)]
pub no_base64: bool,
/// Fast mode: equivalent to --commit-metadata=false --no-base64
#[arg(global = true, long, default_value_t = false)]
pub fast: bool,
/// Timeout for Git repository scanning in seconds
#[arg(global = true, long, default_value_t = 1800, value_name = "SECONDS")]
pub git_repo_timeout: u64,
@ -486,6 +490,11 @@ impl ScanCommandArgs {
self.scan_args.no_dedup = true;
}
if self.scan_args.fast {
self.scan_args.no_base64 = true;
self.scan_args.input_specifier_args.commit_metadata = false;
}
if self.scan_args.access_map && self.scan_args.no_validate {
bail!("--access-map cannot be used with --no-validate");
}

View file

@ -961,6 +961,7 @@ pub(crate) fn create_minimal_scan_args() -> crate::cli::commands::scan::ScanArgs
skip_aws_account_file: None,
output_args: OutputArgs { output: None, format: ReportOutputFormat::Pretty },
no_base64: false,
fast: false,
no_inline_ignore: false,
no_ignore_if_contains: false,
validation_timeout: 10,

View file

@ -577,6 +577,7 @@ fn create_default_scan_args() -> cli::commands::scan::ScanArgs {
skip_aws_account_file: None,
output_args: OutputArgs { output: None, format: ReportOutputFormat::Pretty },
no_base64: false,
fast: false,
no_inline_ignore: false,
no_ignore_if_contains: false,
validation_timeout: 10,

View file

@ -1781,6 +1781,7 @@ mod tests {
view_report: false,
redact: false,
no_base64: false,
fast: false,
git_repo_timeout: 1_800,
output_args: OutputArgs { output: None, format: ReportOutputFormat::Pretty },
baseline_file: None,

View file

@ -193,6 +193,7 @@ mod tests {
skip_aws_account: Vec::new(),
skip_aws_account_file: None,
no_base64: false,
fast: false,
no_inline_ignore: false,
no_ignore_if_contains: false,
validation_timeout: 10,

View file

@ -155,6 +155,7 @@ fn run_skiplist(skip_regex: Vec<String>, skip_skipword: Vec<String>) -> Result<u
skip_aws_account: Vec::new(),
skip_aws_account_file: None,
no_base64: false,
fast: false,
no_inline_ignore: false,
no_ignore_if_contains: false,
validation_retries: 1,

View file

@ -154,6 +154,7 @@ fn test_bitbucket_remote_scan() -> Result<()> {
skip_aws_account: Vec::new(),
skip_aws_account_file: None,
no_base64: false,
fast: false,
extra_ignore_comments: Vec::new(),
no_inline_ignore: false,
no_ignore_if_contains: false,

View file

@ -174,6 +174,7 @@ rules:
skip_aws_account: Vec::new(),
skip_aws_account_file: None,
no_base64: false,
fast: false,
extra_ignore_comments: Vec::new(),
no_inline_ignore: false,
no_ignore_if_contains: false,

View file

@ -161,6 +161,7 @@ fn test_github_remote_scan() -> Result<()> {
skip_aws_account: Vec::new(),
skip_aws_account_file: None,
no_base64: false,
fast: false,
extra_ignore_comments: Vec::new(),
no_inline_ignore: false,
no_ignore_if_contains: false,

View file

@ -160,6 +160,7 @@ fn test_gitlab_remote_scan() -> Result<()> {
skip_aws_account: Vec::new(),
skip_aws_account_file: None,
no_base64: false,
fast: false,
no_inline_ignore: false,
no_ignore_if_contains: false,
validation_retries: 1,
@ -325,6 +326,7 @@ fn test_gitlab_remote_scan_no_history() -> Result<()> {
skip_aws_account: Vec::new(),
skip_aws_account_file: None,
no_base64: false,
fast: false,
extra_ignore_comments: Vec::new(),
no_inline_ignore: false,
no_ignore_if_contains: false,

View file

@ -137,6 +137,7 @@ async fn test_redact_hashes_finding_values() -> Result<()> {
skip_aws_account: Vec::new(),
skip_aws_account_file: None,
no_base64: false,
fast: false,
extra_ignore_comments: Vec::new(),
no_inline_ignore: false,
no_ignore_if_contains: false,

View file

@ -143,6 +143,7 @@ impl TestContext {
skip_aws_account: Vec::new(),
skip_aws_account_file: None,
no_base64: false,
fast: false,
no_inline_ignore: false,
no_ignore_if_contains: false,
validation_retries: 1,
@ -294,6 +295,7 @@ async fn test_scan_slack_messages() -> Result<()> {
skip_aws_account: Vec::new(),
skip_aws_account_file: None,
no_base64: false,
fast: false,
extra_ignore_comments: Vec::new(),
no_inline_ignore: false,
no_ignore_if_contains: false,

View file

@ -217,6 +217,7 @@ async fn test_validation_cache_and_depvars() -> Result<()> {
skip_aws_account: Vec::new(),
skip_aws_account_file: None,
no_base64: false,
fast: false,
extra_ignore_comments: Vec::new(),
no_inline_ignore: false,
no_ignore_if_contains: false,

View file

@ -160,6 +160,7 @@ impl TestContext {
skip_aws_account: Vec::new(),
skip_aws_account_file: None,
no_base64: false,
fast: false,
extra_ignore_comments: Vec::new(),
no_inline_ignore: false,
no_ignore_if_contains: false,
@ -301,6 +302,7 @@ impl TestContext {
skip_aws_account: Vec::new(),
skip_aws_account_file: None,
no_base64: false,
fast: false,
no_inline_ignore: false,
no_ignore_if_contains: false,
validation_retries: 1,