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
//! What:
//! Redacted structured findings shared by embedded and standalone scans.
//! Why:
//! A policy consumer must not recover candidate identity or finding kind by parsing terminal text.
//!
//! In TS you'd write (pseudocode):
//! ```ts
//! // A discriminated union carries rule identity and source location, never matched bytes.
//! ```
/// What:
/// One content/name result or explicit inability to complete a scan.
/// Why:
/// Enum variants keep source locations separate from operational failures without sentinel line numbers.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// type ScanFinding = { kind: 'content'; line: number; rule: string }
/// | { kind: 'name'; component: number; rule: string }
/// | { kind: 'engine-error' } | { kind: 'pathname-line-break' };
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ScanFinding {
/// A rule matched content on one physical source line.
Content {
/// One-based line index;
/// usize indexes an in-memory file rather than a fixed-width wire integer.
line: usize,
/// Owned non-secret configured name or opaque numeric rule token,
/// never the matched source.
rule: String,
},
/// A rule matched an entire logical pathname component.
Name {
/// One-based component number after excluding navigation/volume prefixes.
component: usize,
/// Owned rule identity,
/// independent of the fully masked matching component.
rule: String,
},
/// A matcher failed,
/// so absence of matches cannot be treated as a pass.
EngineError,
/// A pathname contains line endings that the line-based matcher cannot inspect faithfully.
PathnameLineBreak,
}
/// Keep terminal rendering at the standalone consumer boundary.
impl ScanFinding {
/// What:
/// Render the existing standalone protocol using an already sanitized display path.
/// Why:
/// Structured consumers use the enum directly;
/// the executable preserves its current text contract.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// function render(finding, safeDisplayPath): string;
/// ```
pub(crate) fn render(&self, safe_display: &str) -> String {
// Match only the enum's actual variants; adding an operational failure requires an explicit rendering choice.
match self {
Self::Content { line, rule } => return format!("{safe_display}:{line} rule={rule}"),
Self::Name { component, rule } => return format!("{safe_display}:name:{component} rule={rule}"),
Self::EngineError => return format!("{safe_display}: engine error"),
Self::PathnameLineBreak => return format!("{safe_display}: unsupported pathname line break"),
}
}
}