rails_surrogate_key_logging 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d4508c5a982897fd625ce7ee7625cedd7a78691b42a6562f9e036e2577f54b91
4
- data.tar.gz: 5d5b0395a7cb737fd5f1dc90f0dbbf74a493fcdb91ad8644a9e802584b649e9a
3
+ metadata.gz: df6c120ebe49e9724f0c2324feefd62dc61c317b87c118e438d3735364193897
4
+ data.tar.gz: a33a587bdc49075fcf20917797a9a631702ff4b52bd54f021e0088f383e36d3a
5
5
  SHA512:
6
- metadata.gz: 3201bc7f7e84b36813141a3c9e24883d1fd3a416ec4f05d6e6345fd46d063ebf494bcf39ca333f5292eed7ca845e0604d80f4907064b3db78aac6a496a477a08
7
- data.tar.gz: 105d8ed9be27bf5e3f633f230b5836668793c45960628749b09e71570279d7f754207ce4275542fd886129975a6e342da0ac221c32c7ba4b81d27ddc49e12d68
6
+ metadata.gz: f5020c84352f1dc337ae18b2a8e4f6c8a576bea91ecdaf710fe9d0402fc31f82c6c865a23dee02269e45f7e3faa8e72208f8f64764357b765591a97ae8d5157f
7
+ data.tar.gz: e7c60aeebd180e87480c3e5857d94cd3926cb945545cc8c0a56f4bc5735dcd4c40b075aae1373e098a8186c3a641d5a3041582f88d42ae5740ebee6ed11c7abc
@@ -17,10 +17,11 @@ module SurrogateKeyLogging
17
17
  sql = payload[:sql]
18
18
  binds = nil
19
19
 
20
- name_match = /([A-Za-z]+) (Load|Update|Cache)/.match(payload[:name])
20
+ name_match = /([A-Za-z:]+) (Load|Create|Update|Cache)/.match(payload[:name])
21
21
  model = if name_match && name_match[1] && ::ActiveRecord::Base.descendants.map(&:to_s).include?(name_match[1])
22
22
  name_match[1].safe_constantize
23
23
  end
24
+ return if !SurrogateKeyLogging.config.debug && SurrogateKeyLogging.key_store.is_a?(SurrogateKeyLogging::KeyStore::ActiveRecord) && SurrogateKeyLogging.key_store.model == model
24
25
 
25
26
  if payload[:binds]&.any?
26
27
  casted_params = type_casted_binds(payload[:type_casted_binds])
@@ -4,7 +4,7 @@ require 'active_support/parameter_filter'
4
4
 
5
5
  # Add ability for @mask to be a class/instance/lambda/proc
6
6
  module ActiveSupport
7
- module ParameterFilter
7
+ class ParameterFilter
8
8
  class CompiledFilter
9
9
 
10
10
  def value_for_key(key, value, parents = [], original_params = nil) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SurrogateKeyLogging
