castle-rb 6.0.1 → 7.1.2

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.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -8
  3. data/lib/castle/api/approve_device.rb +1 -6
  4. data/lib/castle/api/authenticate.rb +10 -7
  5. data/lib/castle/api/end_impersonation.rb +3 -8
  6. data/lib/castle/api/filter.rb +37 -0
  7. data/lib/castle/api/get_device.rb +1 -6
  8. data/lib/castle/api/get_devices_for_user.rb +1 -6
  9. data/lib/castle/api/log.rb +37 -0
  10. data/lib/castle/api/report_device.rb +1 -6
  11. data/lib/castle/api/risk.rb +37 -0
  12. data/lib/castle/api/start_impersonation.rb +3 -8
  13. data/lib/castle/api/track.rb +1 -6
  14. data/lib/castle/api.rb +7 -12
  15. data/lib/castle/client.rb +36 -16
  16. data/lib/castle/commands/approve_device.rb +1 -5
  17. data/lib/castle/commands/end_impersonation.rb +1 -1
  18. data/lib/castle/commands/{identify.rb → filter.rb} +3 -3
  19. data/lib/castle/commands/get_device.rb +1 -5
  20. data/lib/castle/commands/get_devices_for_user.rb +1 -5
  21. data/lib/castle/commands/log.rb +22 -0
  22. data/lib/castle/commands/report_device.rb +1 -5
  23. data/lib/castle/commands/risk.rb +22 -0
  24. data/lib/castle/commands/start_impersonation.rb +1 -1
  25. data/lib/castle/configuration.rb +18 -8
  26. data/lib/castle/core/get_connection.rb +3 -1
  27. data/lib/castle/core/process_response.rb +5 -2
  28. data/lib/castle/core/process_webhook.rb +10 -5
  29. data/lib/castle/core/send_request.rb +8 -18
  30. data/lib/castle/errors.rb +37 -13
  31. data/lib/castle/failover/prepare_response.rb +6 -1
  32. data/lib/castle/failover/strategy.rb +3 -0
  33. data/lib/castle/headers/extract.rb +4 -4
  34. data/lib/castle/headers/filter.rb +9 -6
  35. data/lib/castle/ips/extract.rb +4 -2
  36. data/lib/castle/logger.rb +3 -3
  37. data/lib/castle/payload/prepare.rb +3 -4
  38. data/lib/castle/secure_mode.rb +3 -2
  39. data/lib/castle/support/hanami.rb +2 -6
  40. data/lib/castle/support/rails.rb +1 -3
  41. data/lib/castle/utils/clean_invalid_chars.rb +1 -3
  42. data/lib/castle/verdict.rb +2 -0
  43. data/lib/castle/version.rb +1 -1
  44. data/lib/castle/webhooks/verify.rb +9 -7
  45. data/lib/castle.rb +7 -11
  46. data/spec/integration/rails/rails_spec.rb +9 -7
  47. data/spec/integration/rails/support/home_controller.rb +26 -24
  48. data/spec/lib/castle/api/approve_device_spec.rb +3 -3
  49. data/spec/lib/castle/api/authenticate_spec.rb +20 -24
  50. data/spec/lib/castle/api/end_impersonation_spec.rb +11 -5
  51. data/spec/lib/castle/api/filter_spec.rb +5 -0
  52. data/spec/lib/castle/api/get_device_spec.rb +3 -3
  53. data/spec/lib/castle/api/get_devices_for_user_spec.rb +3 -3
  54. data/spec/lib/castle/api/log_spec.rb +5 -0
  55. data/spec/lib/castle/api/report_device_spec.rb +3 -3
  56. data/spec/lib/castle/api/risk_spec.rb +5 -0
  57. data/spec/lib/castle/api/start_impersonation_spec.rb +11 -5
  58. data/spec/lib/castle/api/track_spec.rb +11 -7
  59. data/spec/lib/castle/api_spec.rb +4 -20
  60. data/spec/lib/castle/client_id/extract_spec.rb +4 -13
  61. data/spec/lib/castle/client_spec.rb +84 -84
  62. data/spec/lib/castle/commands/authenticate_spec.rb +8 -15
  63. data/spec/lib/castle/commands/end_impersonation_spec.rb +6 -9
  64. data/spec/lib/castle/commands/{identify_spec.rb → filter_spec.rb} +27 -32
  65. data/spec/lib/castle/commands/log_spec.rb +73 -0
  66. data/spec/lib/castle/commands/risk_spec.rb +73 -0
  67. data/spec/lib/castle/commands/start_impersonation_spec.rb +6 -9
  68. data/spec/lib/castle/commands/track_spec.rb +9 -18
  69. data/spec/lib/castle/configuration_spec.rb +2 -6
  70. data/spec/lib/castle/context/get_default_spec.rb +8 -8
  71. data/spec/lib/castle/context/prepare_spec.rb +6 -7
  72. data/spec/lib/castle/core/get_connection_spec.rb +6 -22
  73. data/spec/lib/castle/core/process_response_spec.rb +1 -8
  74. data/spec/lib/castle/core/send_request_spec.rb +26 -27
  75. data/spec/lib/castle/headers/extract_spec.rb +1 -3
  76. data/spec/lib/castle/headers/filter_spec.rb +12 -11
  77. data/spec/lib/castle/ips/extract_spec.rb +4 -13
  78. data/spec/lib/castle/logger_spec.rb +2 -6
  79. data/spec/lib/castle/payload/prepare_spec.rb +5 -4
  80. data/spec/lib/castle/session_spec.rb +13 -36
  81. data/spec/lib/castle/singleton_configuration_spec.rb +2 -6
  82. data/spec/lib/castle/utils/clean_invalid_chars_spec.rb +2 -2
  83. data/spec/lib/castle/utils/merge_spec.rb +3 -1
  84. data/spec/lib/castle/validators/present_spec.rb +5 -6
  85. data/spec/lib/castle/webhooks/verify_spec.rb +8 -24
  86. data/spec/lib/castle_spec.rb +4 -10
  87. data/spec/spec_helper.rb +1 -3
  88. data/spec/support/shared_examples/action_request.rb +155 -0
  89. data/spec/support/shared_examples/configuration.rb +14 -42
  90. metadata +23 -18
  91. data/lib/castle/api/identify.rb +0 -26
  92. data/lib/castle/api/review.rb +0 -24
  93. data/lib/castle/commands/review.rb +0 -17
  94. data/lib/castle/events.rb +0 -49
  95. data/spec/lib/castle/api/identify_spec.rb +0 -68
  96. data/spec/lib/castle/api/review_spec.rb +0 -19
  97. data/spec/lib/castle/commands/review_spec.rb +0 -24
  98. data/spec/lib/castle/events_spec.rb +0 -5
