zanshin 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1e4c4177cdf64faab3875bd1fe144c21284530f211812969e0bd3ec5ab438d56
|
4
|
+
data.tar.gz: abd2455541e409bb6a018f12ba3e644fd32132ebd221f927f257a26d1e81e3b1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0ca6218cf76d9642937df5f15b68c2bec389cd147bc68af25aa2969dcd6a42e3c2722d1fe56a54db17844de2e9222b29b10e6386d2fa152ee243e952001330c9
|
7
|
+
data.tar.gz: fea40647b2780b2059188a477e4644426903164429bc5ae951f69950d78697cb080ca0634da6b6d306e16396fda12012b905b83d1e3d15b2d0e03f246c6d96d1
|
data/LICENSE.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2022 Tenchi Security.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/zanshin.svg)](https://badge.fury.io/rb/zanshin)
|
2
|
+
|
3
|
+
# Zanshin Ruby SDK
|
4
|
+
|
5
|
+
This Ruby gem contains an SDK to interact with the [API of the Zanshin](https://api.zanshin.tenchisecurity.com) from [Tenchi Security](https://www.tenchisecurity.com).
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Install the gem and add to the application's Gemfile by executing:
|
10
|
+
|
11
|
+
```shell
|
12
|
+
bundle add zanshin
|
13
|
+
```
|
14
|
+
|
15
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
16
|
+
|
17
|
+
```shell
|
18
|
+
gem install zanshin
|
19
|
+
```
|
20
|
+
|
21
|
+
## Setting up Credentials
|
22
|
+
|
23
|
+
There are three ways that the SDK handles credentials. The order of evaluation is:
|
24
|
+
- [**1st** Client Parameters](#client-parameters)
|
25
|
+
- [**2nd** Environment Variables](#environment-variables)
|
26
|
+
- [**3rd** Config File](#config-file)
|
27
|
+
|
28
|
+
### Client Parameters
|
29
|
+
|
30
|
+
When calling the `Client` class, you can pass the values API Key(`api_key`), API URL(`api_url`), User Agent(`user_agent`) and Proxy URL(`proxy_url`) you want to use as below:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
client = Zanshin::SDK::Client.new(api_key: "my_zanshin_api_key")
|
34
|
+
puts client.get_me
|
35
|
+
```
|
36
|
+
|
37
|
+
> These values will overwrite anything you set as Environment Variables or in the Config File.
|
38
|
+
|
39
|
+
### Environment Variables
|
40
|
+
|
41
|
+
You can use the following Environment Variables to configure Zanshin SDK:
|
42
|
+
- `ZANSHIN_API_KEY`: Will setup your Zanshin credentials
|
43
|
+
- `ZANSHIN_API_URL`: Will define the API URL. Default is `https://api.zanshin.tenchisecurity.com`
|
44
|
+
- `ZANSHIN_USER_AGENT`: If you want to overwrite the User Agent when calling Zanshin API (The value passed will be concatenated to the SDK's default value `Zanshin Ruby SDK 1.0.0`)
|
45
|
+
- `HTTP_PROXY | HTTPS_PROXY`: Zanshin SDK uses `Net::HTTP` under the hood, checkout the [Net::HTTP RDoc](https://ruby-doc.org/stdlib-3.1.2/libdoc/net/http/rdoc/Net/HTTP.html) section of their documentation for more use cases
|
46
|
+
|
47
|
+
#### Example
|
48
|
+
|
49
|
+
```shell
|
50
|
+
export ZANSHIN_API_KEY="my_zanshin_api_key"
|
51
|
+
```
|
52
|
+
|
53
|
+
> These Environment Variables will overwrite anything you set on the Config File.
|
54
|
+
|
55
|
+
### Config File
|
56
|
+
|
57
|
+
This `Ruby SDK` was built to be used under the same conditions as the [Python SDK](https://github.com/tenchi-security/zanshin-sdk-python), so the configuration file is in the format created by the Python [RawConfigParser](https://docs.python.org/3/library/configparser.html#configparser.RawConfigParser) class.
|
58
|
+
|
59
|
+
The file is located at `~/.tenchi/config`, where `~` is the [current user's home directory](https://docs.python.org/3/library/pathlib.html#pathlib.Path.home).
|
60
|
+
|
61
|
+
Each section is treated as a configuration profile, and the SDK will look for a section called `default` if another is not explicitly selected.
|
62
|
+
|
63
|
+
These are the supported options:
|
64
|
+
|
65
|
+
* `api_key` (required) which contains the Zanshin API key obtained at the [Zanshin web portal](https://zanshin.tenchisecurity.com/my-profile).
|
66
|
+
* `api_url` (optional) directs the SDK to use a different API endpoint than the default (https://api.zanshin.tenchisecurity.com).
|
67
|
+
* `user_agent` (optional) allows you to override the default user-agent header used by the SDK when making API requests (The value passed will be concatenated to the SDK's default value `Zanshin Ruby SDK 1.0.0`).
|
68
|
+
* `proxy_url` (optional) directs the SDK to use a Proxy.
|
69
|
+
|
70
|
+
This is what a minimal configuration file looks like:
|
71
|
+
```ini
|
72
|
+
[default]
|
73
|
+
api_key=my_zanshin_api_key
|
74
|
+
```
|
75
|
+
|
76
|
+
## The SDK
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
client = Zanshin::SDK::Client.new
|
80
|
+
client.get_me
|
81
|
+
```
|
82
|
+
|
83
|
+
## Usage
|
84
|
+
|
85
|
+
### Create instance
|
86
|
+
```ruby
|
87
|
+
client = Zanshin::SDK::Client.new # loads API key from the "default" profile in ~/.tenchi/config
|
88
|
+
```
|
89
|
+
|
90
|
+
### Get logged user info
|
91
|
+
```ruby
|
92
|
+
client.get_me # calls /me API endpoint
|
93
|
+
```
|
94
|
+
|
95
|
+
### Get logged user info
|
96
|
+
|
97
|
+
Methods with prefix `iter_*` return an [Enumerator](https://ruby-doc.org/core-2.6/Enumerator.html), you can use it however you want, in this example we use `to_a` to convert the Enumerator into an Array.
|
98
|
+
```ruby
|
99
|
+
client.iter_organizations.to_a # calls /organizations API endpoint
|
100
|
+
```
|
101
|
+
|
102
|
+
## Support
|
103
|
+
|
104
|
+
If you are a Zanshin customer and have any questions regarding the use of the service, its API or this SDK package, please get in touch via e-mail at `support@tenchisecurity.com` or via the support widget on the [Zanshin Portal](https://zanshin.tenchisecurity.com).
|
105
|
+
|
106
|
+
## Development
|
107
|
+
|
108
|
+
After checking out the repo, run `bundle install` to install dependencies. Then, run `bundle exec rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
109
|
+
|
110
|
+
## Contributing
|
111
|
+
|
112
|
+
Bug reports and pull requests are welcome on GitHub at `https://github.com/tenchi-security/zanshin-sdk-ruby`. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/tenchi-security/zanshin-sdk-ruby/blob/main/CODE_OF_CONDUCT.md).
|
113
|
+
|
114
|
+
## Unit Test
|
115
|
+
|
116
|
+
Currently, the Unit Test only checks if the API call was made in the way it should, after implementing the input validations the tests will be better.
|
117
|
+
|
118
|
+
## TODO
|
119
|
+
|
120
|
+
- Input validation
|
121
|
+
- Coverage badge
|
122
|
+
- File Persistent Alerts Iterator
|
123
|
+
- Onboard Scan Targets (AWS)
|
124
|
+
|
125
|
+
## License
|
126
|
+
|
127
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
128
|
+
|
129
|
+
## Code of Conduct
|
130
|
+
|
131
|
+
Everyone interacting in the `Zanshin Ruby SDK` project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/tenchi-security/zanshin-sdk-ruby/blob/main/CODE_OF_CONDUCT.md).
|
132
|
+
|
133
|
+
## Changelog
|
134
|
+
|
135
|
+
See [CHANGELOG](https://github.com/tenchi-security/zanshin-sdk-ruby/blob/main/CHANGELOG.md) for a list of changes.
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zanshin
|
4
|
+
module SDK
|
5
|
+
# Zanshin SDK Account
|
6
|
+
module Account
|
7
|
+
###################################################
|
8
|
+
# Account
|
9
|
+
###################################################
|
10
|
+
|
11
|
+
# Returns the details of the user account that owns the API key used by this Connection instance
|
12
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getMe)
|
13
|
+
#
|
14
|
+
# @return an Object representing the user
|
15
|
+
def get_me
|
16
|
+
@http.request('GET', '/me')
|
17
|
+
end
|
18
|
+
|
19
|
+
###################################################
|
20
|
+
# Account Invites
|
21
|
+
###################################################
|
22
|
+
|
23
|
+
# Invites Enumerator of current logged user
|
24
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getInvites)
|
25
|
+
#
|
26
|
+
# @return an Invites Enumerator object
|
27
|
+
def iter_invites
|
28
|
+
Enumerator.new do |yielder|
|
29
|
+
@http.request('GET', '/me/invites').each do |e|
|
30
|
+
yielder.yield e
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Gets a specific invitation details, it only works if the invitation was made for the current logged user
|
36
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getInviteById)
|
37
|
+
#
|
38
|
+
# @param invite_id [UUID] of the invite
|
39
|
+
#
|
40
|
+
# @return an Object representing the invite
|
41
|
+
def get_invite(invite_id)
|
42
|
+
@http.request('GET', "/me/invites/#{validate_uuid(invite_id)}")
|
43
|
+
end
|
44
|
+
|
45
|
+
# Accepts an invitation with the informed ID, it only works if the user accepting the invitation is the user that
|
46
|
+
# received the invitation
|
47
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/acceptInviteById)
|
48
|
+
#
|
49
|
+
# @param invite_id [UUID] of the invite
|
50
|
+
#
|
51
|
+
# @return an Object representing the organization of this invite
|
52
|
+
def accept_invite(invite_id)
|
53
|
+
@http.request('POST', "/me/invites/#{validate_uuid(invite_id)}/accept")
|
54
|
+
end
|
55
|
+
|
56
|
+
###################################################
|
57
|
+
# Account API key
|
58
|
+
###################################################
|
59
|
+
|
60
|
+
# API keys Enumerator of current logged user
|
61
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getMyApiKeys)
|
62
|
+
#
|
63
|
+
# @return an API keys Enumerator object
|
64
|
+
def iter_api_keys
|
65
|
+
Enumerator.new do |yielder|
|
66
|
+
@http.request('GET', '/me/apikeys').each do |e|
|
67
|
+
yielder.yield e
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Creates a new API key for the current logged user, API Keys can be used to interact with the zanshin api
|
73
|
+
# directly on behalf of that user
|
74
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/createApiKeys)
|
75
|
+
#
|
76
|
+
# @param name [String] of your new API key
|
77
|
+
#
|
78
|
+
# @return an Object representing the user api key
|
79
|
+
def create_api_key(name)
|
80
|
+
body = {}
|
81
|
+
body['name'] = name
|
82
|
+
@http.request('POST', '/me/apikeys', body)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Deletes a given API key by its id, it will only work if the informed ID belongs to the current logged user
|
86
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/deleteApiKey)
|
87
|
+
#
|
88
|
+
# @param api_key_id [UUID] of your new API key
|
89
|
+
#
|
90
|
+
# @return a Boolean with result
|
91
|
+
def delete_api_key(api_key_id)
|
92
|
+
@http.request('DELETE', "/me/apikeys/#{validate_uuid(api_key_id)}")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,368 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zanshin
|
4
|
+
module SDK
|
5
|
+
# Zanshin SDK Alerts
|
6
|
+
module Alerts
|
7
|
+
###################################################
|
8
|
+
# Alerts
|
9
|
+
###################################################
|
10
|
+
|
11
|
+
# Alerts Enumerator of an organization by loading them, transparently paginating on the API
|
12
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/listAllAlert)
|
13
|
+
#
|
14
|
+
# @param organization_id [UUID] of the organization
|
15
|
+
# @param scan_target_ids [Array<UUID>] Optional list of scan target IDs to list alerts from, defaults to all
|
16
|
+
# @param rule [String] to filter alerts from (rule), not passing the field will fetch all
|
17
|
+
# @param states [Array<'OPEN', 'ACTIVE', 'IN_PROGRESS', 'RISK_ACCEPTED', 'CLOSED'>] Optional list of states to
|
18
|
+
# filter returned alerts, defaults to all
|
19
|
+
# @param severities [Array<'CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'INFO'>] optional list of severities to filter
|
20
|
+
# returned alerts, defaults to all
|
21
|
+
# @param page_size [Integer] the number of alerts to load from the API at a time
|
22
|
+
# @param language ['en-US', 'pt-BR'] Language of the rule will be returned
|
23
|
+
# @param created_at_start [String] Search alerts by creation date - greater or equals than
|
24
|
+
# @param created_at_end [String] Search alerts by creation date - less or equals than
|
25
|
+
# @param updated_at_start [String] Search alerts by update date - greater or equals than
|
26
|
+
# @param updated_at_end [String] Search alerts by update date - less or equals than
|
27
|
+
#
|
28
|
+
# @return an Alerts Enumerator object
|
29
|
+
def iter_alerts(organization_id,
|
30
|
+
scan_target_ids: [],
|
31
|
+
rule: nil,
|
32
|
+
states: nil,
|
33
|
+
severities: nil,
|
34
|
+
page_size: 100,
|
35
|
+
language: nil,
|
36
|
+
created_at_start: nil,
|
37
|
+
created_at_end: nil,
|
38
|
+
updated_at_start: nil,
|
39
|
+
updated_at_end: nil)
|
40
|
+
body = {
|
41
|
+
'organizationId' => validate_uuid(organization_id),
|
42
|
+
'page' => 0,
|
43
|
+
'pageSize' => page_size,
|
44
|
+
'scanTargetIds' => scan_target_ids.each { |scan_target_id| validate_uuid(scan_target_id) },
|
45
|
+
'rule' => rule,
|
46
|
+
'states' => states,
|
47
|
+
'severities' => severities,
|
48
|
+
'lang' => language,
|
49
|
+
'CreatedAtStart' => created_at_start,
|
50
|
+
'CreatedAtEnd' => created_at_end,
|
51
|
+
'UpdatedAtStart' => updated_at_start,
|
52
|
+
'UpdatedAtEnd' => updated_at_end
|
53
|
+
}
|
54
|
+
|
55
|
+
Enumerator.new do |yielder|
|
56
|
+
loop do
|
57
|
+
body['page'] += 1
|
58
|
+
data = @http.request('POST', '/alerts', body.compact)
|
59
|
+
data['data'].each do |e|
|
60
|
+
yielder.yield e
|
61
|
+
end
|
62
|
+
break if body['page'] == (data['total'] / body['pageSize']).ceil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Alerts Following Enumerator over the following alerts froms organizations being followed by
|
68
|
+
# transparently paginating on the API
|
69
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/listFollowingAlerts)
|
70
|
+
#
|
71
|
+
# @param organization_id [UUID] of the organization
|
72
|
+
# @param following_ids [Array<UUID>] Optional list of IDs of organizations you are following to
|
73
|
+
# list alerts from, defaults to all
|
74
|
+
# @param rule [String] to filter alerts from (rule), not passing the field will fetch all
|
75
|
+
# @param states [Array<'OPEN', 'ACTIVE', 'IN_PROGRESS', 'RISK_ACCEPTED', 'CLOSED'>] Optional list of states to
|
76
|
+
# filter returned alerts, defaults to all
|
77
|
+
# @param severities [Array<'CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'INFO'>] optional list of severities to filter
|
78
|
+
# returned alerts, defaults to all
|
79
|
+
# @param page_size [Integer] the number of alerts to load from the API at a time
|
80
|
+
# @param language ['en-US', 'pt-BR'] Language of the rule will be returned
|
81
|
+
# @param created_at_start [String] Search alerts by creation date - greater or equals than
|
82
|
+
# @param created_at_end [String] Search alerts by creation date - less or equals than
|
83
|
+
# @param updated_at_start [String] Search alerts by update date - greater or equals than
|
84
|
+
# @param updated_at_end [String] Search alerts by update date - less or equals than
|
85
|
+
#
|
86
|
+
# @return an Alerts Enumerator object
|
87
|
+
def iter_following_alerts(organization_id,
|
88
|
+
following_ids: [],
|
89
|
+
rule: nil,
|
90
|
+
states: nil,
|
91
|
+
severities: nil,
|
92
|
+
page_size: 100,
|
93
|
+
language: nil,
|
94
|
+
created_at_start: nil,
|
95
|
+
created_at_end: nil,
|
96
|
+
updated_at_start: nil,
|
97
|
+
updated_at_end: nil)
|
98
|
+
body = {
|
99
|
+
'organizationId' => validate_uuid(organization_id),
|
100
|
+
'page' => 0,
|
101
|
+
'pageSize' => page_size,
|
102
|
+
'followingIds' => following_ids.each { |following_id| validate_uuid(following_id) },
|
103
|
+
'rule' => rule,
|
104
|
+
'states' => states,
|
105
|
+
'severities' => severities,
|
106
|
+
'lang' => language,
|
107
|
+
'CreatedAtStart' => created_at_start,
|
108
|
+
'CreatedAtEnd' => created_at_end,
|
109
|
+
'UpdatedAtStart' => updated_at_start,
|
110
|
+
'UpdatedAtEnd' => updated_at_end
|
111
|
+
}
|
112
|
+
|
113
|
+
Enumerator.new do |yielder|
|
114
|
+
loop do
|
115
|
+
body['page'] += 1
|
116
|
+
data = @http.request('POST', '/alerts/following', body.compact)
|
117
|
+
data['data'].each do |e|
|
118
|
+
yielder.yield e
|
119
|
+
end
|
120
|
+
break if body['page'] == (data['total'] / body['pageSize']).ceil
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Alerts History Enumerator of an organization by loading them, transparently paginating on the API
|
126
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/listAllAlertsHistory)
|
127
|
+
#
|
128
|
+
# @param organization_id [UUID] of the organization
|
129
|
+
# @param scan_target_ids [Array<UUID>] Optional list of scan target IDs to list alerts from, defaults to all
|
130
|
+
# @param page_size [Integer] the number of alerts to load from the API at a time
|
131
|
+
# @param language ['en-US', 'pt-BR'] Language of the rule will be returned
|
132
|
+
# @param cursor [String] Alert Cursor of the last alert consumed, when this value is passed, subsequent
|
133
|
+
# alert histories will be returned
|
134
|
+
#
|
135
|
+
# @return an Alerts History Enumerator object
|
136
|
+
def iter_alerts_history(organization_id,
|
137
|
+
scan_target_ids: [],
|
138
|
+
page_size: 100,
|
139
|
+
language: nil,
|
140
|
+
cursor: nil)
|
141
|
+
body = {
|
142
|
+
'organizationId' => validate_uuid(organization_id),
|
143
|
+
'page' => 0,
|
144
|
+
'pageSize' => page_size,
|
145
|
+
'scanTargetIds' => scan_target_ids.each { |scan_target_id| validate_uuid(scan_target_id) },
|
146
|
+
'lang' => language,
|
147
|
+
'cursor' => cursor
|
148
|
+
}
|
149
|
+
|
150
|
+
Enumerator.new do |yielder|
|
151
|
+
loop do
|
152
|
+
body['page'] += 1
|
153
|
+
data = @http.request('POST', '/alerts/history', body.compact)
|
154
|
+
break if data['data'].empty?
|
155
|
+
|
156
|
+
body['cursor'] = data['data'].last['cursor']
|
157
|
+
data['data'].each do |e|
|
158
|
+
yielder.yield e
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Alerts Following History Enumerator of an organization by loading them, transparently paginating on the API
|
165
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/listAllAlertsHistoryFollowing)
|
166
|
+
#
|
167
|
+
# @param organization_id [UUID] of the organization
|
168
|
+
# @param following_ids [Array<UUID>] Optional list of IDs of organizations you are following to
|
169
|
+
# list alerts from, defaults to all
|
170
|
+
# @param page_size [Integer] the number of alerts to load from the API at a time
|
171
|
+
# @param language ['en-US', 'pt-BR'] Language of the rule will be returned
|
172
|
+
# @param cursor [String] Alert Cursor of the last alert consumed, when this value is passed, subsequent
|
173
|
+
# alert histories will be returned
|
174
|
+
#
|
175
|
+
# @return an Alerts Following History Enumerator object
|
176
|
+
def iter_alerts_following_history(organization_id,
|
177
|
+
following_ids: [],
|
178
|
+
page_size: 100,
|
179
|
+
language: nil,
|
180
|
+
cursor: nil)
|
181
|
+
body = {
|
182
|
+
'organizationId' => validate_uuid(organization_id),
|
183
|
+
'page' => 0,
|
184
|
+
'pageSize' => page_size,
|
185
|
+
'followingIds' => following_ids.each { |following_id| validate_uuid(following_id) },
|
186
|
+
'lang' => language,
|
187
|
+
'cursor' => cursor
|
188
|
+
}
|
189
|
+
|
190
|
+
Enumerator.new do |yielder|
|
191
|
+
loop do
|
192
|
+
body['page'] += 1
|
193
|
+
data = @http.request('POST', '/alerts/history/following', body.compact)
|
194
|
+
break if data['data'].empty?
|
195
|
+
|
196
|
+
body['cursor'] = data['data'].last['cursor']
|
197
|
+
data['data'].each do |e|
|
198
|
+
yielder.yield e
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# Grouped Alerts Enumerator of an organization by loading them, transparently paginating on the API
|
205
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/listAllAlertRules)
|
206
|
+
#
|
207
|
+
# @param organization_id [UUID] of the organization
|
208
|
+
# @param scan_target_ids [Array<UUID>] Optional list of scan target IDs to list alerts from, defaults to all
|
209
|
+
# @param states [Array<'OPEN', 'ACTIVE', 'IN_PROGRESS', 'RISK_ACCEPTED', 'CLOSED'>] Optional list of states to
|
210
|
+
# filter returned alerts, defaults to all
|
211
|
+
# @param severities [Array<'CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'INFO'>] optional list of severities to filter
|
212
|
+
# returned alerts, defaults to all
|
213
|
+
# @param page_size [Integer] the number of alerts to load from the API at a time
|
214
|
+
#
|
215
|
+
# @return an Grouped Alerts Enumerator object
|
216
|
+
def iter_grouped_alerts(organization_id,
|
217
|
+
scan_target_ids: [],
|
218
|
+
states: nil,
|
219
|
+
severities: nil,
|
220
|
+
page_size: 100)
|
221
|
+
body = {
|
222
|
+
'organizationId' => validate_uuid(organization_id),
|
223
|
+
'page' => 0,
|
224
|
+
'pageSize' => page_size,
|
225
|
+
'scanTargetIds' => scan_target_ids.each { |scan_target_id| validate_uuid(scan_target_id) },
|
226
|
+
'states' => states,
|
227
|
+
'severities' => severities
|
228
|
+
}
|
229
|
+
|
230
|
+
Enumerator.new do |yielder|
|
231
|
+
loop do
|
232
|
+
body['page'] += 1
|
233
|
+
data = @http.request('POST', '/alerts/rules', body.compact)
|
234
|
+
data['data'].each do |e|
|
235
|
+
yielder.yield e
|
236
|
+
end
|
237
|
+
break if body['page'] == (data['total'] / body['pageSize']).ceil
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# Grouped Alerts Following Enumerator of an organization by loading them, transparently paginating on the API
|
243
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/listAllAlertRulesFollowing)
|
244
|
+
#
|
245
|
+
# @param organization_id [UUID] of the organization
|
246
|
+
# @param following_ids [Array<UUID>] Optional list of IDs of organizations you are following to
|
247
|
+
# list alerts from, defaults to all
|
248
|
+
# @param states [Array<'OPEN', 'ACTIVE', 'IN_PROGRESS', 'RISK_ACCEPTED', 'CLOSED'>] Optional list of states to
|
249
|
+
# filter returned alerts, defaults to all
|
250
|
+
# @param severities [Array<'CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'INFO'>] optional list of severities to filter
|
251
|
+
# returned alerts, defaults to all
|
252
|
+
# @param page_size [Integer] the number of alerts to load from the API at a time
|
253
|
+
#
|
254
|
+
# @return an Grouped Alerts Following Enumerator object
|
255
|
+
def iter_grouped_following_alerts(organization_id,
|
256
|
+
following_ids: [],
|
257
|
+
states: nil,
|
258
|
+
severities: nil,
|
259
|
+
page_size: 100)
|
260
|
+
body = {
|
261
|
+
'organizationId' => validate_uuid(organization_id),
|
262
|
+
'page' => 0,
|
263
|
+
'pageSize' => page_size,
|
264
|
+
'followingIds' => following_ids.each { |following_id| validate_uuid(following_id) },
|
265
|
+
'states' => states,
|
266
|
+
'severities' => severities
|
267
|
+
}
|
268
|
+
|
269
|
+
Enumerator.new do |yielder|
|
270
|
+
loop do
|
271
|
+
body['page'] += 1
|
272
|
+
data = @http.request('POST', '/alerts/rules/following', body.compact)
|
273
|
+
data['data'].each do |e|
|
274
|
+
yielder.yield e
|
275
|
+
end
|
276
|
+
break if body['page'] == (data['total'] / body['pageSize']).ceil
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
# Returns the detailed object that describes an alert
|
282
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getAlertById)
|
283
|
+
#
|
284
|
+
# @param alert_id [UUID] of the alert
|
285
|
+
#
|
286
|
+
# @return a Object representing the alert
|
287
|
+
def get_alert(alert_id)
|
288
|
+
@http.request('GET', "/alerts/#{validate_uuid(alert_id)}")
|
289
|
+
end
|
290
|
+
|
291
|
+
# Alert History Enumerator over the history of an alert
|
292
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/listAllAlertHistory)
|
293
|
+
#
|
294
|
+
# @param alert_id [UUID] of the alert
|
295
|
+
#
|
296
|
+
# @return an Alert History Enumerator object
|
297
|
+
def iter_alert_history(alert_id)
|
298
|
+
Enumerator.new do |yielder|
|
299
|
+
@http.request('GET', "/alerts/#{validate_uuid(alert_id)}/history").each do |e|
|
300
|
+
yielder.yield e
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
# Alert Comments Enumerator over the comment of an alert
|
306
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/listAllAlertComments)
|
307
|
+
#
|
308
|
+
# @param alert_id [UUID] of the alert
|
309
|
+
#
|
310
|
+
# @return an Alert Comments Enumerator object
|
311
|
+
def iter_alert_comments(alert_id)
|
312
|
+
Enumerator.new do |yielder|
|
313
|
+
@http.request('GET', "/alerts/#{validate_uuid(alert_id)}/comments").each do |e|
|
314
|
+
yielder.yield e
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
# Update alert
|
320
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/editOrganizationScanTargetAlertById)
|
321
|
+
#
|
322
|
+
# @param organization_id [UUID] of the organization
|
323
|
+
# @param scan_target_id [UUID] of the scan target
|
324
|
+
# @param alert_id [UUID] of the alert
|
325
|
+
# @param state ['OPEN', 'ACTIVE', 'IN_PROGRESS', 'RISK_ACCEPTED']
|
326
|
+
# @param labels [Array<String>] Optional labels to alert
|
327
|
+
# @param comment [String] Accepted and required only when change :state to 'IN_PROGRESS'
|
328
|
+
#
|
329
|
+
# @return a Object representing the alert updated
|
330
|
+
def update_alert(organization_id, scan_target_id, alert_id, state = nil, labels = nil, comment = nil)
|
331
|
+
body = {
|
332
|
+
'state' => state,
|
333
|
+
'labels' => labels,
|
334
|
+
'comment' => comment
|
335
|
+
}
|
336
|
+
|
337
|
+
@http.request(
|
338
|
+
'PUT',
|
339
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{
|
340
|
+
validate_uuid(scan_target_id)}/alerts/#{validate_uuid(alert_id)}",
|
341
|
+
body.compact
|
342
|
+
)
|
343
|
+
end
|
344
|
+
|
345
|
+
# Create comment in alert
|
346
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/listAllAlertComments)
|
347
|
+
#
|
348
|
+
# @param organization_id [UUID] of the organization
|
349
|
+
# @param scan_target_id [UUID] of the scan target
|
350
|
+
# @param alert_id [UUID] of the alert
|
351
|
+
# @param comment [String] in HTML format
|
352
|
+
#
|
353
|
+
# @return a Object representing the alert comment
|
354
|
+
def create_alert_comment(organization_id, scan_target_id, alert_id, comment)
|
355
|
+
body = {
|
356
|
+
'comment' => comment
|
357
|
+
}
|
358
|
+
|
359
|
+
@http.request(
|
360
|
+
'POST',
|
361
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{
|
362
|
+
validate_uuid(scan_target_id)}/alerts/#{validate_uuid(alert_id)}/comments",
|
363
|
+
body.compact
|
364
|
+
)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|