4
+ class Config < ActiveSupport::OrderedOptions
5
+ end
6
+
7
+ module Configuration
8
+ extend ActiveSupport::Concern
9
+
10
+ def surrogate_key_logging
11
+ SurrogateKeyLogging.config
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails'
4
+ require 'securerandom'
5
+
6
+ module SurrogateKeyLogging
7
+ class Engine < ::Rails::Engine
8
+ isolate_namespace SurrogateKeyLogging
9
+
10
+ config.autoload_paths << root.join('lib')
11
+
12
+ config.generators do |g|
13
+ g.test_framework :rspec
14
+ g.fixture_replacement :factory_bot, dir: 'spec/factories'
15
+ g.assets false
16
+ g.helper false
17
+ g.templates.unshift File.expand_path('lib/templates', root)
18
+ end
19
+
20
+ rake_tasks do
21
+ load 'tasks/surrogate_key_logging.rake'
22
+ load 'tasks/key_store/active_record.rake'
23
+ end
24
+
25
+ initializer 'surrogate_key_logging.config' do |app|
26
+ SurrogateKeyLogging.configure do |config|
27
+ config.enabled = Rails.env.production? unless config.key?(:enabled)
28
+ config.debug = !Rails.env.production? unless config.key?(:debug)
29
+ config.key_prefix = '' unless config.key?(:key_prefix)
30
+ config.key_for ||= -> (value) { "#{config.key_prefix}#{SecureRandom.uuid}" }
31
+ config.cache = true unless config.key?(:cache)
32
+ config.cache_key_for ||= -> (value) { value }
33
+ config.key_ttl ||= 90.days
34
+ end
35
+ end
36
+
37
+ initializer 'surrogate_key_logging.filter_parameters' do
38
+ if SurrogateKeyLogging.config.enabled
39
+ end
40
+ end
41
+
42
+ initializer 'surrogate_key_logging.logs' do
43
+ if SurrogateKeyLogging.config.enabled
44
+ ::ActiveRecord::LogSubscriber.detach_from(:active_record)
45
+ ::SurrogateKeyLogging::ActiveRecord::LogSubscriber.attach_to(:active_record)
46
+ ::ActiveSupport::LogSubscriber.detach_from(:action_controller)
47
+ ::SurrogateKeyLogging::ActionController::LogSubscriber.attach_to(:action_controller)
48
+ ::ActionDispatch::Request.include SurrogateKeyLogging::ActionDispatch::Request
49
+ end
50
+ end
51
+
52
+ initializer 'surrogate_key_logging.middleware' do
53
+ if SurrogateKeyLogging.config.enabled
54
+ Rails.application.config.middleware.insert_before 0, Middleware
55
+ end
56
+ end
57
+
58
+ end
59
+ end
@@ -3,9 +3,40 @@
3
3
  module SurrogateKeyLogging
4
4
  class KeyManager
5
5
 
6
- def call(key, value, _parents = [], _original_params = nil)
7
- surrogate = "SK#{Digest::SHA512.hexdigest(value.to_s)}"
8
- puts "surrogate for key: `#{key}`, value: `#{value}`, surrogate: `#{surrogate}`"
6
+ attr_reader :should_cache, :cache_key_for, :cache, :key_for
7
+
8
+ delegate :key_store, to: SurrogateKeyLogging
9
+
10
+ def initialize
11
+ @should_cache = SurrogateKeyLogging.config.cache
12
+ @cache_key_for = SurrogateKeyLogging.config.cache_key_for
13
+ @cache = {}
14
+ @key_for = SurrogateKeyLogging.config.key_for
15
+ end
16
+
17
+ def get(value)
18
+ if should_cache
19
+ get_cached(value)
20
+ else
21
+ get_non_cached(value)
22
+ end
23
+ end
24
+
25
+ def get_cached(value)
26
+ @cache[cache_key_for.call(value)] ||= get_non_cached(value)
27
+ end
28
+
29
+ def get_non_cached(value)
30
+ stored = key_store.surrogate_for_value(value)
31
+ return stored if stored.present?
32
+ surrogate = key_for.call(value)
33
+ key_store.save(surrogate, value)
34
+ surrogate
35
+ end
36
+
37
+ def call(_key, value, _parents = [], _original_params = nil)
38
+ surrogate = get(value)
39
+ # Rails.logger.tagged('SurrogateKeyLogging') { Rails.logger.info "Surrogate: `#{surrogate}`, value: `#{value}`" } if SurrogateKeyLogging.config.debug
9
40
  surrogate
10
41
  end