@@ -2,9 +2,9 @@
2
2
 
3
3
  describe Castle::API::GetDevicesForUser do
4
4
  before do
5
- stub_request(:any, /api.castle.io/).with(
6
- basic_auth: ['', 'secret']
7
- ).to_return(status: 200, body: '{}', headers: {})
5
+ stub_request(:any, /api.castle.io/)
6
+ .with(basic_auth: ['', 'secret'])
7
+ .to_return(status: 200, body: '{}', headers: {})
8
8
  end
9
9
 
10
10
  describe '.call' do
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Castle::API::Log do
4
+ pending
5
+ end
@@ -2,9 +2,9 @@
2
2
 
3
3
  describe Castle::API::ReportDevice do
4
4
  before do
5
- stub_request(:any, /api.castle.io/).with(
6
- basic_auth: ['', 'secret']
7
- ).to_return(status: 200, body: '{}', headers: {})
5
+ stub_request(:any, /api.castle.io/)
6
+ .with(basic_auth: ['', 'secret'])
7
+ .to_return(status: 200, body: '{}', headers: {})
8
8
  end
9
9
 
10
10
  describe '.call' do
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Castle::API::Risk do
4
+ pending
5
+ end
@@ -22,9 +22,9 @@ describe Castle::API::StartImpersonation do
22
22
  before do
23
23
  Timecop.freeze(time_now)
24
24
  stub_const('Castle::VERSION', '2.2.0')
25
- stub_request(:any, /api.castle.io/).with(
26
- basic_auth: ['', 'secret']
27
- ).to_return(status: 200, body: response_body, headers: {})
25
+ stub_request(:any, /api.castle.io/)
26
+ .with(basic_auth: ['', 'secret'])
27
+ .to_return(status: 200, body: response_body, headers: {})
28
28
  end
