sqreen 0.1.0.pre → 0.7.01461158029

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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CODE_OF_CONDUCT.md +22 -0
  3. data/README.md +77 -0
  4. data/Rakefile +40 -0
  5. data/lib/sqreen.rb +67 -0
  6. data/lib/sqreen/binding_accessor.rb +184 -0
  7. data/lib/sqreen/ca.crt +72 -0
  8. data/lib/sqreen/callback_tree.rb +78 -0
  9. data/lib/sqreen/callbacks.rb +120 -0
  10. data/lib/sqreen/capped_queue.rb +23 -0
  11. data/lib/sqreen/condition_evaluator.rb +169 -0
  12. data/lib/sqreen/conditionable.rb +50 -0
  13. data/lib/sqreen/configuration.rb +151 -0
  14. data/lib/sqreen/context.rb +22 -0
  15. data/lib/sqreen/deliveries/batch.rb +80 -0
  16. data/lib/sqreen/deliveries/simple.rb +36 -0
  17. data/lib/sqreen/detect.rb +14 -0
  18. data/lib/sqreen/detect/shell_injection.rb +61 -0
  19. data/lib/sqreen/detect/sql_injection.rb +115 -0
  20. data/lib/sqreen/event.rb +16 -0
  21. data/lib/sqreen/events/attack.rb +60 -0
  22. data/lib/sqreen/events/remote_exception.rb +53 -0
  23. data/lib/sqreen/exception.rb +31 -0
  24. data/lib/sqreen/frameworks.rb +40 -0
  25. data/lib/sqreen/frameworks/generic.rb +243 -0
  26. data/lib/sqreen/frameworks/rails.rb +155 -0
  27. data/lib/sqreen/frameworks/rails3.rb +36 -0
  28. data/lib/sqreen/frameworks/sinatra.rb +34 -0
  29. data/lib/sqreen/frameworks/sqreen_test.rb +26 -0
  30. data/lib/sqreen/instrumentation.rb +504 -0
  31. data/lib/sqreen/log.rb +116 -0
  32. data/lib/sqreen/metrics.rb +6 -0
  33. data/lib/sqreen/metrics/average.rb +39 -0
  34. data/lib/sqreen/metrics/base.rb +41 -0
  35. data/lib/sqreen/metrics/collect.rb +22 -0
  36. data/lib/sqreen/metrics/sum.rb +20 -0
  37. data/lib/sqreen/metrics_store.rb +94 -0
  38. data/lib/sqreen/parsers/sql.rb +98 -0
  39. data/lib/sqreen/parsers/sql_tokenizer.rb +266 -0
  40. data/lib/sqreen/parsers/unix.rb +110 -0
  41. data/lib/sqreen/payload_creator.rb +132 -0
  42. data/lib/sqreen/performance_notifications.rb +86 -0
  43. data/lib/sqreen/performance_notifications/log.rb +36 -0
  44. data/lib/sqreen/performance_notifications/metrics.rb +36 -0
  45. data/lib/sqreen/performance_notifications/newrelic.rb +36 -0
  46. data/lib/sqreen/remote_command.rb +82 -0
  47. data/lib/sqreen/rule_attributes.rb +25 -0
  48. data/lib/sqreen/rule_callback.rb +97 -0
  49. data/lib/sqreen/rules.rb +116 -0
  50. data/lib/sqreen/rules_callbacks.rb +29 -0
  51. data/lib/sqreen/rules_callbacks/binding_accessor_metrics.rb +79 -0
  52. data/lib/sqreen/rules_callbacks/count_http_codes.rb +18 -0
  53. data/lib/sqreen/rules_callbacks/crawler_user_agent_matches.rb +24 -0
  54. data/lib/sqreen/rules_callbacks/crawler_user_agent_matches_metrics.rb +25 -0
  55. data/lib/sqreen/rules_callbacks/execjs.rb +136 -0
  56. data/lib/sqreen/rules_callbacks/headers_insert.rb +20 -0
  57. data/lib/sqreen/rules_callbacks/inspect_rule.rb +20 -0
  58. data/lib/sqreen/rules_callbacks/matcher_rule.rb +103 -0
  59. data/lib/sqreen/rules_callbacks/rails_parameters.rb +14 -0
  60. data/lib/sqreen/rules_callbacks/record_request_context.rb +23 -0
  61. data/lib/sqreen/rules_callbacks/reflected_xss.rb +40 -0
  62. data/lib/sqreen/rules_callbacks/regexp_rule.rb +36 -0
  63. data/lib/sqreen/rules_callbacks/shell.rb +33 -0
  64. data/lib/sqreen/rules_callbacks/shell_env.rb +32 -0
  65. data/lib/sqreen/rules_callbacks/sql.rb +41 -0
  66. data/lib/sqreen/rules_callbacks/system_shell.rb +25 -0
  67. data/lib/sqreen/rules_callbacks/url_matches.rb +25 -0
  68. data/lib/sqreen/rules_callbacks/user_agent_matches.rb +22 -0
  69. data/lib/sqreen/rules_signature.rb +142 -0
  70. data/lib/sqreen/runner.rb +312 -0
  71. data/lib/sqreen/runtime_infos.rb +127 -0
  72. data/lib/sqreen/session.rb +340 -0
  73. data/lib/sqreen/stats.rb +18 -0
  74. data/lib/sqreen/version.rb +6 -0
  75. metadata +95 -34
