zanshin 1.0.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 +7 -0
- data/LICENSE.md +20 -0
- data/README.md +135 -0
- data/lib/zanshin/account.rb +96 -0
- data/lib/zanshin/alerts.rb +368 -0
- data/lib/zanshin/client.rb +189 -0
- data/lib/zanshin/organization_followers.rb +94 -0
- data/lib/zanshin/organization_following.rb +98 -0
- data/lib/zanshin/organization_members.rb +167 -0
- data/lib/zanshin/organization_scan_targets.rb +177 -0
- data/lib/zanshin/organizations.rb +52 -0
- data/lib/zanshin/request/zanshin_request.rb +51 -0
- data/lib/zanshin/request/zanshin_request_error.rb +22 -0
- data/lib/zanshin/scan_target.rb +114 -0
- data/lib/zanshin/summaries.rb +80 -0
- data/lib/zanshin/version.rb +8 -0
- data/lib/zanshin.rb +17 -0
- metadata +188 -0
@@ -0,0 +1,177 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'scan_target'
|
4
|
+
|
5
|
+
module Zanshin
|
6
|
+
module SDK
|
7
|
+
# Zanshin SDK Organization Scan Target
|
8
|
+
module OrganizationScanTargets
|
9
|
+
###################################################
|
10
|
+
# Organization Scan Targets
|
11
|
+
###################################################
|
12
|
+
|
13
|
+
# Scan Targets Enumerator of an organization
|
14
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationScanTargets)
|
15
|
+
#
|
16
|
+
# @param organization_id [UUID] of the organization
|
17
|
+
#
|
18
|
+
# @return an Scan Targets Enumerator object
|
19
|
+
def iter_organization_scan_targets(organization_id)
|
20
|
+
Enumerator.new do |yielder|
|
21
|
+
@http.request('GET', "/organizations/#{validate_uuid(organization_id)}/scantargets").each do |e|
|
22
|
+
yielder.yield e
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create a new scan target in organization
|
28
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/createOrganizationScanTargets)
|
29
|
+
#
|
30
|
+
# @param organization_id [UUID] of the organization
|
31
|
+
# @param name [UUID] of the organization
|
32
|
+
# @param credential [ScanTarget::AWS, ScanTarget::Azure, ScanTarget::GCP, ScanTarget::HUAWEI, ScanTarget::DOMAIN]
|
33
|
+
# to access the cloud account to be scanned
|
34
|
+
# @param schedule [Cron] in cron format
|
35
|
+
#
|
36
|
+
# @return an Object representing the newly created scan target
|
37
|
+
def create_organization_scan_target(organization_id, name, credential, schedule = '0 0 * * *')
|
38
|
+
unless [ScanTarget::AWS, ScanTarget::Azure, ScanTarget::GCP,
|
39
|
+
ScanTarget::HUAWEI, ScanTarget::DOMAIN].include? credential.class
|
40
|
+
raise "#{credential.class} is invalid instance of Zanshin::SDK::ScanTarget classes"
|
41
|
+
end
|
42
|
+
|
43
|
+
body = {
|
44
|
+
'kind' => credential.class::KIND, 'name' => name,
|
45
|
+
'credential' => credential.to_json, 'schedule' => schedule
|
46
|
+
}
|
47
|
+
@http.request('POST', "/organizations/#{validate_uuid(organization_id)}/scantargets", body)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get scan target details of organization
|
51
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationScanTargetById)
|
52
|
+
#
|
53
|
+
# @param organization_id [UUID] of the organization
|
54
|
+
# @param scan_target_id [UUID] of the scan target
|
55
|
+
#
|
56
|
+
# @return a Object representing the scan target
|
57
|
+
def get_organization_scan_target(organization_id, scan_target_id)
|
58
|
+
@http.request('GET',
|
59
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{validate_uuid(scan_target_id)}")
|
60
|
+
end
|
61
|
+
|
62
|
+
# Update scan target of organization
|
63
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/editOrganizationMembersById)
|
64
|
+
#
|
65
|
+
# @param organization_id [UUID] of the organization
|
66
|
+
# @param scan_target_id [UUID] of the scan target
|
67
|
+
# @param name [String] of the scan target
|
68
|
+
# @param schedule [Cron] of the schedule
|
69
|
+
#
|
70
|
+
# @return a Object representing the scan target updated
|
71
|
+
def update_organization_scan_target(organization_id, scan_target_id, name = nil, schedule = nil)
|
72
|
+
body = {
|
73
|
+
'name' => name,
|
74
|
+
'schedule' => schedule
|
75
|
+
}
|
76
|
+
|
77
|
+
@http.request('PUT',
|
78
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{validate_uuid(scan_target_id)}",
|
79
|
+
body)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Delete scan target of organization
|
83
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/deleteOrganizationScanTargetById)
|
84
|
+
#
|
85
|
+
# @param organization_id [UUID] of the organization
|
86
|
+
# @param scan_target_id [UUID] of the scan target
|
87
|
+
#
|
88
|
+
# @return a Boolean with result
|
89
|
+
def delete_organization_scan_target(organization_id, scan_target_id)
|
90
|
+
@http.request('DELETE',
|
91
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{validate_uuid(scan_target_id)}")
|
92
|
+
end
|
93
|
+
|
94
|
+
# Starts a scan on the specified scan target
|
95
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/scanOrganizationScanTarget)
|
96
|
+
#
|
97
|
+
# @param organization_id [UUID] of the organization
|
98
|
+
# @param scan_target_id [UUID] of the scan target
|
99
|
+
#
|
100
|
+
# @return a Boolean with result
|
101
|
+
def start_organization_scan_target_scan(organization_id, scan_target_id)
|
102
|
+
@http.request(
|
103
|
+
'POST',
|
104
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{validate_uuid(scan_target_id)}/scan"
|
105
|
+
)
|
106
|
+
end
|
107
|
+
|
108
|
+
# TODO: API documentation is not up to date, does not have this endpoint
|
109
|
+
# After updating you will need to add the reference here
|
110
|
+
|
111
|
+
# Stop a scan on the specific scan target
|
112
|
+
#
|
113
|
+
# @param organization_id [UUID] of the organization
|
114
|
+
# @param scan_target_id [UUID] of the scan target
|
115
|
+
#
|
116
|
+
# @return a Boolean with result
|
117
|
+
def stop_organization_scan_target_scan(organization_id, scan_target_id)
|
118
|
+
@http.request(
|
119
|
+
'POST',
|
120
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{validate_uuid(scan_target_id)}/stop"
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Check scan target
|
125
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/checkOrganizationScanTarget)
|
126
|
+
#
|
127
|
+
# @param organization_id [UUID] of the organization
|
128
|
+
# @param scan_target_id [UUID] of the scan target
|
129
|
+
#
|
130
|
+
# @return a Object representing the scan target
|
131
|
+
def check_organization_scan_target(organization_id, scan_target_id)
|
132
|
+
@http.request(
|
133
|
+
'POST',
|
134
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{validate_uuid(scan_target_id)}/check"
|
135
|
+
)
|
136
|
+
end
|
137
|
+
|
138
|
+
###################################################
|
139
|
+
# Organization Scan Target Scan
|
140
|
+
###################################################
|
141
|
+
|
142
|
+
# Scans Enumerator of an Scan Target
|
143
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationScanTargetScans)
|
144
|
+
#
|
145
|
+
# @param organization_id [UUID] of the organization
|
146
|
+
# @param scan_target_id [UUID] of the scan target
|
147
|
+
#
|
148
|
+
# @return an Scans Enumerator object
|
149
|
+
def iter_organization_scan_target_scans(organization_id, scan_target_id)
|
150
|
+
Enumerator.new do |yielder|
|
151
|
+
@http.request(
|
152
|
+
'GET',
|
153
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{validate_uuid(scan_target_id)}/scans"
|
154
|
+
).each do |e|
|
155
|
+
yielder.yield e
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Get scan of scan target
|
161
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationScanTargetScanSlot)
|
162
|
+
#
|
163
|
+
# @param organization_id [UUID] of the organization
|
164
|
+
# @param scan_target_id [UUID] of the scan target
|
165
|
+
# @param scan_id [UUID] of the scan
|
166
|
+
#
|
167
|
+
# @return a Object representing the scan
|
168
|
+
def get_organization_scan_target_scan(organization_id, scan_target_id, scan_id)
|
169
|
+
@http.request(
|
170
|
+
'GET',
|
171
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{
|
172
|
+
validate_uuid(scan_target_id)}/scans/#{validate_uuid(scan_id)}"
|
173
|
+
)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zanshin
|
4
|
+
module SDK
|
5
|
+
# Zanshin SDK Organization
|
6
|
+
module Organizations
|
7
|
+
###################################################
|
8
|
+
# Organizations
|
9
|
+
###################################################
|
10
|
+
|
11
|
+
# Organizations Enumerator of current logged user
|
12
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizations)
|
13
|
+
#
|
14
|
+
# @return an Organizations Enumerator object
|
15
|
+
def iter_organizations
|
16
|
+
Enumerator.new do |yielder|
|
17
|
+
@http.request('GET', '/organizations').each do |e|
|
18
|
+
yielder.yield e
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Gets an organization given its ID
|
24
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationById)
|
25
|
+
#
|
26
|
+
# @param organization_id [UUID] of the organization
|
27
|
+
#
|
28
|
+
# @return an Object representing the organization
|
29
|
+
def get_organization(organization_id)
|
30
|
+
@http.request('GET', "/organizations/#{validate_uuid(organization_id)}")
|
31
|
+
end
|
32
|
+
|
33
|
+
# Gets an organization given its ID
|
34
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/editOrganizationById)
|
35
|
+
#
|
36
|
+
# @param organization_id [UUID] of the organization
|
37
|
+
# @param name [String] Optional name of the organization
|
38
|
+
# @param picture [String] Optional picture URL of the organization, accepted formats: jpg, jpeg, png, svg
|
39
|
+
# @param email [String] Optional e-mail contact of the organization
|
40
|
+
#
|
41
|
+
# @return an Object representing the organization
|
42
|
+
def update_organization(organization_id, name: nil, picture: nil, email: nil)
|
43
|
+
body = {
|
44
|
+
'name' => name,
|
45
|
+
'picture' => picture,
|
46
|
+
'email' => email
|
47
|
+
}
|
48
|
+
@http.request('PUT', "/organizations/#{validate_uuid(organization_id)}", body)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'zanshin/request/zanshin_request_error'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
module Zanshin
|
8
|
+
module SDK
|
9
|
+
# Zanshin SDK Request
|
10
|
+
module Request
|
11
|
+
# Zanshin SDK request HTTPClient
|
12
|
+
class HTTPClient
|
13
|
+
attr_accessor :headers, :http_client
|
14
|
+
|
15
|
+
# Initialize a new HTTP connection to the Zanshin API
|
16
|
+
# @overload initialize(api_key, api_url, user_agent, proxy_url)
|
17
|
+
# @param api_key [String] API key to use
|
18
|
+
# @param api_url [String] URL of the Zanshin API
|
19
|
+
# @param user_agent [String] User agent to use in requests performed
|
20
|
+
# @param proxy_url [String] Optional URL indicating which proxy server to use
|
21
|
+
def initialize(api_key, api_url, user_agent, proxy_url = nil)
|
22
|
+
@headers = { 'Authorization' => "Bearer #{api_key}",
|
23
|
+
'User-Agent' => user_agent,
|
24
|
+
'Content-Type' => 'application/json' }
|
25
|
+
# HACK: Needs to figure out why Net::HTTP is not automatically decoded `gzip` and `deflate` encoding
|
26
|
+
# 'Accept-Encoding' => 'gzip, deflate'
|
27
|
+
|
28
|
+
uri = URI.parse(api_url)
|
29
|
+
proxy = URI.parse(proxy_url || '')
|
30
|
+
|
31
|
+
@http_client = Net::HTTP.new(uri.host, uri.port, proxy.host, proxy.port, proxy.user, proxy.password)
|
32
|
+
@http_client.use_ssl = true
|
33
|
+
end
|
34
|
+
|
35
|
+
# Request to Zanshin
|
36
|
+
# @overload initialize(api_key, api_url, user_agent, proxy_url)
|
37
|
+
# @param method ['GET', 'POST', 'PUT', 'DELETE'] HTTP method to pass along to `:HTTPClient`
|
38
|
+
# @param path [String] API path to access
|
39
|
+
# @param body [Object] request body to pass along to `:HTTPClient`
|
40
|
+
def request(method, path, body = nil)
|
41
|
+
body = body.to_json if body
|
42
|
+
response = @http_client.send_request(method, path, body, @headers)
|
43
|
+
result = JSON.parse(response.body)
|
44
|
+
raise ZanshinError.new(response.code, result['message'] || result['errorName']) if response.code.to_i >= 400
|
45
|
+
|
46
|
+
result
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zanshin
|
4
|
+
module SDK
|
5
|
+
module Request
|
6
|
+
# Zanshin SDK request ZanshinError
|
7
|
+
class ZanshinError < StandardError
|
8
|
+
attr_reader :code, :body
|
9
|
+
|
10
|
+
# Initialize a new Zanshin Error
|
11
|
+
# @overload initialize(code, body)
|
12
|
+
# @param code [String] of the Error
|
13
|
+
# @param body [String] message of the error
|
14
|
+
def initialize(code, body)
|
15
|
+
@code = code
|
16
|
+
@body = body
|
17
|
+
super("Error [#{code}] #{body}")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Zanshin
|
6
|
+
module SDK
|
7
|
+
# Zanshin SDK Scan Target
|
8
|
+
#
|
9
|
+
# This module contains the classes for each provider that Zanshin supports, and which can be used
|
10
|
+
# to create a scan target
|
11
|
+
module ScanTarget
|
12
|
+
# AWS scan target
|
13
|
+
class AWS
|
14
|
+
# Type of provider that will be sent to the API
|
15
|
+
KIND = 'AWS'
|
16
|
+
|
17
|
+
attr_accessor :account
|
18
|
+
|
19
|
+
def initialize(account)
|
20
|
+
@account = account
|
21
|
+
end
|
22
|
+
|
23
|
+
# Convert AWS class to json
|
24
|
+
def to_json(*_args)
|
25
|
+
{
|
26
|
+
'account' => @account
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Azure scan target
|
32
|
+
class Azure
|
33
|
+
# Type of provider that will be sent to the API
|
34
|
+
KIND = 'Azure'
|
35
|
+
|
36
|
+
attr_accessor :application_id, :subscription_id, :directory_id, :secret
|
37
|
+
|
38
|
+
def initialize(application_id, subscription_id, directory_id, secret)
|
39
|
+
@application_id = application_id
|
40
|
+
@subscription_id = subscription_id
|
41
|
+
@directory_id = directory_id
|
42
|
+
@secret = secret
|
43
|
+
end
|
44
|
+
|
45
|
+
# Convert Azure class to json
|
46
|
+
def to_json(*_args)
|
47
|
+
{
|
48
|
+
'application_id' => @application_id,
|
49
|
+
'subscription_id' => @subscription_id,
|
50
|
+
'directory_id' => @directory_id,
|
51
|
+
'secret' => @secret
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# GCP scan target
|
57
|
+
class GCP
|
58
|
+
# Type of provider that will be sent to the API
|
59
|
+
KIND = 'GCP'
|
60
|
+
|
61
|
+
attr_accessor :project_id
|
62
|
+
|
63
|
+
def initialize(project_id)
|
64
|
+
@project_id = project_id
|
65
|
+
end
|
66
|
+
|
67
|
+
# Convert GCP class to json
|
68
|
+
def to_json(*_args)
|
69
|
+
{
|
70
|
+
'project_id' => @project_id
|
71
|
+
}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# HUAWEI scan target
|
76
|
+
class HUAWEI
|
77
|
+
# Type of provider that will be sent to the API
|
78
|
+
KIND = 'HUAWEI'
|
79
|
+
|
80
|
+
attr_accessor :account_id
|
81
|
+
|
82
|
+
def initialize(account_id)
|
83
|
+
@account_id = account_id
|
84
|
+
end
|
85
|
+
|
86
|
+
# Convert HUAWEI class to json
|
87
|
+
def to_json(*_args)
|
88
|
+
{
|
89
|
+
'account_id' => @account_id
|
90
|
+
}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# DOMAIN scan target
|
95
|
+
class DOMAIN
|
96
|
+
# Type of provider that will be sent to the API
|
97
|
+
KIND = 'DOMAIN'
|
98
|
+
|
99
|
+
attr_accessor :domain
|
100
|
+
|
101
|
+
def initialize(domain)
|
102
|
+
@domain = domain
|
103
|
+
end
|
104
|
+
|
105
|
+
# Convert DOMAIN class to json
|
106
|
+
def to_json(*_args)
|
107
|
+
{
|
108
|
+
'domain' => @domain
|
109
|
+
}
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zanshin
|
4
|
+
module SDK
|
5
|
+
# Zanshin SDK Summary
|
6
|
+
module Summaries
|
7
|
+
###################################################
|
8
|
+
# Summaries
|
9
|
+
###################################################
|
10
|
+
|
11
|
+
# Gets a summary of the current state of alerts for an organization, both in total and broken down by scan target
|
12
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/alertSummary)
|
13
|
+
#
|
14
|
+
# @param organization_id [UUID] of the organization whose alert summaries are desired
|
15
|
+
# @param scan_target_ids [Array<UUID>] optional list of scan target IDs to summarize alerts from, defaults to all
|
16
|
+
#
|
17
|
+
# @return a Object representing the alert summaries
|
18
|
+
def get_alert_summaries(organization_id, scan_target_ids = [])
|
19
|
+
body = {
|
20
|
+
'organizationId' => validate_uuid(organization_id),
|
21
|
+
'scanTargetIds' => scan_target_ids.each { |scan_target_id| validate_uuid(scan_target_id) }
|
22
|
+
}
|
23
|
+
|
24
|
+
@http.request('POST', '/alerts/summaries', body)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Gets a summary of the current state of alerts for followed organizations
|
28
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/alertFollowingSummary)
|
29
|
+
#
|
30
|
+
# @param organization_id [UUID] of the organization
|
31
|
+
# @param following_ids [Array<UUID>] list of IDs of organizations being followed to summarize alerts from
|
32
|
+
#
|
33
|
+
# @return a Object representing the alert following summaries
|
34
|
+
def get_following_alert_summaries(organization_id, following_ids = [])
|
35
|
+
body = {
|
36
|
+
'organizationId' => validate_uuid(organization_id),
|
37
|
+
'followingIds' => following_ids.each { |following_id| validate_uuid(following_id) }
|
38
|
+
}
|
39
|
+
|
40
|
+
@http.request('POST', '/alerts/summaries/following', body)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns summaries of scan results over a period of time, summarizing number of alerts that changed states
|
44
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/scanSummary)
|
45
|
+
#
|
46
|
+
# @param organization_id [UUID] of the organization whose alert summaries are desired
|
47
|
+
# @param scan_target_ids [Array<UUID>] optional list of scan target IDs to summarize alerts from, defaults to all
|
48
|
+
# @param days [Integer] number of days to go back in time in historical search
|
49
|
+
#
|
50
|
+
# @return a Object representing the scan summaries
|
51
|
+
def get_scan_summaries(organization_id, scan_target_ids = [], days = 7)
|
52
|
+
body = {
|
53
|
+
'organizationId' => validate_uuid(organization_id),
|
54
|
+
'scanTargetIds' => scan_target_ids.each { |scan_target_id| validate_uuid(scan_target_id) },
|
55
|
+
'daysBefore' => days
|
56
|
+
}
|
57
|
+
|
58
|
+
@http.request('POST', '/alerts/summaries/scans', body)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Gets a summary of the current state of alerts for followed organizations
|
62
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/scanSummaryFollowing)
|
63
|
+
#
|
64
|
+
# @param organization_id [UUID] of the organization whose alert summaries are desired
|
65
|
+
# @param following_ids [Array<UUID>] optional list of IDs of organizations being followed to summarize alerts from
|
66
|
+
# @param days [Integer] number of days to go back in time in historical search
|
67
|
+
#
|
68
|
+
# @return a Object representing the scan summaries
|
69
|
+
def get_following_scan_summaries(organization_id, following_ids = [], days = 7)
|
70
|
+
body = {
|
71
|
+
'organizationId' => validate_uuid(organization_id),
|
72
|
+
'followingIds' => following_ids.each { |following_id| validate_uuid(following_id) },
|
73
|
+
'daysBefore' => days
|
74
|
+
}
|
75
|
+
|
76
|
+
@http.request('POST', '/alerts/summaries/scans/following', body)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/zanshin.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'zanshin/client'
|
4
|
+
require_relative 'zanshin/version'
|
5
|
+
|
6
|
+
# {include:file:README.md}
|
7
|
+
module Zanshin
|
8
|
+
# Zanshin SDK
|
9
|
+
module SDK
|
10
|
+
# The default endpoint for Zanshin API
|
11
|
+
ZANSHIN_API = 'https://api.zanshin.tenchi-dev.com'
|
12
|
+
# The directory that Zanshin uses to store/get private settings
|
13
|
+
CONFIG_DIR = "#{Dir.home}/.tenchi"
|
14
|
+
# The file that Zanshin uses to store/get private settings
|
15
|
+
CONFIG_FILE = "#{CONFIG_DIR}/config"
|
16
|
+
end
|
17
|
+
end
|