29
29
 
30
30
  after { Timecop.return }
@@ -32,8 +32,14 @@ describe Castle::API::StartImpersonation do
32
32
  describe 'call' do
33
33
  let(:impersonator) { 'test@castle.io' }
34
34
  let(:request_body) do
35
- { user_id: '1234', sent_at: time_auto,
36
- properties: { impersonator: impersonator }, context: context }
35
+ {
36
+ user_id: '1234',
37
+ sent_at: time_auto,
38
+ properties: {
39
+ impersonator: impersonator
40
+ },
41
+ context: context
42
+ }
37
43
  end
38
44
  let(:response_body) { { success: true }.to_json }
39
45
  let(:options) do
@@ -24,17 +24,16 @@ describe Castle::API::Track do
24
24
  before do
25
25
  Timecop.freeze(time_now)
26
26
  stub_const('Castle::VERSION', '2.2.0')
27
- stub_request(:any, /api.castle.io/).with(
28
- basic_auth: ['', 'secret']
29
- ).to_return(status: 200, body: response_body, headers: {})
27
+ stub_request(:any, /api.castle.io/)
28
+ .with(basic_auth: ['', 'secret'])
29
+ .to_return(status: 200, body: response_body, headers: {})
30
30
  end
31
31
 
32
32
  after { Timecop.return }
33
33
 
34
34
  describe 'track' do
35
35
  let(:request_body) do
36
- { event: '$login.succeeded', context: context, user_id: '1234',
37
- sent_at: time_auto }
36
+ { event: '$login.succeeded', context: context, user_id: '1234', sent_at: time_auto }
38
37
  end
39
38
 
40
39
  before { call }
@@ -53,8 +52,13 @@ describe Castle::API::Track do
53
52
  { event: '$login.succeeded', user_id: '1234', timestamp: time_user, context: context }
54
53
  end
55
54
  let(:request_body) do
56
- { event: '$login.succeeded', user_id: '1234', context: context,
57
- timestamp: time_user, sent_at: time_auto }
55
+ {
56
+ event: '$login.succeeded',
57
+ user_id: '1234',
58
+ context: context,
59
+ timestamp: time_user,
60
+ sent_at: time_auto
61
+ }
58
62
  end
59
63
 
60
64
  it do
@@ -8,31 +8,19 @@ describe Castle::API do
8
8
  context 'when request timeouts' do
9
9
  before { stub_request(:any, /api.castle.io/).to_timeout }
10
10
 
11
- it do
12
- expect do
13
- call
14
- end.to raise_error(Castle::RequestError)
15
- end
11
+ it { expect { call }.to raise_error(Castle::RequestError) }
16
12
  end
17
13
 
18
14
  context 'when non-OK response code' do
19
15
  before { stub_request(:any, /api.castle.io/).to_return(status: 400) }
20
16
 
21
- it do
22
- expect do
23
- call
24
- end.to raise_error(Castle::BadRequestError)
25
- end
17
+ it { expect { call }.to raise_error(Castle::BadRequestError) }
26
18
  end
27
19
 
28
20
  context 'when no api_secret' do
29
21
  before { allow(Castle.config).to receive(:api_secret).and_return('') }
30
22
 
31
- it do
32
- expect do
33
- call
34
- end.to raise_error(Castle::ConfigurationError)
35
- end
23
+ it { expect { call }.to raise_error(Castle::ConfigurationError) }
36
24
  end
37
25
 
38
26
  context 'when custom config' do
@@ -43,10 +31,6 @@ describe Castle::API do
43
31
  stub_request(:any, /api.castle.io/)
44
32
  end
45
33
 
46
- it do
47
- expect do
48
- call
49
- end.not_to raise_error
50
- end
34
+ it { expect { call }.not_to raise_error }
51
35
  end
52
36
  end
@@ -8,9 +8,7 @@ describe Castle::ClientId::Extract do
8
8
  let(:client_id_header) { 'abcde' }
9
9
  let(:cookies) { request.cookies }
10
10
  let(:request) { Rack::Request.new(env) }
