rollbar 2.22.1 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.github/pull_request_template.md +34 -0
  3. data/.github/workflows/ci.yml +104 -0
  4. data/.rubocop.yml +185 -33
  5. data/Gemfile +26 -28
  6. data/README.md +32 -8
  7. data/data/rollbar.snippet.js +1 -1
  8. data/docs/configuration.md +8 -0
  9. data/gemfiles/rails30.gemfile +17 -35
  10. data/gemfiles/rails31.gemfile +20 -37
  11. data/gemfiles/rails32.gemfile +13 -31
  12. data/gemfiles/rails40.gemfile +12 -32
  13. data/gemfiles/rails41.gemfile +11 -31
  14. data/gemfiles/rails42.gemfile +12 -32
  15. data/gemfiles/rails50.gemfile +16 -30
  16. data/gemfiles/rails51.gemfile +16 -30
  17. data/gemfiles/rails52.gemfile +10 -19
  18. data/gemfiles/rails60.gemfile +10 -25
  19. data/gemfiles/rails61.gemfile +52 -0
  20. data/gemfiles/rails70.gemfile +52 -0
  21. data/lib/generators/rollbar/rollbar_generator.rb +18 -14
  22. data/lib/rails/rollbar_runner.rb +11 -20
  23. data/lib/rollbar/capistrano.rb +17 -9
  24. data/lib/rollbar/capistrano3.rb +8 -2
  25. data/lib/rollbar/capistrano_tasks.rb +44 -8
  26. data/lib/rollbar/configuration.rb +138 -84
  27. data/lib/rollbar/delay/girl_friday.rb +3 -7
  28. data/lib/rollbar/delay/resque.rb +2 -3
  29. data/lib/rollbar/delay/shoryuken.rb +4 -3
  30. data/lib/rollbar/delay/sidekiq.rb +5 -5
  31. data/lib/rollbar/delay/sucker_punch.rb +4 -6
  32. data/lib/rollbar/delay/thread.rb +17 -2
  33. data/lib/rollbar/deploy.rb +8 -7
  34. data/lib/rollbar/encoding/encoder.rb +17 -6
  35. data/lib/rollbar/encoding.rb +2 -7
  36. data/lib/rollbar/exception_reporter.rb +17 -8
  37. data/lib/rollbar/item/backtrace.rb +22 -10
  38. data/lib/rollbar/item/frame.rb +8 -5
  39. data/lib/rollbar/item/locals.rb +49 -2
  40. data/lib/rollbar/item.rb +80 -50
  41. data/lib/rollbar/json.rb +2 -1
  42. data/lib/rollbar/language_support.rb +0 -6
  43. data/lib/rollbar/lazy_store.rb +3 -7
  44. data/lib/rollbar/logger.rb +2 -0
  45. data/lib/rollbar/logger_proxy.rb +3 -1
  46. data/lib/rollbar/middleware/js/json_value.rb +15 -5
  47. data/lib/rollbar/middleware/js.rb +70 -38
  48. data/lib/rollbar/middleware/rack/builder.rb +3 -3
  49. data/lib/rollbar/middleware/rack/test_session.rb +3 -3
  50. data/lib/rollbar/middleware/rack.rb +4 -4
  51. data/lib/rollbar/middleware/rails/rollbar.rb +9 -6
  52. data/lib/rollbar/middleware/rails/show_exceptions.rb +8 -4
  53. data/lib/rollbar/notifier/trace_with_bindings.rb +13 -3
  54. data/lib/rollbar/notifier.rb +309 -172
  55. data/lib/rollbar/plugin.rb +8 -8
  56. data/lib/rollbar/plugins/active_job.rb +20 -3
  57. data/lib/rollbar/plugins/delayed_job/plugin.rb +19 -2
  58. data/lib/rollbar/plugins/error_context.rb +11 -0
  59. data/lib/rollbar/plugins/goalie.rb +27 -16
  60. data/lib/rollbar/plugins/rails/controller_methods.rb +18 -14
  61. data/lib/rollbar/plugins/rails/railtie30.rb +2 -1
  62. data/lib/rollbar/plugins/rails/railtie32.rb +2 -1
  63. data/lib/rollbar/plugins/rails/railtie_mixin.rb +2 -2
  64. data/lib/rollbar/plugins/rails.rb +5 -2
  65. data/lib/rollbar/plugins/rake.rb +2 -1
  66. data/lib/rollbar/plugins/sidekiq/plugin.rb +39 -21
  67. data/lib/rollbar/plugins/sidekiq.rb +1 -1
  68. data/lib/rollbar/plugins/thread.rb +8 -7
  69. data/lib/rollbar/plugins/validations.rb +3 -1
  70. data/lib/rollbar/rake_tasks.rb +1 -2
  71. data/lib/rollbar/request_data_extractor.rb +53 -19
  72. data/lib/rollbar/rollbar_test.rb +9 -118
  73. data/lib/rollbar/scrubbers/params.rb +13 -7
  74. data/lib/rollbar/scrubbers/url.rb +56 -17
  75. data/lib/rollbar/scrubbers.rb +2 -6
  76. data/lib/rollbar/truncation/frames_strategy.rb +1 -1
  77. data/lib/rollbar/truncation/mixin.rb +1 -1
  78. data/lib/rollbar/truncation/remove_any_key_strategy.rb +4 -1
  79. data/lib/rollbar/truncation/remove_extra_strategy.rb +3 -1
  80. data/lib/rollbar/truncation/strings_strategy.rb +4 -2
  81. data/lib/rollbar/util/hash.rb +14 -7
  82. data/lib/rollbar/util/ip_anonymizer.rb +1 -1
  83. data/lib/rollbar/util.rb +23 -13
  84. data/lib/rollbar/version.rb +1 -1
  85. data/lib/rollbar.rb +12 -7
  86. data/lib/tasks/benchmark.rake +2 -1
  87. data/rollbar.gemspec +6 -3
  88. data/spec/support/rollbar_api.rb +67 -0
  89. metadata +19 -12
  90. data/.travis.yml +0 -281
  91. data/lib/rollbar/encoding/legacy_encoder.rb +0 -20
  92. /data/lib/generators/rollbar/templates/{initializer.rb → initializer.erb} +0 -0
