sift 4.4.0 → 4.5.1
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/.github/workflows/ci.yml +49 -0
- data/HISTORY +6 -0
- data/README.md +33 -2
- data/lib/sift/client.rb +17 -9
- data/lib/sift/version.rb +2 -1
- data/lib/sift.rb +3 -3
- data/spec/unit/client_spec.rb +30 -0
- data/test_integration_app/decisions_api/test_decisions_api.rb +31 -0
- data/test_integration_app/events_api/test_events_api.rb +843 -0
- data/test_integration_app/globals.rb +2 -0
- data/test_integration_app/main.rb +67 -0
- data/test_integration_app/psp_merchants_api/test_psp_merchant_api.rb +44 -0
- data/test_integration_app/score_api/test_score_api.rb +11 -0
- data/test_integration_app/verification_api/test_verification_api.rb +32 -0
- metadata +13 -6
- data/.circleci/config.yml +0 -88
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0be867318fbb8cb5cb85b614e48de3748def9c8d9a6122c066c785d65c6b3b48
|
4
|
+
data.tar.gz: abf0fe3da0bbf939f29cdb1071e9acb7db62473bc9fdc37dcde52631db930abc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc2d9d80295f6f4605413d001bb29b4745e28ecc58e9595a526bd8a7d8529d2b63dc14fce063e1ee347bde3b9d9370ad160917a795e59377a54d5eeb50f876b7
|
7
|
+
data.tar.gz: f5f75423865db471ed649a4146a8e3e388203977ec6607c20966c9622f9b074f8e149574f9bbe28db22f44b21203e9ae082b52386bea6f8c2096afd869955a65
|
@@ -0,0 +1,49 @@
|
|
1
|
+
name: Ruby-ci
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
pull_request:
|
8
|
+
branches:
|
9
|
+
- master
|
10
|
+
|
11
|
+
env:
|
12
|
+
ACCOUNT_ID: ${{ secrets.ACCOUNT_ID }}
|
13
|
+
API_KEY: ${{ secrets.API_KEY }}
|
14
|
+
|
15
|
+
permissions:
|
16
|
+
contents: read
|
17
|
+
|
18
|
+
jobs:
|
19
|
+
build:
|
20
|
+
runs-on: ubuntu-latest
|
21
|
+
strategy:
|
22
|
+
matrix:
|
23
|
+
ruby-version: ['2.4.2']
|
24
|
+
steps:
|
25
|
+
- uses: actions/checkout@v4
|
26
|
+
- name: Set up Ruby
|
27
|
+
uses: ruby/setup-ruby@v1
|
28
|
+
with:
|
29
|
+
ruby-version: ${{ matrix.ruby-version }}
|
30
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
31
|
+
- name: Run tests
|
32
|
+
run: bundle exec rspec --format RspecJunitFormatter --out test_results/rspec.xml --format progress
|
33
|
+
|
34
|
+
run_integration_tests:
|
35
|
+
runs-on: ubuntu-latest
|
36
|
+
if: ${{ github.ref == 'refs/heads/master' }}
|
37
|
+
strategy:
|
38
|
+
matrix:
|
39
|
+
ruby-version: [ '2.4.2' ]
|
40
|
+
steps:
|
41
|
+
- uses: actions/checkout@v4
|
42
|
+
- name: Set up Ruby
|
43
|
+
uses: ruby/setup-ruby@v1
|
44
|
+
with:
|
45
|
+
ruby-version: ${{ matrix.ruby-version }}
|
46
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
47
|
+
- name: Run tests
|
48
|
+
run: |
|
49
|
+
bundle exec ruby test_integration_app/main.rb
|
data/HISTORY
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# sift-ruby
|
2
|
-
[](https://circleci.com/gh/SiftScience/sift-ruby)
|
3
2
|
|
4
3
|
The official Ruby bindings for the latest version (v205) of the [Sift API](https://sift.com/developers/docs/java/apis-overview).
|
5
4
|
|
@@ -39,8 +38,22 @@ client = Sift::Client.new(api_key: '<your_api_key_here>', account_id: '<your_acc
|
|
39
38
|
|
40
39
|
```
|
41
40
|
|
42
|
-
### Sending
|
41
|
+
### Sending an event
|
42
|
+
Send event to Sift.
|
43
|
+
To learn more about the Events API visit our [developer docs](https://developers.sift.com/docs/ruby/events-api/overview).
|
43
44
|
|
45
|
+
|
46
|
+
**Optional Params**
|
47
|
+
- `return_score`: `:true` or `:false`
|
48
|
+
- `return_action`: `:true` or `:false`
|
49
|
+
- `return_workflow_status`: `:true` or `:false`
|
50
|
+
- `return_route_info`: `:true` or `:false`
|
51
|
+
- `force_workflow_run`: `:true` or `:false`
|
52
|
+
- `include_score_percentiles`: `:true` or `:false`
|
53
|
+
- `warnings`: `:true` or `:false`
|
54
|
+
- `abuse_types`: `["payment_abuse", "content_abuse", "content_abuse", "account_abuse", "legacy", "account_takeover"]`
|
55
|
+
|
56
|
+
**Example:**
|
44
57
|
```ruby
|
45
58
|
event = "$transaction"
|
46
59
|
|
@@ -318,3 +331,21 @@ To run the various tests use the rake command as follows:
|
|
318
331
|
```ruby
|
319
332
|
$ rake spec
|
320
333
|
```
|
334
|
+
|
335
|
+
## Integration testing app
|
336
|
+
|
337
|
+
For testing the app with real calls it is possible to run the integration testing app,
|
338
|
+
it makes calls to almost all our public endpoints to make sure the library integrates
|
339
|
+
well. At the moment, the app is run on every merge to master
|
340
|
+
|
341
|
+
#### How to run it locally
|
342
|
+
|
343
|
+
1. Add env variable `ACCOUNT_ID` with the valid account id
|
344
|
+
2. Add env variable `API_KEY` with the valid Api Key associated from the account
|
345
|
+
3. Run the following under the project root folder
|
346
|
+
```
|
347
|
+
# Install the budle locally
|
348
|
+
bundle check || bundle install
|
349
|
+
# Run the app
|
350
|
+
bundle exec ruby test_integration_app/main.rb
|
351
|
+
```
|
data/lib/sift/client.rb
CHANGED
@@ -139,6 +139,7 @@ module Sift
|
|
139
139
|
@api_key = opts[:api_key] || Sift.api_key
|
140
140
|
@account_id = opts[:account_id] || Sift.account_id
|
141
141
|
@version = opts[:version] || API_VERSION
|
142
|
+
@verification_version = opts[:verification_version] || VERIFICATION_API_VERSION
|
142
143
|
@timeout = opts[:timeout] || 2 # 2-second timeout by default
|
143
144
|
@path = opts[:path] || Sift.rest_api_path(@version)
|
144
145
|
|
@@ -201,10 +202,13 @@ module Sift
|
|
201
202
|
#
|
202
203
|
# :path::
|
203
204
|
# Overrides the URI path for this API call.
|
204
|
-
#
|
205
|
+
#
|
205
206
|
# :include_score_percentiles::
|
206
207
|
# include_score_percentiles(optional) : Whether to add new parameter in the query parameter.
|
207
208
|
#
|
209
|
+
# :warnings::
|
210
|
+
# warnings(optional) : Whether to add list of warnings (if any) to response.
|
211
|
+
#
|
208
212
|
# ==== Returns:
|
209
213
|
#
|
210
214
|
# In the case of a network error (timeout, broken connection, etc.),
|
@@ -223,6 +227,7 @@ module Sift
|
|
223
227
|
force_workflow_run = opts[:force_workflow_run]
|
224
228
|
abuse_types = opts[:abuse_types]
|
225
229
|
include_score_percentiles = opts[:include_score_percentiles]
|
230
|
+
warnings = opts[:warnings]
|
226
231
|
|
227
232
|
raise("event must be a non-empty string") if (!event.is_a? String) || event.empty?
|
228
233
|
raise("properties cannot be empty") if properties.empty?
|
@@ -235,8 +240,12 @@ module Sift
|
|
235
240
|
query["return_route_info"] = "true" if return_route_info
|
236
241
|
query["force_workflow_run"] = "true" if force_workflow_run
|
237
242
|
query["abuse_types"] = abuse_types.join(",") if abuse_types
|
238
|
-
|
239
|
-
|
243
|
+
|
244
|
+
if include_score_percentiles == "true" || warnings == "true"
|
245
|
+
fields = []
|
246
|
+
fields << "SCORE_PERCENTILES" if include_score_percentiles == "true"
|
247
|
+
fields << "WARNINGS" if warnings == "true"
|
248
|
+
query["fields"] = fields.join(",")
|
240
249
|
end
|
241
250
|
|
242
251
|
options = {
|
@@ -278,7 +287,7 @@ module Sift
|
|
278
287
|
#
|
279
288
|
# :version::
|
280
289
|
# Overrides the version of the Events API to call.
|
281
|
-
#
|
290
|
+
#
|
282
291
|
# :include_score_percentiles::
|
283
292
|
# include_score_percentiles(optional) : Whether to add new parameter in the query parameter.
|
284
293
|
#
|
@@ -342,7 +351,7 @@ module Sift
|
|
342
351
|
#
|
343
352
|
# :timeout::
|
344
353
|
# Overrides the timeout (in seconds) for this call.
|
345
|
-
#
|
354
|
+
#
|
346
355
|
# :include_score_percentiles::
|
347
356
|
# include_score_percentiles(optional) : Whether to add new parameter in the query parameter.
|
348
357
|
#
|
@@ -747,7 +756,7 @@ module Sift
|
|
747
756
|
|
748
757
|
def verification_send(properties = {}, opts = {})
|
749
758
|
api_key = opts[:api_key] || @api_key
|
750
|
-
version = opts[:
|
759
|
+
version = opts[:verification_version] || @verification_version
|
751
760
|
timeout = opts[:timeout] || @timeout
|
752
761
|
|
753
762
|
raise("properties cannot be empty") if properties.empty?
|
@@ -759,14 +768,13 @@ module Sift
|
|
759
768
|
:headers => build_default_headers_post(api_key)
|
760
769
|
}
|
761
770
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
762
|
-
|
763
771
|
response = self.class.post(Sift.verification_api_send_path(@version), options)
|
764
772
|
Response.new(response.body, response.code, response.response)
|
765
773
|
end
|
766
774
|
|
767
775
|
def verification_resend(properties = {}, opts = {})
|
768
776
|
api_key = opts[:api_key] || @api_key
|
769
|
-
version = opts[:
|
777
|
+
version = opts[:verification_version] || @verification_version
|
770
778
|
timeout = opts[:timeout] || @timeout
|
771
779
|
|
772
780
|
raise("properties cannot be empty") if properties.empty?
|
@@ -785,7 +793,7 @@ module Sift
|
|
785
793
|
|
786
794
|
def verification_check(properties = {}, opts = {})
|
787
795
|
api_key = opts[:api_key] || @api_key
|
788
|
-
version = opts[:
|
796
|
+
version = opts[:verification_version] || @verification_version
|
789
797
|
timeout = opts[:timeout] || @timeout
|
790
798
|
|
791
799
|
raise("properties cannot be empty") if properties.empty?
|
data/lib/sift/version.rb
CHANGED
data/lib/sift.rb
CHANGED
@@ -10,17 +10,17 @@ module Sift
|
|
10
10
|
end
|
11
11
|
|
12
12
|
# Returns the path for the specified API version
|
13
|
-
def self.verification_api_send_path(version=
|
13
|
+
def self.verification_api_send_path(version=VERIFICATION_API_VERSION)
|
14
14
|
"/v#{version}/verification/send"
|
15
15
|
end
|
16
16
|
|
17
17
|
# Returns the path for the specified API version
|
18
|
-
def self.verification_api_resend_path(version=
|
18
|
+
def self.verification_api_resend_path(version=VERIFICATION_API_VERSION)
|
19
19
|
"/v#{version}/verification/resend"
|
20
20
|
end
|
21
21
|
|
22
22
|
# Returns the path for the specified API version
|
23
|
-
def self.verification_api_check_path(version=
|
23
|
+
def self.verification_api_check_path(version=VERIFICATION_API_VERSION)
|
24
24
|
"/v#{version}/verification/check"
|
25
25
|
end
|
26
26
|
|
data/spec/unit/client_spec.rb
CHANGED
@@ -110,6 +110,15 @@ describe Sift::Client do
|
|
110
110
|
}
|
111
111
|
end
|
112
112
|
|
113
|
+
def warnings
|
114
|
+
{
|
115
|
+
:count => 1,
|
116
|
+
:items => [{
|
117
|
+
:message => 'Invalid currency'
|
118
|
+
}]
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
113
122
|
def percentile_response_json
|
114
123
|
{
|
115
124
|
:user_id => 'billy_jones_301',
|
@@ -689,4 +698,25 @@ describe Sift::Client do
|
|
689
698
|
expect(response.body["scores"]["payment_abuse"]["score"]).to eq(0.78)
|
690
699
|
end
|
691
700
|
|
701
|
+
it "Successfully submits a v205 event with WARNINGS" do
|
702
|
+
response_json =
|
703
|
+
{ :status => 0, :error_message => "OK", :warnings => warnings}
|
704
|
+
stub_request(:post, "https://api.siftscience.com/v205/events?fields=WARNINGS").
|
705
|
+
with { | request|
|
706
|
+
parsed_body = JSON.parse(request.body)
|
707
|
+
expect(parsed_body).to include("$api_key" => "overridden")
|
708
|
+
}.to_return(:status => 200, :body => MultiJson.dump(response_json), :headers => {})
|
709
|
+
|
710
|
+
api_key = "foobar"
|
711
|
+
event = "$transaction"
|
712
|
+
properties = valid_transaction_properties
|
713
|
+
|
714
|
+
response = Sift::Client.new(:api_key => api_key, :version => "205")
|
715
|
+
.track(event, properties, :api_key => "overridden",:warnings => "true")
|
716
|
+
expect(response.ok?).to eq(true)
|
717
|
+
expect(response.api_status).to eq(0)
|
718
|
+
expect(response.api_error_message).to eq("OK")
|
719
|
+
expect(response.body["warnings"]["count"]).to eq(1)
|
720
|
+
expect(response.body["warnings"]["items"][0]["message"]).to eq("Invalid currency")
|
721
|
+
end
|
692
722
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "sift"
|
2
|
+
|
3
|
+
class DecisionAPI
|
4
|
+
|
5
|
+
@@client = Sift::Client.new(:api_key => ENV["API_KEY"], :account_id => ENV["ACCOUNT_ID"])
|
6
|
+
|
7
|
+
def apply_user_decision()
|
8
|
+
properties = {
|
9
|
+
"decision_id": "integration_app_watch_account_abuse",
|
10
|
+
"description": "User linked to three other payment abusers and ordering high value items",
|
11
|
+
"source": "manual_review",
|
12
|
+
"analyst": "analyst@example.com",
|
13
|
+
"user_id": "userId"
|
14
|
+
}
|
15
|
+
|
16
|
+
return @@client.apply_decision(properties)
|
17
|
+
end
|
18
|
+
|
19
|
+
def apply_order_decision()
|
20
|
+
properties = {
|
21
|
+
"decision_id": "block_order_payment_abuse",
|
22
|
+
"description": "applied via the high priority queue, queued user because their risk score exceeded 85",
|
23
|
+
"source": "AUTOMATED_RULE",
|
24
|
+
"user_id": "userId",
|
25
|
+
"order_id": "orderId"
|
26
|
+
}
|
27
|
+
|
28
|
+
return @@client.apply_decision(properties)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|