rails_surrogate_key_logging 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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