@@ -10,11 +10,11 @@ module Rollbar
10
10
  class Js
11
11
  include Rollbar::RequestDataExtractor
12
12
 
13
- attr_reader :app
14
- attr_reader :config
13
+ attr_reader :app, :config
15
14
 
16
15
  JS_IS_INJECTED_KEY = 'rollbar.js_is_injected'.freeze
17
- SNIPPET = File.read(File.expand_path('../../../../data/rollbar.snippet.js', __FILE__))
16
+ SNIPPET = File.read(File.expand_path('../../../../data/rollbar.snippet.js',
17
+ __FILE__))
18
18
 
19
19
  def initialize(app, config)
20
20
  @app = app
@@ -30,7 +30,9 @@ module Rollbar
30
30
  response_string = add_js(env, app_result[2])
31
31
  build_response(env, app_result, response_string)
32
32
  rescue StandardError => e
33
- Rollbar.log_error("[Rollbar] Rollbar.js could not be added because #{e} exception")
33
+ Rollbar.log_error(
34
+ "[Rollbar] Rollbar.js could not be added because #{e} exception"
35
+ )
34
36
 
35
37
  app_result
36
38
  end
@@ -58,7 +60,8 @@ module Rollbar
58
60
  def streaming?(env)
59
61
  return false unless defined?(ActionController::Live)
60
62
 
61
- env['action_controller.instance'].class.included_modules.include?(ActionController::Live)
63
+ env['action_controller.instance']
64
+ .class.included_modules.include?(ActionController::Live)
62
65
  end
63
66
 
64
67
  def add_js(env, response)
@@ -72,7 +75,9 @@ module Rollbar
72
75
 
73
76
  build_body_with_js(env, body, insert_after_idx)
74
77
  rescue StandardError => e
75
- Rollbar.log_error("[Rollbar] Rollbar.js could not be added because #{e} exception")
78
+ Rollbar.log_error(
79
+ "[Rollbar] Rollbar.js could not be added because #{e} exception"
80
+ )
76
81
  nil
77
82
  end
78
83
 
@@ -80,10 +85,22 @@ module Rollbar
80
85
  return app_result unless response_string
81
86
 
82
87
  env[JS_IS_INJECTED_KEY] = true
83
- response = ::Rack::Response.new(response_string, app_result[0],
84
- app_result[1])
85
88
 
86
- response.finish
89
+ status, headers, = app_result
90
+ if headers.key?('Content-Length')
91
+ headers['Content-Length'] =
92
+ response_string.bytesize.to_s
93
+ end
94
+
95
+ response = ::Rack::Response.new(response_string, status, headers)
96
+
97
+ finished = response.finish
98
+
99
+ # Rack < 2.x Response#finish returns self in array[2].
100
+ # Rack >= 2.x returns self.body.
101
+ # Always return with the response object here regardless of rack version.
102
+ finished[2] = response
103
+ finished
87
104
  end
