bugsnag 2.8.13 → 3.0.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -4
- data/CHANGELOG.md +17 -0
- data/README.md +20 -19
- data/VERSION +1 -1
- data/bugsnag.gemspec +1 -0
- data/lib/bugsnag.rb +1 -0
- data/lib/bugsnag/cleaner.rb +122 -0
- data/lib/bugsnag/delivery/thread_queue.rb +2 -2
- data/lib/bugsnag/helpers.rb +0 -92
- data/lib/bugsnag/middleware/rack_request.rb +1 -1
- data/lib/bugsnag/middleware/rails2_request.rb +1 -1
- data/lib/bugsnag/notification.rb +2 -2
- data/lib/bugsnag/rails/controller_methods.rb +6 -1
- data/spec/cleaner_spec.rb +138 -0
- data/spec/helper_spec.rb +0 -114
- data/spec/integration_spec.rb +22 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c47737bc08fe70bfdc4b9391ab04d5b6aa6900aa
|
4
|
+
data.tar.gz: abe70b3cc901bf48a06fab50bd410e1927ca7a6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eedb7804e481f0ecfd3436b758e7880f7ebfe232cc7fc93ee5a670738e61df4751a7ff11523cd523c9ec873259f21880df84d214f2a63333c3f6bda704c34184
|
7
|
+
data.tar.gz: afc1a1885938f4926dea26e9eb4f22080ea506f15997afe4acd4302085a445e5ff7a0e7191c2d55f50f2919a8a56c664ea7e64b261d6c4c76d360ed823d5da23
|
data/.travis.yml
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
sudo: false
|
1
2
|
language: ruby
|
2
3
|
rvm:
|
3
4
|
- 2.1.0
|
@@ -9,7 +10,3 @@ rvm:
|
|
9
10
|
before_install:
|
10
11
|
- gem update --system 2.1.11
|
11
12
|
- gem --version
|
12
|
-
notifications:
|
13
|
-
hipchat:
|
14
|
-
rooms:
|
15
|
-
secure: cv5V8ivZExOywKL9n0CODnxy9m5u4rQ5ZMYK8XHPIoqQKkvH9DQOeb2ItW2aM2kxeupJEcQEy1Eu4sYMGhyzKUNdqbFtQBhDYxRwSAgTRIkGlHQCnznyExHWZbGfDB8y/m11HiZ1wuPuqs8ZZ+VccNb4bwJKbhPTbf1RZ+GPeU8=
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,23 @@
|
|
1
1
|
Changelog
|
2
2
|
=========
|
3
3
|
|
4
|
+
3.0.0 (23 Dec 2015)
|
5
|
+
-----
|
6
|
+
|
7
|
+
### Enhancements
|
8
|
+
|
9
|
+
* Fix warning from usage of `before_filter` in Rails 5
|
10
|
+
| [Scott Ringwelski](https://github.com/sgringwe)
|
11
|
+
| [#267](https://github.com/bugsnag/bugsnag-ruby/pull/267)
|
12
|
+
|
13
|
+
* Use Rails 5-style deep parameter filtering
|
14
|
+
| [fimmtiu](https://github.com/fimmtiu)
|
15
|
+
| [#256](https://github.com/bugsnag/bugsnag-ruby/pull/256)
|
16
|
+
|
17
|
+
Note: This is a backwards incompatible change, as filters containing `.` are
|
18
|
+
now parsed as nested instead of as a single key.
|
19
|
+
|
20
|
+
|
4
21
|
2.8.13
|
5
22
|
------
|
6
23
|
|
data/README.md
CHANGED
@@ -24,16 +24,13 @@ Contents
|
|
24
24
|
- [Sending Non-fatal Exceptions](#sending-non-fatal-exceptions)
|
25
25
|
- [Deploy Tracking](#deploy-tracking)
|
26
26
|
- [Callbacks](#callbacks)
|
27
|
+
- [Configuration](https://github.com/bugsnag/bugsnag-ruby/tree/master/docs/Configuration.md)
|
28
|
+
- [Notification Options](https://github.com/bugsnag/bugsnag-ruby/tree/master/docs/Notification Options.md)
|
27
29
|
- [Demo Applications](#demo-applications)
|
28
30
|
- [Support](#support)
|
29
31
|
- [Contributing](#contributing)
|
30
32
|
- [License](#license)
|
31
33
|
|
32
|
-
- [Additional Documentation](https://github.com/bugsnag/bugsnag-ruby/tree/master/docs)
|
33
|
-
- [Configuration](docs/Configuration.md)
|
34
|
-
- [Notification Options](docs/Notification Options.md)
|
35
|
-
|
36
|
-
|
37
34
|
|
38
35
|
Getting Started
|
39
36
|
---------------
|
@@ -69,17 +66,19 @@ Getting Started
|
|
69
66
|
end
|
70
67
|
```
|
71
68
|
|
72
|
-
The Bugsnag module will read the `BUGSNAG_API_KEY` environment variable if
|
73
|
-
do not configure one automatically.
|
69
|
+
The Bugsnag module will read the `BUGSNAG_API_KEY` environment variable if
|
70
|
+
you do not configure one automatically.
|
74
71
|
|
75
72
|
### Rake Integration
|
76
73
|
|
77
|
-
Rake integration is automatically enabled in Rails 3/4 apps, so providing you
|
78
|
-
in your Rake tasks you dont need to do anything to get Rake
|
79
|
-
|
74
|
+
Rake integration is automatically enabled in Rails 3/4/5 apps, so providing you
|
75
|
+
load the environment in your Rake tasks you dont need to do anything to get Rake
|
76
|
+
support. If you choose not to load your environment, you can manually configure
|
77
|
+
Bugsnag with a `bugsnag.configure` block in the Rakefile.
|
80
78
|
|
81
|
-
Bugsnag can automatically notify of all exceptions that happen in your rake
|
82
|
-
to enable this, you need to `require "bugsnag/rake"` in your
|
79
|
+
Bugsnag can automatically notify of all exceptions that happen in your rake
|
80
|
+
tasks. In order to enable this, you need to `require "bugsnag/rake"` in your
|
81
|
+
Rakefile, like so:
|
83
82
|
|
84
83
|
```ruby
|
85
84
|
require File.expand_path('../config/application', __FILE__)
|
@@ -93,27 +92,29 @@ end
|
|
93
92
|
YourApp::Application.load_tasks
|
94
93
|
```
|
95
94
|
|
96
|
-
> Note: We also configure Bugsnag in the Rakefile, so the tasks that do not load
|
97
|
-
environment can still notify Bugsnag.
|
95
|
+
> Note: We also configure Bugsnag in the Rakefile, so the tasks that do not load
|
96
|
+
> the full environment can still notify Bugsnag.
|
98
97
|
|
99
98
|
### Sending a Test Notification
|
100
99
|
|
101
|
-
To test that bugsnag is properly configured, you can use the `test_exception`
|
100
|
+
To test that bugsnag is properly configured, you can use the `test_exception`
|
101
|
+
rake task:
|
102
102
|
|
103
103
|
```bash
|
104
104
|
rake bugsnag:test_exception
|
105
105
|
```
|
106
106
|
|
107
|
-
A test exception will be sent to your bugsnag dashboard if everything is
|
107
|
+
A test exception will be sent to your bugsnag dashboard if everything is
|
108
|
+
configured correctly.
|
108
109
|
|
109
110
|
Usage
|
110
111
|
-----
|
111
112
|
|
112
113
|
### Catching and Reporting Exceptions
|
113
114
|
|
114
|
-
Bugsnag Ruby works out of the box with Rails, Sidekiq, Resque, DelayedJob (3+),
|
115
|
-
should be easy to add support for other frameworks,
|
116
|
-
to those projects.
|
115
|
+
Bugsnag Ruby works out of the box with Rails, Sidekiq, Resque, DelayedJob (3+),
|
116
|
+
Mailman, Rake and Rack. It should be easy to add support for other frameworks,
|
117
|
+
either by sending a pull request here or adding a hook to those projects.
|
117
118
|
|
118
119
|
#### Rack/Sinatra Apps
|
119
120
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
3.0.0
|
data/bugsnag.gemspec
CHANGED
data/lib/bugsnag.rb
CHANGED
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Bugsnag
|
4
|
+
class Cleaner
|
5
|
+
ENCODING_OPTIONS = {:invalid => :replace, :undef => :replace}.freeze
|
6
|
+
FILTERED = '[FILTERED]'.freeze
|
7
|
+
RECURSION = '[RECURSION]'.freeze
|
8
|
+
OBJECT = '[OBJECT]'.freeze
|
9
|
+
|
10
|
+
def initialize(filters)
|
11
|
+
@filters = Array(filters)
|
12
|
+
@deep_filters = @filters.any? {|f| f.kind_of?(Regexp) && f.to_s.include?("\\.".freeze) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def clean_object(obj)
|
16
|
+
traverse_object(obj, {}, nil)
|
17
|
+
end
|
18
|
+
|
19
|
+
def traverse_object(obj, seen, scope)
|
20
|
+
return nil unless obj
|
21
|
+
|
22
|
+
# Protect against recursion of recursable items
|
23
|
+
protection = if obj.is_a?(Hash) || obj.is_a?(Array) || obj.is_a?(Set)
|
24
|
+
return seen[obj] if seen[obj]
|
25
|
+
seen[obj] = RECURSION
|
26
|
+
end
|
27
|
+
|
28
|
+
value = case obj
|
29
|
+
when Hash
|
30
|
+
clean_hash = {}
|
31
|
+
obj.each do |k,v|
|
32
|
+
if filters_match_deeply?(k, scope)
|
33
|
+
clean_hash[k] = FILTERED
|
34
|
+
else
|
35
|
+
clean_hash[k] = traverse_object(v, seen, [scope, k].compact.join('.'))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
clean_hash
|
39
|
+
when Array, Set
|
40
|
+
obj.map { |el| traverse_object(el, seen, scope) }.compact
|
41
|
+
when Numeric, TrueClass, FalseClass
|
42
|
+
obj
|
43
|
+
when String
|
44
|
+
clean_string(obj)
|
45
|
+
else
|
46
|
+
str = obj.to_s
|
47
|
+
# avoid leaking potentially sensitive data from objects' #inspect output
|
48
|
+
if str =~ /#<.*>/
|
49
|
+
OBJECT
|
50
|
+
else
|
51
|
+
clean_string(str)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
seen[obj] = value if protection
|
56
|
+
value
|
57
|
+
end
|
58
|
+
|
59
|
+
def clean_string(str)
|
60
|
+
if defined?(str.encoding) && defined?(Encoding::UTF_8)
|
61
|
+
if str.encoding == Encoding::UTF_8
|
62
|
+
str.valid_encoding? ? str : str.encode('utf-16', ENCODING_OPTIONS).encode('utf-8')
|
63
|
+
else
|
64
|
+
str.encode('utf-8', ENCODING_OPTIONS)
|
65
|
+
end
|
66
|
+
elsif defined?(Iconv)
|
67
|
+
Iconv.conv('UTF-8//IGNORE', 'UTF-8', str) || str
|
68
|
+
else
|
69
|
+
str
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.clean_object_encoding(obj)
|
74
|
+
new(nil).clean_object(obj)
|
75
|
+
end
|
76
|
+
|
77
|
+
def clean_url(url)
|
78
|
+
return url if @filters.empty?
|
79
|
+
|
80
|
+
uri = URI(url)
|
81
|
+
return url unless uri.query
|
82
|
+
|
83
|
+
query_params = uri.query.split('&').map { |pair| pair.split('=') }
|
84
|
+
query_params.map! do |key, val|
|
85
|
+
if filters_match?(key)
|
86
|
+
"#{key}=#{FILTERED}"
|
87
|
+
else
|
88
|
+
"#{key}=#{val}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
uri.query = query_params.join('&')
|
93
|
+
uri.to_s
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def filters_match?(key)
|
99
|
+
str = key.to_s
|
100
|
+
|
101
|
+
@filters.any? do |f|
|
102
|
+
case f
|
103
|
+
when Regexp
|
104
|
+
str.match(f)
|
105
|
+
else
|
106
|
+
str.include?(f.to_s)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# If someone has a Rails filter like /^stuff\.secret/, it won't match "request.params.stuff.secret",
|
112
|
+
# so we try it both with and without the "request.params." bit.
|
113
|
+
def filters_match_deeply?(key, scope)
|
114
|
+
return true if filters_match?(key)
|
115
|
+
return false unless @deep_filters
|
116
|
+
|
117
|
+
long = [scope, key].compact.join('.')
|
118
|
+
short = long.sub(/^request\.params\./, '')
|
119
|
+
filters_match?(long) || filters_match?(short)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/lib/bugsnag/helpers.rb
CHANGED
@@ -3,98 +3,6 @@ require 'uri'
|
|
3
3
|
module Bugsnag
|
4
4
|
module Helpers
|
5
5
|
MAX_STRING_LENGTH = 4096
|
6
|
-
ENCODING_OPTIONS = {:invalid => :replace, :undef => :replace}.freeze
|
7
|
-
|
8
|
-
def self.cleanup_obj(obj, filters = nil, seen = {})
|
9
|
-
return nil unless obj
|
10
|
-
|
11
|
-
# Protect against recursion of recursable items
|
12
|
-
protection = if obj.is_a?(Hash) || obj.is_a?(Array) || obj.is_a?(Set)
|
13
|
-
return seen[obj] if seen[obj]
|
14
|
-
seen[obj] = '[RECURSION]'.freeze
|
15
|
-
end
|
16
|
-
|
17
|
-
value = case obj
|
18
|
-
when Hash
|
19
|
-
clean_hash = {}
|
20
|
-
obj.each do |k,v|
|
21
|
-
if filters_match?(k, filters)
|
22
|
-
clean_hash[k] = '[FILTERED]'.freeze
|
23
|
-
else
|
24
|
-
clean_obj = cleanup_obj(v, filters, seen)
|
25
|
-
clean_hash[k] = clean_obj
|
26
|
-
end
|
27
|
-
end
|
28
|
-
clean_hash
|
29
|
-
when Array, Set
|
30
|
-
obj.map { |el| cleanup_obj(el, filters, seen) }.compact
|
31
|
-
when Numeric, TrueClass, FalseClass
|
32
|
-
obj
|
33
|
-
when String
|
34
|
-
cleanup_string(obj)
|
35
|
-
else
|
36
|
-
str = obj.to_s
|
37
|
-
# avoid leaking potentially sensitive data from objects' #inspect output
|
38
|
-
if str =~ /#<.*>/
|
39
|
-
'[OBJECT]'.freeze
|
40
|
-
else
|
41
|
-
cleanup_string(str)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
seen[obj] = value if protection
|
46
|
-
value
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.cleanup_string(str)
|
50
|
-
if defined?(str.encoding) && defined?(Encoding::UTF_8)
|
51
|
-
if str.encoding == Encoding::UTF_8
|
52
|
-
str.valid_encoding? ? str : str.encode('utf-16', ENCODING_OPTIONS).encode('utf-8')
|
53
|
-
else
|
54
|
-
str.encode('utf-8', ENCODING_OPTIONS)
|
55
|
-
end
|
56
|
-
elsif defined?(Iconv)
|
57
|
-
Iconv.conv('UTF-8//IGNORE', 'UTF-8', str) || str
|
58
|
-
else
|
59
|
-
str
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def self.cleanup_obj_encoding(obj)
|
64
|
-
cleanup_obj(obj, nil)
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.filters_match?(object, filters)
|
68
|
-
str = object.to_s
|
69
|
-
|
70
|
-
Array(filters).any? do |f|
|
71
|
-
case f
|
72
|
-
when Regexp
|
73
|
-
str.match(f)
|
74
|
-
else
|
75
|
-
str.include?(f.to_s)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def self.cleanup_url(url, filters = [])
|
81
|
-
return url if filters.empty?
|
82
|
-
|
83
|
-
uri = URI(url)
|
84
|
-
return url unless uri.query
|
85
|
-
|
86
|
-
query_params = uri.query.split('&').map { |pair| pair.split('=') }
|
87
|
-
query_params.map! do |key, val|
|
88
|
-
if filters_match?(key, filters)
|
89
|
-
"#{key}=[FILTERED]"
|
90
|
-
else
|
91
|
-
"#{key}=#{val}"
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
uri.query = query_params.join('&')
|
96
|
-
uri.to_s
|
97
|
-
end
|
98
6
|
|
99
7
|
def self.reduce_hash_size(hash)
|
100
8
|
return {} unless hash.is_a?(Hash)
|
@@ -23,7 +23,7 @@ module Bugsnag::Middleware
|
|
23
23
|
# Build the clean url (hide the port if it is obvious)
|
24
24
|
url = "#{request.scheme}://#{request.host}"
|
25
25
|
url << ":#{request.port}" unless [80, 443].include?(request.port)
|
26
|
-
url << Bugsnag::
|
26
|
+
url << Bugsnag::Cleaner.new(notification.configuration.params_filters).clean_url(request.fullpath)
|
27
27
|
|
28
28
|
headers = {}
|
29
29
|
|
@@ -19,7 +19,7 @@ module Bugsnag::Middleware
|
|
19
19
|
# Build the clean url
|
20
20
|
url = "#{request.protocol}#{request.host}"
|
21
21
|
url << ":#{request.port}" unless [80, 443].include?(request.port)
|
22
|
-
url << Bugsnag::
|
22
|
+
url << Bugsnag::Cleaner.new(notification.configuration.params_filters).clean_url(request.fullpath)
|
23
23
|
|
24
24
|
# Add a request tab
|
25
25
|
notification.add_tab(:request, {
|
data/lib/bugsnag/notification.rb
CHANGED
@@ -250,10 +250,10 @@ module Bugsnag
|
|
250
250
|
payload_event[:device] = {:hostname => @configuration.hostname} if @configuration.hostname
|
251
251
|
|
252
252
|
# cleanup character encodings
|
253
|
-
payload_event = Bugsnag::
|
253
|
+
payload_event = Bugsnag::Cleaner.clean_object_encoding(payload_event)
|
254
254
|
|
255
255
|
# filter out sensitive values in (and cleanup encodings) metaData
|
256
|
-
payload_event[:metaData] = Bugsnag::
|
256
|
+
payload_event[:metaData] = Bugsnag::Cleaner.new(@configuration.params_filters).clean_object(@meta_data)
|
257
257
|
payload_event.reject! {|k,v| v.nil? }
|
258
258
|
|
259
259
|
# return the payload hash
|
@@ -17,7 +17,7 @@ module Bugsnag::Rails
|
|
17
17
|
def _add_bugsnag_notify_callback(callback_key, *methods, &block)
|
18
18
|
options = methods.last.is_a?(Hash) ? methods.pop : {}
|
19
19
|
|
20
|
-
|
20
|
+
action = lambda do |controller|
|
21
21
|
request_data = Bugsnag.configuration.request_data
|
22
22
|
request_data[callback_key] ||= []
|
23
23
|
|
@@ -33,6 +33,11 @@ module Bugsnag::Rails
|
|
33
33
|
controller.instance_exec(notification, &block)
|
34
34
|
} if block_given?
|
35
35
|
end
|
36
|
+
if respond_to?(:before_action)
|
37
|
+
before_action(options, &action)
|
38
|
+
else
|
39
|
+
before_filter(options, &action)
|
40
|
+
end
|
36
41
|
end
|
37
42
|
end
|
38
43
|
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Bugsnag::Cleaner do
|
6
|
+
subject { described_class.new(nil) }
|
7
|
+
|
8
|
+
describe "#clean_object" do
|
9
|
+
it "cleans up recursive hashes" do
|
10
|
+
a = {:a => {}}
|
11
|
+
a[:a][:b] = a
|
12
|
+
expect(subject.clean_object(a)).to eq({:a => {:b => "[RECURSION]"}})
|
13
|
+
end
|
14
|
+
|
15
|
+
it "cleans up recursive arrays" do
|
16
|
+
a = []
|
17
|
+
a << a
|
18
|
+
a << "hello"
|
19
|
+
expect(subject.clean_object(a)).to eq(["[RECURSION]", "hello"])
|
20
|
+
end
|
21
|
+
|
22
|
+
it "allows multiple copies of the same string" do
|
23
|
+
a = {:name => "bugsnag"}
|
24
|
+
a[:second] = a[:name]
|
25
|
+
expect(subject.clean_object(a)).to eq({:name => "bugsnag", :second => "bugsnag"})
|
26
|
+
end
|
27
|
+
|
28
|
+
it "allows multiple copies of the same object" do
|
29
|
+
a = []
|
30
|
+
b = ["hello"]
|
31
|
+
a << b; a << b
|
32
|
+
expect(subject.clean_object(a)).to eq([["hello"], ["hello"]])
|
33
|
+
end
|
34
|
+
|
35
|
+
it "cleans up UTF8 strings properly" do
|
36
|
+
obj = "André"
|
37
|
+
expect(subject.clean_object(obj)).to eq("André")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "cleans up binary strings properly" do
|
41
|
+
if RUBY_VERSION > "1.9"
|
42
|
+
obj = "Andr\xc7\xff"
|
43
|
+
if obj.respond_to? :force_encoding
|
44
|
+
obj = obj.force_encoding('BINARY')
|
45
|
+
end
|
46
|
+
expect(subject.clean_object(obj)).to eq("Andr��")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "cleans up strings returned from #to_s properly" do
|
51
|
+
if RUBY_VERSION > "1.9"
|
52
|
+
str = "Andr\xc7\xff"
|
53
|
+
if str.respond_to? :force_encoding
|
54
|
+
str = str.force_encoding('BINARY')
|
55
|
+
end
|
56
|
+
obj = RuntimeError.new(str)
|
57
|
+
expect(subject.clean_object(obj)).to eq("Andr��")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "filters by string inclusion" do
|
62
|
+
expect(described_class.new(['f']).clean_object({ :foo => 'bar' })).to eq({ :foo => '[FILTERED]' })
|
63
|
+
expect(described_class.new(['b']).clean_object({ :foo => 'bar' })).to eq({ :foo => 'bar' })
|
64
|
+
end
|
65
|
+
|
66
|
+
it "filters by regular expression" do
|
67
|
+
expect(described_class.new([/fb?/]).clean_object({ :foo => 'bar' })).to eq({ :foo => '[FILTERED]' })
|
68
|
+
expect(described_class.new([/fb+/]).clean_object({ :foo => 'bar' })).to eq({ :foo => 'bar' })
|
69
|
+
end
|
70
|
+
|
71
|
+
it "filters deeply nested keys" do
|
72
|
+
params = {:foo => {:bar => "baz"}}
|
73
|
+
expect(described_class.new([/^foo\.bar/]).clean_object(params)).to eq({:foo => {:bar => '[FILTERED]'}})
|
74
|
+
end
|
75
|
+
|
76
|
+
it "filters deeply nested request parameters" do
|
77
|
+
params = {:request => {:params => {:foo => {:bar => "baz"}}}}
|
78
|
+
expect(described_class.new([/^foo\.bar/]).clean_object(params)).to eq({:request => {:params => {:foo => {:bar => '[FILTERED]'}}}})
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "#clean_url" do
|
83
|
+
let(:filters) { [] }
|
84
|
+
subject { described_class.new(filters).clean_url(url) }
|
85
|
+
|
86
|
+
context "with no filters configured" do
|
87
|
+
let(:url) { "/dir/page?param1=value1¶m2=value2" }
|
88
|
+
it { should eq "/dir/page?param1=value1¶m2=value2" }
|
89
|
+
end
|
90
|
+
|
91
|
+
context "with no get params" do
|
92
|
+
let(:url) { "/dir/page" }
|
93
|
+
it { should eq "/dir/page" }
|
94
|
+
end
|
95
|
+
|
96
|
+
context "with no matching parameters" do
|
97
|
+
let(:filters) { ["param3"] }
|
98
|
+
let(:url) { "/dir/page?param1=value1¶m2=value2" }
|
99
|
+
it { should eq "/dir/page?param1=value1¶m2=value2" }
|
100
|
+
end
|
101
|
+
|
102
|
+
context "with a single matching parameter" do
|
103
|
+
let(:filters) { ["param1"] }
|
104
|
+
let(:url) { "/dir/page?param1=value1¶m2=value2" }
|
105
|
+
it { should eq "/dir/page?param1=[FILTERED]¶m2=value2" }
|
106
|
+
end
|
107
|
+
|
108
|
+
context "with partially matching parameters" do
|
109
|
+
let(:filters) { ["param"] }
|
110
|
+
let(:url) { "/dir/page?param1=value1¶m2=value2&bla=yes" }
|
111
|
+
it { should eq "/dir/page?param1=[FILTERED]¶m2=[FILTERED]&bla=yes" }
|
112
|
+
end
|
113
|
+
|
114
|
+
context "with multiple matching filters" do
|
115
|
+
let(:filters) { ["param1", "param2"] }
|
116
|
+
let(:url) { "/dir/page?param1=value1¶m2=value2¶m3=value3" }
|
117
|
+
it { should eq "/dir/page?param1=[FILTERED]¶m2=[FILTERED]¶m3=value3" }
|
118
|
+
end
|
119
|
+
|
120
|
+
context "with both string and regexp filters" do
|
121
|
+
let(:filters) { ["param1", /param2/] }
|
122
|
+
let(:url) { "/dir/page?param1=value1¶m2=value2¶m3=value3" }
|
123
|
+
it { should eq "/dir/page?param1=[FILTERED]¶m2=[FILTERED]¶m3=value3" }
|
124
|
+
end
|
125
|
+
|
126
|
+
context "with matching regexp filters" do
|
127
|
+
let(:filters) { [/\Aaccess_token\z/] }
|
128
|
+
let(:url) { "https://host.example/sessions?access_token=abc123" }
|
129
|
+
it { should eq "https://host.example/sessions?access_token=[FILTERED]" }
|
130
|
+
end
|
131
|
+
|
132
|
+
context "with partially-matching regexp filters" do
|
133
|
+
let(:filters) { [/token/] }
|
134
|
+
let(:url) { "https://host.example/sessions?access_token=abc123" }
|
135
|
+
it { should eq "https://host.example/sessions?access_token=[FILTERED]" }
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/spec/helper_spec.rb
CHANGED
@@ -3,68 +3,6 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe Bugsnag::Helpers do
|
6
|
-
it "cleans up recursive hashes" do
|
7
|
-
a = {:a => {}}
|
8
|
-
a[:a][:b] = a
|
9
|
-
expect(Bugsnag::Helpers.cleanup_obj(a)).to eq({:a => {:b => "[RECURSION]"}})
|
10
|
-
end
|
11
|
-
|
12
|
-
it "cleans up recursive arrays" do
|
13
|
-
a = []
|
14
|
-
a << a
|
15
|
-
a << "hello"
|
16
|
-
expect(Bugsnag::Helpers.cleanup_obj(a)).to eq(["[RECURSION]", "hello"])
|
17
|
-
end
|
18
|
-
|
19
|
-
it "allows multiple copies of the same string" do
|
20
|
-
a = {:name => "bugsnag"}
|
21
|
-
a[:second] = a[:name]
|
22
|
-
expect(Bugsnag::Helpers.cleanup_obj(a)).to eq({:name => "bugsnag", :second => "bugsnag"})
|
23
|
-
end
|
24
|
-
|
25
|
-
it "allows multiple copies of the same object" do
|
26
|
-
a = []
|
27
|
-
b = ["hello"]
|
28
|
-
a << b; a << b
|
29
|
-
expect(Bugsnag::Helpers.cleanup_obj(a)).to eq([["hello"], ["hello"]])
|
30
|
-
end
|
31
|
-
|
32
|
-
it "cleans up UTF8 strings properly" do
|
33
|
-
obj = "André"
|
34
|
-
expect(Bugsnag::Helpers.cleanup_obj(obj)).to eq("André")
|
35
|
-
end
|
36
|
-
|
37
|
-
it "cleans up binary strings properly" do
|
38
|
-
if RUBY_VERSION > "1.9"
|
39
|
-
obj = "Andr\xc7\xff"
|
40
|
-
if obj.respond_to? :force_encoding
|
41
|
-
obj = obj.force_encoding('BINARY')
|
42
|
-
end
|
43
|
-
expect(Bugsnag::Helpers.cleanup_obj(obj)).to eq("Andr��")
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
it "cleans up strings returned from #to_s properly" do
|
48
|
-
if RUBY_VERSION > "1.9"
|
49
|
-
str = "Andr\xc7\xff"
|
50
|
-
if str.respond_to? :force_encoding
|
51
|
-
str = str.force_encoding('BINARY')
|
52
|
-
end
|
53
|
-
obj = RuntimeError.new(str)
|
54
|
-
expect(Bugsnag::Helpers.cleanup_obj(obj)).to eq("Andr��")
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
it "filters by string inclusion" do
|
59
|
-
expect(Bugsnag::Helpers.cleanup_obj({ :foo => 'bar' }, ['f'])).to eq({ :foo => '[FILTERED]' })
|
60
|
-
expect(Bugsnag::Helpers.cleanup_obj({ :foo => 'bar' }, ['b'])).to eq({ :foo => 'bar' })
|
61
|
-
end
|
62
|
-
|
63
|
-
it "filters by regular expression" do
|
64
|
-
expect(Bugsnag::Helpers.cleanup_obj({ :foo => 'bar' }, [/fb?/])).to eq({ :foo => '[FILTERED]' })
|
65
|
-
expect(Bugsnag::Helpers.cleanup_obj({ :foo => 'bar' }, [/fb+/])).to eq({ :foo => 'bar' })
|
66
|
-
end
|
67
|
-
|
68
6
|
it "reduces hash size correctly" do
|
69
7
|
meta_data = {
|
70
8
|
:key_one => "this should not be truncated",
|
@@ -89,56 +27,4 @@ describe Bugsnag::Helpers do
|
|
89
27
|
expect(meta_data[:key_one].length).to eq(28)
|
90
28
|
expect(meta_data[:key_one]).to eq("this should not be truncated")
|
91
29
|
end
|
92
|
-
|
93
|
-
it "works with no filters configured" do
|
94
|
-
url = Bugsnag::Helpers.cleanup_url "/dir/page?param1=value1¶m2=value2"
|
95
|
-
|
96
|
-
expect(url).to eq("/dir/page?param1=value1¶m2=value2")
|
97
|
-
end
|
98
|
-
|
99
|
-
it "does not filter with no get params" do
|
100
|
-
url = Bugsnag::Helpers.cleanup_url "/dir/page"
|
101
|
-
|
102
|
-
expect(url).to eq("/dir/page")
|
103
|
-
end
|
104
|
-
|
105
|
-
it "leaves a url alone if no filters match" do
|
106
|
-
url = Bugsnag::Helpers.cleanup_url "/dir/page?param1=value1¶m2=value2", ["param3"]
|
107
|
-
|
108
|
-
expect(url).to eq("/dir/page?param1=value1¶m2=value2")
|
109
|
-
end
|
110
|
-
|
111
|
-
it "filters a single get param" do
|
112
|
-
url = Bugsnag::Helpers.cleanup_url "/dir/page?param1=value1¶m2=value2", ["param1"]
|
113
|
-
|
114
|
-
expect(url).to eq("/dir/page?param1=[FILTERED]¶m2=value2")
|
115
|
-
end
|
116
|
-
|
117
|
-
it "filters a get param that contains a filtered term" do
|
118
|
-
url = Bugsnag::Helpers.cleanup_url '/dir/page?param1=value1¶m2=value2&bla=yes', ["param"]
|
119
|
-
|
120
|
-
expect(url).to eq("/dir/page?param1=[FILTERED]¶m2=[FILTERED]&bla=yes")
|
121
|
-
end
|
122
|
-
|
123
|
-
it "filters multiple matches" do
|
124
|
-
url = Bugsnag::Helpers.cleanup_url "/dir/page?param1=value1¶m2=value2¶m3=value3", ["param1", "param2"]
|
125
|
-
|
126
|
-
expect(url).to eq("/dir/page?param1=[FILTERED]¶m2=[FILTERED]¶m3=value3")
|
127
|
-
end
|
128
|
-
|
129
|
-
it "filters using a combination of string and regex filters" do
|
130
|
-
url = Bugsnag::Helpers.cleanup_url "/dir/page?param1=value1¶m2=value2¶m3=value3", ["param1", /param2/]
|
131
|
-
|
132
|
-
expect(url).to eq("/dir/page?param1=[FILTERED]¶m2=[FILTERED]¶m3=value3")
|
133
|
-
end
|
134
|
-
|
135
|
-
it "filters regex matches" do
|
136
|
-
url = Bugsnag::Helpers.cleanup_url "https://host.example/sessions?access_token=abc123", [/\Aaccess_token\z/]
|
137
|
-
expect(url).to eq("https://host.example/sessions?access_token=[FILTERED]")
|
138
|
-
end
|
139
|
-
|
140
|
-
it "filters partial regex matches" do
|
141
|
-
url = Bugsnag::Helpers.cleanup_url "https://host.example/sessions?access_token=abc123", [/token/]
|
142
|
-
expect(url).to eq("https://host.example/sessions?access_token=[FILTERED]")
|
143
|
-
end
|
144
30
|
end
|
data/spec/integration_spec.rb
CHANGED
@@ -17,6 +17,7 @@ describe 'Bugsnag' do
|
|
17
17
|
end
|
18
18
|
after do
|
19
19
|
server.stop
|
20
|
+
queue.clear
|
20
21
|
end
|
21
22
|
|
22
23
|
let(:request) { JSON.parse(queue.pop) }
|
@@ -68,6 +69,27 @@ describe 'Bugsnag' do
|
|
68
69
|
expect(request['events'][0]['exceptions'][0]['message']).to eq('yo')
|
69
70
|
end
|
70
71
|
|
72
|
+
it 'should work with threadpool delivery after fork' do
|
73
|
+
is_jruby = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
|
74
|
+
unless is_jruby #jruby doesn't support fork, so this test doesn't apply
|
75
|
+
Bugsnag.configure do |config|
|
76
|
+
config.endpoint = "localhost:#{server.config[:Port]}"
|
77
|
+
config.use_ssl = false
|
78
|
+
config.delivery_method = :thread_queue
|
79
|
+
end
|
80
|
+
WebMock.allow_net_connect!
|
81
|
+
|
82
|
+
Bugsnag.notify 'yo'
|
83
|
+
|
84
|
+
Process.fork do
|
85
|
+
Bugsnag.notify 'yo too'
|
86
|
+
end
|
87
|
+
Process.wait
|
88
|
+
|
89
|
+
expect(queue.length).to eq(2)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
71
93
|
describe 'with a proxy' do
|
72
94
|
proxy = nil
|
73
95
|
pqueue = Queue.new
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bugsnag
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-12-
|
11
|
+
date: 2015-12-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -86,6 +86,20 @@ dependencies:
|
|
86
86
|
- - '>='
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
version: '0'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: addressable
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ~>
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 2.3.8
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ~>
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 2.3.8
|
89
103
|
- !ruby/object:Gem::Dependency
|
90
104
|
name: webmock
|
91
105
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,6 +140,7 @@ files:
|
|
126
140
|
- lib/bugsnag.rb
|
127
141
|
- lib/bugsnag/capistrano.rb
|
128
142
|
- lib/bugsnag/capistrano2.rb
|
143
|
+
- lib/bugsnag/cleaner.rb
|
129
144
|
- lib/bugsnag/configuration.rb
|
130
145
|
- lib/bugsnag/delay/resque.rb
|
131
146
|
- lib/bugsnag/delayed_job.rb
|
@@ -161,6 +176,7 @@ files:
|
|
161
176
|
- lib/bugsnag/version.rb
|
162
177
|
- lib/generators/bugsnag/bugsnag_generator.rb
|
163
178
|
- rails/init.rb
|
179
|
+
- spec/cleaner_spec.rb
|
164
180
|
- spec/code_spec.rb
|
165
181
|
- spec/fixtures/crashes/end_of_file.rb
|
166
182
|
- spec/fixtures/crashes/short_file.rb
|