Skip to main content

xchecker_selectors/
lib.rs

1use globset::Glob;
2
3/// High-confidence secret file patterns that are always excluded from packet building.
4///
5/// These patterns target files that almost certainly contain secrets (private keys,
6/// environment files, certificates). They are enforced at multiple layers:
7/// 1. Default config selectors (this module)
8/// 2. Engine-level enforcement in `ContentSelector` (defense-in-depth)
9///
10/// # Patterns
11///
12/// - `.env` and `.env.*` - Environment variable files
13/// - `*.pem`, `*.pfx`, `*.p12`, `*.key`, `*.p8` - Certificate/key files
14/// - `id_rsa`, `id_ed25519` - SSH private keys
15/// - `.ssh/**` - SSH configuration directory
16/// - `.aws/**` - AWS credentials directory
17/// - `.kube/**` - Kubernetes config directory
18/// - `*.kdbx` - KeePass password databases
19/// - `secrets.yaml`, `secrets.yml` - Secrets configuration files
20pub const ALWAYS_EXCLUDE_PATTERNS: &[&str] = &[
21    "**/.env",
22    "**/.env.*",
23    "**/*.pem",
24    "**/id_rsa",
25    "**/id_ed25519",
26    "**/.ssh/**",
27    "**/*.pfx",
28    "**/*.p12",
29    "**/*.key",
30    "**/*.kdbx",
31    "**/.aws/**",
32    "**/.kube/**",
33    "**/*.p8",
34    "**/secrets.yaml",
35    "**/secrets.yml",
36];
37
38/// Content selection configuration
39#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
40pub struct Selectors {
41    pub include: Vec<String>,
42    pub exclude: Vec<String>,
43}
44
45impl Default for Selectors {
46    fn default() -> Self {
47        let mut exclude = vec![
48            "target/**".to_string(),
49            "node_modules/**".to_string(),
50            ".git/**".to_string(),
51            "**/.DS_Store".to_string(),
52        ];
53
54        // Add mandatory security exclusions
55        exclude.extend(ALWAYS_EXCLUDE_PATTERNS.iter().map(|s| (*s).to_string()));
56
57        Self {
58            include: vec![
59                "docs/**/SPEC*.md".to_string(),
60                "docs/**/ADR*.md".to_string(),
61                "README.md".to_string(),
62                "SCHEMASET.*".to_string(),
63                "**/Cargo.toml".to_string(),
64                "**/*.core.yaml".to_string(),
65            ],
66            exclude,
67        }
68    }
69}
70
71impl Selectors {
72    /// Validate glob patterns in selectors
73    pub fn validate(&self) -> Result<(), xchecker_utils::error::XCheckerError> {
74        // Validate glob patterns in selectors
75        for pattern in &self.include {
76            Glob::new(pattern).map_err(|e| {
77                xchecker_utils::error::XCheckerError::Config(
78                    xchecker_utils::error::ConfigError::InvalidValue {
79                        key: "selectors.include".to_string(),
80                        value: format!("Invalid glob pattern '{pattern}': {e}"),
81                    },
82                )
83            })?;
84        }
85
86        for pattern in &self.exclude {
87            Glob::new(pattern).map_err(|e| {
88                xchecker_utils::error::XCheckerError::Config(
89                    xchecker_utils::error::ConfigError::InvalidValue {
90                        key: "selectors.exclude".to_string(),
91                        value: format!("Invalid glob pattern '{pattern}': {e}"),
92                    },
93                )
94            })?;
95        }
96
97        Ok(())
98    }
99}