88
105
 
89
106
  def build_body_with_js(env, body, head_open_end)
@@ -116,13 +133,16 @@ module Rollbar
116
133
  end
117
134
 
118
135
  def config_js_tag(env)
136
+ require 'json'
137
+ require 'rollbar/middleware/js/json_value'
138
+
119
139
  js_config = Rollbar::Util.deep_copy(config[:options])
120
140
 
121
141
  add_person_data(js_config, env)
122
142
 
123
143
  # MUST use the Ruby JSON encoder (JSON#generate).
124
144
  # See lib/rollbar/middleware/js/json_value
125
- json = ::JSON.generate(js_config)
145
+ json = ::JSON.generate(js_config, Rollbar::JSON::JsOptionsState.new)
126
146
 
127
147
  script_tag("var _rollbarConfig = #{json};", env)
128
148
  end
@@ -145,14 +165,12 @@ module Rollbar
145
165
  end
146
166
 
147
167
  def script_tag(content, env)
148
- if (nonce = rails5_nonce(env))
149
- script_tag_content = "\n<script type=\"text/javascript\" nonce=\"#{nonce}\">#{content}</script>"
150
- elsif secure_headers_nonce?
151
- nonce = ::SecureHeaders.content_security_policy_script_nonce(::Rack::Request.new(env))
152
- script_tag_content = "\n<script type=\"text/javascript\" nonce=\"#{nonce}\">#{content}</script>"
153
- else
154
- script_tag_content = "\n<script type=\"text/javascript\">#{content}</script>"
155
- end
168
+ nonce = rails5_nonce(env) || secure_headers_nonce(env)
169
+ script_tag_content = if nonce
170
+ "\n<script nonce=\"#{nonce}\">#{content}</script>"
171
+ else
172
+ "\n<script>#{content}</script>"
173
+ end
156
174
 
157
175
  html_safe_if_needed(script_tag_content)
158
176
  end
@@ -162,34 +180,46 @@ module Rollbar
162
180
  string
163
181
  end
164
182
 
165
- # Rails 5.2 Secure Content Policy
183
+ # Rails 5.2+ Secure Content Policy
166
184
  def rails5_nonce(env)
167
- # The nonce is the preferred method, however 'unsafe-inline' is also possible.
168
- # The app gets to decide, so we handle both. If the script_src key is missing,
169
- # Rails will not add the nonce to the headers, so we should not add it either.
170
- # If the 'unsafe-inline' value is present, the app should not add a nonce and
171
- # we should ignore it if they do.
172
- req = ::ActionDispatch::Request.new env
185
+ req = ::ActionDispatch::Request.new(env)
186
+
187
+ # Rails will only return a nonce if the app has set a nonce generator.
188
+ # So if we get a valid nonce here, we know we should use it.
189
+ #
190
+ # Having both 'unsafe-inline' and a nonce is a valid and preferred
191
+ # browser compatibility configuration.
192
+ #
193
+ # If the script_src key is missing, Rails will not add the nonce to the headers,
194
+ # so we detect this and will not add it in this case.
173
195
  req.respond_to?(:content_security_policy) &&
174
196
  req.content_security_policy &&
175
197
  req.content_security_policy.directives['script-src'] &&
176
- !req.content_security_policy.directives['script-src'].include?("'unsafe-inline'") &&
177
198
  req.content_security_policy_nonce
178
199
  end
179
200
 
180
201
  # Secure Headers gem
181
- def secure_headers_nonce?
182
- secure_headers.append_nonce?
202
+ def secure_headers_nonce(env)
203
+ req = ::Rack::Request.new(env)
204
+
205
+ return unless secure_headers(req).append_nonce?
206
+
207
+ ::SecureHeaders.content_security_policy_script_nonce(req)
183
208
  end
184
209
 
185
- def secure_headers
210
+ def secure_headers(req)
186
211
  return SecureHeadersFalse.new unless defined?(::SecureHeaders::Configuration)
187
212
 
188
- config = ::SecureHeaders::Configuration
213
+ # If the nonce key has been set, the app is using nonces for this request.
214
+ # If it hasn't, we shouldn't cause one to be added to script_src, so return now.
215
+ return SecureHeadersFalse.new unless secure_headers_nonce_key(req)
189
216
 
190
- secure_headers_cls = nil
217
+ config = ::SecureHeaders::Configuration
191
218
 
