bugsnag 6.12.0 → 6.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.buildkite/pipeline.yml +470 -0
  3. data/.rubocop.yml +55 -0
  4. data/.rubocop_todo.yml +530 -160
  5. data/CHANGELOG.md +67 -0
  6. data/CONTRIBUTING.md +1 -9
  7. data/Gemfile +14 -7
  8. data/TESTING.md +81 -0
  9. data/VERSION +1 -1
  10. data/docker-compose.yml +46 -0
  11. data/dockerfiles/Dockerfile.jruby-unit-tests +13 -0
  12. data/dockerfiles/Dockerfile.ruby-maze-runner +26 -0
  13. data/dockerfiles/Dockerfile.ruby-unit-tests +12 -0
  14. data/features/delayed_job.feature +6 -22
  15. data/features/fixtures/delayed_job/Dockerfile +2 -4
  16. data/features/fixtures/delayed_job/app/Gemfile +1 -1
  17. data/features/fixtures/delayed_job/app/Rakefile +18 -0
  18. data/features/fixtures/docker-compose.yml +28 -40
  19. data/features/fixtures/expected_breadcrumbs/active_job.json +9 -0
  20. data/features/fixtures/expected_breadcrumbs/mongo_failed.json +15 -0
  21. data/features/fixtures/expected_breadcrumbs/mongo_filtered_request.json +15 -0
  22. data/features/fixtures/expected_breadcrumbs/mongo_filtered_result.json +15 -0
  23. data/features/fixtures/expected_breadcrumbs/mongo_success.json +14 -0
  24. data/features/fixtures/expected_breadcrumbs/request.json +13 -0
  25. data/features/fixtures/expected_breadcrumbs/sql_with_bindings.json +12 -0
  26. data/features/fixtures/expected_breadcrumbs/sql_without_bindings.json +11 -0
  27. data/features/fixtures/plain/Dockerfile +2 -2
  28. data/features/fixtures/plain/app/app.rb +1 -3
  29. data/features/fixtures/plain/app/delivery/fork_threadpool.rb +3 -1
  30. data/features/fixtures/plain/app/unhandled/{Interrupt.rb → interrupt.rb} +0 -0
  31. data/features/fixtures/rack1/Dockerfile +2 -2
  32. data/features/fixtures/rack2/Dockerfile +2 -2
  33. data/features/fixtures/rails3/Dockerfile +2 -2
  34. data/features/fixtures/rails3/app/Gemfile +4 -0
  35. data/features/fixtures/rails3/app/config/initializers/bugsnag.rb +3 -2
  36. data/features/fixtures/rails4/Dockerfile +2 -5
  37. data/features/fixtures/rails4/app/config/initializers/bugsnag.rb +2 -1
  38. data/features/fixtures/rails5/Dockerfile +2 -2
  39. data/features/fixtures/rails5/app/Gemfile +3 -2
  40. data/features/fixtures/rails5/app/config/initializers/bugsnag.rb +2 -1
  41. data/features/fixtures/rails6/Dockerfile +2 -2
  42. data/features/fixtures/rails6/app/Gemfile +3 -2
  43. data/features/fixtures/rails6/app/app/controllers/mongo_controller.rb +22 -0
  44. data/features/fixtures/rails6/app/app/models/mongo_model.rb +6 -0
  45. data/features/fixtures/rails6/app/config/environments/development.rb +2 -0
  46. data/features/fixtures/rails6/app/config/environments/production.rb +1 -0
  47. data/features/fixtures/rails6/app/config/environments/rails_env.rb +1 -0
  48. data/features/fixtures/rails6/app/config/environments/test.rb +1 -0
  49. data/features/fixtures/rails6/app/config/initializers/bugsnag.rb +2 -1
  50. data/features/fixtures/rails6/app/config/mongoid.yml +23 -0
  51. data/features/fixtures/rails6/app/config/routes.rb +4 -0
  52. data/features/fixtures/resque/Dockerfile +2 -2
  53. data/features/fixtures/sidekiq/Dockerfile +5 -7
  54. data/features/fixtures/sidekiq/app/Gemfile +2 -1
  55. data/features/fixtures/sidekiq/app/Rakefile.rb +14 -0
  56. data/features/fixtures/sinatra1/Dockerfile +2 -2
  57. data/features/fixtures/sinatra2/Dockerfile +2 -2
  58. data/features/plain_features/add_tab.feature +24 -97
  59. data/features/plain_features/app_type.feature +6 -25
  60. data/features/plain_features/app_version.feature +6 -25
  61. data/features/plain_features/auto_notify.feature +4 -20
  62. data/features/plain_features/delivery.feature +12 -60
  63. data/features/plain_features/exception_data.feature +24 -94
  64. data/features/plain_features/filters.feature +9 -43
  65. data/features/plain_features/handled_errors.feature +16 -78
  66. data/features/plain_features/ignore_classes.feature +5 -23
  67. data/features/plain_features/ignore_report.feature +6 -24
  68. data/features/plain_features/proxies.feature +13 -56
  69. data/features/plain_features/release_stages.feature +9 -40
  70. data/features/plain_features/report_api_key.feature +9 -35
  71. data/features/plain_features/report_severity.feature +8 -35
  72. data/features/plain_features/report_stack_frames.feature +24 -92
  73. data/features/plain_features/report_user.feature +23 -96
  74. data/features/plain_features/unhandled_errors.feature +17 -88
  75. data/features/rails_features/api_key.feature +12 -58
  76. data/features/rails_features/app_type.feature +13 -58
  77. data/features/rails_features/app_version.feature +19 -80
  78. data/features/rails_features/auto_capture_sessions.feature +31 -112
  79. data/features/rails_features/auto_notify.feature +28 -105
  80. data/features/rails_features/before_notify.feature +18 -83
  81. data/features/rails_features/breadcrumbs.feature +40 -137
  82. data/features/rails_features/handled.feature +18 -82
  83. data/features/rails_features/ignore_classes.feature +12 -51
  84. data/features/rails_features/meta_data_filters.feature +9 -33
  85. data/features/rails_features/mongo_breadcrumbs.feature +22 -96
  86. data/features/rails_features/project_root.feature +19 -84
  87. data/features/rails_features/release_stage.feature +20 -82
  88. data/features/rails_features/send_code.feature +13 -55
  89. data/features/rails_features/send_environment.feature +7 -33
  90. data/features/rails_features/unhandled.feature +6 -31
  91. data/features/rails_features/user_info.feature +27 -65
  92. data/features/sidekiq.feature +12 -79
  93. data/features/steps/ruby_notifier_steps.rb +59 -15
  94. data/features/support/env.rb +12 -45
  95. data/lib/bugsnag.rb +74 -21
  96. data/lib/bugsnag/breadcrumbs/breadcrumbs.rb +0 -2
  97. data/lib/bugsnag/breadcrumbs/validator.rb +0 -6
  98. data/lib/bugsnag/cleaner.rb +129 -60
  99. data/lib/bugsnag/configuration.rb +31 -2
  100. data/lib/bugsnag/helpers.rb +2 -4
  101. data/lib/bugsnag/integrations/que.rb +7 -4
  102. data/lib/bugsnag/integrations/railtie.rb +1 -1
  103. data/lib/bugsnag/middleware/discard_error_class.rb +30 -0
  104. data/lib/bugsnag/middleware/exception_meta_data.rb +15 -9
  105. data/lib/bugsnag/middleware/ignore_error_class.rb +2 -0
  106. data/lib/bugsnag/middleware/rack_request.rb +2 -4
  107. data/lib/bugsnag/report.rb +3 -13
  108. data/lib/bugsnag/stacktrace.rb +6 -10
  109. data/spec/breadcrumbs/breadcrumb_spec.rb +1 -1
  110. data/spec/breadcrumbs/validator_spec.rb +1 -26
  111. data/spec/bugsnag_spec.rb +2 -2
  112. data/spec/cleaner_spec.rb +202 -10
  113. data/spec/configuration_spec.rb +16 -1
  114. data/spec/fixtures/apps/rails-initializer-config/Gemfile +5 -1
  115. data/spec/fixtures/apps/rails-invalid-initializer-config/Gemfile +5 -1
  116. data/spec/fixtures/apps/rails-no-config/Gemfile +5 -1
  117. data/spec/helper_spec.rb +0 -31
  118. data/spec/integrations/logger_spec.rb +1 -1
  119. data/spec/integrations/rack_spec.rb +8 -6
  120. data/spec/integrations/rake_spec.rb +1 -1
  121. data/spec/report_spec.rb +324 -26
  122. data/spec/spec_helper.rb +6 -1
  123. data/spec/stacktrace_spec.rb +179 -72
  124. metadata +23 -7
  125. data/.travis.yml +0 -117
  126. data/features/plain_features/api_key.feature +0 -25