11
42
 
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SurrogateKeyLogging
4
+ module KeyStore
5
+
6
+ class ActiveRecord < Base
7
+
8
+ attr_reader :model
9
+
10
+ def initialize
11
+ if SurrogateKeyLogging.config.key?(:model) && SurrogateKeyLogging.config.model.present?
12
+ raise 'SurrogateKeyLogging::KeyStore::ActiveRecord config.model must descend from ActiveRecord::Base' unless SurrogateKeyLogging.config <= ::ActiveRecord::Base
13
+ @model = SurrogateKeyLogging.config.model
14
+ else
15
+ @model = SurrogateKeyLogging::Surrogate
16
+ end
17
+ end
18
+
19
+ def surrogate_for_value(value)
20
+ key = model.surrogate_for_value(value)
21
+ use(key)
22
+ key
23
+ end
24
+
25
+ def value_for_surrogate(surrogate)
26
+ model.value_for_surrogate(surrogate)
27
+ end
28
+
29
+ def save(surrogate, value)
30
+ model.add(surrogate, value)
31
+ end
32
+
33
+ def use(surrogate)
34
+ model.use(surrogate)
35
+ end
36
+
37
+ end
38
+
39
+ add(:active_record, ActiveRecord)
40
+
41
+ end
42
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SurrogateKeyLogging
4
+ module KeyStore
5
+ class Base
6
+
7
+ def surrogate_for_value(value)
8
+ raise NotImplementedError
9
+ end
10
+
11
+ def value_for_surrogate(surrogate)
12
+ raise NotImplementedError
13
+ end
14
+
15
+ def save(surrogate, value)
16
+ raise NotImplementedError
17
+ end
18
+
19
+ def use(surrogate)
20
+ raise NotImplementedError
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SurrogateKeyLogging
4
+ module KeyStore
5
+ extend ActiveSupport::Autoload
6
+
7
+ eager_autoload do
8
+ autoload :Base
9
+ autoload :ActiveRecord
10
+ end
11
+
12
+ @map = {}.with_indifferent_access
13
+
14
+ class << self
15
+ attr_reader :map
16
+
17
+ def get(key_store)
18
+ map[key_store] || raise("SurrogateKeyLogging unknown key_store: `#{key_store}`")
19
+ end
20
+
21
+ def add(name, klass)
22
+ map[name] = klass
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
@@ -6,7 +6,6 @@ module SurrogateKeyLogging
6
6
 
7
7
  def initialize(app)
8
8
  @app = app
9
- puts 'surrogate new'
10
9
  end
11
10
 
12
11
  def call(env)
@@ -4,8 +4,8 @@ module SurrogateKeyLogging
4
4
 
5
5
  module Version
6
6
  MAJOR = 0
7
- MINOR = 0
8
- PATCH = 1
7
+ MINOR = 1
8
+ PATCH = 0
9
9
 
10
10
  end
11
11
 
@@ -6,17 +6,28 @@ require 'active_support'
6
6
  module SurrogateKeyLogging
7
7
  extend ActiveSupport::Autoload
8
8
 
9
- autoload :Railtie
10
- autoload :Version
11
9
  autoload :ActionController
12
10
  autoload :ActionDispatch
13
11
  autoload :ActiveSupport
14
12
  autoload :ActiveRecord
13
+ autoload :Config, 'surrogate_key_logging/configuration'
14
+ autoload :Configuration
15
15
  autoload :KeyManager
16
+ autoload :KeyStore
16
17
  autoload :Middleware
18
+ autoload :Engine
19
+ autoload :Version
20
+
21
+ @config = Config.new
17
22
 
18
23
  class << self
19
24
 
25
+ attr_reader :config
26
+
27
+ def configure
28
+ yield config
29
+ end
30
+
20
31
  def surrogate_attributes(*attrs)
21
32
  @surrogate_attributes ||= []
22
33
  attrs.each do |attr|
@@ -26,6 +37,10 @@ module SurrogateKeyLogging
26
37
  end
27
38
 
28
39
  def reset
40
+ reset! if config.cache
41
+ end
42
+
43
+ def reset!
29
44
  @key_manager = @parameter_filter = nil
30
45
  end
31
46
 
@@ -37,24 +52,30 @@ module SurrogateKeyLogging
37
52
  @parameter_filter ||= ::ActiveSupport::ParameterFilter.new(surrogate_attributes, mask: key_manager)
38
53
  end
39
54
 
55
+ def key_store
56
+ @key_store ||= KeyStore.get(config.key_store).new
57
+ end
58
+
40
59
  def filter_parameters(params)
41
60
  parameter_filter.filter params
42
61
  end
43
62
 
44
- def add_param_to_filter(attr, parent = nil)
45
- if parent.nil?
63
+ def add_param_to_filter(attr, *parents)
64
+ if parents.empty?
46
65
  surrogate_attributes attr.to_s
47
66
  else