192
- secure_headers_cls = if !::SecureHeaders.respond_to?(:content_security_policy_script_nonce)
219
+ has_nonce = ::SecureHeaders.respond_to?(
220
+ :content_security_policy_script_nonce
221
+ )
222
+ secure_headers_cls = if !has_nonce
193
223
  SecureHeadersFalse
194
224
  elsif config.respond_to?(:get)
195
225
  SecureHeaders3To5
@@ -202,6 +232,11 @@ module Rollbar
202
232
  secure_headers_cls.new
203
233
  end
204
234
 
235
+ def secure_headers_nonce_key(req)
236
+ defined?(::SecureHeaders::NONCE_KEY) &&
237
+ req.env[::SecureHeaders::NONCE_KEY]
238
+ end
239
+
205
240
  class SecureHeadersResolver
206
241
  def append_nonce?
207
242
  csp_needs_nonce?(find_csp)
@@ -214,16 +249,12 @@ module Rollbar
214
249
  end
215
250
 
216
251
  def csp_needs_nonce?(csp)
217
- !opt_out?(csp) && !unsafe_inline?(csp)
252
+ !opt_out?(csp)
218
253
  end
219
254
 
220
255
  def opt_out?(_csp)
221
256
  raise NotImplementedError
222
257
  end
223
-
224
- def unsafe_inline?(csp)
225
- csp[:script_src].to_a.include?("'unsafe-inline'")
226
- end
227
258
  end
228
259
 
229
260
  class SecureHeadersFalse < SecureHeadersResolver
@@ -243,7 +274,8 @@ module Rollbar
243
274
  if csp.respond_to?(:opt_out?) && csp.opt_out?
244
275
  csp.opt_out?
245
276
  # secure_headers csp 3.0.x-3.4.x doesn't respond to 'opt_out?'
246
- elsif defined?(::SecureHeaders::OPT_OUT) && ::SecureHeaders::OPT_OUT.is_a?(Symbol)
277
+ elsif defined?(::SecureHeaders::OPT_OUT) &&
278
+ ::SecureHeaders::OPT_OUT.is_a?(Symbol)
247
279
  csp == ::SecureHeaders::OPT_OUT
248
280
  end
249
281
  end
@@ -14,8 +14,8 @@ module Rollbar
14
14
  Rollbar.scoped(fetch_scope(env)) do
15
15
  begin
16
16
  call_without_rollbar(env)
17
- rescue ::Exception => exception
18
- report_exception_to_rollbar(env, exception)
17
+ rescue ::Exception => e # rubocop:disable Lint/RescueException
18
+ report_exception_to_rollbar(env, e)
19
19
  raise
20
20
  end
21
21
  end
@@ -26,7 +26,7 @@ module Rollbar
26
26
  :request => proc { extract_request_data_from_rack(env) },
27
27
  :person => person_data_proc(env)
28
28
  }
29
- rescue Exception => e
29
+ rescue Exception => e # rubocop:disable Lint/RescueException
30
30
  report_exception_to_rollbar(env, e)
31
31
  raise
32
32
  end
@@ -6,9 +6,9 @@ module Rollbar
6
6
 
7
7
  def env_for_with_rollbar(path, env)
8
8
  env_for_without_rollbar(path, env)
9
- rescue Exception => exception
10
- report_exception_to_rollbar(env, exception)
11
- raise exception
9
+ rescue Exception => e # rubocop:disable Lint/RescueException
10
+ report_exception_to_rollbar(env, e)
11
+ raise e
12
12
  end
13
13
 
14
14
  def self.included(base)
@@ -21,7 +21,7 @@ module Rollbar
21
21
  response = @app.call(env)
22
22
  report_exception_to_rollbar(env, framework_error(env)) if framework_error(env)
23
23
  response
24
- rescue Exception => e
24
+ rescue Exception => e # rubocop:disable Lint/RescueException
25
25
  report_exception_to_rollbar(env, e)
26
26
  raise
27
27
  ensure
@@ -35,7 +35,7 @@ module Rollbar
35
35
  :request => proc { extract_request_data_from_rack(env) },
36
36
  :person => person_data_proc(env)
37
37
  }
38
- rescue Exception => e
38
+ rescue Exception => e # rubocop:disable Lint/RescueException
39
39
  report_exception_to_rollbar(env, e)
40
40
  raise
41
41
  end
@@ -44,8 +44,8 @@ module Rollbar
44
44
  proc { extract_person_data_from_controller(env) }