@@ -17,12 +17,10 @@ module Bugsnag
17
17
  def self.trim_if_needed(value)
18
18
  value = "" if value.nil?
19
19
 
20
- # Sanitize object
21
- sanitized_value = Bugsnag::Cleaner.clean_object_encoding(value)
22
- return sanitized_value unless payload_too_long?(sanitized_value)
20
+ return value unless payload_too_long?(value)
23
21
 
24
22
  # Trim metadata
25
- reduced_value = trim_metadata(sanitized_value)
23
+ reduced_value = trim_metadata(value)
26
24
  return reduced_value unless payload_too_long?(reduced_value)
27
25
 
28
26
  # Trim code from stacktrace
@@ -37,13 +37,16 @@ if defined?(::Que)
37
37
  end
38
38
  end
39
39
 
40
- if Que.respond_to?(:error_notifier=)
41
- Bugsnag.configuration.app_type ||= "que"
40
+ Bugsnag.configuration.app_type ||= "que"
41
+ if defined?(::Que::Version)
42
42
  Bugsnag.configuration.runtime_versions["que"] = ::Que::Version
43
+ elsif defined?(::Que::VERSION)
44
+ Bugsnag.configuration.runtime_versions["que"] = ::Que::VERSION
45
+ end
46
+
47
+ if Que.respond_to?(:error_notifier=)
43
48
  Que.error_notifier = handler