11
- let(:env) do
12
- Rack::MockRequest.env_for('/', headers)
13
- end
11
+ let(:env) { Rack::MockRequest.env_for('/', headers) }
14
12
 
15
13
  context 'with client_id' do
16
14
  let(:headers) do
@@ -20,17 +18,12 @@ describe Castle::ClientId::Extract do
20
18
  }
21
19
  end
22
20
 
23
- it do
24
- expect(extractor.call).to eql(client_id_cookie)
25
- end
21
+ it { expect(extractor.call).to eql(client_id_cookie) }
26
22
  end
27
23
 
28
24
  context 'with X-Castle-Client-Id header' do
29
25
  let(:headers) do
30
- {
31
- 'HTTP_X_FORWARDED_FOR' => '1.2.3.4',
32
- 'HTTP_X_CASTLE_CLIENT_ID' => client_id_header
33
- }
26
+ { 'HTTP_X_FORWARDED_FOR' => '1.2.3.4', 'HTTP_X_CASTLE_CLIENT_ID' => client_id_header }
34
27
  end
35
28
 
36
29
  it 'appends the client_id' do
@@ -42,9 +35,7 @@ describe Castle::ClientId::Extract do
42
35
  let(:cookies) { nil }
43
36
  let(:headers) { {} }
44
37
 
45
- it do
46
- expect(extractor.call).to eql('')
47
- end
38
+ it { expect(extractor.call).to eql('') }
48
39
  end
49
40
 
50
41
  context 'with X-Castle-Client-Id header and cookies client' do
@@ -21,9 +21,7 @@ describe Castle::Client do
21
21
  let(:client_with_no_timestamp) { described_class.new(context: request_to_context) }
22
22
 
23
23
  let(:headers) do
24
- {
25
- 'Content-Length': '0', 'User-Agent': ua, 'X-Forwarded-For': ip.to_s, 'Cookie': true
26
- }
24
+ { 'Content-Length': '0', 'User-Agent': ua, 'X-Forwarded-For': ip.to_s, 'Cookie': true }
27
25
  end
28
26
  let(:context) do
29
27
  {
@@ -32,7 +30,10 @@ describe Castle::Client do
32
30
  user_agent: ua,
33
31
  headers: headers,
34
32
  ip: ip,
35
- library: { name: 'castle-rb', version: '2.2.0' }
33
+ library: {
34
+ name: 'castle-rb',
35
+ version: '2.2.0'
36
+ }
36
37
  }
37
38
  end
38
39
 
@@ -44,17 +45,15 @@ describe Castle::Client do
44
45
  before do
45
46
  Timecop.freeze(time_now)
46
47
  stub_const('Castle::VERSION', '2.2.0')
47
- stub_request(:any, /api.castle.io/).with(
48
- basic_auth: ['', 'secret']
49
- ).to_return(status: 200, body: response_body, headers: {})
48
+ stub_request(:any, /api.castle.io/)
49
+ .with(basic_auth: ['', 'secret'])
50
+ .to_return(status: 200, body: response_body, headers: {})
50
51
  end
51
52
 
52
53
  after { Timecop.return }
53
54
 
54
55
  describe 'parses the request' do
55
- before do
56
- allow(Castle::API).to receive(:send_request).and_call_original
57
- end
56
+ before { allow(Castle::API).to receive(:send_request).and_call_original }
58
57
 
59
58
  it do
60
59
  client.authenticate(event: '$login.succeeded', user_id: '1234')
@@ -65,8 +64,15 @@ describe Castle::Client do
65
64
  describe 'end impersonation' do
66
65
  let(:impersonator) { 'test@castle.io' }
67
66
  let(:request_body) do
68
- { user_id: '1234', timestamp: time_auto, sent_at: time_auto,
69
- properties: { impersonator: impersonator }, context: context }
67
+ {
68
+ user_id: '1234',
69
+ timestamp: time_auto,
70
+ sent_at: time_auto,
71
+ properties: {
72
+ impersonator: impersonator
73
+ },
74
+ context: context
75
+ }
70
76
  end
71
77
  let(:response_body) { { success: true }.to_json }
72
78
  let(:options) { { user_id: '1234', properties: { impersonator: impersonator } } }
@@ -93,8 +99,15 @@ describe Castle::Client do
93
99
  describe 'start impersonation' do