45
45
  end
46
46
 
47
- def framework_error(_env)
48
- nil
47
+ def framework_error(env)
48
+ env['rack.exception']
49
49
  end
50
50
  end
51
51
  end
@@ -29,8 +29,8 @@ module Rollbar
29
29
  end
30
30
 
31
31
  response
32
- rescue Exception => exception
33
- report_exception_to_rollbar(env, exception)
32
+ rescue Exception => e # rubocop:disable Lint/RescueException
33
+ report_exception_to_rollbar(env, e)
34
34
  raise
35
35
  ensure
36
36
  Rollbar.notifier.disable_locals
@@ -63,7 +63,9 @@ module Rollbar
63
63
 
64
64
  def person_data_proc(env)
65
65
  block = proc { extract_person_data_from_controller(env) }
66
- return block unless defined?(ActiveRecord::Base) && ActiveRecord::Base.connected?
66
+ unless defined?(ActiveRecord::Base) && ActiveRecord::Base.connected?
67
+ return block
68
+ end
67
69
 
68
70
  proc do
69
71
  begin
@@ -75,11 +77,12 @@ module Rollbar
75
77
  end
76
78
 
77
79
  def context(request_data)
78
- return unless request_data[:params]
79
-
80
80
  route_params = request_data[:params]
81
+
81
82
  # make sure route is a hash built by RequestDataExtractor
82
- return route_params[:controller].to_s + '#' + route_params[:action].to_s if route_params.is_a?(Hash) && !route_params.empty?
83
+ return unless route_params.is_a?(Hash) && !route_params.empty?
84
+
85
+ "#{route_params[:controller]}##{route_params[:action]}"
83
86
  end
84
87
  end
85
88
  end
@@ -20,20 +20,24 @@ module Rollbar
20
20
 
21
21
  def call_with_rollbar(env)
22
22
  call_without_rollbar(env)
23
- rescue ActionController::RoutingError => exception
23
+ rescue ActionController::RoutingError => e
24
24
  # won't reach here if show_detailed_exceptions is true
25
25
  scope = extract_scope_from(env)
26
26
 
27
27
  Rollbar.scoped(scope) do
28
- report_exception_to_rollbar(env, exception)
28
+ report_exception_to_rollbar(env, e)
29
29
  end
30
30
 
31
- raise exception
31
+ raise e
32
32
  end
33
33
 
34
34
  def extract_scope_from(env)
35
35
  scope = env['rollbar.scope']
36
- Rollbar.log_warn('[Rollbar] rollbar.scope key has been removed from Rack env.') unless scope
36
+ unless scope
37
+ Rollbar.log_warn(
38
+ '[Rollbar] rollbar.scope key has been removed from Rack env.'
39
+ )
40
+ end
37
41
 
38
42
  scope || {}
39
43
  end
@@ -36,7 +36,8 @@ module Rollbar
36
36
  def trace_point
37
37
  return unless defined?(TracePoint)
38
38
 
39
- @trace_point ||= TracePoint.new(:call, :return, :b_call, :b_return, :c_call, :c_return, :raise) do |tp|
39
+ @trace_point ||= TracePoint.new(:call, :return, :b_call, :b_return, :c_call,
40
+ :c_return, :raise) do |tp|
40
41
  case tp.event
41
42
  when :call, :b_call, :c_call, :class
42
43
  frames.push frame(tp)
@@ -44,7 +45,8 @@ module Rollbar
44
45
  frames.pop
45
46
  when :raise
46
47
  unless detect_reraise(tp) # ignore reraised exceptions
47
- @exception_frames = @frames.dup # may be possible to optimize better than #dup
48
+ # may be possible to optimize better than #dup
49
+ @exception_frames = @frames.dup
48
50
  @exception_signature = exception_signature(tp)
49
51
  end
50
52
  end
@@ -53,13 +55,21 @@ module Rollbar
53
55
 
54
56
  def frame(trace)
55
57
  {
56
- :binding => trace.binding,
58
+ :binding => binding(trace),
57
59
  :defined_class => trace.defined_class,
58
60
  :method_id => trace.method_id,
59
61
  :path => trace.path,
60
62
  :lineno => trace.lineno
61
63
  }
62
64
  end
65
+
66
+ def binding(trace)
67
+ trace.binding
68
+ rescue StandardError
69
+ # Ruby internals will raise if we're on a Fiber,
70
+ # since bindings aren't valid on Fibers.
71
+ nil
72
+ end
63
73
  end
64
74
  end
65
75
  end