Skip to main content

keyhog_scanner/context/
mod.rs

1//! Structural context analysis: understand WHERE in code a potential secret appears.
2//!
3//! Instead of treating code as flat text, we infer the structural context of
4//! each match (assignment, comment, test code, encrypted block, documentation)
5//! and adjust confidence accordingly. Not an AST parser - just fast,
6//! language-agnostic structural inference.
7
8mod documentation;
9mod false_positive;
10mod inference;
11
12pub use documentation::documentation_line_flags;
13pub use false_positive::{
14    is_false_positive_context, is_false_positive_context_with_path, is_false_positive_match_context,
15};
16pub use inference::{
17    infer_context, infer_context_with_documentation, infer_context_with_regions,
18    is_known_example_credential, is_sequential_placeholder, ContextRegions,
19};
20
21const ASSIGNMENT_CONFIDENCE_MULTIPLIER: f64 = 1.0;
22const STRING_LITERAL_CONFIDENCE_MULTIPLIER: f64 = 0.9;
23const UNKNOWN_CONFIDENCE_MULTIPLIER: f64 = 0.8;
24const DOCUMENTATION_CONFIDENCE_MULTIPLIER: f64 = 0.3;
25const COMMENT_CONFIDENCE_MULTIPLIER: f64 = 0.4;
26const TEST_CODE_CONFIDENCE_MULTIPLIER: f64 = 0.3;
27const ENCRYPTED_CONFIDENCE_MULTIPLIER: f64 = 0.05;
28
29/// The structural context of a code location.
30#[derive(Debug, Clone, Copy, PartialEq)]
31pub enum CodeContext {
32    /// Direct assignment: `key = value`, `key: value`, `KEY=value`.
33    Assignment,
34    /// Inside a comment (`//`, `#`, `/*`, `--`, and similar).
35    Comment,
36    /// Inside a test function or test file.
37    TestCode,
38    /// Inside an encrypted/sealed block.
39    Encrypted,
40    /// Inside documentation (docstring, markdown code fence).
41    Documentation,
42    /// Inside a string literal in ordinary code.
43    StringLiteral,
44    /// Unknown or unstructured context.
45    Unknown,
46}
47
48impl CodeContext {
49    /// Confidence multiplier for this context.
50    pub fn confidence_multiplier(&self) -> f64 {
51        match self {
52            Self::Assignment => ASSIGNMENT_CONFIDENCE_MULTIPLIER,
53            Self::StringLiteral => STRING_LITERAL_CONFIDENCE_MULTIPLIER,
54            Self::Unknown => UNKNOWN_CONFIDENCE_MULTIPLIER,
55            Self::Documentation => DOCUMENTATION_CONFIDENCE_MULTIPLIER,
56            Self::Comment => COMMENT_CONFIDENCE_MULTIPLIER,
57            Self::TestCode => TEST_CODE_CONFIDENCE_MULTIPLIER,
58            Self::Encrypted => ENCRYPTED_CONFIDENCE_MULTIPLIER,
59        }
60    }
61
62    /// Returns `true` if this context should trigger hard suppression for low-confidence findings.
63    pub fn should_hard_suppress(&self, confidence: f64) -> bool {
64        match self {
65            Self::Documentation | Self::TestCode | Self::Comment => confidence < 0.5,
66            Self::Encrypted => confidence < 0.8,
67            _ => false,
68        }
69    }
70}