44
49
  elsif Que.respond_to?(:error_handler=)
45
- Bugsnag.configuration.app_type ||= "que"
46
- Bugsnag.configuration.runtime_versions["que"] = ::Que::Version
47
50
  Que.error_handler = handler
48
51
  end
49
52
  end
@@ -79,7 +79,7 @@ module Bugsnag
79
79
  filtered_data = data.slice(*event[:allowed_data])
80
80
  filtered_data[:event_name] = event[:id]
81
81
  filtered_data[:event_id] = event_id
82
- if event[:id] == "sql.active_record"
82
+ if event[:id] == "sql.active_record" && data.key?(:binds)
83
83
  binds = data[:binds].each_with_object({}) { |bind, output| output[bind.name] = '?' if defined?(bind.name) }
84
84
  filtered_data[:binds] = JSON.dump(binds) unless binds.empty?
85
85
  end
@@ -0,0 +1,30 @@
1
+ module Bugsnag::Middleware
2
+ ##
3
+ # Determines if the exception should be ignored based on the configured
4
+ # `discard_classes`
5
+ class DiscardErrorClass
6
+ ##
7
+ # @param middleware [#call] The next middleware to call
8
+ def initialize(middleware)
9
+ @middleware = middleware
10
+ end
11
+
12
+ ##
13
+ # @param report [Report]
14
+ def call(report)
15
+ should_discard = report.raw_exceptions.any? do |ex|
16
+ report.configuration.discard_classes.any? do |to_ignore|
17
+ case to_ignore
18
+ when String then to_ignore == ex.class.name
19
+ when Regexp then to_ignore =~ ex.class.name
20
+ else false
21
+ end
22
+ end
23
+ end
24
+
25
+ report.ignore! if should_discard
26
+
27
+ @middleware.call(report)
28
+ end
29
+ end
30
+ end
@@ -9,21 +9,27 @@ module Bugsnag::Middleware
9
9
  def call(report)
10
10
  # Apply the user's information attached to the exceptions
11
11
  report.raw_exceptions.each do |exception|
12
- if exception.respond_to?(:bugsnag_user_id) && exception.bugsnag_user_id.is_a?(String)
13
- report.user = {id: exception.bugsnag_user_id}
12
+ if exception.respond_to?(:bugsnag_user_id)
13
+ user_id = exception.bugsnag_user_id
14
+ report.user = {id: user_id} if user_id.is_a?(String)
14
15
  end