48
67
  surrogate_attributes(
49
- "#{parent}.#{attr}",
50
- "#{parent}[#{attr}]",
51
- "[#{parent}][#{attr}]"
68
+ "#{parents.join('.')}.#{attr}",
69
+ "#{parents.first}#{parents[1..-1].map{|x|"[#{x}]"}.join('')}[#{attr}]",
70
+ "#{parents.map{|x|"[#{x}]"}.join('')}[#{attr}]"
52
71
  )
53
72
  end
54
73
  end
55
74
 
56
75
  end
57
76
 
58
- end
77
+ KeyStore.eager_load!
78
+ ::Rails::Application::Configuration.send(:include, Configuration)
79
+ require 'surrogate_key_logging/engine'
59
80
 
60
- require 'surrogate_key_logging/railtie'
81
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :skl do
4
+ namespace :key_store do
5
+ namespace :active_record do |ar_ns|
6
+
7
+ task clear: :environment do
8
+ ActiveRecord::Base.connection.truncate(SurrogateKeyLogging.key_store.model.table_name)
9
+ end
10
+
11
+ namespace :clear do
12
+ task stale: :environment do
13
+ if SurrogateKeyLogging.config.key_ttl > 0
14
+ SurrogateKeyLogging.key_store.model.where('updated_at < ?', Time.now - SurrogateKeyLogging.config.key_ttl).destroy_all
15
+ else
16
+ puts "SurrogateKeyLogging config.key_ttl is set to 0, which makes keys never go stale."
17
+ end
18
+ end
19
+ end
20
+
21
+ namespace :db do |db_ns|
22
+ %i[drop create setup migrate rollback seed version].each do |task_name|
23
+ task task_name => :environment do
24
+ Rake::Task["db:#{task_name}"].invoke
25
+ end
26
+ end
27
+
28
+ namespace :migrate do
29
+ %i[up down redo].each do |task_name|
30
+ task task_name => :environment do
31
+ Rake::Task["db:migrate:#{task_name}"].invoke
32
+ end
33
+ end
34
+ end
35
+
36
+ namespace :schema do
37
+ %i[load dump].each do |task_name|
38
+ task task_name => :environment do
39
+ Rake::Task["db:schema:#{task_name}"].invoke
40
+ end
41
+ end
42
+ end
43
+
44
+ namespace :test do
45
+ task prepare: :environment do
46
+ Rake::Task['db:test:prepare'].invoke
47
+ end
48
+ end
49
+
50
+ namespace :environment do
51
+ task set: :environment do
52
+ Rake::Task['db:environment:set'].invoke
53
+ end
54
+ end
55
+
56
+ namespace :__config__ do
57
+ task set_surrogate_key_logging_db_config: :environment do
58
+ # save current vars
59
+ @original_db_config = {
60
+ env_schema: ENV['SCHEMA'],
61
+ config: Rails.application.config.dup,
62
+ ar_config: ActiveRecord::Base.
63
+ configurations.
64
+ configurations.inject({}) do |memo, db_config|
65
+ memo.merge(db_config.env_name => db_config.configuration_hash.stringify_keys)
66
+ end,
67
+ }
68
+
69
+ # set config variables for custom database
70
+ db_dir = SurrogateKeyLogging::Engine.root.join('db')
71
+ schema_path = Rails.root.join('db', "surrogate_key_logging_schema.#{Rails.application.config.active_record.schema_format}")
72
+ ENV['SCHEMA'] = schema_path.to_s
73
+ Rails.application.config.paths['db'] = [db_dir]
74
+ Rails.application.config.paths['db/migrate'] = [db_dir.join('migrate')]
75
+ Rails.application.config.paths['db/seeds'] = [db_dir.join('seeds.rb')]
76
+ Rails.application.config.paths['config/database'] = [SurrogateKeyLogging::Engine.root.join('config', 'database.yml')]
77
+ ActiveRecord::Base.configurations = ActiveRecord::Base.
78
+ configurations.
79
+ configurations.inject({}) do |memo, db_config|
80
+ next memo unless db_config.env_name.start_with?('surrogate_key_logging_')
81
+ memo.merge(db_config.env_name.sub(/^surrogate_key_logging_/, '') => db_config.configuration_hash.stringify_keys)
82
+ end
83
+ ActiveRecord::Base.establish_connection Rails.application.config.database_configuration[Rails.env]
84
+ end
85
+
86
+ task revert_surrogate_key_logging_db_config: :environment do
87
+ # reset config variables to original values
88
+ ENV['SCHEMA'] = @original_db_config[:env_schema]
89
+ Rails.application.config = @original_db_config[:config]
90
+ ActiveRecord::Base.configurations = @original_db_config[:ar_config]
91
+ ActiveRecord::Base.establish_connection Rails.application.config.database_configuration[Rails.env]
92
+ end
93
+ end
94
+
95
+ db_ns.tasks.each do |task|
96
+ next if task.scope.first == '__config__'
97
+ task.enhance ['skl:key_store:active_record:db:__config__:set_surrogate_key_logging_db_config'] do
98
+ Rake::Task['skl:key_store:active_record:db:__config__:revert_surrogate_key_logging_db_config'].invoke
99
+ Rake::Task['skl:key_store:active_record:db:__config__:set_surrogate_key_logging_db_config'].reenable
100
+ Rake::Task['skl:key_store:active_record:db:__config__:revert_surrogate_key_logging_db_config'].reenable
101
+ end
102
+ end
103
+ end
104
+
105
+ namespace :__config__ do
106
+ task check_config: :environment do
107
+ raise "SurrogateKeyLogging config.key_store must be set to :active_record for this task to function, it is currently set to `#{SurrogateKeyLogging.config.key_store.inspect}`" unless SurrogateKeyLogging.config.key_store == :active_record
108
+ end
109
+ end
110
+
111
+ ar_ns.tasks.each do |task|
112
+ next if task.scope.first == '__config__'
113
+ task.prerequisites.prepend('skl:key_store:active_record:__config__:check_config')
114
+ task.actions.prepend(&Rake::Task['skl:key_store:active_record:__config__:check_config'].method(:reenable))
115
+ end
116
+
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :skl do
4
+ task clear: :environment do
5
+ Rake::Task["skl:key_store:#{SurrogateKeyLogging.config.key_store}:clear"].invoke
6
+ end
7
+
8
+ namespace :clear do
9
+ task stale: :environment do
10
+ Rake::Task["skl:key_store:#{SurrogateKeyLogging.config.key_store}:clear:stale"].invoke
11
+ end
12
+ end
13
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_surrogate_key_logging
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Taylor Yelverton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-13 00:00:00.000000000 Z
11
+ date: 2023-01-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -83,10 +83,16 @@ files:
83
83
  - lib/surrogate_key_logging/active_record/attributes.rb
84
84
  - lib/surrogate_key_logging/active_record/log_subscriber.rb
85
85
  - lib/surrogate_key_logging/active_support.rb
86
+ - lib/surrogate_key_logging/configuration.rb
87
+ - lib/surrogate_key_logging/engine.rb
86
88
  - lib/surrogate_key_logging/key_manager.rb
89
+ - lib/surrogate_key_logging/key_store.rb
90
+ - lib/surrogate_key_logging/key_store/active_record.rb
91
+ - lib/surrogate_key_logging/key_store/base.rb
87
92
  - lib/surrogate_key_logging/middleware.rb
88
- - lib/surrogate_key_logging/railtie.rb
89
93
  - lib/surrogate_key_logging/version.rb
94
+ - lib/tasks/key_store/active_record.rake
95
+ - lib/tasks/surrogate_key_logging.rake
90
96
  - rails_surrogate_key_logging.gemspec
91
97
  homepage: https://github.com/ComplyMD/rails_surrogate_key_logging
92
98
  licenses:
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rails'
4
-
5
- module SurrogateKeyLogging
6
- class Railtie < Rails::Railtie
7
- railtie_name :surrogate_key_logging
8
-
9
- initializer 'surrogate_key_logging.filter_parameters' do
10
- puts 'surrogate_key_logging.filter_parameters'
11
- end
12
-
13
- initializer 'surrogate_key_logging.logs' do
14
- puts 'surrogate_key_logging.logs'
15
- ::ActiveRecord::LogSubscriber.detach_from(:active_record)
16
- ::SurrogateKeyLogging::ActiveRecord::LogSubscriber.attach_to(:active_record)
17
- ::ActiveSupport::LogSubscriber.detach_from(:action_controller)
18
- ::SurrogateKeyLogging::ActionController::LogSubscriber.attach_to(:action_controller)
19
- ::ActionDispatch::Request.include SurrogateKeyLogging::ActionDispatch::Request
20
- end
21
-
22
- initializer 'surrogate_key_logging.middleware' do
23
- puts 'surrogate_key_logging.middleware'
24
- Rails.application.config.middleware.insert_before 0, Middleware
25
- end
26
-
27
- end
28
- end