94
100
  let(:impersonator) { 'test@castle.io' }
95
101
  let(:request_body) do
96
- { user_id: '1234', timestamp: time_auto, sent_at: time_auto,
97
- properties: { impersonator: impersonator }, context: context }
102
+ {
103
+ user_id: '1234',
104
+ timestamp: time_auto,
105
+ sent_at: time_auto,
106
+ properties: {
107
+ impersonator: impersonator
108
+ },
109
+ context: context
110
+ }
98
111
  end
99
112
  let(:response_body) { { success: true }.to_json }
100
113
  let(:options) { { user_id: '1234', properties: { impersonator: impersonator } } }
@@ -118,70 +131,17 @@ describe Castle::Client do
118
131
  end
119
132
  end
120
133
 
121
- describe 'identify' do
122
- let(:request_body) do
123
- { user_id: '1234', timestamp: time_auto,
124
- sent_at: time_auto, context: context, user_traits: { name: 'Jo' } }
125
- end
126
-
127
- before { client.identify(options) }
128
-
129
- context 'when used with symbol keys' do
130
- let(:options) { { user_id: '1234', user_traits: { name: 'Jo' } } }
131
-
132
- it do
133
- assert_requested :post, 'https://api.castle.io/v1/identify', times: 1 do |req|
134
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
135
- end
136
- end
137
-
138
- context 'when passed timestamp in options and no defined timestamp' do
139
- let(:client) { client_with_no_timestamp }
140
- let(:options) { { user_id: '1234', user_traits: { name: 'Jo' }, timestamp: time_user } }
141
- let(:request_body) do
142
- { user_id: '1234', user_traits: { name: 'Jo' }, context: context,
143
- timestamp: time_user, sent_at: time_auto }
144
- end
145
-
146
- it do
147
- assert_requested :post, 'https://api.castle.io/v1/identify', times: 1 do |req|
148
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
149
- end
150
- end
151
- end
152
-
153
- context 'with client initialized with timestamp' do
154
- let(:client) { client_with_user_timestamp }
155
- let(:request_body) do
156
- { user_id: '1234', timestamp: time_user, sent_at: time_auto,
157
- context: context, user_traits: { name: 'Jo' } }
158
- end
159
-
160
- it do
161
- assert_requested :post, 'https://api.castle.io/v1/identify', times: 1 do |req|
162
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
163
- end
164
- end
165
- end
166
- end
167
-
168
- context 'when used with string keys' do
169
- let(:options) { { 'user_id' => '1234', 'user_traits' => { 'name' => 'Jo' } } }
170
-
171
- it do
172
- assert_requested :post, 'https://api.castle.io/v1/identify', times: 1 do |req|
173
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
174
- end
175
- end
176
- end
177
- end
178
-
179
134
  describe 'authenticate' do
180
135
  let(:options) { { event: '$login.succeeded', user_id: '1234' } }
181
136
  let(:request_response) { client.authenticate(options) }
182
137
  let(:request_body) do
183
- { event: '$login.succeeded', user_id: '1234', context: context,
184
- timestamp: time_auto, sent_at: time_auto }
138
+ {
139
+ event: '$login.succeeded',
140
+ user_id: '1234',
141
+ context: context,
142
+ timestamp: time_auto,
143
+ sent_at: time_auto
144
+ }
185
145
  end
186
146
 
187
147
  context 'when used with symbol keys' do
@@ -197,8 +157,13 @@ describe Castle::Client do
197
157
  let(:client) { client_with_no_timestamp }
198
158
  let(:options) { { event: '$login.succeeded', user_id: '1234', timestamp: time_user } }
199
159
  let(:request_body) do
200
- { event: '$login.succeeded', user_id: '1234', context: context,
201
- timestamp: time_user, sent_at: time_auto }
160
+ {
161
+ event: '$login.succeeded',
162
+ user_id: '1234',
163
+ context: context,
164
+ timestamp: time_user,
165
+ sent_at: time_auto
166
+ }
202
167
  end
203
168
 
204
169
  it do
@@ -211,8 +176,13 @@ describe Castle::Client do
211
176
  context 'with client initialized with timestamp' do
212
177
  let(:client) { client_with_user_timestamp }
213
178
  let(:request_body) do