15
16
 
16
- if exception.respond_to?(:bugsnag_context) && exception.bugsnag_context.is_a?(String)
17
- report.context = exception.bugsnag_context
17
+ if exception.respond_to?(:bugsnag_context)
18
+ context = exception.bugsnag_context
19
+ report.context = context if context.is_a?(String)
18
20
  end
19
21
 
20
- if exception.respond_to?(:bugsnag_grouping_hash) && exception.bugsnag_grouping_hash.is_a?(String)
21
- report.grouping_hash = exception.bugsnag_grouping_hash
22
+ if exception.respond_to?(:bugsnag_grouping_hash)
23
+ group_hash = exception.bugsnag_grouping_hash
24
+ report.grouping_hash = group_hash if group_hash.is_a?(String)
22
25
  end
23
26
 
24
- if exception.respond_to?(:bugsnag_meta_data) && exception.bugsnag_meta_data.is_a?(Hash)
25
- exception.bugsnag_meta_data.each do |key, value|
26
- report.add_tab key, value
27
+ if exception.respond_to?(:bugsnag_meta_data)
28
+ meta_data = exception.bugsnag_meta_data
29
+ if meta_data.is_a?(Hash)
30
+ meta_data.each do |key, value|
31
+ report.add_tab key, value
32
+ end
27
33
  end
28
34
  end
29
35
  end
@@ -2,6 +2,8 @@ module Bugsnag::Middleware
2
2
  ##
3
3
  # Determines if the exception should be ignored based on the configured
4
4
  # `ignore_classes`
5
+ #
6
+ # @deprecated Use {DiscardErrorClass} instead
5
7
  class IgnoreErrorClass
6
8
  def initialize(bugsnag)
7
9
  @bugsnag = bugsnag
@@ -28,18 +28,16 @@ module Bugsnag::Middleware
28
28
  url = "#{request.scheme}://#{request.host}"
29
29
  url << ":#{request.port}" unless [80, 443].include?(request.port)
30
30
 
31
- cleaner = Bugsnag::Cleaner.new(report.configuration.meta_data_filters)
32
-
33
31
  # If app is passed a bad URL, this code will crash attempting to clean it
34
32
  begin
35
- url << cleaner.clean_url(request.fullpath)
33
+ url << Bugsnag.cleaner.clean_url(request.fullpath)
36
34
  rescue StandardError => stde
37
35
  Bugsnag.configuration.warn "RackRequest - Rescued error while cleaning request.fullpath: #{stde}"
38
36
  end
39
37
 
40
38
  referer = nil
41
39
  begin
42
- referer = cleaner.clean_url(request.referer) if request.referer
40
+ referer = Bugsnag.cleaner.clean_url(request.referer) if request.referer
43
41
  rescue StandardError => stde
44
42
  Bugsnag.configuration.warn "RackRequest - Rescued error while cleaning request.referer: #{stde}"
45
43
  end
@@ -97,6 +97,7 @@ module Bugsnag
97
97
  releaseStage: release_stage,
98
98
  type: app_type
99
99
  },
100
+ breadcrumbs: breadcrumbs.map(&:to_h),
100
101
  context: context,
101
102
  device: {
102
103
  hostname: hostname,
@@ -104,6 +105,7 @@ module Bugsnag
104
105
  },
105
106
  exceptions: exceptions,
106
107
  groupingHash: grouping_hash,
108
+ metaData: meta_data,
107
109
  session: session,
108
110
  severity: severity,
109
111
  severityReason: severity_reason,
@@ -111,19 +113,7 @@ module Bugsnag
111
113
  user: user
112
114
  }
113
115
 
114
- # cleanup character encodings
115
- payload_event = Bugsnag::Cleaner.clean_object_encoding(payload_event)
116
-
117
- # filter out sensitive values in (and cleanup encodings) metaData
118
- filter_cleaner = Bugsnag::Cleaner.new(configuration.meta_data_filters)
119
- payload_event[:metaData] = filter_cleaner.clean_object(meta_data)
120
- payload_event[:breadcrumbs] = breadcrumbs.map do |breadcrumb|
121
- breadcrumb_hash = breadcrumb.to_h
122
- breadcrumb_hash[:metaData] = filter_cleaner.clean_object(breadcrumb_hash[:metaData])
123
- breadcrumb_hash
124
- end
125
-
126
- payload_event.reject! {|k,v| v.nil? }
116
+ payload_event.reject! {|k, v| v.nil? }
127
117
 
