Module: AnalyticsOps::Redaction

Defined in:
lib/analytics_ops/redaction.rb

Overview

Removes credential-shaped material before text reaches user-visible output.

Constant Summary collapse

BEARER =
/\bBearer\s+[^\s,;]+/i
AUTHORIZATION =
/\bAuthorization\s*[:=]\s*[^\r\n,;]+/i
PRIVATE_KEY =
/-----BEGIN[^-]*PRIVATE KEY-----.*?-----END[^-]*PRIVATE KEY-----/mi
SECRET_ASSIGNMENT =
/
  (
    access[_ -]?token|refresh[_ -]?token|client[_ -]?(?:id|secret)|
    private[_ -]?key|password|api[_ -]?key|credentials?
  )
  ["']?\s*(?:[:=]\s*|=>\s*)(?:["'][^"'\r\n]*["']|[^\s,;\r\n}]+)
/ix
CONTROL_CHARACTERS =
/[\u0000-\u001f\u007f]/

Class Method Summary collapse

Class Method Details

.credential_shaped?(value) ⇒ Boolean

Returns:

  • (Boolean)


22
23
24
25
# File 'lib/analytics_ops/redaction.rb', line 22

def credential_shaped?(value)
  text = value.to_s.encode(Encoding::UTF_8, invalid: :replace, undef: :replace, replace: "?")
  [PRIVATE_KEY, AUTHORIZATION, BEARER, SECRET_ASSIGNMENT].any? { |pattern| pattern.match?(text) }
end

.message(value) ⇒ Object



27
28
29
# File 'lib/analytics_ops/redaction.rb', line 27

def message(value)
  text(value, limit: 1_000)
end

.text(value, limit: nil) ⇒ Object



31
32
33
34
35
36
37
38
39
# File 'lib/analytics_ops/redaction.rb', line 31

def text(value, limit: nil)
  text = value.to_s.encode(Encoding::UTF_8, invalid: :replace, undef: :replace, replace: "?")
  redacted = text.gsub(PRIVATE_KEY, "[REDACTED]")
                 .gsub(AUTHORIZATION, "Authorization: [REDACTED]")
                 .gsub(BEARER, "Bearer [REDACTED]")
                 .gsub(SECRET_ASSIGNMENT) { "#{Regexp.last_match(1)}=[REDACTED]" }
                 .gsub(CONTROL_CHARACTERS, "?")
  limit ? redacted.slice(0, limit) : redacted
end