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
use super::*;
/// Intent pin for the `CREDENTIAL_KEYWORD_NEEDLES` unification: `passwd`
/// is a canonical credential keyword (same set the entropy keyword list and
/// the TS non-null identifier gate use), so a camel-cased dotted candidate
/// carrying a `passwd` segment IS a source identifier and must suppress.
/// If someone narrows the canonical set and drops `passwd`, this fails.
#[test]
fn dotted_source_identifier_suppresses_camel_passwd_segment() {
assert!(
looks_like_dotted_source_identifier("userDb.passwd.value"),
"camel-cased dotted candidate with a passwd segment must be a source identifier",
);
}
/// Guardrail on the widening: `passwd` alone (no camel segment, no known
/// receiver) must NOT suppress, so the passwd inclusion does not silently
/// swallow flat dotted credential paths.
#[test]
fn dotted_passwd_without_camel_or_receiver_does_not_suppress() {
assert!(
!looks_like_dotted_source_identifier("db.passwd.field"),
"a flat passwd dotted path with no camel segment must not be suppressed",
);
}
/// Single-pass rewrite must preserve the 2..=5 segment-count window and the
/// empty-segment / non-alnum rejections.
#[test]
fn dotted_source_identifier_segment_count_and_body_bounds() {
// 6 dotted segments is over the 5-segment ceiling → not an identifier.
assert!(!looks_like_dotted_source_identifier("aB.cD.eF.gH.iJ.kL"));
// Single segment (no dot) is under the floor.
assert!(!looks_like_dotted_source_identifier("userDbPasswd"));
// Empty segment rejects regardless of count.
assert!(!looks_like_dotted_source_identifier("userDb..passwd"));
// Non-alnum body byte rejects.
assert!(!looks_like_dotted_source_identifier("userDb.pass-wd.value"));
}
/// First-segment receiver match short-circuits to true without needing a
/// camel/credential segment (the `first` capture in the single pass).
#[test]
fn dotted_source_identifier_receiver_first_segment() {
assert!(looks_like_dotted_source_identifier(&format!(
"{}.field",
SOURCE_RECEIVERS[0].as_str()
)));
}
/// A dotted lowercase snake_case path is a config key or a field access, not a
/// credential: the self-scan surfaced `plausibility.reject_repeated_blocks`
/// from a documentation table and `entropy_match.value` from scanner source as
/// entropy findings, because the gate demanded a camelCase segment that
/// snake_case code and TOML keys never carry. Every member of the shape is
/// covered, not the one that was reported: a two-segment key, a long
/// multi-word key, a key whose last segment carries a credential word, and a
/// field access behind a reference sigil.
#[test]
fn dotted_snake_case_config_key_is_a_source_identifier() {
for value in [
"plausibility.mixed_alnum_floor",
"plausibility.reject_repeated_blocks",
"plausibility.second_half_entropy_floor",
"plausibility.allow_alphabetic_credential",
"entropy_match.value",
"&entropy_match.value",
"*self.detector_id",
"plausibility.leading_slash_base64_min_len",
"checksum.sha256_floor",
"config.detector.min_confidence",
] {
assert!(
looks_like_dotted_source_identifier(value),
"{value} is a snake_case identifier path, not a credential",
);
}
}
/// The snake_case widening must not swallow dotted values that carry real
/// credential entropy: bare lowercase word paths stay visible (the
/// `db.passwd.field` contract above), and so does anything with digits, case
/// variation, or a non-identifier byte in a segment.
#[test]
fn dotted_snake_case_widening_keeps_credential_shapes_visible() {
for value in [
"db.passwd.field",
"sk_live.AbC9dEf",
"api_key.7f3d9b2c1a",
"prod_secret.aGVsbG8=",
"&db.passwd",
] {
assert!(
!looks_like_dotted_source_identifier(value),
"{value} must stay visible to the entropy path",
);
}
}
#[test]
fn generated_template_interpolation_prefix_is_source_syntax() {
let randomness = TokenRandomness::for_candidate("__vlist$");
assert!(looks_like_source_code_expression_with_randomness(
"__vlist$",
&randomness
));
assert!(!looks_like_template_interpolation_prefix("realSecret$"));
}
#[test]
fn indexed_javascript_length_expression_is_source_syntax() {
for value in [
"_a8fe8b046732.length]))",
"_715561396085.length]))",
"$715561396085.length])",
] {
let randomness = TokenRandomness::for_candidate(value);
assert!(looks_like_source_code_expression_with_randomness(
value,
&randomness
));
}
for value in [
"_a8fe8b046732.length",
"opaque-key.length]))",
"_a8fe8b046732.length]))suffix",
"715561396085.length]))",
] {
let randomness = TokenRandomness::for_candidate(value);
assert!(!looks_like_source_code_expression_with_randomness(
value,
&randomness
));
}
}