Module: Foam::Otel::Redaction

Defined in:
lib/foam/otel/redaction.rb

Overview

Central redaction engine — the ONE place sensitive keys are stripped. Case-insensitive key match; deep-redacts nested structures with a depth guard; values become the literal "[REDACTED]".

Class Method Summary collapse

Class Method Details

.redact(raw, keys) ⇒ Object

Redacts a raw string: JSON payloads are deep-redacted; non-JSON strings pass through unchanged.



37
38
39
40
41
42
# File 'lib/foam/otel/redaction.rb', line 37

def redact(raw, keys)
  parsed = JSON.parse(raw)
  JSON.generate(redact_value(parsed, keys))
rescue StandardError
  raw
end

.redact_query(query, keys) ⇒ Object

Per-key query-string redaction ('a=1&token=x' form), mirroring the other cores: split on '&', split each pair on the FIRST '=', URL-decode the key for matching ONLY, emit the RAW key + '=[REDACTED]' (matched) or the raw pair unchanged — never re-encode, never leak on failure.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/foam/otel/redaction.rb', line 48

def redact_query(query, keys)
  return query if query.nil? || query.empty?

  query.split("&", -1).map do |pair|
    eq = pair.index("=")
    next pair if eq.nil?

    raw_key = pair[0...eq]
    decoded_key = URI.decode_www_form_component(raw_key)
    if keys.include?(decoded_key.downcase)
      "#{raw_key}=[REDACTED]"
    else
      pair
    end
  end.join("&")
rescue StandardError
  ""
end

.redact_value(obj, keys, depth = 0) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/foam/otel/redaction.rb', line 16

def redact_value(obj, keys, depth = 0)
  return "[depth limit]" if depth > MAX_REDACT_DEPTH

  case obj
  when Array
    obj.map { |item| redact_value(item, keys, depth + 1) }
  when Hash
    obj.each_with_object({}) do |(key, val), result|
      if key.is_a?(String) && keys.include?(key.downcase)
        result[key] = "[REDACTED]"
      else
        result[key] = redact_value(val, keys, depth + 1)
      end
    end
  else
    obj
  end
end