keyhog_core/lib.rs
1//! Core types shared across all KeyHog crates.
2//!
3//! Defines the [`Source`] trait for pluggable input backends, [`DetectorSpec`]
4//! for TOML-based pattern definitions, [`RawMatch`] and [`VerifiedFinding`] for
5//! scanner output, [`DedupedMatch`] for grouped findings, and [`Reporter`] for
6//! structured result formatting.
7
8/// Credential/path allowlist parsing and matching.
9pub mod allowlist;
10/// ANSI-colored CLI startup banner with detector counts.
11pub mod banner;
12/// Configuration system for KeyHog scanning options.
13pub mod config;
14/// Secure credential storage and redaction.
15pub mod credential;
16mod dedup;
17/// Shared standard Base64 decode (wire / K8s), bounded for DoS safety.
18pub mod encoding;
19mod finding;
20/// Security hardening: memory zeroization and process isolation helpers.
21pub mod hardening;
22/// Structured reporting (JSON, SARIF, Text).
23pub mod report;
24/// Safe absolute-path resolution for external binaries.
25pub mod safe_bin;
26mod source;
27mod spec;
28use std::borrow::Cow;
29
30/// Global registry for sources and verifiers.
31pub mod registry;
32
33pub use allowlist::*;
34pub use config::*;
35pub use credential::{Credential, SensitiveString};
36pub use dedup::*;
37pub use finding::*;
38pub use report::*;
39pub use source::*;
40/// Auto-fix suggestion logic for SARIF output.
41pub mod auto_fix;
42/// Bayesian confidence calibration for detectors.
43pub mod calibration;
44/// Incremental scan state via BLAKE3 Merkle index.
45pub mod merkle_index;
46pub use spec::*;
47
48// Embedded detectors compiled into the binary at build time.
49// These are used when no external detectors directory is found.
50mod embedded {
51 include!(concat!(env!("OUT_DIR"), "/embedded_detectors.rs"));
52}
53
54/// Load detectors from embedded data (compiled into the binary).
55/// Returns detector TOML strings that can be parsed by the spec loader.
56pub fn embedded_detector_tomls() -> &'static [(&'static str, &'static str)] {
57 embedded::EMBEDDED_DETECTORS
58}
59
60/// Number of embedded detector specs (authoritative for banners and tests).
61#[inline]
62pub fn embedded_detector_count() -> usize {
63 embedded_detector_tomls().len()
64}
65
66/// Redact a sensitive credential string for safe display.
67pub fn redact(s: &str) -> Cow<'static, str> {
68 // ASCII fast path: byte indexing is valid (no UTF-8 boundary risk),
69 // skips the O(n) `chars().count()` walk plus two intermediate `String`
70 // allocations from `take(4).collect()` / `skip(n).collect()`. Most
71 // credentials are pure ASCII (provider keys, hashes, base64 tokens).
72 if s.is_ascii() {
73 if s.len() <= 8 {
74 return Cow::Borrowed("****");
75 }
76 let mut out = String::with_capacity(s.len().min(11));
77 out.push_str(&s[..4]);
78 out.push_str("...");
79 out.push_str(&s[s.len() - 4..]);
80 return Cow::Owned(out);
81 }
82 // UTF-8 path: char-count for grapheme correctness.
83 let char_count = s.chars().count();
84 if char_count <= 8 {
85 return Cow::Borrowed("****");
86 }
87 let first_four: String = s.chars().take(4).collect();
88 let last_four: String = s.chars().skip(char_count.saturating_sub(4)).collect();
89 Cow::Owned(format!("{first_four}...{last_four}"))
90}