Class: LittleGhost::Support::Redactor
- Inherits:
-
Object
- Object
- LittleGhost::Support::Redactor
- Defined in:
- lib/little_ghost/support/redactor.rb
Overview
Redactor removes common credential keys, known secret values, and secret-shaped strings from nested diagnostic data. It returns a copy and leaves the caller's value unchanged.
Redaction is a defense-in-depth aid, not proof that arbitrary sensitive content is safe to export. Applications should add known secret values and keep telemetry within an appropriate trust boundary.
Constant Summary collapse
- SENSITIVE_KEY =
:nodoc:
/(authorization|api[_-]?key|credential|password|secret|(?:^|[_-])token(?:$|[_-])|cookie|private[_-]?key)/i- SECRET_PATTERNS =
[ /\bBearer\s+[A-Za-z0-9._~+\/-]+=*/i, /\b(?:gh[opusr]_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,})\b/, /\bAKIA[A-Z0-9]{16}\b/, /\b(?:sk|pk)-[A-Za-z0-9_-]{20,}\b/ ].freeze
Instance Method Summary collapse
-
#call(value, key: nil) ⇒ Object
Produces a redacted copy of
value. -
#initialize(redactions: [], stringify_keys: false) ⇒ Redactor
constructor
Adds literal secrets to the built-in patterns.
-
#scrub_string(value) ⇒ Object
Normalizes invalid UTF-8 and replaces configured and common secrets.
-
#sensitive_key?(key) ⇒ Boolean
Checks whether
keymatches a credential-like name.
Constructor Details
#initialize(redactions: [], stringify_keys: false) ⇒ Redactor
Adds literal secrets to the built-in patterns. Values shorter than eight characters are ignored to avoid over-redaction.
23 24 25 26 |
# File 'lib/little_ghost/support/redactor.rb', line 23 def initialize(redactions: [], stringify_keys: false) @redactions = Array(redactions).map(&:to_s).reject { |value| value.length < 8 }.uniq.freeze @stringify_keys = stringify_keys end |
Instance Method Details
#call(value, key: nil) ⇒ Object
Produces a redacted copy of value.
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/little_ghost/support/redactor.rb', line 29 def call(value, key: nil) return "[REDACTED]" if key && sensitive_key?(key) case value when Hash value.to_h do |child_key, child| output_key = @stringify_keys ? child_key.to_s : child_key [output_key, call(child, key: child_key)] end when Array value.map { |child| call(child) } when String scrub_string(value) else value end end |
#scrub_string(value) ⇒ Object
Normalizes invalid UTF-8 and replaces configured and common secrets.
53 54 55 56 57 |
# File 'lib/little_ghost/support/redactor.rb', line 53 def scrub_string(value) normalized = value.encode(Encoding::UTF_8, invalid: :replace, undef: :replace, replace: "\uFFFD") text = @redactions.reduce(normalized) { |current, secret| current.gsub(secret, "[REDACTED]") } SECRET_PATTERNS.reduce(text) { |current, pattern| current.gsub(pattern, "[REDACTED]") } end |
#sensitive_key?(key) ⇒ Boolean
Checks whether key matches a credential-like name.
48 49 50 |
# File 'lib/little_ghost/support/redactor.rb', line 48 def sensitive_key?(key) SENSITIVE_KEY.match?(normalize_key(key)) end |