@@ -0,0 +1,36 @@
1
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
+
4
+ require 'sqreen/frameworks/rails'
5
+
6
+ module Sqreen
7
+ module Frameworks
8
+ # Handle Rails 3 specifics
9
+ class Rails3Framework < RailsFramework
10
+ def root
11
+ Rails.root
12
+ end
13
+
14
+ def prevent_startup
15
+ res = super
16
+ return res if res
17
+ return :rails_console if defined?(Rails::Console)
18
+ nil
19
+ end
20
+
21
+ def instrument_when_ready!(instrumentor, rules)
22
+ config = Rails.configuration
23
+ if config.cache_classes
24
+ instrumentor.instrument!(rules, self)
25
+ else
26
+ # FIXME: What needs to be done if no active_record?
27
+ # (probably related to SQREEN-219)
28
+ frm = self
29
+ ActiveSupport.on_load(:active_record) do
30
+ instrumentor.instrument!(rules, frm)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,34 @@
1
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
+
4
+ require 'sqreen/frameworks/generic'
5
+
6
+ module Sqreen
7
+ module Frameworks
8
+ # Handle Sinatra specific functions
9
+ class SinatraFramework < GenericFramework
10
+ def framework_infos
11
+ h = super
12
+ h[:framework_type] = 'Sinatra'
13
+ h[:framework_version] = Sinatra::VERSION
14
+ h
15
+ end
16
+
17
+ def db_settings(options = {})
18
+ adapter = options[:connection_adapter]
19
+ return nil unless adapter
20
+
21
+ begin
22
+ adapter_name = adapter.class.const_get 'ADAPTER_NAME'
23
+ rescue
24
+ # FIXME: we may want to log that
25
+ Sqreen.log.error 'cannot find ADAPTER_NAME'
26
+ return nil
27
+ end
28
+ db_type = DB_MAPPING[adapter_name]
29
+ db_infos = { :name => adapter_name }
30
+ [db_type, db_infos]
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
+
4
+ require 'sqreen/frameworks/generic'
5
+
6
+ module Sqreen
7
+ module Frameworks
8
+ # Rails related framework code
9
+ class SqreenTestFramework < GenericFramework
10
+ def framework_infos
11
+ {
12
+ :framework_type => 'SqreenTest',
13
+ :framework_version => '0.1',
14
+ }
15
+ end
16
+
17
+ def client_ip
18
+ '127.0.0.1'
19
+ end
20
+
21
+ def request_infos
22
+ {}
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,504 @@
1
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
+
4
+ require 'sqreen/callback_tree'
5
+ require 'sqreen/log'
6
+ require 'sqreen/stats'
7
+ require 'sqreen/exception'
8
+ require 'sqreen/performance_notifications'
9
+ require 'sqreen/events/remote_exception'
10
+ require 'sqreen/rules_signature'
11
+ require 'set'
12
+
13
+ # How to override a class method:
14
+ #
15
+ # class Cache
16
+ #
17
+ # def self.get3
18
+ # puts "GET3"
19
+ # end
20
+ # def self.get
21
+ # puts "GET"
22
+ # end
23
+ # end
24
+ #
25
+ # class << Cache # Change context to metaclass of Cache
26
+ # def get_modified
27
+ # puts "GET MODIFI"
28
+ # end
29
+ # alias_method :get_not_modified, :get
30
+ # alias_method :get, :get_modified
31
+ # end
32
+
33
+ module Sqreen
34
+ class Instrumentation
35
+ @@override_semaphore = Mutex.new
36
+
37
+ ## Overriden methods and callbacks globals
38
+ @@overriden_methods = []
39
+ @@registered_callbacks = CBTree.new
40
+
41
+ def self.semaphore
42
+ @@override_semaphore
43
+ end
44
+
45
+ def self.callbacks
46
+ @@registered_callbacks
47
+ end
48
+
49
+ def self.overriden
50
+ @@overriden_methods
51
+ end
52
+
53
+ def self.callback_wrapper_pre(klass, method, instance, *args, &block)
54
+ Instrumentation.guard_call(method, []) do
55
+ callbacks = @@registered_callbacks.get(klass, method, :pre)
56
+
57
+ returns = []
58
+ callbacks.each do |cb|
59
+ rule = cb.rule_name if cb.respond_to?(:rule_name)
60
+ Sqreen.log.debug { "running pre cb #{cb}" }
61
+ Sqreen::PerformanceNotifications.instrument("Callbacks/#{rule || cb.class.name}/pre") do
62
+ begin
63
+ res = cb.send(:pre, instance, *args, &block)
64
+ if !res.nil? && cb.respond_to?(:block) && (!cb.block && !Sqreen.config_get(:block_all_rules))
65
+ Sqreen.log.debug do
66
+ "#{cb} cannot block, overriding return value"
67
+ end
68
+ res = nil
69
+ elsif res.is_a?(Hash)
70
+ res[:rule_name] = rule
71
+ end
72
+ returns << res
73
+ rescue => e
74
+ Sqreen.log.error "we catch an exception: #{e.inspect}"
75
+ Sqreen.log.error e.backtrace
76
+ if cb.respond_to?(:record_exception)
77
+ cb.record_exception(e)
78
+ else
79
+ Sqreen::RemoteException.record(e)
80
+ end
81
+ next
82
+ end
83
+ end
84
+ end
85
+ returns
86
+ end
87
+ end
88
+
89
+ def self.callback_wrapper_post(klass, method, return_val, instance, *args, &block)
90
+ Instrumentation.guard_call(method, []) do
91
+ callbacks = @@registered_callbacks.get(klass, method, :post)
92
+
93
+ returns = []
94
+ callbacks.reverse_each do |cb|
95
+ rule = cb.rule_name if cb.respond_to?(:rule_name)
96
+ Sqreen.log.debug { "running post cb #{cb}" }
97
+ Sqreen::PerformanceNotifications.instrument("Callbacks/#{rule || cb.class.name}/post") do
98
+ begin
99
+ res = cb.send(:post, return_val, instance, *args, &block)
100
+ if !res.nil? && cb.respond_to?(:block) && (!cb.block && !Sqreen.config_get(:block_all_rules))
101
+ Sqreen.log.debug do
102
+ "#{cb} cannot block, overriding return value"
103
+ end
104
+ res = nil
105
+ elsif res.is_a?(Hash)
106
+ res[:rule_name] = rule
107
+ end
108
+ returns << res
109
+ rescue => e
110
+ Sqreen.log.error "we catch an exception: #{e.inspect}"
111
+ Sqreen.log.error e.backtrace
112
+ if cb.respond_to?(:record_exception)
113
+ cb.record_exception(e)
114
+ else
115
+ Sqreen::RemoteException.record(e)
116
+ end
117
+ next
118
+ end
119
+ end
120
+ end
121
+ returns
122
+ end
123
+ end
124
+
125
+ def self.callback_wrapper_failing(exception, klass, method, instance, *args, &block)
126
+ Instrumentation.guard_call(method, []) do
127
+ callbacks = @@registered_callbacks.get(klass, method, :failing)
128
+
129
+ returns = []
130
+ callbacks.each do |cb|
131
+ rule = cb.rule_name if cb.respond_to?(:rule_name)
132
+ Sqreen.log.debug { "running failing cb #{cb}" }
133
+ Sqreen::PerformanceNotifications.instrument("Callbacks/#{rule || cb.class.name}/failing") do
134
+ begin
135
+ res = cb.send(:failing, exception, instance, *args, &block)
136
+ if !res.nil? && cb.respond_to?(:block) && (!cb.block && !Sqreen.config_get(:block_all_rules))
137
+ Sqreen.log.debug do
138
+ "#{cb} cannot block, overriding return value"
139
+ end
140
+ res = nil
141
+ elsif res.is_a?(Hash)
142
+ res[:rule_name] = rule
143
+ end
144
+ returns << res
145
+ rescue => e
146
+ Sqreen.log.error "we catch an exception: #{e.inspect}"
147
+ Sqreen.log.error e.backtrace
148
+ if cb.respond_to?(:record_exception)
149
+ cb.record_exception(e)
150
+ else
151
+ Sqreen::RemoteException.record(e)
152
+ end
153
+ next
154
+ end
155
+ end
156
+ end
157
+ returns
158
+ end
159
+ end
160
+
161
+ def self.guard_call(method, retval)
162
+ if @sqreen_in_instr && @sqreen_in_instr.member?(method)
163
+ return retval
164
+ else
165
+ @sqreen_in_instr ||= Set.new
166
+ @sqreen_in_instr.add(method)
167
+ r = yield
168
+ @sqreen_in_instr.delete(method)
169
+ return r
170
+ end
171
+ rescue Exception => e
172
+ @sqreen_in_instr.delete(method)
173
+ raise e
174
+ end
175
+
176
+ def self.define_callback_method(meth, original_meth, klass_name)
177
+ proc do |*args, &block|
178
+ Sqreen.stats.callbacks_calls += 1
179
+
180
+ skip = false
181
+ result = nil
182
+
183
+ # pre callback
184
+ returns = Instrumentation.callback_wrapper_pre(klass_name,
185
+ meth,
186
+ self,
187
+ *args,
188
+ &block)
189
+ returns.each do |ret|
190
+ next unless ret.is_a? Hash
191
+ case ret[:status]
192
+ when :skip, 'skip'
193
+ skip = true
194
+ result = ret[:new_return_value] if ret.key? :new_return_value
195
+ next
196
+ when :raise, 'raise'
197
+ fail Sqreen::AttackBlocked, "Sqreen blocked a security threat (type: #{ret[:rule_name]}). No action is required."
198
+ end
199
+ end
200
+
201
+ return result if skip
202
+ begin
203
+ result = send(original_meth, *args, &block)
204
+ rescue => e
205
+ returns = Instrumentation.callback_wrapper_failing(e, klass_name,
206
+ meth,
207
+ self,
208
+ *args,
209
+ &block)
210
+ will_retry = false
211
+ will_raise = returns.empty?
212
+ returns.each do |ret|
213
+ will_raise = true if ret.nil?
214
+ next unless ret.is_a? Hash
215
+ case ret[:status]
216
+ when :override, 'override'
217
+ result = ret[:new_return_value] if ret.key? :new_return_value
218
+ when :retry, 'retry'
219
+ will_retry = true
220
+ else # :reraise, 'reraise'
221
+ will_raise = true
222
+ end
223
+ end
224
+ raise e if will_raise
225
+ retry if will_retry
226
+ result
227
+ else
228
+
229
+ # post callback
230
+ returns = Instrumentation.callback_wrapper_post(klass_name,
231
+ meth,
232
+ result,
233
+ self,
234
+ *args,
235
+ &block)
236
+ returns.each do |ret|
237
+ next unless ret.is_a? Hash
238
+ case ret[:status]
239
+ when :raise, 'raise'
240
+ fail Sqreen::AttackBlocked, "Sqreen blocked a security threat (type: #{ret[:rule_name]}). No action is required."
241
+ when :override, 'override'
242
+ result = ret[:new_return_value]
243
+ else
244
+ next
245
+ end
246
+ end
247
+ result
248
+ end
249
+ end
250
+ end
251
+
252
+ def override_class_method(klass, meth)
253
+ # FIXME: This is somehow ugly. We should reduce the amount of
254
+ # `evaled` code.
255
+ str = " class << #{klass}
256
+
257
+ original = '#{meth}'.to_sym
258
+ saved_meth_name = '#{get_saved_method_name(meth)}'.to_sym
259
+ new_method = '#{meth}_modified'.to_sym
260
+
261
+ alias_method saved_meth_name, original
262
+
263
+ p = Instrumentation.define_callback_method(original, saved_meth_name,
264
+ #{klass})
265
+ define_method(new_method, p)
266
+
267
+ private new_method
268
+
269
+ method_kind = nil
270
+ case
271
+ when public_method_defined?(original)
272
+ method_kind = :public
273
+ when protected_method_defined?(original)
274
+ method_kind = :protected
275
+ when private_method_defined?(original)
276
+ method_kind = :private
277
+ end
278
+ alias_method original, new_method
279
+ send(method_kind, original)
280
+ private saved_meth_name
281
+ end "
282
+ eval str
283
+ end
284
+
285
+ def unoverride_instance_method(obj, meth)
286
+ saved_meth_name = get_saved_method_name(meth)
287
+
288
+ method_kind = nil
289
+ obj.class_eval do
290
+ # Note: As a lambda the following will crash ruby 2.2.3p173
291
+ case
292
+ when public_method_defined?(meth)
293
+ method_kind = :public
294
+ when protected_method_defined?(meth)
295
+ method_kind = :protected
296
+ when private_method_defined?(meth)
297
+ method_kind = :private
298
+ end
299
+ alias_method meth, saved_meth_name
300
+ send(method_kind, meth)
301
+ end
302
+ end
303
+
304
+ def get_saved_method_name(meth)
305
+ "#{meth}_not_modified".to_sym
306
+ end
307
+
308
+ def override_instance_method(klass_name, meth)
309
+ saved_meth_name = get_saved_method_name(meth)
310
+ new_method = "#{meth}_modified".to_sym
311
+
312
+ p = Instrumentation.define_callback_method(meth, saved_meth_name,
313
+ klass_name)
314
+ method_kind = nil
315
+ klass_name.class_eval do
316
+ alias_method saved_meth_name, meth
317
+
318
+ define_method(new_method, p)
319
+
320
+ case
321
+ when public_method_defined?(meth)
322
+ method_kind = :public
323
+ when protected_method_defined?(meth)
324
+ method_kind = :protected
325
+ when private_method_defined?(meth)
326
+ method_kind = :private
327
+ end
328
+ alias_method meth, new_method
329
+ private saved_meth_name
330
+ private new_method
331
+ send(method_kind, meth)
332
+ end
333
+ saved_meth_name
334
+ end
335
+
336
+ # WARNING We do not actually remove `meth`
337
+ def unoverride_class_method(klass, meth)
338
+ saved_meth_name = get_saved_method_name(meth)
339
+
340
+ eval "method_kind = nil; class << #{klass}
341
+ new_method = '#{meth}_modified'.to_sym
342
+ case
343
+ when public_method_defined?(#{meth.to_sym.inspect})
344
+ method_kind = :public
345
+ when protected_method_defined?(original)
346
+ method_kind = :protected
347
+ when private_method_defined?(#{meth.to_sym.inspect})
348
+ method_kind = :private
349
+ end
350
+ alias_method #{meth.to_sym.inspect}, #{saved_meth_name.to_sym.inspect}
351
+ send(method_kind, #{meth.to_sym.inspect})
352
+ end "
353
+ end
354
+
355
+ if RUBY_VERSION < '1.9'
356
+ def adjust_method_name(method)
357
+ method.to_s
358
+ end
359
+ else
360
+ def adjust_method_name(method)
361
+ method
362
+ end
363
+ end
364
+
365
+ def is_instance_method?(klass, method)
366
+ method = adjust_method_name(method)
367
+ klass.instance_methods.include?(method) ||
368
+ klass.private_instance_methods.include?(method)
369
+ end
370
+
371
+ def is_class_method?(klass, method)
372
+ method = adjust_method_name(method)
373
+ klass.singleton_methods.include? method
374
+ end
375
+
376
+ def add_callback(cb)
377
+ @@override_semaphore.synchronize do
378
+ klass = cb.klass
379
+ method = cb.method
380
+ key = [klass, method]
381
+
382
+ already_overriden = @@overriden_methods.include? key
383
+
384
+ if !already_overriden
385
+ if is_class_method?(klass, method)
386
+ Sqreen.log.debug "overriding class method for #{cb}"
387
+ success = override_class_method(klass, method)
388
+ elsif is_instance_method?(klass, method)
389
+ Sqreen.log.debug "overriding instance method for #{cb}"
390
+ success = override_instance_method(klass, method)
391
+ else
392
+ # FIXME: Override define_method and other dynamic ways to
393
+ # The following should be monitored to make sure we
394
+ # don't forget dynamically added methods:
395
+ # - define_method
396
+ # - method_added
397
+ # - method_missing
398
+ # ...
399
+ #
400
+ msg = "#{cb} is neither singleton or instance"
401
+ raise Sqreen::NotImplementedYet, msg
402
+ end
403
+
404
+ @@overriden_methods += [key] if success
405
+ else
406
+ Sqreen.log.debug "#{key} was already overriden"
407
+ end
408
+
409
+ @@registered_callbacks.add(cb)
410
+ end
411
+ end
412
+
413
+ def remove_callback(cb)
414
+ @@override_semaphore.synchronize do
415
+ remove_callback_no_lock(cb)
416
+ end
417
+ end
418
+
419
+ def remove_callback_no_lock(cb)
420
+ klass = cb.klass
421
+ method = cb.method
422
+
423
+ key = [klass, method]
424
+
425
+ already_overriden = @@overriden_methods.include? key
426
+ unless already_overriden
427
+ Sqreen.log.debug "#{key} not overriden, returning"
428
+ return
429
+ end
430
+
431
+ defined_cbs = @@registered_callbacks.get(klass, method)
432
+
433
+ nb_removed = 0
434
+ defined_cbs.each do |found_cb|
435
+ if found_cb == cb
436
+ Sqreen.log.debug "Removing callback #{found_cb}"
437
+ @@registered_callbacks.remove(found_cb)
438
+ nb_removed += 1
439
+ else
440
+ Sqreen.log.debug "Not removing callback #{found_cb} (remains #{defined_cbs.size} cbs)"
441
+ end
442
+ end
443
+
444
+ return unless nb_removed == defined_cbs.size
445
+
446
+ Sqreen.log.debug "Removing overriden method #{key}"
447
+ @@overriden_methods.delete(key)
448
+
449
+ if is_class_method?(klass, method)
450
+ unoverride_class_method(klass, method)
451
+ elsif is_instance_method?(klass, method)
452
+ unoverride_instance_method(klass, method)
453
+ else
454
+ # FIXME: Override define_method and other dynamic ways to
455
+ # The following should be monitored to make sure we
456
+ # don't forget dynamically added methods:
457
+ # - define_method
458
+ # - method_added
459
+ # - method_missing
460
+ # ...
461
+ #
462
+ msg = "#{cb} is neither singleton or instance"
463
+ raise Sqreen::NotImplementedYet, msg
464
+ end
465
+ end
466
+
467
+ def remove_all_callbacks
468
+ @@override_semaphore.synchronize do
469
+ @@registered_callbacks.entries.each do |cb|
470
+ remove_callback_no_lock(cb)
471
+ end
472
+ Sqreen.instrumentation_ready = false
473
+ end
474
+ end
475
+
476
+ attr_accessor :metrics_engine
477
+
478
+ # Instrument the application code using the rules
479
+ # @param rules [Array<Hash>] Rules to instrument
480
+ # @param metrics_engine [MetricsStore] Metric storage facility
481
+ def instrument!(rules, framework)
482
+ verifier = nil
483
+ if Sqreen.features['rules_signature'] &&
484
+ Sqreen.config_get(:rules_verify_signature) &&
485
+ !defined?(::JRUBY_VERSION)
486
+ verifier = Sqreen::RulesSignature.new
487
+ else
488
+ Sqreen.log.debug('Rules signature is not enabled')
489
+ end
490
+ remove_all_callbacks # Force cb tree to be empty before instrumenting
491
+ rules.each do |rule|
492
+ rcb = Sqreen::Rules.cb_from_rule(rule, metrics_engine, verifier)
493
+ next unless rcb
494
+ rcb.framework = framework
495
+ add_callback(rcb)
496
+ end
497
+ Sqreen.instrumentation_ready = true
498
+ end
499
+
500
+ def initialize(metrics_engine = nil)
501
+ self.metrics_engine = metrics_engine
502
+ end
503
+ end
504
+ end