128
118
  # return the payload hash
129
119
  {
@@ -7,32 +7,27 @@ module Bugsnag
7
7
  # e.g. "org.jruby.Ruby.runScript(Ruby.java:807)"
8
8
  JAVA_BACKTRACE_REGEX = /^(.*)\((.*)(?::([0-9]+))?\)$/
9
9
 
10
- # Path to vendored code. Used to mark file paths as out of project.
11
- VENDOR_PATH = /^(vendor\/|\.bundle\/)/
12
-
13
10
  ##
14
11
  # Process a backtrace and the configuration into a parsed stacktrace.
12
+ #
13
+ # rubocop:todo Metrics/CyclomaticComplexity
15
14
  def initialize(backtrace, configuration)
16
15
  @configuration = configuration
17
16
 
18
17
  backtrace = caller if !backtrace || backtrace.empty?
19
18
 
20
19
  @processed_backtrace = backtrace.map do |trace|
20
+ # Parse the stacktrace line
21
21
  if trace.match(BACKTRACE_LINE_REGEX)
22
22
  file, line_str, method = [$1, $2, $3]
23
23
  elsif trace.match(JAVA_BACKTRACE_REGEX)
24
24
  method, file, line_str = [$1, $2, $3]
25
25
  end
26
26
 
27
- # Parse the stacktrace line
28
-
29
27
  next(nil) if file.nil?
30
28
 
31
29
  # Expand relative paths
32
- p = Pathname.new(file)
33
- if p.relative?
34
- file = p.realpath.to_s rescue file
35
- end
30
+ file = File.realpath(file) rescue file
36
31
 
37
32
  # Generate the stacktrace line hash
38
33
  trace_hash = {}
@@ -46,7 +41,7 @@ module Bugsnag
46
41
  if defined?(@configuration.project_root) && @configuration.project_root.to_s != ''
47
42
  trace_hash[:inProject] = true if file.start_with?(@configuration.project_root.to_s)
48
43
  file.sub!(/#{@configuration.project_root}\//, "")
49
- trace_hash.delete(:inProject) if file.match(VENDOR_PATH)
44
+ trace_hash.delete(:inProject) if file.match(@configuration.vendor_path)
50
45
  end
51
46
 
52
47
 
@@ -67,6 +62,7 @@ module Bugsnag
67
62
  end
68
63
  end.compact
69
64
  end
65
+ # rubocop:enable Metrics/CyclomaticComplexity
70
66
 
71
67
  ##
72
68
  # Returns the processed backtrace
@@ -90,4 +90,4 @@ RSpec.describe Bugsnag::Breadcrumbs::Breadcrumb do
90
90
  )
91
91
  end
92
92
  end
93
- end
93
+ end
@@ -31,31 +31,6 @@ RSpec.describe Bugsnag::Breadcrumbs::Validator do
31
31
  validator.validate(breadcrumb)
32
32
  end
33
33
 
34
- it "trims long messages to length and warns" do
35
- config = instance_double(Bugsnag::Configuration)
36
- allow(config).to receive(:enabled_automatic_breadcrumb_types).and_return(enabled_automatic_breadcrumb_types)
37
- validator = Bugsnag::Breadcrumbs::Validator.new(config)
38
-
39
- name = "1234567890123456789012345678901234567890"
40
-
41
- breadcrumb = instance_double(Bugsnag::Breadcrumbs::Breadcrumb, {
42
- :auto => auto,
43
- :name => name,
44
- :type => type,
45
- :meta_data => meta_data,
46
- :meta_data= => nil
47
- })
48
-
49
- expect(breadcrumb).to_not receive(:ignore!)
50
- expect(breadcrumb).to receive(:name=).with("123456789012345678901234567890")
51
- expected_string = "Breadcrumb name trimmed to length 30. Original name: #{name}"
52
- expect(config).to receive(:debug).with(expected_string)
53
-
54
- validator.validate(breadcrumb)
55
- # Check the original message has not been modified
56
- expect(name).to eq("1234567890123456789012345678901234567890")
57
- end
58
-
59
34
  describe "tests meta_data types" do
60
35
  it "accepts Strings, Numerics, Booleans, & nil" do
61
36
  config = instance_double(Bugsnag::Configuration)
@@ -198,4 +173,4 @@ RSpec.describe Bugsnag::Breadcrumbs::Validator do
198
173
  end
199
174
  end
200
175
  end
201
- end
176
+ end
@@ -268,7 +268,7 @@ describe Bugsnag do
268
268
  )
