sqreen 1.17.0-java → 1.17.2.beta1-java

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.
@@ -0,0 +1,37 @@
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/version'
5
+ require 'sqreen/instrumentation'
6
+ require 'sqreen/session'
7
+ require 'sqreen/runner'
8
+ require 'sqreen/callbacks'
9
+ require 'sqreen/log'
10
+ require 'sqreen/exception'
11
+ require 'sqreen/configuration'
12
+ require 'sqreen/events/attack'
13
+ require 'sqreen/sdk'
14
+ require 'sqreen/dependency/detector'
15
+ require 'sqreen/worker'
16
+ require 'sqreen/web_server'
17
+
18
+ module Sqreen
19
+ module Agent
20
+ module_function
21
+
22
+ def start
23
+ return if Sqreen.to_bool(ENV['SQREEN_DISABLE'])
24
+
25
+ Sqreen::Dependency::Detector.hook do
26
+ Sqreen.log.debug "[#{Process.pid}] Attaching to webserver"
27
+ Sqreen::WebServer.attach do
28
+ Sqreen.log.debug "[#{Process.pid}] Attached to webserver"
29
+ # TODO: maybe in dependency, not here, to separate concerns?
30
+ Sqreen::Dependency::Sentry.ignore_sqreen_exceptions
31
+ Sqreen::Dependency::NewRelic.ignore_sqreen_exceptions
32
+ Sqreen::Worker.start(Sqreen.framework)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -33,20 +33,20 @@ module Sqreen
33
33
  FAILING = 'failing'.freeze
34
34
  COUNT_CALLS = 'sqreen_call_counts'.freeze
35
35
 
36
- def pre_with_count(inst, *args, &block)
37
- ret = pre_without_count(inst, *args, &block)
36
+ def pre_with_count(inst, args, budget = nil, &block)
37
+ ret = pre_without_count(inst, args, budget, &block)
38
38
  count_calls('pre')
39
39
  ret
40
40
  end
41
41
 
42
- def post_with_count(rv, inst, *args, &block)
43
- ret = post_without_count(rv, inst, *args, &block)
42
+ def post_with_count(rv, inst, args, budget = nil, &block)
43
+ ret = post_without_count(rv, inst, args, budget, &block)
44
44
  count_calls('post')
45
45
  ret
46
46
  end
47
47
 
48
- def failing_with_count(rv, inst, *args, &block)
49
- ret = failing_without_count(rv, inst, *args, &block)
48
+ def failing_with_count(rv, inst, args, budget = nil, &block)
49
+ ret = failing_without_count(rv, inst, args, budget, &block)
50
50
  count_calls('failing')
51
51
  ret
52
52
  end
@@ -25,22 +25,22 @@ module Sqreen
25
25
  end
26
26
  end
27
27
 
28
- def pre_with_conditions(inst, *args, &block)
28
+ def pre_with_conditions(inst, args, budget = nil, &block)
29
29
  eargs = [nil, framework, inst, args, @data, nil]
30
30
  return nil if !pre_conditions.nil? && !pre_conditions.evaluate(*eargs)
31
- pre_without_conditions(inst, *args, &block)
31
+ pre_without_conditions(inst, args, budget, &block)
32
32
  end
33
33
 
34
- def post_with_conditions(rv, inst, *args, &block)
34
+ def post_with_conditions(rv, inst, args, budget = nil, &block)
35
35
  eargs = [nil, framework, inst, args, @data, rv]
36
36
  return nil if !post_conditions.nil? && !post_conditions.evaluate(*eargs)
37
- post_without_conditions(rv, inst, *args, &block)
37
+ post_without_conditions(rv, inst, args, budget, &block)
38
38
  end
39
39
 
40
- def failing_with_conditions(rv, inst, *args, &block)
40
+ def failing_with_conditions(rv, inst, args, budget = nil, &block)
41
41
  eargs = [nil, framework, inst, args, @data, rv]
