Module: Api2Convert::Support::Redactor

Defined in:
lib/api2convert/support/redactor.rb

Overview

Credential redaction for cloud connectors.

Cloud credentials ride in the plaintext request body, so they must never surface where a value object or an SDK-emitted string could leak them. This helper centralizes the masks the contract mandates:

  • the whole credentials object collapses to MARKER on every object-inspection path (#inspect / #to_s);
  • any parameters leaf whose key contains a sensitive token (SENSITIVE_SUBSTRINGS, case-insensitive substring) collapses to MARKER;
  • the decoded error body is deep-walked (Redactor.redact_body) as belt-and- suspenders — the API only ever echoes field names, never a credential value, but a future server/proxy change must not be able to leak one.

Internal helper, not part of the public API.

Constant Summary collapse

MARKER =

The fixed, fleet-wide redaction marker (D9).

"[REDACTED]"
SENSITIVE_SUBSTRINGS =

Case-insensitive substrings that mark a key as carrying a secret. A key containing any of these has its whole value masked.

%w[
  token password passwd secret key keyfile
  credential passphrase sas sig signature
].freeze
SENSITIVE_PATTERN =

Precompiled union: a key is sensitive iff it contains any substring above. Equivalent to SENSITIVE_SUBSTRINGS.any? { |s| key.include?(s) } but written as a regex so Style/ArrayIntersect can't rewrite the String#include? substring test into Array#intersect? (which would need an array argument and change the semantics).

Regexp.union(SENSITIVE_SUBSTRINGS).freeze

Class Method Summary collapse

Class Method Details

.parameters(params) ⇒ Object

Mask sensitive leaves of a parameters map: any key matching sensitive_key? has its value replaced by MARKER; nested Hashes are walked recursively. Non-secret keys (bucket, host, file, container, projectid, …) are left untouched.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/api2convert/support/redactor.rb', line 50

def parameters(params)
  return params unless params.is_a?(Hash)

  params.each_with_object({}) do |(key, value), out|
    out[key] =
      if sensitive_key?(key)
        MARKER
      elsif value.is_a?(Hash)
        parameters(value)
      else
        value
      end
  end
end

.redact_body(body) ⇒ Object

Deep-walk a decoded error body and mask the value of every sensitive key (including a flattened/dotted key like input.0.credentials.secretaccesskey) to MARKER. Nested Hashes and Arrays are walked; scalars pass through.



69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/api2convert/support/redactor.rb', line 69

def redact_body(body)
  case body
  when Hash
    body.each_with_object({}) do |(key, value), out|
      out[key] = sensitive_key?(key) ? MARKER : redact_body(value)
    end
  when Array
    body.map { |value| redact_body(value) }
  else
    body
  end
end

.sensitive_key?(key) ⇒ Boolean

Whether a key name marks its value as sensitive (case-insensitive substring match). Accepts String or Symbol keys.

Returns:

  • (Boolean)


42
43
44
# File 'lib/api2convert/support/redactor.rb', line 42

def sensitive_key?(key)
  SENSITIVE_PATTERN.match?(key.to_s.downcase)
end