Skip to content

Commit 9e53d52

Browse files
bumahkib7claude
andcommitted
feat: exclude test files by default across all languages
- Test files are now excluded from scans by default - Add --include-tests flag to opt-in to scanning test files - Deprecate --skip-tests (tests excluded by default now) - Unify test patterns: security command now uses same 70+ patterns as scan - Patterns cover: JS/TS, Python, Go, Rust, Java, Kotlin test conventions BREAKING CHANGE: Tests are now excluded by default. Use --include-tests to scan them. Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent ade7564 commit 9e53d52

File tree

4 files changed

+58
-32
lines changed

4 files changed

+58
-32
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased]
9+
10+
### Changed
11+
- **Test Files Excluded by Default**: Tests are now excluded from scans by default across all languages
12+
- Use `--include-tests` to opt-in to scanning test files
13+
- Unified test pattern detection: 70+ patterns for JS/TS, Python, Go, Rust, Java, Kotlin
14+
- `--skip-tests` flag deprecated (tests excluded by default)
15+
- `security` command now uses same comprehensive patterns as `scan` command
16+
917
## [0.15.1] - 2026-02-02
1018

1119
### Fixed

crates/cli/src/commands/scan.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,12 @@ pub struct ScanArgs {
5555
pub diff_base: String,
5656
/// Read unified diff from stdin instead of running git diff
5757
pub diff_stdin: bool,
58-
/// Skip test files and directories (security rules still apply)
59-
pub skip_tests: bool,
58+
/// Include test files in analysis (tests excluded by default)
59+
pub include_tests: bool,
6060
/// Skip ALL findings in tests including security rules
6161
pub skip_tests_all: bool,
62+
/// [DEPRECATED] Tests are now excluded by default
63+
pub skip_tests: bool,
6264
/// Maximum findings to display
6365
pub limit: usize,
6466
/// Show all findings without limit
@@ -464,14 +466,14 @@ fn apply_mode_defaults(args: &ScanArgs) -> EffectiveScanSettings {
464466
}
465467
Some(ScanMode::Local) | None => {
466468
// Local mode: use all explicit settings
467-
// --skip-tests or --skip-tests-all enables default test/example suppressions
469+
// Tests are excluded by default; use --include-tests to scan them
468470
EffectiveScanSettings {
469471
format: args.format,
470472
severity: args.severity,
471473
changed_only: args.changed_only,
472474
baseline_mode: args.baseline_mode,
473475
timing: args.timing,
474-
use_default_presets: args.skip_tests || args.skip_tests_all,
476+
use_default_presets: !args.include_tests,
475477
skip_security_in_tests: args.skip_tests_all,
476478
include_suppressed: args.include_suppressed,
477479
diff: args.diff,
@@ -1557,6 +1559,7 @@ mod tests {
15571559
diff: false,
15581560
diff_base: "origin/main".to_string(),
15591561
diff_stdin: false,
1562+
include_tests: false,
15601563
skip_tests: false,
15611564
skip_tests_all: false,
15621565
limit: 20,
@@ -1603,7 +1606,20 @@ mod tests {
16031606
assert!(effective.changed_only);
16041607
assert!(effective.baseline_mode);
16051608
assert!(effective.timing);
1606-
assert!(!effective.use_default_presets); // Local mode doesn't use presets
1609+
assert!(effective.use_default_presets); // Tests excluded by default
1610+
}
1611+
1612+
#[test]
1613+
fn test_include_tests_disables_presets() {
1614+
let args = ScanArgs {
1615+
mode: Some(ScanMode::Local),
1616+
include_tests: true, // Opt-in to scan test files
1617+
..create_test_args()
1618+
};
1619+
1620+
let effective = apply_mode_defaults(&args);
1621+
1622+
assert!(!effective.use_default_presets); // Tests included when flag is set
16071623
}
16081624

16091625
#[test]

crates/cli/src/commands/security.rs

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,16 @@
1212
use anyhow::Result;
1313
use colored::Colorize;
1414
use rma_analyzer::providers::{AnalysisProvider, OsvProvider, RustSecProvider};
15-
use rma_common::{Finding, OsvEcosystem, OsvProviderConfig, RmaConfig, Severity};
15+
use rma_common::{
16+
Finding, OsvEcosystem, OsvProviderConfig, RmaConfig, Severity,
17+
DEFAULT_EXAMPLE_IGNORE_PATHS, DEFAULT_TEST_IGNORE_PATHS,
18+
};
1619
use rma_parser::ParserEngine;
1720
use serde::{Deserialize, Serialize};
1821
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
1922
use std::fs;
2023
use std::path::{Path, PathBuf};
2124

22-
/// Default patterns to exclude from code security scanning (test fixtures)
23-
pub const DEFAULT_SECURITY_EXCLUDES: &[&str] = &[
24-
"**/tests/**",
25-
"**/test/**",
26-
"**/fixtures/**",
27-
"**/__tests__/**",
28-
"**/*.test.*",
29-
"**/*.spec.*",
30-
"**/testdata/**",
31-
"**/test_*",
32-
"**/*_test.rs",
33-
"**/*_test.go",
34-
"**/*_test.py",
35-
];
36-
3725
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
3826
pub enum FailSeverity {
3927
None,
@@ -1270,7 +1258,11 @@ fn scan_code_security(args: &SecurityArgs, report: &mut SecurityReport) -> Resul
12701258

12711259
for parsed in &parsed_files {
12721260
// Check if file should be excluded (default excludes for tests/fixtures)
1273-
if !args.include_tests && matches_exclude_pattern(&parsed.path, DEFAULT_SECURITY_EXCLUDES) {
1261+
// Use the same comprehensive patterns as the scan command
1262+
if !args.include_tests
1263+
&& (matches_exclude_pattern(&parsed.path, DEFAULT_TEST_IGNORE_PATHS)
1264+
|| matches_exclude_pattern(&parsed.path, DEFAULT_EXAMPLE_IGNORE_PATHS))
1265+
{
12741266
files_excluded += 1;
12751267
continue;
12761268
}
@@ -2008,35 +2000,39 @@ mod tests {
20082000

20092001
#[test]
20102002
fn test_matches_exclude_pattern() {
2003+
// Test patterns should match test directories
20112004
assert!(matches_exclude_pattern(
20122005
Path::new("/project/src/tests/test_foo.rs"),
2013-
DEFAULT_SECURITY_EXCLUDES
2006+
DEFAULT_TEST_IGNORE_PATHS
20142007
));
20152008

2009+
// Example patterns should match fixtures
20162010
assert!(matches_exclude_pattern(
20172011
Path::new("/project/fixtures/secrets.json"),
2018-
DEFAULT_SECURITY_EXCLUDES
2012+
DEFAULT_EXAMPLE_IGNORE_PATHS
20192013
));
20202014

2015+
// Test patterns should match *.test.ts files
20212016
assert!(matches_exclude_pattern(
20222017
Path::new("/project/src/foo.test.ts"),
2023-
DEFAULT_SECURITY_EXCLUDES
2018+
DEFAULT_TEST_IGNORE_PATHS
20242019
));
20252020

2021+
// Test patterns should match __tests__ directories
20262022
assert!(matches_exclude_pattern(
20272023
Path::new("/project/__tests__/auth.spec.js"),
2028-
DEFAULT_SECURITY_EXCLUDES
2024+
DEFAULT_TEST_IGNORE_PATHS
20292025
));
20302026

20312027
// Should NOT match regular source files
20322028
assert!(!matches_exclude_pattern(
20332029
Path::new("/project/src/auth/login.rs"),
2034-
DEFAULT_SECURITY_EXCLUDES
2030+
DEFAULT_TEST_IGNORE_PATHS
20352031
));
20362032

20372033
assert!(!matches_exclude_pattern(
20382034
Path::new("/project/lib/security.py"),
2039-
DEFAULT_SECURITY_EXCLUDES
2035+
DEFAULT_TEST_IGNORE_PATHS
20402036
));
20412037
}
20422038

crates/cli/src/main.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,16 +181,20 @@ pub enum Commands {
181181
#[arg(long, requires = "diff")]
182182
diff_stdin: bool,
183183

184-
/// Skip test files and test directories (security rules still apply)
185-
/// Automatically excludes common test patterns: *_test.go, *.test.ts, test_*.py, src/test/**, etc.
184+
/// Include test files in analysis (tests are excluded by default)
185+
/// Use this flag to scan test files: *_test.go, *.test.ts, test_*.py, src/test/**, etc.
186186
#[arg(long)]
187-
skip_tests: bool,
187+
include_tests: bool,
188188

189189
/// Skip ALL findings in test files including security rules
190-
/// Use with caution - security vulnerabilities in tests can still be exploited
190+
/// By default, tests are excluded but security rules still apply if tests are included
191191
#[arg(long)]
192192
skip_tests_all: bool,
193193

194+
/// [DEPRECATED] Tests are now excluded by default. Use --include-tests to scan them.
195+
#[arg(long, hide = true)]
196+
skip_tests: bool,
197+
194198
/// Maximum findings to display (default: 20, use --all for unlimited)
195199
#[arg(long, default_value = "20")]
196200
limit: usize,
@@ -929,6 +933,7 @@ fn main() -> Result<()> {
929933
diff,
930934
diff_base,
931935
diff_stdin,
936+
include_tests,
932937
skip_tests,
933938
skip_tests_all,
934939
limit,
@@ -981,6 +986,7 @@ fn main() -> Result<()> {
981986
diff,
982987
diff_base,
983988
diff_stdin,
989+
include_tests,
984990
skip_tests,
985991
skip_tests_all,
986992
limit,

0 commit comments

Comments
 (0)