diff --git a/CHANGELOG.md b/CHANGELOG.md index 1278533..416af87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to this project will be documented in this file. +## [v1.57.0] +- Added inline ignore directive detection to treat suppression tokens anywhere on surrounding lines, including multi-line handling +- Added a `--no-ignore` CLI flag to disable inline directives when you need every potential secret reported +- Added: `--compat-ignore-comments` to reuse existing inline directives from other scanners: NOSONAR, kics-scan ignore, gitleaks:allow and trufflehog:ignore + ## [v1.56.0] - Fixed tree-sitter scanning bug where passing --no-base64 caused errors to be printed when the file type couldn’t be determined diff --git a/Cargo.toml b/Cargo.toml index 37a2e32..852194d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ publish = false [package] name = "kingfisher" -version = "1.56.0" +version = "1.57.0" description = "MongoDB's blazingly fast and accurate secret scanning and validation tool" edition.workspace = true rust-version.workspace = true diff --git a/README.md b/README.md index 14faccf..08f2394 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ See ([docs/COMPARISON.md](docs/COMPARISON.md)) - [Notable Scan Options](#notable-scan-options) - [Understanding `--confidence`](#understanding---confidence) - [Ignore known false positives](#ignore-known-false-positives) + - [Inline ignore directives](#inline-ignore-directives) - [Finding Fingerprint](#finding-fingerprint) - [Rule Performance Profiling](#rule-performance-profiling) - [CLI Options](#cli-options) @@ -962,6 +963,8 @@ leaves the default unchanged. - `--manage-baseline`: Create or update the baseline file with current findings - `--skip-regex `: Ignore findings whose text matches this regex (repeatable) - `--skip-word `: Ignore findings containing this case-insensitive word (repeatable) +- `--compat-ignore-comments`: Honor inline directives from other scanners (treat `gitleaks:allow` and `trufflehog:ignore` like native suppressions) +- `--no-ignore`: Disable inline directives entirely so every match is reported ## Understanding `--confidence` The `--confidence` flag sets a minimum confidence threshold, not an exact match. @@ -972,7 +975,22 @@ The `--confidence` flag sets a minimum confidence threshold, not an exact match. ### Ignore known false positives -Use `--skip-regex` and `--skip-word` to suppress findings you know are benign. Both flags may be provided multiple times and are tested against the secret value **and** the full match context. +Use `--skip-regex` and `--skip-word` to suppress findings you know are benign. Both flags may be provided multiple times and are tested against the secret value **and** the full match context. + +### Inline ignore directives + +Add `kingfisher:ignore` (or `kingfisher:allow`) anywhere on the same line as a finding to silence it. Multi-line strings may also be ignored by placing the directive on the closing delimiter line, on the next logical line after the string, **or** on a comment immediately before the value: + +```python +# kingfisher:ignore +API_KEY = """ +line 1 +line 2 +""" +# kingfisher:ignore +``` + +Kingfisher searches the surrounding lines for these tokens without requiring language-specific comment markers, so directives work even in templated files or unusual syntaxes. To reuse existing inline directives from other scanners, pass `--compat-ignore-comments` to also accept `gitleaks:allow` and `trufflehog:ignore`. Use `--no-ignore` when you want to disable inline suppressions entirely. With `--skip-regex`, these should be Rust compatible regular expressions, which you can test out at [regex101](https://regex101.com) diff --git a/src/cli/commands/scan.rs b/src/cli/commands/scan.rs index 255417f..ad09f5e 100644 --- a/src/cli/commands/scan.rs +++ b/src/cli/commands/scan.rs @@ -118,6 +118,14 @@ pub struct ScanArgs { /// Skipwords to allow-list secret matches (case-insensitive, repeatable) #[arg(long = "skip-word", value_name = "WORD")] pub skip_word: Vec, + + /// Also recognise `gitleaks:allow` and `trufflehog:ignore` inline directives + #[arg(long = "compat-ignore-comments", default_value_t = false)] + pub compat_ignore_comments: bool, + + /// Disable inline ignore directives entirely + #[arg(long = "no-ignore", default_value_t = false)] + pub no_inline_ignore: bool, } /// Confidence levels for findings diff --git a/src/inline_ignore.rs b/src/inline_ignore.rs new file mode 100644 index 0000000..bfdd00a --- /dev/null +++ b/src/inline_ignore.rs @@ -0,0 +1,285 @@ +use crate::location::OffsetSpan; + +/// Configuration for inline ignore directives. +#[derive(Clone, Debug, Default)] +pub struct InlineIgnoreConfig { + tokens: Vec<&'static str>, +} + +impl InlineIgnoreConfig { + /// Create a new configuration. + /// + /// * `include_external_syntax` - when true, also recognise the comment + /// directives used by other scanners such as Gitleaks and Trufflehog. + pub fn new(include_external_syntax: bool) -> Self { + let mut tokens = vec!["kingfisher:ignore", "kingfisher:allow"]; + if include_external_syntax { + tokens.extend(["gitleaks:allow", "trufflehog:ignore"]); + } + Self { tokens } + } + + /// Return a configuration with inline ignores disabled. + pub fn disabled() -> Self { + Self { tokens: Vec::new() } + } + + #[inline] + fn has_tokens(&self) -> bool { + !self.tokens.is_empty() + } + + /// Returns `true` when the provided blob slice contains an inline ignore + /// directive that should suppress a finding for the given span. + pub fn should_ignore(&self, blob_bytes: &[u8], span: &OffsetSpan) -> bool { + if !self.has_tokens() { + return false; + } + + let (start_line_start, start_line_end) = line_bounds(blob_bytes, span.start); + if start_line_end > start_line_start { + let start_line = &blob_bytes[start_line_start..start_line_end]; + if line_has_directive(start_line, &self.tokens) { + return true; + } + } + + // Scan backwards to allow directives that appear before the start of a + // multi-line string or value. This mirrors tools like Gitleaks where + // the ignore directive is often placed immediately above the secret. + let mut cursor = start_line_start; + while cursor > 0 { + let previous_index = cursor.saturating_sub(1); + let (prev_start, prev_end) = line_bounds(blob_bytes, previous_index); + if prev_end <= prev_start { + break; + } + + let prev_line = &blob_bytes[prev_start..prev_end]; + if line_has_directive(prev_line, &self.tokens) { + return true; + } + + if !should_skip_for_directive_search(prev_line) { + break; + } + + if prev_start == 0 { + break; + } + + cursor = prev_start; + } + + let end_index = if span.end == 0 { 0 } else { span.end - 1 }; + let (closing_line_start, closing_line_end) = + line_bounds(blob_bytes, end_index.min(blob_bytes.len())); + if closing_line_end > closing_line_start + && (closing_line_start != start_line_start || closing_line_end != start_line_end) + { + let closing_line = &blob_bytes[closing_line_start..closing_line_end]; + if line_has_directive(closing_line, &self.tokens) { + return true; + } + } + + // Also consider lines after the match so that multi-line strings can be + // ignored when the directive appears after the closing delimiter (a + // common pattern in languages like Python). + let mut cursor = closing_line_end; + while cursor < blob_bytes.len() { + if blob_bytes[cursor] == b'\n' { + cursor += 1; + continue; + } + + let (_, next_end) = line_bounds(blob_bytes, cursor); + if next_end <= cursor { + break; + } + + let next_line = &blob_bytes[cursor..next_end]; + if line_has_directive(next_line, &self.tokens) { + return true; + } + + if !should_skip_for_directive_search(next_line) { + break; + } + + cursor = next_end; + } + + false + } +} + +fn should_skip_for_directive_search(line: &[u8]) -> bool { + let trimmed = trim_ascii_whitespace(line); + if trimmed.is_empty() { + return true; + } + + if trimmed.iter().all(|&b| b == trimmed[0]) && matches!(trimmed[0], b'"' | b'\'' | b'`') { + return true; + } + + if ends_with_multiline_delimiter(trimmed) { + return true; + } + + false +} + +fn ends_with_multiline_delimiter(trimmed: &[u8]) -> bool { + if trimmed.len() < 3 { + return false; + } + + let last = *trimmed.last().unwrap(); + if !matches!(last, b'"' | b'\'' | b'`') { + return false; + } + + let count = trimmed.iter().rev().take_while(|&&ch| ch == last).count(); + + count >= 3 +} + +fn trim_ascii_whitespace(line: &[u8]) -> &[u8] { + let mut start = 0; + while start < line.len() && line[start].is_ascii_whitespace() { + start += 1; + } + + let mut end = line.len(); + while end > start && line[end - 1].is_ascii_whitespace() { + end -= 1; + } + + &line[start..end] +} + +fn line_bounds(bytes: &[u8], index: usize) -> (usize, usize) { + if bytes.is_empty() { + return (0, 0); + } + let mut start = index.min(bytes.len()); + while start > 0 && bytes[start - 1] != b'\n' { + start -= 1; + } + let mut end = index.min(bytes.len()); + while end < bytes.len() && bytes[end] != b'\n' { + end += 1; + } + (start, end) +} + +fn line_has_directive(line: &[u8], tokens: &[&'static str]) -> bool { + if line.is_empty() { + return false; + } + + let mut lowercase = line.to_vec(); + lowercase.iter_mut().for_each(|b| *b = b.to_ascii_lowercase()); + + tokens.iter().any(|token| memchr::memmem::find(&lowercase, token.as_bytes()).is_some()) +} + +#[cfg(test)] +mod tests { + use super::{ + line_bounds, line_has_directive, should_skip_for_directive_search, trim_ascii_whitespace, + InlineIgnoreConfig, + }; + use crate::location::OffsetSpan; + + #[test] + fn bounds_cover_expected_ranges() { + let data = b"one\ntwo\nthree"; + assert_eq!(line_bounds(data, 0), (0, 3)); + assert_eq!(line_bounds(data, 4), (4, 7)); + assert_eq!(line_bounds(data, data.len()), (8, 13)); + } + + #[test] + fn detects_directives_in_lines() { + let tokens = ["kingfisher:ignore", "kingfisher:allow"]; + assert!(line_has_directive(b"secret # kingfisher:ignore", &tokens)); + assert!(line_has_directive(b"kingfisher:allow before value", &tokens)); + assert!(line_has_directive(b"value // TruffleHog:Ignore", &["trufflehog:ignore"])); + assert!(!line_has_directive(b"secret", &tokens)); + } + + #[test] + fn respects_multiline_block_comment_prefix() { + let tokens = ["kingfisher:ignore"]; + assert!(line_has_directive(b" * kingfisher:ignore", &tokens)); + } + + #[test] + fn ignores_multi_line_string_with_trailing_comment() { + let blob = b"let secret = \"\"\"\nline1\nline2\n\"\"\"\n# kingfisher:ignore\n"; + let matched = b"line1\nline2\n"; + let start = blob + .windows(matched.len()) + .position(|window| window == matched) + .expect("match bytes present"); + let span = OffsetSpan::from_range(start..start + matched.len()); + let config = InlineIgnoreConfig::new(false); + assert!(config.should_ignore(blob, &span)); + } + + #[test] + fn ignores_multiline_without_trailing_newline() { + let blob = b"let secret = \"\"\"\nline1\nline2\n\"\"\"\n# kingfisher:ignore\n"; + let matched = b"line1\nline2"; + let start = blob + .windows(matched.len()) + .position(|window| window == matched) + .expect("match bytes present"); + let span = OffsetSpan::from_range(start..start + matched.len()); + let config = InlineIgnoreConfig::new(false); + assert!(config.should_ignore(blob, &span)); + } + + #[test] + fn ignores_multiline_with_directive_before_secret() { + let blob = b"// kingfisher:ignore\nlet secret = \"\"\"\nline1\nline2\n\"\"\"\n"; + let matched = b"line1\nline2\n"; + let start = blob + .windows(matched.len()) + .position(|window| window == matched) + .expect("match bytes present"); + let span = OffsetSpan::from_range(start..start + matched.len()); + let config = InlineIgnoreConfig::new(false); + assert!(config.should_ignore(blob, &span)); + } + + #[test] + fn trim_ascii_whitespace_returns_inner_slice() { + assert_eq!(trim_ascii_whitespace(b" abc "), b"abc"); + assert!(trim_ascii_whitespace(b" ").is_empty()); + } + + #[test] + fn skips_lines_with_only_delimiters() { + assert!(should_skip_for_directive_search(b"\"\"\"")); + assert!(should_skip_for_directive_search(b" \"\"\" ")); + assert!(should_skip_for_directive_search(b"let secret = \"\"\"")); + assert!(!should_skip_for_directive_search(b"value")); + } + + #[test] + fn disabled_config_never_ignores() { + let blob = b"let secret = 'value' # kingfisher:ignore"; + let matched = b"value"; + let start = blob + .windows(matched.len()) + .position(|window| window == matched) + .expect("match bytes present"); + let span = OffsetSpan::from_range(start..start + matched.len()); + let config = InlineIgnoreConfig::disabled(); + assert!(!config.should_ignore(blob, &span)); + } +} diff --git a/src/lib.rs b/src/lib.rs index 3ceed02..9fc8106 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ pub mod git_url; pub mod gitea; pub mod github; pub mod gitlab; +pub mod inline_ignore; pub mod jira; pub mod liquid_filters; pub mod location; diff --git a/src/main.rs b/src/main.rs index b6bb1fd..aa052cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -437,6 +437,8 @@ fn create_default_scan_args() -> cli::commands::scan::ScanArgs { skip_word: Vec::new(), output_args: OutputArgs { output: None, format: ReportOutputFormat::Pretty }, no_base64: false, + compat_ignore_comments: false, + no_inline_ignore: false, } } /// Run the rules check command diff --git a/src/matcher.rs b/src/matcher.rs index 102820b..c880f61 100644 --- a/src/matcher.rs +++ b/src/matcher.rs @@ -23,6 +23,7 @@ use xxhash_rust::xxh3::xxh3_64; use crate::{ blob::{Blob, BlobId, BlobIdMap}, entropy::calculate_shannon_entropy, + inline_ignore::InlineIgnoreConfig, location::{Location, LocationMapping, OffsetSpan, SourcePoint, SourceSpan}, origin::OriginSet, parser, @@ -199,6 +200,9 @@ pub struct Matcher<'a> { /// Rule profiler for measuring performance of individual rules profiler: Option>, + + /// Configuration that controls inline ignore directives + inline_ignore_config: InlineIgnoreConfig, } /// This `Drop` implementation updates the `global_stats` with the local stats impl<'a> Drop for Matcher<'a> { @@ -226,6 +230,8 @@ impl<'a> Matcher<'a> { global_stats: Option<&'a Mutex>, enable_profiling: bool, shared_profiler: Option>, + include_external_ignore_syntax: bool, + disable_inline_ignores: bool, ) -> Result { // Changed: removed `with_capacity(16384)` so we don't pre-allocate a large Vec let raw_matches_scratch = Vec::new(); @@ -247,6 +253,11 @@ impl<'a> Matcher<'a> { seen_blobs, user_data, profiler, + inline_ignore_config: if disable_inline_ignores { + InlineIgnoreConfig::disabled() + } else { + InlineIgnoreConfig::new(include_external_ignore_syntax) + }, }) } @@ -403,6 +414,7 @@ impl<'a> Matcher<'a> { redact, &filename, self.profiler.as_ref(), + &self.inline_ignore_config, ); } // If tree-sitter produced base64-decoded matches, try them against all rules @@ -427,6 +439,7 @@ impl<'a> Matcher<'a> { redact, &filename, self.profiler.as_ref(), + &self.inline_ignore_config, ); } } @@ -457,6 +470,7 @@ impl<'a> Matcher<'a> { redact, &filename, self.profiler.as_ref(), + &self.inline_ignore_config, ); } if depth + 1 < MAX_B64_DEPTH { @@ -560,6 +574,7 @@ fn filter_match<'b>( redact: bool, filename: &str, profiler: Option<&Arc>, + inline_ignore_config: &InlineIgnoreConfig, ) { let mut timer = profiler.map(|p| RuleTimer::new(p, rule.id(), rule.name(), &rule.syntax.pattern, filename)); @@ -590,6 +605,10 @@ fn filter_match<'b>( let matching_input_offset_span = OffsetSpan::from_range( (start + matching_input.start())..(start + matching_input.end()), ); + if inline_ignore_config.should_ignore(blob_bytes, &matching_input_offset_span) { + debug!("Skipping match due to inline ignore directive"); + continue; + } let match_key = compute_match_key( matching_input.as_bytes(), rule.id().as_bytes(), @@ -961,7 +980,7 @@ pub fn compute_finding_fingerprint( // ------------------------------------------------------------------------------------------------- #[cfg(test)] mod test { - use std::collections::BTreeMap; + use std::{collections::BTreeMap, path::PathBuf}; use pretty_assertions::assert_eq; // --------------------------------------------------------------------- @@ -970,7 +989,11 @@ mod test { use proptest::prelude::*; use super::*; - use crate::rules::rule::{DependsOnRule, HttpRequest, HttpValidation, RuleSyntax, Validation}; + use crate::{ + blob::{Blob, BlobIdMap}, + origin::{Origin, OriginSet}, + rules::rule::{DependsOnRule, HttpRequest, HttpValidation, RuleSyntax, Validation}, + }; proptest! { #[test] @@ -1009,7 +1032,17 @@ mod test { let rules_db = RulesDatabase::from_rules(vec![rule]).unwrap(); let seen = BlobIdMap::new(); let scanner_pool = Arc::new(ScannerPool::new(Arc::new(rules_db.vsdb.clone()))); - let mut m = Matcher::new(&rules_db, scanner_pool, &seen, None, false, None).unwrap(); + let mut m = Matcher::new( + &rules_db, + scanner_pool, + &seen, + None, + false, + None, + false, + false, + ) + .unwrap(); // ── run the scan ────────────────────────────────────────────── m.scan_bytes_raw(&noise, "buf").unwrap(); @@ -1080,6 +1113,8 @@ mod test { None, enable_rule_profiling, None, // Pass the shared profiler + false, + false, )?; matcher.scan_bytes_raw(input.as_bytes(), "fname")?; assert_eq!( @@ -1167,7 +1202,7 @@ mod test { let rules_db = RulesDatabase::from_rules(vec![rule])?; let seen = BlobIdMap::new(); let scanner_pool = Arc::new(ScannerPool::new(Arc::new(rules_db.vsdb.clone()))); - let mut m = Matcher::new(&rules_db, scanner_pool, &seen, None, false, None)?; + let mut m = Matcher::new(&rules_db, scanner_pool, &seen, None, false, None, false, false)?; let buf = b"dup dup"; // two literal hits, same rule @@ -1184,4 +1219,119 @@ mod test { assert_eq!(second_len, 2); Ok(()) } + + #[test] + fn inline_comment_skips_match() -> Result<()> { + let rule = Rule::new(RuleSyntax { + id: "inline.ignore".into(), + name: "inline".into(), + pattern: "secret_token".into(), + confidence: crate::rules::rule::Confidence::Low, + min_entropy: 0.0, + visible: true, + examples: vec![], + negative_examples: vec![], + references: vec![], + validation: None::, + depends_on_rule: vec![], + }); + let rules_db = RulesDatabase::from_rules(vec![rule])?; + let seen = BlobIdMap::new(); + let scanner_pool = Arc::new(ScannerPool::new(Arc::new(rules_db.vsdb.clone()))); + let mut matcher = + Matcher::new(&rules_db, scanner_pool, &seen, None, false, None, false, false)?; + + let blob = Blob::from_bytes(b"let key = \"secret_token\" # kingfisher:ignore".to_vec()); + let origin = OriginSet::from(Origin::from_file(PathBuf::from("inline.txt"))); + + match matcher.scan_blob(&blob, &origin, None, false, false, false)? { + ScanResult::New(matches) => assert!(matches.is_empty()), + _ => panic!("unexpected scan result"), + } + + Ok(()) + } + + #[test] + fn inline_comment_after_multiline_secret_skips_match() -> Result<()> { + let rule = Rule::new(RuleSyntax { + id: "inline.multiline".into(), + name: "inline multiline".into(), + pattern: "line1\\s+line2".into(), + confidence: crate::rules::rule::Confidence::Low, + min_entropy: 0.0, + visible: true, + examples: vec![], + negative_examples: vec![], + references: vec![], + validation: None::, + depends_on_rule: vec![], + }); + let rules_db = RulesDatabase::from_rules(vec![rule])?; + let seen = BlobIdMap::new(); + let scanner_pool = Arc::new(ScannerPool::new(Arc::new(rules_db.vsdb.clone()))); + let mut matcher = + Matcher::new(&rules_db, scanner_pool, &seen, None, false, None, false, false)?; + + let blob = Blob::from_bytes( + br#"let data = """ +line1 +line2 +""" +# kingfisher:ignore +"# + .to_vec(), + ); + let origin = OriginSet::from(Origin::from_file(PathBuf::from("multiline.txt"))); + + match matcher.scan_blob(&blob, &origin, None, false, false, false)? { + ScanResult::New(matches) => assert!(matches.is_empty()), + _ => panic!("unexpected scan result"), + } + + Ok(()) + } + + #[test] + fn compat_flag_controls_external_directives() -> Result<()> { + let rule = Rule::new(RuleSyntax { + id: "inline.compat".into(), + name: "inline compat".into(), + pattern: "supersecret123".into(), + confidence: crate::rules::rule::Confidence::Low, + min_entropy: 0.0, + visible: true, + examples: vec![], + negative_examples: vec![], + references: vec![], + validation: None::, + depends_on_rule: vec![], + }); + let rules_db = RulesDatabase::from_rules(vec![rule])?; + + let blob = Blob::from_bytes(b"token = \"supersecret123\" # gitleaks:allow".to_vec()); + let origin = OriginSet::from(Origin::from_file(PathBuf::from("compat.txt"))); + + let seen = BlobIdMap::new(); + let scanner_pool = Arc::new(ScannerPool::new(Arc::new(rules_db.vsdb.clone()))); + let mut matcher = + Matcher::new(&rules_db, scanner_pool, &seen, None, false, None, false, false)?; + let matches_without_compat = + match matcher.scan_blob(&blob, &origin, None, false, false, false)? { + ScanResult::New(matches) => matches.len(), + _ => panic!("unexpected scan result"), + }; + assert_eq!(matches_without_compat, 1, "directive should be ignored without compat flag"); + + let seen = BlobIdMap::new(); + let scanner_pool = Arc::new(ScannerPool::new(Arc::new(rules_db.vsdb.clone()))); + let mut matcher = + Matcher::new(&rules_db, scanner_pool, &seen, None, false, None, true, false)?; + match matcher.scan_blob(&blob, &origin, None, false, false, false)? { + ScanResult::New(matches) => assert!(matches.is_empty()), + _ => panic!("unexpected scan result"), + } + + Ok(()) + } } diff --git a/src/reporter.rs b/src/reporter.rs index 73bc541..b03bdc6 100644 --- a/src/reporter.rs +++ b/src/reporter.rs @@ -863,6 +863,8 @@ mod tests { manage_baseline: false, skip_regex: Vec::new(), skip_word: Vec::new(), + compat_ignore_comments: false, + no_inline_ignore: false, }; let record = reporter.build_finding_record(&report_match, &scan_args); diff --git a/src/reporter/json_format.rs b/src/reporter/json_format.rs index 8b4f59c..0a14361 100644 --- a/src/reporter/json_format.rs +++ b/src/reporter/json_format.rs @@ -163,6 +163,8 @@ mod tests { skip_regex: Vec::new(), skip_word: Vec::new(), no_base64: false, + compat_ignore_comments: false, + no_inline_ignore: false, } } diff --git a/src/scanner/enumerate.rs b/src/scanner/enumerate.rs index df56427..24f92fb 100644 --- a/src/scanner/enumerate.rs +++ b/src/scanner/enumerate.rs @@ -144,6 +144,8 @@ pub fn enumerate_filesystem_inputs( Some(&matcher_stats), enable_profiling, Some(shared_profiler), + args.compat_ignore_comments, + args.no_inline_ignore, )?; let blob_processor_init_time = Mutex::new(t1.elapsed()); let make_blob_processor = || -> BlobProcessor { diff --git a/src/scanner/repos.rs b/src/scanner/repos.rs index eb4ad10..3f0bc16 100644 --- a/src/scanner/repos.rs +++ b/src/scanner/repos.rs @@ -622,6 +622,8 @@ pub async fn fetch_s3_objects( Some(matcher_stats), enable_profiling, Some(shared_profiler.clone()), + args.compat_ignore_comments, + args.no_inline_ignore, )?; let mut processor = BlobProcessor { matcher }; diff --git a/tests/int_allowlist.rs b/tests/int_allowlist.rs index 72bd950..c94b4b0 100644 --- a/tests/int_allowlist.rs +++ b/tests/int_allowlist.rs @@ -133,6 +133,8 @@ fn run_skiplist(skip_regex: Vec, skip_skipword: Vec) -> Result Result<()> { skip_regex: Vec::new(), skip_word: Vec::new(), no_base64: false, + compat_ignore_comments: false, + no_inline_ignore: false, }; let global_args = GlobalArgs { diff --git a/tests/int_dedup.rs b/tests/int_dedup.rs index cd83a7f..f7ac9c4 100644 --- a/tests/int_dedup.rs +++ b/tests/int_dedup.rs @@ -152,6 +152,8 @@ rules: skip_regex: Vec::new(), skip_word: Vec::new(), no_base64: false, + compat_ignore_comments: false, + no_inline_ignore: false, }; let global_args = GlobalArgs { diff --git a/tests/int_github.rs b/tests/int_github.rs index 06c67a7..3460863 100644 --- a/tests/int_github.rs +++ b/tests/int_github.rs @@ -139,6 +139,8 @@ fn test_github_remote_scan() -> Result<()> { skip_regex: Vec::new(), skip_word: Vec::new(), no_base64: false, + compat_ignore_comments: false, + no_inline_ignore: false, }; // Create global arguments let global_args = GlobalArgs { diff --git a/tests/int_gitlab.rs b/tests/int_gitlab.rs index e55655a..37bb856 100644 --- a/tests/int_gitlab.rs +++ b/tests/int_gitlab.rs @@ -137,6 +137,8 @@ fn test_gitlab_remote_scan() -> Result<()> { skip_regex: Vec::new(), skip_word: Vec::new(), no_base64: false, + compat_ignore_comments: false, + no_inline_ignore: false, }; let global_args = GlobalArgs { @@ -272,6 +274,8 @@ fn test_gitlab_remote_scan_no_history() -> Result<()> { skip_regex: Vec::new(), skip_word: Vec::new(), no_base64: false, + compat_ignore_comments: false, + no_inline_ignore: false, }; let global_args = GlobalArgs { diff --git a/tests/int_redact.rs b/tests/int_redact.rs index 48247af..6772af0 100644 --- a/tests/int_redact.rs +++ b/tests/int_redact.rs @@ -116,6 +116,8 @@ async fn test_redact_hashes_finding_values() -> Result<()> { skip_regex: Vec::new(), skip_word: Vec::new(), no_base64: false, + compat_ignore_comments: false, + no_inline_ignore: false, }; let global_args = GlobalArgs { diff --git a/tests/int_slack.rs b/tests/int_slack.rs index 2575a3c..3de13e4 100644 --- a/tests/int_slack.rs +++ b/tests/int_slack.rs @@ -123,6 +123,8 @@ impl TestContext { skip_regex: Vec::new(), skip_word: Vec::new(), no_base64: false, + compat_ignore_comments: false, + no_inline_ignore: false, }; let loaded = RuleLoader::from_rule_specifiers(&scan_args.rules).load(&scan_args)?; @@ -246,6 +248,8 @@ async fn test_scan_slack_messages() -> Result<()> { skip_regex: Vec::new(), skip_word: Vec::new(), no_base64: false, + compat_ignore_comments: false, + no_inline_ignore: false, }; let global_args = GlobalArgs { diff --git a/tests/int_validation_cache.rs b/tests/int_validation_cache.rs index ea1c809..c6ff0f5 100644 --- a/tests/int_validation_cache.rs +++ b/tests/int_validation_cache.rs @@ -195,6 +195,8 @@ async fn test_validation_cache_and_depvars() -> Result<()> { skip_regex: Vec::new(), skip_word: Vec::new(), no_base64: false, + compat_ignore_comments: false, + no_inline_ignore: false, }; /* --------------------------------------------------------- * diff --git a/tests/int_vulnerable_files.rs b/tests/int_vulnerable_files.rs index b87d721..79cbb26 100644 --- a/tests/int_vulnerable_files.rs +++ b/tests/int_vulnerable_files.rs @@ -138,6 +138,8 @@ impl TestContext { skip_regex: Vec::new(), skip_word: Vec::new(), no_base64: false, + compat_ignore_comments: false, + no_inline_ignore: false, }; let loaded = RuleLoader::from_rule_specifiers(&scan_args.rules) @@ -248,6 +250,8 @@ impl TestContext { skip_regex: Vec::new(), skip_word: Vec::new(), no_base64: false, + compat_ignore_comments: false, + no_inline_ignore: false, }; let global_args = GlobalArgs {