42
42
  return nil if !failing_conditions.nil? && !failing_conditions.evaluate(*eargs)
43
- failing_without_conditions(rv, inst, *args, &block)
43
+ failing_without_conditions(rv, inst, args, budget, &block)
44
44
  end
45
45
 
46
46
  protected
@@ -0,0 +1,18 @@
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
+ module Sqreen
5
+ module Dependency
6
+ def self.const_exist?(name)
7
+ resolve_const(name) && true
8
+ rescue NameError, ArgumentError
9
+ false
10
+ end
11
+
12
+ def self.resolve_const(name)
13
+ raise ArgumentError if name.nil? || name.empty?
14
+
15
+ name.to_s.split('::').inject(Object) { |a, e| a.const_get(e) }
16
+ end
17
+ end
18
+ 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
+ module Sqreen
5
+ module Dependency
6
+ class Callback
7
+ attr_reader :name
8
+
9
+ def initialize(name = nil, &block)
10
+ @name = name
11
+ @block = block
12
+ @disabled = false
13
+ end
14
+
15
+ def call(*args, &block)
16
+ Sqreen.log.debug "[#{Process.pid}] Callback #{@name} disabled:#{disabled?}"
17
+ return if @disabled
18
+ @block.call(*args, &block)
19
+ end
20
+
21
+ def disable
22
+ @disabled = true
23
+ end
24
+
25
+ def enable
26
+ @disabled = false
27
+ end
28
+
29
+ def disabled?
30
+ @disabled
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,97 @@
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/dependency/hook'
5
+ require 'sqreen/dependency/rails'
6
+ require 'sqreen/dependency/rack'
7
+ require 'sqreen/dependency/sentry'
8
+ require 'sqreen/dependency/new_relic'
9
+
10
+ module Sqreen
11
+ module Dependency
12
+ module Detector
13
+ module_function
14
+
15
+ def start_mode
16
+ if Sqreen::Dependency::Rails.server?
17
+ :rails
18
+ elsif Sqreen::Dependency::Rack.rackup?
19
+ :rackup
20
+ else
21
+ :default
22
+ end
23
+ end
24
+
25
+ def hook(&block)
26
+ Sqreen.log.debug "[#{Process.pid}] Startup command: #{$0}"
27
+
28
+ # ensure middleware presence
29
+
30
+ ActiveSupport.on_load(:before_initialize, :yield => true) do
31
+ Sqreen::Dependency::Rails.insert_sqreen_middlewares
32
+ end if Sqreen::Dependency::Rails.required?
33
+
34
+ Sqreen::Dependency::Hook.add('Rack::Builder#to_app') do
35
+ after do
36
+ Sqreen::Dependency::Rails.inspect_middlewares
37
+ end
38
+ end if Sqreen::Dependency::Rails.required?
39
+
40
+ # ensure startup of thread in request handling processes
41
+
42
+ Sqreen::Dependency::Hook.add('Rack::Builder#to_app') do
43
+ after do |callback, *|
44
+ Sqreen.log.debug "[#{Process.pid}] Start mode #{Sqreen::Dependency::Detector.start_mode}"
45
+ if Sqreen::Dependency::Detector.start_mode == :rails || Sqreen::Dependency::Detector.start_mode == :rackup
46
+
47
+ Sqreen::Dependency::Rack.find_handler do |handler|
48
+ Sqreen::Dependency::Rack.on_run(handler) do
49
+ case handler.name
50
+ when 'Rack::Handler::Puma'
51
+ Sqreen::Dependency::Hook.add('Puma::Launcher#run') do
52
+ before do
53
+ # HACK: Puma master? hack falls apart when not preloading
54
+ # it would think master is not, triggering startup
55
+ Sqreen::WebServer.instance_eval { @master_pid = Process.pid }
56
+ block.call
57
+ # HACK: because to_app callback is disabled, so won't run again in fork
58
+ if Sqreen::WebServer.forking? && !Sqreen::WebServer.preload_app?
59
+ Sqreen::WebServer.after_fork { block.call }
60
+ end
61
+ end
62
+ end
63
+ Sqreen::Dependency::Hook['Puma::Launcher#run'].install
64
+ when 'Rack::Handler::PhusionPassenger'
65
+ # noop, passenger will start his own separate process
66
+ Sqreen.log.debug "[#{Process.pid}] Passenger will start in standalone process"
67
+ when 'Rack::Handler::Unicorn' # unicorn-rails
68
+ Sqreen::Dependency::Hook.add('Unicorn::HttpServer.new') do
69
+ before do
70
+ # BUG: detects single process...
71
+ end
72
+ end.install
73
+ else
74
+ block.call
75
+ end
76
+ end
77
+ end
78
+ else
79
+ block.call
80
+ end
81
+
82
+ # #to_app can be called multiple times, run callback once only
83
+ callback.disable
84
+ end
85
+ end
86
+
87
+ Sqreen::Dependency::Hook['Rack::Builder#to_app'].install
88
+
89
+ # Sqreen::Dependency::Hook.add('Rails::Server#start') do
90
+ # before { }
91
+ # end
92
+ # Sqreen::Dependency::Hook['Rails::Server#start'].install
93
+ # /!\ double instrument Rails < Rack => Rails.start_with -> Rails.start_without -> super -> Rack.start_with -> Rails.start_without
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,102 @@
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/dependency/callback'
5
+ require 'sqreen/dependency/hook_point'
6
+
7
+ module Sqreen
8
+ module Dependency
9
+ class Hook
10
+ @hooks = {}
11
+
12
+ def self.[](hook_point)
13
+ @hooks[hook_point] ||= new(hook_point)
14
+ end
15
+
16
+ def self.add(hook_point, &block)
17
+ self[hook_point].add(&block)
18
+ end
19
+
20
+ attr_reader :point
21
+
22
+ def initialize(hook_point, dependency_test = nil)
23
+ @disabled = false
24
+ @point = hook_point.is_a?(HookPoint) ? hook_point : HookPoint.new(hook_point)
25
+ @before = []
26
+ @after = []
27
+ @raised = []
28
+ @dependency_test = dependency_test || Proc.new { point.exist? }
29
+ end
30
+
31
+ def dependency?
32
+ @dependency_test.call if @dependency_test
33
+ end
34
+
35
+ def add(&block)
36
+ tap { instance_eval(&block) }
37
+ end
38
+
39
+ def callback_name(whence, tag = nil)
40
+ "#{point}@#{whence}" << (tag ? ":#{tag}" : "")
41
+ end
42
+
43
+ def before(tag = nil, &block)
44
+ return @before if block.nil?
45
+
46
+ @before << Callback.new(callback_name(:before, tag), &block)
47
+ end
48
+
49
+ def after(tag = nil, &block)
50
+ return @after if block.nil?
51
+
52
+ @after << Callback.new(callback_name(:after, tag), &block)
53
+ end
54
+
55
+ def raised(tag = nil, &block)
56
+ return @raised if block.nil?
57
+
58
+ @raised << Callback.new(callback_name(:raised, tag), &block)
59
+ end
60
+
61
+ def depends_on(&block)
62
+ @dependency_test = block
63
+ end
64
+
65
+ def enable
66
+ @disabled = false
67
+ end
68
+
69
+ def disable
70
+ @disabled = true
71
+ end
72
+
73
+ def disabled?
74
+ @disabled
75
+ end
76
+
77
+ def install
78
+ unless point.exist?
79
+ Sqreen.log.debug "[#{Process.pid}] #{point} not found"
80
+ return
81
+ end
82
+ Sqreen.log.debug "[#{Process.pid}] Hook #{point}: installing"
83
+
84
+ point.install('sqreen_hook', &Sqreen::Dependency::Hook.wrapper(self))
85
+ end
86
+
87
+ def self.wrapper(hook)
88
+ # pass self to cbs
89
+ Proc.new do |*args, &block|
90
+ Sqreen.log.debug "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} caller:#{Kernel.caller[1].inspect}"
91
+ hook.before.each { |c| c.call(c, self, args) } unless hook.disabled?
92
+ begin
93
+ hook.point.apply(self, 'sqreen_hook', *args, &block)
94
+ rescue ::Exception => e # rubocop:disable Lint/RescueException
95
+ hook.raised.each { |c| c.call(c, self, e, args) } unless hook.disabled?
96
+ raise
97
+ end.tap { |v| hook.after.each { |c| c.call(c, self, v, args) } unless hook.disabled? }
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,219 @@
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/dependency'
5
+
6
+ module Sqreen
7
+ module Dependency
8
+ class HookPointError < StandardError; end
9
+
10
+ class HookPoint
11
+ def self.parse(hook_point)
12
+ klass_name, separator, method_name = hook_point.split(/(\#|\.)/, 2)
13
+
14
+ raise ArgumentError, hook_point if klass_name.nil? || separator.nil? || method_name.nil?
15
+ raise ArgumentError, hook_point unless ['.', '#'].include?(separator)
16
+
17
+ method_kind = separator == '.' ? :klass_method : :instance_method
18
+
19
+ [klass_name.to_sym, method_kind, method_name.to_sym]
20
+ end
21
+
22
+ attr_reader :klass_name, :method_kind, :method_name
23
+
24
+ def initialize(hook_point)
25
+ @klass_name, @method_kind, @method_name = Sqreen::Dependency::HookPoint.parse(hook_point)
26
+ end
27
+
28
+ def to_s
29
+ "#{@klass_name}#{@method_kind == :instance_method ? '#' : '.'}#{@method_name}"
30
+ end
31
+
32
+ def exist?
33
+ return false unless Sqreen::Dependency.const_exist?(@klass_name)
34
+
35
+ if klass_method?
36
+ (klass.methods + klass.protected_methods + klass.private_methods).include?(@method_name)
37
+ elsif instance_method?
38
+ (klass.instance_methods + klass.protected_instance_methods + klass.private_instance_methods).include?(@method_name)
39
+ else
40
+ raise HookPointError, 'unknown hook point kind'
41
+ end
42
+ end
43
+
44
+ def klass
45
+ Sqreen::Dependency.resolve_const(@klass_name)
46
+ end
47
+
48
+ def klass_method?
49
+ @method_kind == :klass_method
50
+ end
51
+
52
+ def private_method?
53
+ if klass_method?
54
+ klass.private_methods.include?(@method_name)
55
+ elsif instance_method?
56
+ klass.private_instance_methods.include?(@method_name)
57
+ else
58
+ raise HookPointError, 'unknown hook point kind'
59
+ end
60
+ end
61
+
62
+ def protected_method?
63
+ if klass_method?
64
+ klass.protected_methods.include?(@method_name)
65
+ elsif instance_method?
66
+ klass.protected_instance_methods.include?(@method_name)
67
+ else
68
+ raise HookPointError, 'unknown hook point kind'
69
+ end
70
+ end
71
+
72
+ def instance_method?
73
+ @method_kind == :instance_method
74
+ end
75
+
76
+ def installed?(suffix)
77
+ if klass_method?
78
+ (klass.methods + klass.protected_methods + klass.private_methods).include?(:"#{method_name}_with_#{suffix}")
79
+ elsif instance_method?
80
+ (klass.instance_methods + klass.protected_instance_methods + klass.private_instance_methods).include?(:"#{method_name}_with_#{suffix}")
81
+ else
82
+ raise HookPointError, 'unknown hook point kind'
83
+ end
84
+ end
85
+
86
+ def apply(obj, suffix, *args, &block)
87
+ obj.send("#{method_name}_without_#{suffix}", *args, &block)
88
+ end
89
+
90
+ def install(suffix, &block)
91
+ if installed?(suffix)
92
+ Sqreen.log.debug "[#{Process.pid}] #{self} already installed"
93
+ end
94
+ unless exist?
95
+ Sqreen.log.debug "[#{Process.pid}] #{self} hook point not found"
96
+ end
97
+
98
+ define(suffix, &block)
99
+ enable(suffix)
100
+ end
101
+
102
+ def uninstall(suffix)
103
+ disable(suffix)
104
+ remove(suffix)
105
+ end
106
+
107
+ def enable(suffix)
108
+ chain(suffix)
109
+ end
110
+
111
+ def disable(suffix)
112
+ unchain(suffix)
113
+ end
114
+
115
+ def disabled?(suffix)
116
+ !chained?(suffix)
117
+ end
118
+
119
+ private
120
+
121
+ def define(suffix, &block)
122
+ hook_point = self
123
+ method_name = @method_name
124
+
125
+ if klass_method?
126
+ klass.singleton_class.instance_eval do
127
+ if hook_point.protected_method?
128
+ private
129
+ elsif hook_point.protected_method?
130
+ protected
131
+ else
132
+ public
133
+ end
134
+
135
+ define_method(:"#{method_name}_with_#{suffix}", &block)
136
+ end
137
+ elsif instance_method?
138
+ klass.class_eval do
139
+ if hook_point.protected_method?
140
+ private
141
+ elsif hook_point.protected_method?
142
+ protected
143
+ else
144
+ public
145
+ end
146
+
147
+ define_method(:"#{method_name}_with_#{suffix}", &block)
148
+ end
149
+ else
150
+ raise HookPointError, 'unknown hook point kind'
151
+ end
152
+ end
153
+
154
+ def remove(suffix)
155
+ method_name = @method_name
156
+
157
+ if klass_method?
158
+ klass.singleton_class.instance_eval do
159
+ remove_method(:"#{method_name}_with_#{suffix}")
160
+ end
161
+ elsif instance_method?
162
+ klass.class_eval do
163
+ remove_method(:"#{method_name}_with_#{suffix}")
164
+ end
165
+ else
166
+ raise HookPointError, 'unknown hook point kind'
167
+ end
168
+ end
169
+
170
+ def chained?(suffix)
171
+ method_name = @method_name
172
+
173
+ if klass_method?
174
+ klass.singleton_class.instance_eval do
175
+ instance_method(:"#{method_name}").original_name == :"#{method_name}_with_#{suffix}"
176
+ end
177
+ elsif instance_method?
178
+ klass.class_eval do
179
+ instance_method(:"#{method_name}").original_name == :"#{method_name}_with_#{suffix}"
180
+ end
181
+ else
182
+ raise HookPointError, 'unknown hook point kind'
183
+ end
184
+ end
185
+
186
+ def chain(suffix)
187
+ method_name = @method_name
188
+
189
+ if klass_method?
190
+ klass.singleton_class.instance_eval do
191
+ alias_method :"#{method_name}_without_#{suffix}", :"#{method_name}"
192
+ alias_method :"#{method_name}", :"#{method_name}_with_#{suffix}"
193
+ end
194
+ elsif instance_method?
195
+ klass.class_eval do
196
+ alias_method :"#{method_name}_without_#{suffix}", :"#{method_name}"
197
+ alias_method :"#{method_name}", :"#{method_name}_with_#{suffix}"
198
+ end
199
+ else
200
+ raise HookPointError, 'unknown hook point kind'
201
+ end
202
+ end
203
+
204
+ def unchain(suffix)
205
+ method_name = @method_name
206
+
207
+ if klass_method?
208
+ klass.singleton_class.instance_eval do
209
+ alias_method :"#{method_name}", :"#{method_name}_without_#{suffix}"
210
+ end
211
+ elsif instance_method?
212
+ klass.class_eval do
213
+ alias_method :"#{method_name}", :"#{method_name}_without_#{suffix}"
214
+ end
215
+ end
216
+ end
217
+ end
218
+ end
219
+ end