Class: StandardAudit::SensitiveKeysDryRun

Inherits:
Object
  • Object
show all
Defined in:
lib/standard_audit/sensitive_keys_dry_run.rb

Overview

Answers "is this redaction rule safe for MY data?" against the rows an app already has, before the rule is switched on.

This matters more here than in most gems: audit rows are append-only, so a rule that swallows real audit content cannot be undone after the fact — the content is simply never written from then on. Reading the historical rows first turns the judgement call into a command.

Keys are extracted in Ruby, not with jsonb_object_keys, so this works against SQLite (the dummy app), MySQL, and Postgres alike. The install template's migration uses jsonb + GIN, but the gem itself stays backend-neutral.

StandardAudit::SensitiveKeysDryRun.call(sensitive_key_patterns: [/secret/i])
# => #<Report rows_scanned=1204 stripped={"client_secret"=>18, ...} ...>

Defined Under Namespace

Classes: Report

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sensitive_keys: nil, sensitive_key_patterns: nil, sensitive_key_exceptions: nil, nested: nil) ⇒ SensitiveKeysDryRun

Returns a new instance of SensitiveKeysDryRun.



89
90
91
92
93
94
95
96
97
98
99
# File 'lib/standard_audit/sensitive_keys_dry_run.rb', line 89

def initialize(sensitive_keys: nil, sensitive_key_patterns: nil, sensitive_key_exceptions: nil, nested: nil)
  live = StandardAudit.config

  candidate = Configuration.new
  candidate.sensitive_keys = sensitive_keys || live.sensitive_keys
  candidate.sensitive_key_patterns = sensitive_key_patterns || live.sensitive_key_patterns
  candidate.sensitive_key_exceptions = sensitive_key_exceptions || live.sensitive_key_exceptions

  @nested = nested.nil? ? live. : nested
  @filter = MetadataFilter.new(config: candidate)
end

Class Method Details

.call(sensitive_keys: nil, sensitive_key_patterns: nil, sensitive_key_exceptions: nil, nested: nil, relation: nil, batch_size: 1000) ⇒ Object

Every keyword defaults to the app's live configuration, so calling it with no arguments reports what the current config does.



78
79
80
81
82
83
84
85
86
# File 'lib/standard_audit/sensitive_keys_dry_run.rb', line 78

def call(sensitive_keys: nil, sensitive_key_patterns: nil, sensitive_key_exceptions: nil,
         nested: nil, relation: nil, batch_size: 1000)
  new(
    sensitive_keys: sensitive_keys,
    sensitive_key_patterns: sensitive_key_patterns,
    sensitive_key_exceptions: sensitive_key_exceptions,
    nested: nested
  ).call(relation: relation, batch_size: batch_size)
end

Instance Method Details

#call(relation: nil, batch_size: 1000) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/standard_audit/sensitive_keys_dry_run.rb', line 101

def call(relation: nil, batch_size: 1000)
  relation ||= StandardAudit::AuditLog.all

  rows = 0
  stripped = Hash.new(0)
  kept = Hash.new(0)
  nested_unfiltered = Hash.new(0)

  relation.select(:id, :metadata).find_each(batch_size: batch_size) do |log|
    rows += 1
     = log.
    next unless .respond_to?(:each_pair)

    # Collect distinct paths per row first, then increment once each. A row
    # whose `charges[]` array holds two matching hashes is ONE affected row,
    # not two — the counts are documented as row counts.
    row = { stripped: Set.new, kept: Set.new, nested_unfiltered: Set.new }
    walk(, nil, row, top_level: true)

    row[:stripped].each { |path| stripped[path] += 1 }
    row[:kept].each { |path| kept[path] += 1 }
    row[:nested_unfiltered].each { |path| nested_unfiltered[path] += 1 }
  end

  Report.new(
    rows_scanned: rows,
    stripped: stripped,
    kept: kept,
    nested_unfiltered: nested_unfiltered,
    nested: @nested
  )
end