214
- { event: '$login.succeeded', user_id: '1234', context: context,
215
- timestamp: time_user, sent_at: time_auto }
179
+ {
180
+ event: '$login.succeeded',
181
+ user_id: '1234',
182
+ context: context,
183
+ timestamp: time_user,
184
+ sent_at: time_auto
185
+ }
216
186
  end
217
187
 
218
188
  it do
@@ -255,6 +225,7 @@ describe Castle::Client do
255
225
  end
256
226
 
257
227
  it { assert_not_requested :post, 'https://api.castle.io/v1/authenticate' }
228
+ it { expect(request_response[:policy][:action]).to be_eql(Castle::Verdict::ALLOW) }
258
229
  it { expect(request_response[:action]).to be_eql(Castle::Verdict::ALLOW) }
259
230
  it { expect(request_response[:user_id]).to be_eql('1234') }
260
231
  it { expect(request_response[:failover]).to be true }
@@ -276,6 +247,7 @@ describe Castle::Client do
276
247
 
277
248
  context 'with request error and not throw on eg deny strategy' do
278
249
  it { assert_not_requested :post, 'https://:secret@api.castle.io/v1/authenticate' }
250
+ it { expect(request_response[:policy][:action]).to be_eql('allow') }
279
251
  it { expect(request_response[:action]).to be_eql('allow') }
280
252
  it { expect(request_response[:user_id]).to be_eql('1234') }
281
253
  it { expect(request_response[:failover]).to be true }
@@ -296,6 +268,7 @@ describe Castle::Client do
296
268
 
297
269
  describe 'not throw on eg deny strategy' do
298
270
  it { assert_not_requested :post, 'https://:secret@api.castle.io/v1/authenticate' }
271
+ it { expect(request_response[:policy][:action]).to be_eql('allow') }
299
272
  it { expect(request_response[:action]).to be_eql('allow') }
300
273
  it { expect(request_response[:user_id]).to be_eql('1234') }
301
274
  it { expect(request_response[:failover]).to be true }
@@ -306,8 +279,13 @@ describe Castle::Client do
306
279
 
307
280
  describe 'track' do
308
281
  let(:request_body) do
309
- { event: '$login.succeeded', context: context, user_id: '1234',
310
- timestamp: time_auto, sent_at: time_auto }
282
+ {
283
+ event: '$login.succeeded',
284
+ context: context,
285
+ user_id: '1234',
286
+ timestamp: time_auto,
287
+ sent_at: time_auto
288
+ }
311
289
  end
312
290
 
313
291
  before { client.track(options) }
@@ -325,8 +303,13 @@ describe Castle::Client do
325
303
  let(:client) { client_with_no_timestamp }
326
304
  let(:options) { { event: '$login.succeeded', user_id: '1234', timestamp: time_user } }
327
305
  let(:request_body) do
328
- { event: '$login.succeeded', user_id: '1234', context: context,
329
- timestamp: time_user, sent_at: time_auto }
306
+ {
307
+ event: '$login.succeeded',
308
+ user_id: '1234',
309
+ context: context,
310
+ timestamp: time_user,
311
+ sent_at: time_auto
312
+ }
330
313
  end
331
314
 
332
315
  it do
@@ -339,8 +322,13 @@ describe Castle::Client do
339
322
  context 'with client initialized with timestamp' do
340
323
  let(:client) { client_with_user_timestamp }
341
324
  let(:request_body) do
342
- { event: '$login.succeeded', context: context, user_id: '1234',
343
- timestamp: time_user, sent_at: time_auto }
325
+ {
326
+ event: '$login.succeeded',
327
+ context: context,
328
+ user_id: '1234',
329
+ timestamp: time_user,
330
+ sent_at: time_auto
331
+ }
344
332
  end
345
333
 
346
334
  it do
@@ -375,4 +363,16 @@ describe Castle::Client do
375
363
  it { expect(client).to be_tracked }
376
364
  end
377
365
  end
366
+
367
+ describe 'filter' do
368
+ it_behaves_like 'action request', :filter
369
+ end
370
+
371
+ describe 'risk' do
372
+ it_behaves_like 'action request', :risk
373
+ end
374
+
375
+ describe 'log' do
376
+ it_behaves_like 'action request', :log
377
+ end
378
378
  end