269
269
  expect(breadcrumbs.to_a.size).to eq(1)
270
270
  expect(breadcrumbs.first.to_h).to match({
271
- :name => "123123123123123123123123123123",
271
+ :name => "123123123123123123123123123123456456456456456456456456456456",
272
272
  :type => Bugsnag::Breadcrumbs::MANUAL_BREADCRUMB_TYPE,
273
273
  :metaData => {
274
274
  :a => 1
@@ -311,7 +311,7 @@ describe Bugsnag do
311
311
  Bugsnag.leave_breadcrumb("TestName")
312
312
  expect(breadcrumbs.to_a.size).to eq(1)
313
313
  expect(breadcrumbs.first.to_h).to match({
314
- :name => "123123123123123123123123123123",
314
+ :name => "123123123123123123123123123123456456456456456",
315
315
  :type => Bugsnag::Breadcrumbs::MANUAL_BREADCRUMB_TYPE,
316
316
  :metaData => {
317
317
  :int => 1
@@ -3,15 +3,87 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Bugsnag::Cleaner do
6
- subject { described_class.new(nil) }
6
+ subject { Bugsnag::Cleaner.new(Bugsnag::Configuration.new) }
7
7
 
8
8
  describe "#clean_object" do
9
+ is_jruby = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
10
+
9
11
  it "cleans up recursive hashes" do
10
12
  a = {:a => {}}
11
13
  a[:a][:b] = a
12
14
  expect(subject.clean_object(a)).to eq({:a => {:b => "[RECURSION]"}})
13
15
  end
14
16
 
17
+ it "cleans up hashes when keys infinitely recurse in to_s" do
18
+ skip "JRuby doesn't allow recovery from SystemStackErrors" if is_jruby
19
+
20
+ class RecursiveHashKey
21
+ def to_s
22
+ to_s
23
+ end
24
+ end
25
+
26
+ key = RecursiveHashKey.new
27
+
28
+ a = {}
29
+ a[key] = 1
30
+
31
+ expect(subject.clean_object(a)).to eq({ "[RECURSION]" => "[FILTERED]" })
32
+ end
33
+
34
+ it "cleans up hashes when a nested key infinitely recurse in to_s" do
35
+ skip "JRuby doesn't allow recovery from SystemStackErrors" if is_jruby
36
+
37
+ class RecursiveHashKey
38
+ def to_s
39
+ to_s
40
+ end
41
+ end
42
+
43
+ key = RecursiveHashKey.new
44
+
45
+ a = {}
46
+ a[:b] = {}
47
+ a[:b][key] = 1
48
+
49
+ expected = { :b => { "[RECURSION]" => "[FILTERED]" } }
50
+
51
+ expect(subject.clean_object(a)).to eq(expected)
52
+ end
53
+
54
+ it "cleans up hashes when keys raise in to_s" do
55
+ class RaisingHashKey
56
+ def to_s
57
+ raise "hey!"
58
+ end
59
+ end
60
+
61
+ key = RaisingHashKey.new
62
+
63
+ a = {}
64
+ a[key] = 1
65
+
66
+ expect(subject.clean_object(a)).to eq({ "[RAISED]" => "[FILTERED]" })
67
+ end
68
+
69
+ it "cleans up hashes when nested keys raise in to_s" do
70
+ class RaisingHashKey
71
+ def to_s
72
+ raise "hey!"
73
+ end
74
+ end
75
+
76
+ key = RaisingHashKey.new
77
+
78
+ a = {}
79
+ a[:b] = {}
80
+ a[:b][key] = 1
81
+
82
+ expected = { :b => { "[RAISED]" => "[FILTERED]" } }
83
+
84
+ expect(subject.clean_object(a)).to eq(expected)
85
+ end
86
+
15
87
  it "cleans up recursive arrays" do
16
88
  a = []
17
89
  a << a
@@ -48,6 +120,31 @@ describe Bugsnag::Cleaner do
48
120
  expect(subject.clean_object(a)).to eq('[OBJECT]')
49
121
  end
50
122
 
123
+ it "cleans custom objects when they infinitely recurse" do
124
+ skip "JRuby doesn't allow recovery from SystemStackErrors" if is_jruby
125
+
126
+ class RecursiveObject
127
+ def to_s
128
+ to_s
129
+ end
130
+ end
131
+
132
+ object = RecursiveObject.new
133
+
134
+ expect(subject.clean_object(object)).to eq("[RECURSION]")
135
+ end
136
+
137
+ it "cleans custom objects to show the id of the object if object responds to id method" do
138
+ class MacaronWithId
139
+ def id
140
+ 10
141
+ end
142
+ end
143
+
144
+ a = MacaronWithId.new
145
+ expect(subject.clean_object(a)).to eq("[OBJECT]: [Class]: #{a.class.name} [ID]: #{a.id}")
146
+ end
147
+
51
148
  it "cleans up binary strings properly" do
52
149
  if RUBY_VERSION > "1.9"
53
150
  obj = "Andr\xc7\xff"
@@ -70,23 +167,113 @@ describe Bugsnag::Cleaner do
70
167
  end
71
168
 
72
169
  it "filters by string inclusion" do
73
- expect(described_class.new(['f']).clean_object({ :foo => 'bar' })).to eq({ :foo => '[FILTERED]' })
74
- expect(described_class.new(['b']).clean_object({ :foo => 'bar' })).to eq({ :foo => 'bar' })
170
+ object = { events: { metaData: { foo: 'bar' } } }
171
+
172
+ configuration = Bugsnag::Configuration.new
173
+ configuration.meta_data_filters = ['f']
174
+
175
+ cleaner = Bugsnag::Cleaner.new(configuration)
176
+ expect(cleaner.clean_object(object)).to eq({ events: { metaData: { foo: '[FILTERED]' } } })
177
+
178
+ configuration = Bugsnag::Configuration.new
179
+ configuration.meta_data_filters = ['b']
180
+
181
+ cleaner = Bugsnag::Cleaner.new(configuration)
182
+ expect(cleaner.clean_object(object)).to eq({ events: { metaData: { foo: 'bar' } } })
75
183
  end
76
184
 
77
185
  it "filters by regular expression" do
78
- expect(described_class.new([/fb?/]).clean_object({ :foo => 'bar' })).to eq({ :foo => '[FILTERED]' })
79
- expect(described_class.new([/fb+/]).clean_object({ :foo => 'bar' })).to eq({ :foo => 'bar' })
186
+ object = { events: { metaData: { foo: 'bar' } } }
187
+
188
+ configuration = Bugsnag::Configuration.new
189
+ configuration.meta_data_filters = [/fb?/]
190
+
191
+ cleaner = Bugsnag::Cleaner.new(configuration)
192
+ expect(cleaner.clean_object(object)).to eq({ events: { metaData: { foo: '[FILTERED]' } } })
193
+
194
+ configuration = Bugsnag::Configuration.new
195
+ configuration.meta_data_filters = [/fb+/]
196
+
197
+ cleaner = Bugsnag::Cleaner.new(configuration)
198
+ expect(cleaner.clean_object(object)).to eq({ events: { metaData: { foo: 'bar' } } })
80
199
  end
81
200
 
82
201
  it "filters deeply nested keys" do
83
- params = {:foo => {:bar => "baz"}}
84
- expect(described_class.new([/^foo\.bar/]).clean_object(params)).to eq({:foo => {:bar => '[FILTERED]'}})
202
+ configuration = Bugsnag::Configuration.new
203
+ configuration.meta_data_filters = [/^foo\.bar/]
204
+
205
+ cleaner = Bugsnag::Cleaner.new(configuration)
206
+
207
+ params = { events: { metaData: { foo: { bar: 'baz' } } } }
208
+ expect(cleaner.clean_object(params)).to eq({ events: { metaData: { foo: { bar: '[FILTERED]' } } } })
85
209
  end
86
210
 
87
211
  it "filters deeply nested request parameters" do
88
- params = {:request => {:params => {:foo => {:bar => "baz"}}}}
89
- expect(described_class.new([/^foo\.bar/]).clean_object(params)).to eq({:request => {:params => {:foo => {:bar => '[FILTERED]'}}}})
212
+ configuration = Bugsnag::Configuration.new
213
+ configuration.meta_data_filters = [/^foo\.bar/]
214
+
215
+ cleaner = Bugsnag::Cleaner.new(configuration)
216
+
217
+ params = { events: { metaData: { request: { params: { foo: { bar: 'baz' } } } } } }
218
+ expect(cleaner.clean_object(params)).to eq({ events: { metaData: { request: { params: { foo: { bar: '[FILTERED]' } } } } } })
219
+ end
220
+
221
+ it "doesn't filter by string inclusion when the scope is not in 'scopes_to_filter'" do
222
+ object = { foo: 'bar' }
223
+
224
+ configuration = Bugsnag::Configuration.new
225
+ configuration.meta_data_filters = ['f']
226
+
227
+ cleaner = Bugsnag::Cleaner.new(configuration)
228
+
229
+ expect(cleaner.clean_object(object)).to eq({ foo: 'bar' })
230
+
231
+ configuration = Bugsnag::Configuration.new
232
+ configuration.meta_data_filters = ['b']
233
+
234
+ cleaner = Bugsnag::Cleaner.new(configuration)
235
+
236
+ expect(cleaner.clean_object(object)).to eq({ foo: 'bar' })
237
+ end
238
+
239
+ it "doesn't filter by regular expression when the scope is not in 'scopes_to_filter'" do
240
+ object = { foo: 'bar' }
241
+
242
+ configuration = Bugsnag::Configuration.new
243
+ configuration.meta_data_filters = [/fb?/]
244
+
245
+ cleaner = Bugsnag::Cleaner.new(configuration)
246
+
247
+ expect(cleaner.clean_object(object)).to eq({ foo: 'bar' })
248
+
249
+ configuration = Bugsnag::Configuration.new
250
+ configuration.meta_data_filters = [/fb+/]
251
+
252
+ cleaner = Bugsnag::Cleaner.new(configuration)
253
+
254
+ expect(cleaner.clean_object(object)).to eq({ foo: 'bar' })
255
+ end
256
+
257
+ it "doesn't filter deeply nested keys when the scope is not in 'scopes_to_filter'" do
258
+ params = { foo: { bar: 'baz' } }
259
+
260
+ configuration = Bugsnag::Configuration.new
261
+ configuration.meta_data_filters = [/^foo\.bar/]
262
+
263
+ cleaner = Bugsnag::Cleaner.new(configuration)
264
+
265
+ expect(cleaner.clean_object(params)).to eq({ foo: { bar: 'baz' } })
266
+ end
267
+
268
+ it "doesn't filter deeply nested request parameters when the scope is not in 'scopes_to_filter'" do
269
+ params = { request: { params: { foo: { bar: 'baz' } } } }
270
+
271
+ configuration = Bugsnag::Configuration.new
272
+ configuration.meta_data_filters = [/^foo\.bar/]
273
+
274
+ cleaner = Bugsnag::Cleaner.new(configuration)
275
+
276
+ expect(cleaner.clean_object(params)).to eq({ request: { params: { foo: { bar: 'baz' } } } })
90
277
  end
91
278
 
92
279
  it "filters objects which can't be stringified" do
@@ -101,7 +288,12 @@ describe Bugsnag::Cleaner do
101
288
 
102
289
  describe "#clean_url" do
103
290
  let(:filters) { [] }
104
- subject { described_class.new(filters).clean_url(url) }
291
+
292
+ subject do
293
+ configuration = Bugsnag::Configuration.new
294
+ configuration.meta_data_filters = filters
295
+ described_class.new(configuration).clean_url(url)
296
+ end
105
297
 
106
298
  context "with no filters configured" do
107
299
  let(:url) { "/dir/page?param1=value1&param2=value2" }