logasm-jruby 1.2.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.
@@ -0,0 +1,131 @@
1
+ require 'spec_helper'
2
+ require_relative '../../lib/logasm/preprocessors/blacklist'
3
+
4
+ describe Logasm::Preprocessors::Blacklist do
5
+ subject(:processed_data) { described_class.new(config).process(data) }
6
+
7
+ let(:config) {{
8
+ fields: [{ key: 'field', action: action }]
9
+ }}
10
+
11
+ let(:action) {}
12
+ let(:data) {{
13
+ field: value,
14
+ data: {
15
+ field: 'secret'
16
+ },
17
+ array: [{field: 'secret'}]
18
+ }}
19
+
20
+ let(:value) { 'secret' }
21
+
22
+ context 'when action is unsupported' do
23
+ let(:action) { 'reverse' }
24
+
25
+ it 'throws exception' do
26
+ expect { processed_data }.to raise_exception(Logasm::Preprocessors::Blacklist::UnsupportedActionException)
27
+ end
28
+ end
29
+
30
+ context 'when action is "exclude"' do
31
+ let(:action) { 'exclude' }
32
+
33
+ it 'removes the field' do
34
+ expect(processed_data).not_to include(:field)
35
+ end
36
+
37
+ it 'removes nested field' do
38
+ expect(processed_data).not_to include_at_depth({field: 'secret'}, 1)
39
+ end
40
+
41
+ it 'removes nested in array field' do
42
+ expect(processed_data[:array]).not_to include({field: 'secret'})
43
+ end
44
+
45
+ context 'when field is deeply nested' do
46
+ let(:depth) { 10 }
47
+ let(:data) { data_with_nested_field({field: 'secret'}, depth) }
48
+
49
+ it 'removes deeply nested field' do
50
+ expect(processed_data).not_to include_at_depth({field: 'secret'}, depth)
51
+ end
52
+ end
53
+ end
54
+
55
+ context 'when action is "mask"' do
56
+ let(:action) { 'mask' }
57
+
58
+ it 'masks nested field' do
59
+ expect(processed_data).to include_at_depth({field: '*****'}, 1)
60
+ end
61
+
62
+ it 'masks nested in array field' do
63
+ expect(processed_data[:array]).to include({field: '*****'})
64
+ end
65
+
66
+ context 'when field is string' do
67
+ let(:value) { 'secret' }
68
+
69
+ it 'masks value with asterisks' do
70
+ expect(processed_data).to include(field: '*****')
71
+ end
72
+ end
73
+
74
+ context 'when field is number' do
75
+ let(:value) { 42 }
76
+
77
+ it 'masks number value' do
78
+ expect(processed_data).to include(field: '*****')
79
+ end
80
+ end
81
+
82
+ context 'when field is boolean' do
83
+ let(:value) { true }
84
+
85
+ it 'masks value with asterisks' do
86
+ expect(processed_data).to include(field: '*****')
87
+ end
88
+ end
89
+
90
+ context 'when field is array' do
91
+ let(:value) { [1,2,3,4] }
92
+
93
+ it 'masks value with asterisks' do
94
+ expect(processed_data).to include(field: '*****')
95
+ end
96
+ end
97
+
98
+ context 'when field is hash' do
99
+ let(:value) { {data: {}} }
100
+
101
+ it 'masks value with asterisks' do
102
+ expect(processed_data).to include(field: '*****')
103
+ end
104
+ end
105
+
106
+ context 'when field is deeply nested' do
107
+ let(:depth) { 10 }
108
+ let(:data) { data_with_nested_field({field: 'secret'}, depth) }
109
+
110
+ it 'masks deeply nested field' do
111
+ expect(processed_data).to include_at_depth({field: '*****'}, depth)
112
+ end
113
+ end
114
+ end
115
+
116
+ def data_with_nested_field(field, depth)
117
+ depth.times.inject(field) do |mem|
118
+ {}.merge(data: mem)
119
+ end
120
+ end
121
+
122
+ RSpec::Matchers.define :include_at_depth do |expected_hash, depth|
123
+ match do |actual|
124
+ nested_data = depth.times.inject(actual) do |mem|
125
+ mem[:data]
126
+ end
127
+
128
+ expect(nested_data).to include(expected_hash)
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'logasm/preprocessors/json_pointer_trie'
3
+
4
+ RSpec.describe Logasm::Preprocessors::JSONPointerTrie do
5
+ let(:trie) { described_class.new }
6
+
7
+ describe '#includes?' do
8
+ it 'returns true for empty prefix' do
9
+ expect(trie).to include('')
10
+ end
11
+
12
+ it 'returns true if trie contains requested prefix or value itself' do
13
+ trie.insert('/data/nested/key')
14
+
15
+ expect(trie).to include('/data')
16
+ expect(trie).to include('/data/nested')
17
+ expect(trie).to include('/data/nested/key')
18
+ end
19
+
20
+ it 'returns false if trie does not contain requested prefix or value' do
21
+ trie.insert('/data/nested/key')
22
+
23
+ expect(trie).to_not include('/bad_data')
24
+ expect(trie).to_not include('/data/bad_nested')
25
+ expect(trie).to_not include('/data/nested/bad_key')
26
+ end
27
+
28
+ it 'returns true if trie contains requested prefix under wildcard' do
29
+ trie.insert('/data/~/key')
30
+
31
+ expect(trie).to include('/data/arbitrary_key/key')
32
+ expect(trie).to include('/data/another_key/key')
33
+ expect(trie).to_not include('/data/arbitrary_key/bad_nested_key')
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,335 @@
1
+ require 'spec_helper'
2
+ require_relative '../../lib/logasm/preprocessors/whitelist'
3
+
4
+ RSpec.describe Logasm::Preprocessors::Whitelist, 'when :action is :mask or omitted' do
5
+ subject(:processed_data) { described_class.new(config).process(data) }
6
+
7
+ let(:config) { { pointers: pointers } }
8
+ let(:pointers) { [] }
9
+ let(:data) do
10
+ {
11
+ field: 'secret',
12
+ data: {
13
+ field: 'secret'
14
+ },
15
+ array: [{ field: 'secret' }]
16
+ }
17
+ end
18
+
19
+ it 'masks all non-whitelisted fields' do
20
+ expect(processed_data).to eq(
21
+ field: '*****',
22
+ data: '*****',
23
+ array: '*****'
24
+ )
25
+ end
26
+
27
+ context 'when pointer has trailing slash' do
28
+ let(:pointers) { ['/field/'] }
29
+
30
+ it 'throws exception' do
31
+ expect { processed_data }.to raise_exception(Logasm::Preprocessors::Whitelist::InvalidPointerFormatException)
32
+ end
33
+ end
34
+
35
+ context 'with whitelisted field' do
36
+ let(:pointers) { ['/field'] }
37
+
38
+ it 'includes the field' do
39
+ expect(processed_data).to eq(
40
+ field: 'secret',
41
+ data: '*****',
42
+ array: '*****'
43
+ )
44
+ end
45
+ end
46
+
47
+ context 'with whitelisted nested field' do
48
+ let(:pointers) { ['/data/field'] }
49
+
50
+ it 'includes nested field' do
51
+ expect(processed_data).to eq(
52
+ field: '*****',
53
+ data: {
54
+ field: 'secret'
55
+ },
56
+ array: '*****'
57
+ )
58
+ end
59
+ end
60
+
61
+ context 'with whitelisted array element field' do
62
+ let(:pointers) { ['/array/0/field'] }
63
+
64
+ it 'includes array element' do
65
+ expect(processed_data).to eq(
66
+ field: '*****',
67
+ data: '*****',
68
+ array: [{ field: 'secret' }]
69
+ )
70
+ end
71
+ end
72
+
73
+ context 'with whitelisted hash' do
74
+ it 'includes all whitelisted hash elements' do
75
+ source = { foo: { bar: 'baz' } }
76
+ target = { foo: { bar: 'baz' } }
77
+ expect(process(['/foo/~'], source)).to eq(target)
78
+ end
79
+
80
+ it 'does not include nested elements' do
81
+ source = { foo: { bar: { baz: 'asd' } } }
82
+ target = { foo: { bar: { baz: '*****' } } }
83
+ expect(process(['/foo/~'], source)).to eq(target)
84
+ end
85
+ end
86
+
87
+ context 'with whitelisted array elements field with wildcard' do
88
+ let(:data) do
89
+ {
90
+ array: [
91
+ { field: 'data1', secret: 'secret1' },
92
+ { field: 'data2', secret: 'secret2' }
93
+ ]
94
+ }
95
+ end
96
+ let(:pointers) { ['/array/~/field'] }
97
+
98
+ it 'includes array elements field' do
99
+ expect(processed_data).to include(
100
+ array: [
101
+ { field: 'data1', secret: '*****' },
102
+ { field: 'data2', secret: '*****' }
103
+ ]
104
+ )
105
+ end
106
+ end
107
+
108
+ context 'with whitelisted string array elements with wildcard' do
109
+ let(:data) do
110
+ { array: %w[secret secret] }
111
+ end
112
+ let(:pointers) { ['/array/~'] }
113
+
114
+ it 'includes array elements' do
115
+ expect(processed_data).to include(array: %w[secret secret])
116
+ end
117
+ end
118
+
119
+ context 'with whitelisted string array elements in an array with wildcard' do
120
+ let(:data) do
121
+ {
122
+ nested: [{ array: %w[secret secret] }]
123
+ }
124
+ end
125
+ let(:pointers) { ['/nested/~/array/~'] }
126
+
127
+ it 'includes array elements' do
128
+ expect(processed_data).to include(nested: [{ array: %w[secret secret] }])
129
+ end
130
+ end
131
+
132
+
133
+ context 'with whitelisted array element' do
134
+ let(:pointers) { ['/array/0'] }
135
+
136
+ it 'masks array element' do
137
+ expect(processed_data).to include(array: [{ field: '*****' }])
138
+ end
139
+ end
140
+
141
+ context 'with whitelisted array' do
142
+ let(:pointers) { ['/array'] }
143
+
144
+ it 'masks array' do
145
+ expect(processed_data).to include(array: ['*****'])
146
+ end
147
+ end
148
+
149
+ context 'with whitelisted hash' do
150
+ let(:pointers) { ['/data'] }
151
+
152
+ it 'masks hash' do
153
+ expect(processed_data).to include(data: { field: '*****' })
154
+ end
155
+ end
156
+
157
+ context 'when boolean present' do
158
+ let(:data) { { bool: true } }
159
+
160
+ it 'masks it with asteriks' do
161
+ expect(processed_data).to eq(bool: '*****')
162
+ end
163
+ end
164
+
165
+ context 'when field has slash in the name' do
166
+ let(:data) do
167
+ { 'field_with_/' => 'secret' }
168
+ end
169
+ let(:pointers) { ['/field_with_~1'] }
170
+
171
+ it 'includes field' do
172
+ expect(processed_data).to include('field_with_/'=> 'secret')
173
+ end
174
+ end
175
+
176
+ context 'when field has tilde in the name' do
177
+ let(:data) do
178
+ { 'field_with_~' => 'secret' }
179
+ end
180
+ let(:pointers) { ['/field_with_~0'] }
181
+
182
+ it 'includes field' do
183
+ expect(processed_data).to include('field_with_~'=> 'secret')
184
+ end
185
+ end
186
+
187
+ context 'when field has tilde and 1' do
188
+ let(:data) do
189
+ { 'field_with_~1' => 'secret' }
190
+ end
191
+ let(:pointers) { ['/field_with_~01'] }
192
+
193
+ it 'includes field' do
194
+ expect(processed_data).to include('field_with_~1'=> 'secret')
195
+ end
196
+ end
197
+
198
+ def process(pointers, data)
199
+ described_class.new(pointers: pointers).process(data)
200
+ end
201
+ end
202
+
203
+ RSpec.describe Logasm::Preprocessors::Whitelist, 'when :action is :exclude or :prune' do
204
+ subject(:processed_data) { described_class.new(config).process(data) }
205
+
206
+ let(:config) { { pointers: pointers, action: :prune } }
207
+ let(:pointers) { [] }
208
+ let(:data) do
209
+ {
210
+ field: 'secret',
211
+ data: {
212
+ field: 'secret'
213
+ },
214
+ array: [{ field: 'secret' }, { field2: 'secret' }]
215
+ }
216
+ end
217
+
218
+ context 'when pointers is empty' do
219
+ it 'prunes all fields from the input' do
220
+ expect(processed_data).to eq({})
221
+ end
222
+ end
223
+
224
+ context 'with whitelisted field' do
225
+ let(:pointers) { ['/field'] }
226
+
227
+ it 'includes the field' do
228
+ expect(processed_data).to eq(field: 'secret')
229
+ end
230
+ end
231
+
232
+ context 'with whitelisted nested field' do
233
+ let(:pointers) { ['/data/field'] }
234
+
235
+ it 'includes nested field' do
236
+ expect(processed_data).to eq(data: { field: 'secret' })
237
+ end
238
+ end
239
+
240
+ context 'with whitelisted array element field' do
241
+ let(:pointers) { ['/array/0/field'] }
242
+
243
+ it 'includes array element' do
244
+ expect(processed_data).to eq(array: [{ field: 'secret' }])
245
+ end
246
+ end
247
+
248
+ context 'with whitelisted hash' do
249
+ it 'includes all whitelisted hash elements' do
250
+ source = { foo: { bar: 'baz' } }
251
+ target = { foo: { bar: 'baz' } }
252
+ expect(process(['/foo/~'], source)).to eq(target)
253
+ end
254
+
255
+ it 'does not include nested elements' do
256
+ source = { foo: { bar: { baz: 'asd' } } }
257
+ target = { foo: { bar: {} } }
258
+ expect(process(['/foo/~'], source)).to eq(target)
259
+ end
260
+ end
261
+
262
+ context 'with whitelisted array elements field with wildcard' do
263
+ let(:data) do
264
+ {
265
+ array: [
266
+ { field: 'data1', secret: 'secret1' },
267
+ { field: 'data2', secret: 'secret2' }
268
+ ]
269
+ }
270
+ end
271
+ let(:pointers) { ['/array/~/field'] }
272
+
273
+ it 'includes array elements field' do
274
+ expect(processed_data).to include(
275
+ array: [
276
+ { field: 'data1' },
277
+ { field: 'data2' }
278
+ ]
279
+ )
280
+ end
281
+ end
282
+
283
+ context 'with whitelisted string array elements with wildcard' do
284
+ let(:data) do
285
+ { array: %w[secret1 secret2] }
286
+ end
287
+ let(:pointers) { ['/array/~'] }
288
+
289
+ it 'includes array elements' do
290
+ expect(processed_data).to include(array: %w[secret1 secret2])
291
+ end
292
+ end
293
+
294
+ context 'with whitelisted string array elements in an array with wildcard' do
295
+ let(:data) do
296
+ {
297
+ nested: [{ array: %w[secret1 secret2] }]
298
+ }
299
+ end
300
+ let(:pointers) { ['/nested/~/array/~'] }
301
+
302
+ it 'includes array elements' do
303
+ expect(processed_data).to include(nested: [{ array: %w[secret1 secret2] }])
304
+ end
305
+ end
306
+
307
+
308
+ context 'with whitelisted array element' do
309
+ let(:pointers) { ['/array/0'] }
310
+
311
+ it 'masks array element' do
312
+ expect(processed_data).to eq(array: [{}])
313
+ end
314
+ end
315
+
316
+ context 'with whitelisted array' do
317
+ let(:pointers) { ['/array'] }
318
+
319
+ it 'masks array' do
320
+ expect(processed_data).to include(array: [])
321
+ end
322
+ end
323
+
324
+ context 'with whitelisted hash' do
325
+ let(:pointers) { ['/data'] }
326
+
327
+ it 'masks hash' do
328
+ expect(processed_data).to include(data: {})
329
+ end
330
+ end
331
+
332
+ def process(pointers, data)
333
+ described_class.new(pointers: pointers, action: :prune).process(data)
334
+ end
335
+ end