threatstack 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bb2d3822b5477af93812d538e414b247230d3539
4
+ data.tar.gz: 46428650cbe22613630d2f91daa71e8bb79bafee
5
+ SHA512:
6
+ metadata.gz: eccd2edb7ed85e4cb2e9818413e8ecc54361407c03920b912d12a5209302cd0a9b6d88deba537ec54ef07b354d42604ae691f78dbefb26deea069e88e3efe835
7
+ data.tar.gz: fcfca22363bef5e091c8aae805c9589af22d3b61ff1007f3286ef753c37389d728cee48af7e0379c5b79e99a8194f2ea52fcb08ce8c497a9cd117c61a69d0716
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.3
5
+ before_install: gem install bundler -v 1.14.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in threatstack.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Ryan Canty
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,130 @@
1
+ # Threatstack
2
+
3
+ Threatstack is a tool for monitoring your infrastructure and hosts for malicious or suspicious activity. They have this handy little API that I decided to write a Ruby wrapper for. This is a very thin wrapper that only transforms keys for the purpose of changing them to snake_case like the rest of the ruby world. Otherwise, this maps very closely to the API docs found here: https://app.threatstack.com/api/docs
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'threatstack'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install threatstack
20
+
21
+ ## Usage
22
+
23
+ You can access all attributes on responses thanks to the method_missing function in Ruby. We only munged the attributes that don't correspond to snake_case. If you want to see a list of all available attributes for a serializable response object, simply do something like this:
24
+
25
+ ```
26
+ client = Threatstack::Client.new(API_TOKEN)
27
+ client.policies.first.attrs
28
+ => [:rules,
29
+ :id,
30
+ :name,
31
+ :created_at,
32
+ :updated_at,
33
+ :enabled,
34
+ :agent_count,
35
+ :alert_rule_count,
36
+ :description,
37
+ :organization_id,
38
+ :alert_policy_id,
39
+ :alert_policy,
40
+ :file_integrity_rules]
41
+ ```
42
+
43
+ ### Alerts
44
+
45
+ ```
46
+ client = Threatstack::Client.new(API_TOKEN)
47
+ ## All these are optional url params. See the Threatstack API Docs
48
+ alert = client.alerts(start: 3.days.ago, end: Time.now, count: 5).last
49
+ => #<Threatstack::Alert::Alert:0x007fde0b01cbd8
50
+ @raw=
51
+ {"created_at"=>1496850520000,
52
+ "expires_at"=>1496936920000,
53
+ "last_updated_at"=>"2017-06-07T16:03:56.270Z",
54
+ "count"=>4,
55
+ "title"=>"CloudTrail Activity : EC2 Service Policy Changes : CreateVolume by ryan_canty",
56
+ ...
57
+ event = alert.latest_events.last
58
+ => <Threatstack::Alert::Event:0x007fde0ca08420
59
+ @raw=
60
+ {"user"=>"ryan_canty",
61
+ "userType"=>"IAMUser",
62
+ ...
63
+ user_that_caused_the_event = event.user_identity.arn
64
+ => "arn:aws:iam::1234567890:user/ryan_canty"
65
+
66
+ ```
67
+
68
+ You can also limit the response if that's important to you:
69
+
70
+ ```
71
+ client.alerts(fields: ['title', 'alerts'])
72
+ => [#<Threatstack::Alert::Alert:0x007fd61348c768
73
+ @raw={"title"=>"CloudTrail Activity (IAM Policy Changes) : CreateAccessKey by ryan_canty", "severity"=>2}>]
74
+ ```
75
+
76
+ You can also get a single alert by id using:
77
+
78
+ ```
79
+ client.alert('1234567890')
80
+ ```
81
+
82
+ ### Agents
83
+
84
+ ```
85
+ client.agents
86
+ => [#<Threatstack::Agent::Agent:0x007fa262b0b2e0 @raw={...}> ]
87
+ client.agent
88
+ => #<Threatstack::Agent::Agent:0x007fa262b0b2e0 @raw={...}>
89
+ ```
90
+
91
+
92
+ ### Policies
93
+
94
+ ```
95
+ client.policies
96
+ => [#<Threatstack::Policy::Policy:0x007fa262b0b2e0 @raw={...}> ]
97
+ client.policy
98
+ => #<Threatstack::Policy::Policy:0x007fa262b0b2e0 @raw={...}>
99
+ ```
100
+
101
+ ### Organizations
102
+
103
+ ```
104
+ client.organizations
105
+ => [#<Threatstack::Organization::Organization:0x007fa262b0b2e0 @raw={...}> ]
106
+ ```
107
+
108
+ ### Audit Logs
109
+
110
+ ```
111
+ client.logs
112
+ => [#<Threatstack::Log::Log:0x007fa262b0b2e0 @raw={...}>]
113
+ client.search('query')
114
+ => [#<Threatstack::Log::Log:0x007fa262b0b2e0 @raw={...}>]
115
+ ```
116
+
117
+ ## Development
118
+
119
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
120
+
121
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
122
+
123
+ ## Contributing
124
+
125
+ Bug reports and pull requests are welcome on GitHub at https://github.com/onetwopunch/threatstack.
126
+
127
+
128
+ ## License
129
+
130
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
3
+ require "bundler/setup"
4
+ require "threatstack"
5
+ require "pry"
6
+
7
+ Pry.config.prompt = lambda do |context, nesting, pry|
8
+ "[threatstack] #{context}> "
9
+ end
10
+
11
+ Pry.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,5 @@
1
+ require "threatstack/version"
2
+ require "threatstack/client"
3
+
4
+ module Threatstack
5
+ end
@@ -0,0 +1,9 @@
1
+ require 'threatstack/agent/agent'
2
+
3
+ module Threatstack
4
+ module Agent
5
+ class Agent
6
+ include Serializable
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ require 'threatstack/agent/agent'
2
+
3
+ module Threatstack
4
+ module Agent
5
+ class Response
6
+ attr_reader :raw
7
+ def initialize(raw)
8
+ @raw = raw
9
+ end
10
+
11
+ def agents
12
+ raw.map{ |a| Agent.new(a) }
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ require 'threatstack/alert/event'
2
+ require 'threatstack/alert/rule'
3
+ require 'threatstack/serializable'
4
+
5
+ module Threatstack
6
+ module Alert
7
+ class Alert
8
+ include Serializable
9
+ attributes :latest_events, :rule
10
+
11
+ def latest_events
12
+ raw['latest_events'].map do |event|
13
+ Event.new(event)
14
+ end
15
+ end
16
+
17
+ def rule
18
+ Rule.new(raw['rule'])
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ require 'threatstack/alert/user_identity'
2
+ require 'threatstack/serializable'
3
+
4
+ module Threatstack
5
+ module Alert
6
+ class Event
7
+ include Serializable
8
+ attributes :user_identity
9
+
10
+ def user_identity
11
+ UserIdentity.new(raw['userIdentity'])
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'threatstack/alert/alert'
2
+ require 'threatstack/serializable'
3
+
4
+ module Threatstack
5
+ module Alert
6
+ class Response
7
+ include Serializable
8
+ attributes :alerts
9
+
10
+ def alerts
11
+ raw.map{ |a| Alert.new(a) }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ require 'threatstack/serializable'
2
+ module Threatstack
3
+ module Alert
4
+ class Rule
5
+ include Serializable
6
+ attributes :original_rule
7
+
8
+ def original_rule
9
+ Rule.new(raw['original_rule'])
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ require 'threatstack/serializable'
2
+
3
+ module Threatstack
4
+ module Alert
5
+ class UserIdentity
6
+ include Serializable
7
+ attributes :user_name, :session_context, :invoked_by, :account_id, :access_key_id, :principal_id
8
+
9
+ def user_name
10
+ raw['userName']
11
+ end
12
+
13
+ def session_context
14
+ raw['sessionContext']
15
+ end
16
+
17
+ def invoked_by
18
+ raw['invokedBy']
19
+ end
20
+
21
+ def account_id
22
+ raw['accountId']
23
+ end
24
+
25
+ def access_key_id
26
+ raw['accessKeyId']
27
+ end
28
+
29
+ def principal_id
30
+ raw['principalId']
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,93 @@
1
+ require 'open-uri'
2
+ require 'httparty'
3
+ require 'threatstack/alert/response'
4
+ require 'threatstack/alert/alert'
5
+ require 'threatstack/agent/response'
6
+ require 'threatstack/agent/agent'
7
+ require 'threatstack/policy/response'
8
+ require 'threatstack/policy/policy'
9
+ require 'threatstack/organization/response'
10
+ require 'threatstack/log/response'
11
+
12
+ module Threatstack
13
+ class ThreatstackError < StandardError; end
14
+
15
+ class Client
16
+ THREATSTACK_API = 'https://app.threatstack.com/api/v1'
17
+
18
+ attr_reader :token, :org_id
19
+
20
+ def initialize(token)
21
+ @token = token
22
+ end
23
+
24
+ def alerts(params = {})
25
+ response = do_request(:get, 'alerts', params)
26
+ Alert::Response.new(response).alerts
27
+ end
28
+
29
+ def alert(alert_id, params = {})
30
+ raise ThreatstackError, "Must specify alert id" unless alert_id
31
+ response = do_request(:get, "alerts/#{alert_id}", params)
32
+ Alert::Alert.new(response)
33
+ end
34
+
35
+ def agents(params = {})
36
+ response = do_request(:get, 'agents', params)
37
+ Agent::Response.new(response).agents
38
+ end
39
+
40
+ def agent(agent_id, params = {})
41
+ raise ThreatstackError, "Must specify agent id" unless agent_id
42
+ response = do_request(:get, "agents/#{agent_id}", params)
43
+ Agent::Agent.new(response)
44
+ end
45
+
46
+ def policies(params = {})
47
+ response = do_request(:get, 'policies', params)
48
+ Policy::Response.new(response).policies
49
+ end
50
+
51
+ def policy(policy_id, params = {})
52
+ raise ThreatstackError, "Must specify policy id" unless policy_id
53
+ response = do_request(:get, "policies/#{policy_id}", params)
54
+ Policy::Policy.new(response)
55
+ end
56
+
57
+ def organizations(params = {})
58
+ response = do_request(:get, 'organizations', params)
59
+ Organization::Response.new(response).organizations
60
+ end
61
+
62
+ def logs(params = {})
63
+ response = do_request(:get, 'logs', params)
64
+ Log::Response.new(response).logs
65
+ end
66
+
67
+ def search(query, params = {})
68
+ logs(params.merge(q: query))
69
+ end
70
+
71
+ private
72
+
73
+ def do_request(method, path, params = {})
74
+ response = HTTParty.public_send(method, build_uri(path, params), headers: { "Authorization" => token })
75
+ if response.instance_of?(Hash) && response['status'] == 'error'
76
+ raise ThreatstackError, response['message']
77
+ end
78
+ response
79
+ end
80
+
81
+ def build_uri(path, params = {})
82
+ params[:start] = params[:start].utc if params[:start]
83
+ params[:end] = params[:end].utc if params[:end]
84
+ params[:fields] = params[:fields].join(',') if params[:fields]&.is_a?(Array)
85
+
86
+ query = params.each_pair.map { |k, v| "#{k}=#{v}" }.join('&')
87
+ uri = "#{THREATSTACK_API}/#{path}"
88
+ uri += "?#{URI::encode(query)}" if params.any?
89
+ uri
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,9 @@
1
+ require 'threatstack/serializable'
2
+
3
+ module Threatstack
4
+ module Log
5
+ class Log
6
+ include Serializable
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ require 'threatstack/log/log'
2
+
3
+ module Threatstack
4
+ module Log
5
+ class Response
6
+ include Serializable
7
+ attributes :logs
8
+
9
+ def logs
10
+ raw.map{ |a| Log.new(a) }
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ require 'threatstack/organization/organization'
2
+ require 'threatstack/serializable'
3
+
4
+ module Threatstack
5
+ module Organization
6
+ class Organization
7
+ include Serializable
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ require 'threatstack/organization/organization'
2
+ require 'threatstack/serializable'
3
+
4
+ module Threatstack
5
+ module Organization
6
+ class Response
7
+ include Serializable
8
+ attributes :organizations
9
+
10
+ def organizations
11
+ raw.map{ |a| Organization.new(a) }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'threatstack/policy/policy'
2
+ require 'threatstack/alert/rule'
3
+
4
+ module Threatstack
5
+ module Policy
6
+ class Policy
7
+ include Serializable
8
+ attributes :rules
9
+
10
+ def rules
11
+ raw['alert_policy'].map{ |r| Threatstack::Alert::Rule.new(r) }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'threatstack/policy/policy'
2
+ require 'threatstack/serializable'
3
+
4
+ module Threatstack
5
+ module Policy
6
+ class Response
7
+ include Serializable
8
+ attributes :policies
9
+
10
+ def policies
11
+ raw.map{ |a| Policy.new(a) }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ module Threatstack
2
+ module Serializable
3
+ attr_reader :raw
4
+
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ def initialize(raw)
10
+ @raw = raw
11
+ end
12
+
13
+ def method_missing(m, *args)
14
+ raw[m.to_s]
15
+ end
16
+
17
+ def attrs
18
+ @attrs ||= self.class.default_attrs + raw.keys.map(&:to_sym)
19
+ end
20
+
21
+ module ClassMethods
22
+ def attributes(*args)
23
+ @default_attrs = args
24
+ end
25
+
26
+ def default_attrs
27
+ @default_attrs ||= []
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module Threatstack
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'threatstack/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "threatstack"
8
+ spec.version = Threatstack::VERSION
9
+ spec.authors = ["Ryan Canty"]
10
+ spec.email = ["jrcanty@gmail.com"]
11
+
12
+ spec.summary = %q{Threatstack API integration for Ruby}
13
+ spec.description = %q{Threatstack API integration for Ruby}
14
+ spec.homepage = "https://github.com/onetwopunch/threatstack"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.14"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "minitest", "~> 5.0"
27
+ spec.add_development_dependency "pry"
28
+ spec.add_runtime_dependency "httparty"
29
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: threatstack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Canty
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-06-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.14'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: httparty
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Threatstack API integration for Ruby
84
+ email:
85
+ - jrcanty@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".travis.yml"
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - bin/console
97
+ - bin/setup
98
+ - lib/threatstack.rb
99
+ - lib/threatstack/agent/agent.rb
100
+ - lib/threatstack/agent/response.rb
101
+ - lib/threatstack/alert/alert.rb
102
+ - lib/threatstack/alert/event.rb
103
+ - lib/threatstack/alert/response.rb
104
+ - lib/threatstack/alert/rule.rb
105
+ - lib/threatstack/alert/user_identity.rb
106
+ - lib/threatstack/client.rb
107
+ - lib/threatstack/log/log.rb
108
+ - lib/threatstack/log/response.rb
109
+ - lib/threatstack/organization/organization.rb
110
+ - lib/threatstack/organization/response.rb
111
+ - lib/threatstack/policy/policy.rb
112
+ - lib/threatstack/policy/response.rb
113
+ - lib/threatstack/serializable.rb
114
+ - lib/threatstack/version.rb
115
+ - threatstack.gemspec
116
+ homepage: https://github.com/onetwopunch/threatstack
117
+ licenses:
118
+ - MIT
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 2.6.10
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: Threatstack API integration for Ruby
140
+ test_files: []