castle-rb 6.0.1 → 7.1.2

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