1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! Source trait and chunk types: the abstraction for pluggable input backends.
use crateSensitiveString;
use Serialize;
use Error;
/// A scannable chunk of text with metadata about where it came from.
///
/// # Examples
///
/// ```rust
/// use keyhog_core::{Chunk, ChunkMetadata};
///
/// let chunk = Chunk {
/// data: "API_KEY=sk_live_example".into(),
/// metadata: ChunkMetadata {
/// source_type: "filesystem".into(),
/// path: Some("app.env".into()),
/// ..Default::default()
/// },
/// };
///
/// assert_eq!(chunk.metadata.path.as_deref(), Some("app.env"));
/// ```
/// Metadata that tracks the source location for a scanned chunk.
///
/// # Examples
///
/// ```rust
/// use keyhog_core::ChunkMetadata;
///
/// let metadata = ChunkMetadata {
/// source_type: "git-diff".into(),
/// path: Some("src/lib.rs".into()),
/// commit: Some("abc123".into()),
/// author: Some("Dev".into()),
/// date: Some("2026-03-26T00:00:00Z".into()),
/// ..Default::default()
/// };
///
/// assert_eq!(metadata.source_type, "git-diff");
/// ```
/// Produces chunks of text for the scanner to process.
/// Each implementation handles a different input source.
///
/// # Examples
///
/// ```rust
/// use keyhog_core::{Chunk, ChunkMetadata, Source, SourceError};
///
/// struct StaticSource;
///
/// impl Source for StaticSource {
/// fn name(&self) -> &str {
/// "static"
/// }
///
/// fn chunks(&self) -> Box<dyn Iterator<Item = Result<Chunk, SourceError>> + '_> {
/// Box::new(std::iter::once(Ok(Chunk {
/// data: "TOKEN=value".into(),
/// metadata: ChunkMetadata {
/// source_type: "static".into(),
/// ..Default::default()
/// },
/// })))
/// }
///
/// fn as_any(&self) -> &dyn std::any::Any {
/// self
/// }
/// }
///
/// let source = StaticSource;
/// assert_eq!(source.name(), "static");
/// ```
/// Errors returned by input sources while enumerating or reading content.
///
/// # Examples
///
/// ```rust
/// use keyhog_core::SourceError;
///
/// let error = SourceError::Other("pass a readable file or directory".into());
/// assert!(error.to_string().contains("Fix"));
/// ```