airbrake-ruby 2.2.3 → 2.2.4
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/lib/airbrake-ruby.rb +1 -2
- data/lib/airbrake-ruby/filter_chain.rb +1 -25
- data/lib/airbrake-ruby/filters/keys_filter.rb +5 -0
- data/lib/airbrake-ruby/filters/thread_filter.rb +25 -12
- data/lib/airbrake-ruby/notice.rb +11 -21
- data/lib/airbrake-ruby/notifier.rb +24 -4
- data/lib/airbrake-ruby/{payload_truncator.rb → truncator.rb} +22 -39
- data/lib/airbrake-ruby/version.rb +1 -1
- data/spec/filter_chain_spec.rb +22 -198
- data/spec/filters/gem_root_filter_spec.rb +46 -0
- data/spec/filters/keys_blacklist_spec.rb +181 -6
- data/spec/filters/keys_whitelist_spec.rb +213 -0
- data/spec/filters/root_directory_filter_spec.rb +44 -0
- data/spec/filters/system_exit_filter_spec.rb +16 -0
- data/spec/filters/thread_filter_spec.rb +197 -51
- data/spec/notice_spec.rb +1 -1
- data/spec/sync_sender_spec.rb +1 -1
- data/spec/{payload_truncator_spec.rb → truncator_spec.rb} +15 -35
- metadata +13 -10
- data/lib/airbrake-ruby/filters.rb +0 -10
- data/spec/notifier_spec/blacklist_keys_spec.rb +0 -192
- data/spec/notifier_spec/whitelist_keys_spec.rb +0 -248
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Airbrake::Filters::GemRootFilter do
|
4
|
+
let(:notice) do
|
5
|
+
Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new)
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:root1) { '/my/gem/root' }
|
9
|
+
let(:root2) { '/my/other/gem/root' }
|
10
|
+
|
11
|
+
before { Gem.path << root1 << root2 }
|
12
|
+
after { 2.times { Gem.path.pop } }
|
13
|
+
|
14
|
+
it "replaces gem root in the backtrace with a label" do
|
15
|
+
# rubocop:disable Metrics/LineLength
|
16
|
+
notice[:errors].first[:backtrace] = [
|
17
|
+
{ file: "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb" },
|
18
|
+
{ file: "#{root1}/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb" },
|
19
|
+
{ file: "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb" },
|
20
|
+
{ file: "#{root2}/gems/rspec-core-3.3.2/exe/rspec" }
|
21
|
+
]
|
22
|
+
# rubocop:enable Metrics/LineLength
|
23
|
+
|
24
|
+
subject.call(notice)
|
25
|
+
|
26
|
+
# rubocop:disable Metrics/LineLength
|
27
|
+
expect(notice[:errors].first[:backtrace]).to(
|
28
|
+
eq(
|
29
|
+
[
|
30
|
+
{ file: "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb" },
|
31
|
+
{ file: "[GEM_ROOT]/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb" },
|
32
|
+
{ file: "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb" },
|
33
|
+
{ file: "[GEM_ROOT]/gems/rspec-core-3.3.2/exe/rspec" }
|
34
|
+
]
|
35
|
+
)
|
36
|
+
)
|
37
|
+
# rubocop:enable Metrics/LineLength
|
38
|
+
end
|
39
|
+
|
40
|
+
it "does not filter file when it is nil" do
|
41
|
+
expect(notice[:errors].first[:file]).to be_nil
|
42
|
+
expect { subject.call(notice) }.not_to(
|
43
|
+
change { notice[:errors].first[:file] }
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
@@ -1,22 +1,197 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe Airbrake::Filters::KeysBlacklist do
|
4
|
-
subject
|
5
|
-
|
4
|
+
subject { described_class.new(Logger.new('/dev/null'), patterns) }
|
5
|
+
|
6
|
+
let(:notice) do
|
7
|
+
Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new)
|
6
8
|
end
|
7
9
|
|
8
|
-
|
9
|
-
let(:
|
10
|
-
|
10
|
+
shared_examples 'pattern matching' do |patts, params|
|
11
|
+
let(:patterns) { patts }
|
12
|
+
|
13
|
+
it "filters out the matching values" do
|
14
|
+
notice[:params] = params.first
|
15
|
+
subject.call(notice)
|
16
|
+
expect(notice[:params]).to eq(params.last)
|
11
17
|
end
|
18
|
+
end
|
12
19
|
|
13
|
-
|
20
|
+
context "when a pattern is a Regexp" do
|
21
|
+
include_examples(
|
22
|
+
'pattern matching',
|
23
|
+
[/\Abon/],
|
24
|
+
[
|
25
|
+
{ bongo: 'bango' },
|
26
|
+
{ bongo: '[Filtered]' }
|
27
|
+
]
|
28
|
+
)
|
29
|
+
|
30
|
+
context "and when a key is a hash" do
|
14
31
|
let(:patterns) { [/bango/] }
|
15
32
|
|
33
|
+
# https://github.com/airbrake/airbrake/issues/739
|
16
34
|
it "doesn't fail" do
|
17
35
|
notice[:params] = { bingo: { {} => 'unfiltered' } }
|
18
36
|
expect { subject.call(notice) }.not_to raise_error
|
19
37
|
end
|
20
38
|
end
|
21
39
|
end
|
40
|
+
|
41
|
+
context "when a pattern is a Symbol" do
|
42
|
+
include_examples(
|
43
|
+
'pattern matching',
|
44
|
+
[:bingo],
|
45
|
+
[
|
46
|
+
{ bingo: 'bango' },
|
47
|
+
{ bingo: '[Filtered]' }
|
48
|
+
]
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when a pattern is a String" do
|
53
|
+
include_examples(
|
54
|
+
'pattern matching',
|
55
|
+
['bingo'],
|
56
|
+
[
|
57
|
+
{ bingo: 'bango' },
|
58
|
+
{ bingo: '[Filtered]' }
|
59
|
+
]
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when a Proc pattern was provided" do
|
64
|
+
context "along with normal keys" do
|
65
|
+
include_examples(
|
66
|
+
'pattern matching',
|
67
|
+
[proc { 'bongo' }, :bash],
|
68
|
+
[
|
69
|
+
{ bingo: 'bango', bongo: 'bish', bash: 'bosh' },
|
70
|
+
{ bingo: 'bango', bongo: '[Filtered]', bash: '[Filtered]' }
|
71
|
+
]
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
context "which doesn't return an array of keys" do
|
76
|
+
include_examples(
|
77
|
+
'pattern matching',
|
78
|
+
[proc { Object.new }],
|
79
|
+
[
|
80
|
+
{ bingo: 'bango', bongo: 'bish' },
|
81
|
+
{ bingo: 'bango', bongo: 'bish' }
|
82
|
+
]
|
83
|
+
)
|
84
|
+
|
85
|
+
it "logs an error" do
|
86
|
+
out = StringIO.new
|
87
|
+
logger = Logger.new(out)
|
88
|
+
keys_blacklist = described_class.new(logger, patterns)
|
89
|
+
keys_blacklist.call(notice)
|
90
|
+
|
91
|
+
expect(out.string).to(
|
92
|
+
match(/ERROR.+KeysBlacklist is invalid.+patterns: \[#<Object:.+>\]/)
|
93
|
+
)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "which returns another Proc" do
|
98
|
+
let(:patterns) { [proc { proc { ['bingo'] } }] }
|
99
|
+
|
100
|
+
context "and when the filter is called once" do
|
101
|
+
it "logs an error" do
|
102
|
+
out = StringIO.new
|
103
|
+
logger = Logger.new(out)
|
104
|
+
keys_blacklist = described_class.new(logger, patterns)
|
105
|
+
keys_blacklist.call(notice)
|
106
|
+
|
107
|
+
expect(out.string).to(
|
108
|
+
match(/ERROR.+KeysBlacklist is invalid.+patterns: \[#<Proc:.+>\]/)
|
109
|
+
)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context "and when the filter is called twice" do
|
114
|
+
it "unwinds procs and filters keys" do
|
115
|
+
notice[:params] = { bingo: 'bango', bongo: 'bish' }
|
116
|
+
2.times { subject.call(notice) }
|
117
|
+
expect(notice[:params]).to eq(bingo: '[Filtered]', bongo: 'bish')
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context "when a pattern is invalid" do
|
124
|
+
include_examples(
|
125
|
+
'pattern matching',
|
126
|
+
[Object.new],
|
127
|
+
[
|
128
|
+
{ bingo: 'bango', bongo: 'bish' },
|
129
|
+
{ bingo: 'bango', bongo: 'bish' }
|
130
|
+
]
|
131
|
+
)
|
132
|
+
|
133
|
+
it "logs an error" do
|
134
|
+
out = StringIO.new
|
135
|
+
logger = Logger.new(out)
|
136
|
+
keys_blacklist = described_class.new(logger, patterns)
|
137
|
+
keys_blacklist.call(notice)
|
138
|
+
|
139
|
+
expect(out.string).to(
|
140
|
+
match(/ERROR.+KeysBlacklist is invalid.+patterns: \[#<Object:.+>\]/)
|
141
|
+
)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context "when a value contains a nested hash" do
|
146
|
+
context "and it is non-recursive" do
|
147
|
+
include_examples(
|
148
|
+
'pattern matching',
|
149
|
+
['bish'],
|
150
|
+
[
|
151
|
+
{ bongo: { bish: 'bash' } },
|
152
|
+
{ bongo: { bish: '[Filtered]' } }
|
153
|
+
]
|
154
|
+
)
|
155
|
+
end
|
156
|
+
|
157
|
+
context "and it is recursive" do
|
158
|
+
bongo = { bingo: {} }
|
159
|
+
bongo[:bingo][:bango] = bongo
|
160
|
+
|
161
|
+
include_examples(
|
162
|
+
'pattern matching',
|
163
|
+
['bango'],
|
164
|
+
[
|
165
|
+
bongo,
|
166
|
+
{ bingo: { bango: '[Filtered]' } }
|
167
|
+
]
|
168
|
+
)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe "context payload" do
|
173
|
+
context "when a URL with query params is present" do
|
174
|
+
let(:patterns) { ['bish'] }
|
175
|
+
|
176
|
+
it "filters the params" do
|
177
|
+
notice[:context][:url] =
|
178
|
+
'http://localhost:3000/crash?foo=bar&baz=bongo&bish=bash&color=%23FFAAFF'
|
179
|
+
|
180
|
+
subject.call(notice)
|
181
|
+
expect(notice[:context][:url]).to(
|
182
|
+
eq 'http://localhost:3000/crash?foo=bar&baz=bongo&bish=[Filtered]&color=%23FFAAFF'
|
183
|
+
)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context "when the user key is present" do
|
188
|
+
let(:patterns) { ['user'] }
|
189
|
+
|
190
|
+
it "filters out the user" do
|
191
|
+
notice[:context][:user] = { id: 1337, name: 'Bingo Bango' }
|
192
|
+
subject.call(notice)
|
193
|
+
expect(notice[:context][:user]).to eq('[Filtered]')
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
22
197
|
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Airbrake::Filters::KeysWhitelist do
|
4
|
+
subject { described_class.new(Logger.new('/dev/null'), patterns) }
|
5
|
+
|
6
|
+
let(:notice) do
|
7
|
+
Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new)
|
8
|
+
end
|
9
|
+
|
10
|
+
shared_examples 'pattern matching' do |patts, params|
|
11
|
+
let(:patterns) { patts }
|
12
|
+
|
13
|
+
it "filters out the matching values" do
|
14
|
+
notice[:params] = params.first
|
15
|
+
subject.call(notice)
|
16
|
+
expect(notice[:params]).to eq(params.last)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when a pattern is a Regexp" do
|
21
|
+
include_examples(
|
22
|
+
'pattern matching',
|
23
|
+
[/\Abin/],
|
24
|
+
[
|
25
|
+
{ bingo: 'bango', bongo: 'bish', bash: 'bosh' },
|
26
|
+
{ bingo: 'bango', bongo: '[Filtered]', bash: '[Filtered]' }
|
27
|
+
]
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when a pattern is a Symbol" do
|
32
|
+
include_examples(
|
33
|
+
'pattern matching',
|
34
|
+
[:bongo],
|
35
|
+
[
|
36
|
+
{ bongo: 'bish', bash: 'bosh', bbashh: 'bboshh' },
|
37
|
+
{ bongo: 'bish', bash: '[Filtered]', bbashh: '[Filtered]' }
|
38
|
+
]
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
context "when a pattern is a String" do
|
43
|
+
include_examples(
|
44
|
+
'pattern matching',
|
45
|
+
['bash'],
|
46
|
+
[
|
47
|
+
{ bingo: 'bango', bongo: 'bish', bash: 'bosh' },
|
48
|
+
{ bingo: '[Filtered]', bongo: '[Filtered]', bash: 'bosh' }
|
49
|
+
]
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when a Proc pattern was provided" do
|
54
|
+
context "along with normal keys" do
|
55
|
+
include_examples(
|
56
|
+
'pattern matching',
|
57
|
+
[proc { 'bongo' }, :bash],
|
58
|
+
[
|
59
|
+
{ bingo: 'bango', bongo: 'bish', bash: 'bosh' },
|
60
|
+
{ bingo: '[Filtered]', bongo: 'bish', bash: 'bosh' }
|
61
|
+
]
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
context "which doesn't return an array of keys" do
|
66
|
+
include_examples(
|
67
|
+
'pattern matching',
|
68
|
+
[proc { Object.new }],
|
69
|
+
[
|
70
|
+
{ bingo: 'bango', bongo: 'bish', bash: 'bosh' },
|
71
|
+
{ bingo: '[Filtered]', bongo: '[Filtered]', bash: '[Filtered]' }
|
72
|
+
]
|
73
|
+
)
|
74
|
+
|
75
|
+
it "logs an error" do
|
76
|
+
out = StringIO.new
|
77
|
+
logger = Logger.new(out)
|
78
|
+
keys_whitelist = described_class.new(logger, patterns)
|
79
|
+
keys_whitelist.call(notice)
|
80
|
+
|
81
|
+
expect(out.string).to(
|
82
|
+
match(/ERROR.+KeysWhitelist is invalid.+patterns: \[#<Object:.+>\]/)
|
83
|
+
)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "which returns another Proc" do
|
88
|
+
let(:patterns) { [proc { proc { ['bingo'] } }] }
|
89
|
+
|
90
|
+
context "and when the filter is called once" do
|
91
|
+
it "logs an error" do
|
92
|
+
out = StringIO.new
|
93
|
+
logger = Logger.new(out)
|
94
|
+
keys_whitelist = described_class.new(logger, patterns)
|
95
|
+
keys_whitelist.call(notice)
|
96
|
+
|
97
|
+
expect(out.string).to(
|
98
|
+
match(/ERROR.+KeysWhitelist is invalid.+patterns: \[#<Proc:.+>\]/)
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
include_examples(
|
103
|
+
'pattern matching',
|
104
|
+
[proc { proc { ['bingo'] } }],
|
105
|
+
[
|
106
|
+
{ bingo: 'bango', bongo: 'bish', bash: 'bosh' },
|
107
|
+
{ bingo: '[Filtered]', bongo: '[Filtered]', bash: '[Filtered]' }
|
108
|
+
]
|
109
|
+
)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "when a pattern is invalid" do
|
115
|
+
include_examples(
|
116
|
+
'pattern matching',
|
117
|
+
[Object.new],
|
118
|
+
[
|
119
|
+
{ bingo: 'bango', bongo: 'bish', bash: 'bosh' },
|
120
|
+
{ bingo: '[Filtered]', bongo: '[Filtered]', bash: '[Filtered]' }
|
121
|
+
]
|
122
|
+
)
|
123
|
+
|
124
|
+
it "logs an error" do
|
125
|
+
out = StringIO.new
|
126
|
+
logger = Logger.new(out)
|
127
|
+
keys_whitelist = described_class.new(logger, patterns)
|
128
|
+
keys_whitelist.call(notice)
|
129
|
+
|
130
|
+
expect(out.string).to(
|
131
|
+
match(/ERROR.+KeysWhitelist is invalid.+patterns: \[#<Object:.+>\]/)
|
132
|
+
)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context "when a value contains a nested hash" do
|
137
|
+
context "and it is non-recursive" do
|
138
|
+
include_examples(
|
139
|
+
'pattern matching',
|
140
|
+
%w[bongo bish],
|
141
|
+
[
|
142
|
+
{ bingo: 'bango', bongo: { bish: 'bash' } },
|
143
|
+
{ bingo: '[Filtered]', bongo: { bish: 'bash' } }
|
144
|
+
]
|
145
|
+
)
|
146
|
+
end
|
147
|
+
|
148
|
+
context "and it is recursive" do
|
149
|
+
let(:patterns) { %w[bingo bango] }
|
150
|
+
|
151
|
+
it "errors when nested hashes are not filtered" do
|
152
|
+
bongo = { bingo: {} }
|
153
|
+
bongo[:bingo][:bango] = bongo
|
154
|
+
notice[:params] = bongo
|
155
|
+
|
156
|
+
if RUBY_ENGINE == 'jruby'
|
157
|
+
# JRuby might raise two different exceptions, which represent the
|
158
|
+
# same thing. One is a Java exception, the other is a Ruby
|
159
|
+
# exception. It's probably a JRuby bug:
|
160
|
+
# https://github.com/jruby/jruby/issues/1903
|
161
|
+
begin
|
162
|
+
expect do
|
163
|
+
subject.call(notice)
|
164
|
+
end.to raise_error(SystemStackError)
|
165
|
+
rescue RSpec::Expectations::ExpectationNotMetError
|
166
|
+
expect do
|
167
|
+
subject.call(notice)
|
168
|
+
end.to raise_error(java.lang.StackOverflowError)
|
169
|
+
end
|
170
|
+
else
|
171
|
+
expect do
|
172
|
+
subject.call(notice)
|
173
|
+
end.to raise_error(SystemStackError)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "context payload" do
|
180
|
+
describe "URL" do
|
181
|
+
let(:patterns) { ['bish'] }
|
182
|
+
|
183
|
+
context "when it contains query params" do
|
184
|
+
it "filters the params" do
|
185
|
+
notice[:context][:url] = 'http://localhost:3000/crash?foo=bar&baz=bongo&bish=bash'
|
186
|
+
subject.call(notice)
|
187
|
+
expect(notice[:context][:url]).to(
|
188
|
+
eq('http://localhost:3000/crash?foo=[Filtered]&baz=[Filtered]&bish=bash')
|
189
|
+
)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
context "when it is invalid" do
|
194
|
+
it "leaves the URL unfiltered" do
|
195
|
+
notice[:context][:url] =
|
196
|
+
'http://localhost:3000/cra]]]sh?foo=bar&baz=bongo&bish=bash'
|
197
|
+
subject.call(notice)
|
198
|
+
expect(notice[:context][:url]).to(
|
199
|
+
eq('http://localhost:3000/cra]]]sh?foo=bar&baz=bongo&bish=bash')
|
200
|
+
)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context "when it is without a query" do
|
205
|
+
it "leaves the URL untouched" do
|
206
|
+
notice[:context][:url] = 'http://localhost:3000/crash'
|
207
|
+
subject.call(notice)
|
208
|
+
expect(notice[:context][:url]).to(eq('http://localhost:3000/crash'))
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|