bugsnag 2.8.13 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|