huntress 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
+ SHA256:
3
+ metadata.gz: b47fbf82bfacb413dde2b52eed39dfaf2aa240d38798a315efdf3e669b3859c8
4
+ data.tar.gz: 7726b763502f9ab5f18a1c86057c9118a44abd5ddf518161b528add65cfeaf04
5
+ SHA512:
6
+ metadata.gz: 075da61fc4b04310b673b0a1e72d32eb2d2a1c044667587fa28781952753873604361c6ccb0c4f87a9dc7e4e16833982ecc754696351596953c14a10d3c9dfc1
7
+ data.tar.gz: 7c6c0769058c8e5da1b5eefeb9577a9c47b83fb99078e718bd9cd78cbdda79ea494fca3906db623198dc99d129ea3aa603215735de0dd45fb3cba246f6a1d1ab
data/.env.template ADDED
@@ -0,0 +1,2 @@
1
+ HUNTRESS_API_KEY=xxx
2
+ HUNTRESS_API_SECRET=xxx
data/.gitignore ADDED
@@ -0,0 +1,44 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+ /data/
13
+ *.log
14
+ *.txt
15
+ *.json
16
+ *.yml
17
+
18
+ # Used by dotenv library to load environment variables.
19
+ .env
20
+
21
+
22
+ ## Documentation cache and generated files:
23
+ /.yardoc/
24
+ /_yardoc/
25
+ /doc/
26
+ /rdoc/
27
+
28
+ ## Environment normalization:
29
+ /.bundle/
30
+ /vendor/bundle
31
+ /lib/bundler/man/
32
+
33
+ # for a library or gem, you might want to ignore these files since the code is
34
+ # intended to run in multiple environments; otherwise, check them in:
35
+ # Gemfile.lock
36
+ # .ruby-version
37
+ # .ruby-gemset
38
+
39
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
40
+ .rvmrc
41
+
42
+ # Used by RuboCop. Remote config files pulled in from inherit_from directive.
43
+ # .rubocop-https?--*
44
+ Gemfile.lock
data/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0] - 2025-10-31
4
+
5
+ - Initial release
6
+
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in cloudally.gemspec
6
+ gemspec
7
+
8
+ gem 'rake', '~> 13.0'
9
+ gem 'rubocop', '~> 1.7'
10
+ gem 'simplecov', require: false, group: :test
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # Sophos Central Partner API
2
+
3
+ [![Version](https://img.shields.io/gem/v/huntress.svg)](https://rubygems.org/gems/huntress)
4
+
5
+
6
+ This is a wrapper for the Huntress API.
7
+ You can see the [API endpoints](https://api.huntress.io/docs)
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'huntress'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ ```console
20
+ > bundle install
21
+ ```
22
+
23
+ Or install it yourself as:
24
+
25
+ ```console
26
+ > gem install huntress
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ Before you start making the requests to API provide the client id and client secret
32
+ and email/password using the configuration wrapping.
33
+
34
+ ```ruby
35
+ require 'huntress'
36
+
37
+ LOGGER = 'huntres-api.log'
38
+
39
+ Huntress.reset
40
+ Huntress.logger = Logger.new(AUTH_LOGGER)
41
+
42
+ Huntress.configure do |config|
43
+ config.client_id = ENV['HUNTRESS_API_KEY']
44
+ config.client_secret = ENV['HUNTRESS_API_SECRET']
45
+ end
46
+ client = Huntress.client
47
+ result = client.login
48
+ ```
49
+
50
+ ## Resources
51
+
52
+ ### Authentication
53
+
54
+ ```ruby
55
+ # setup configuration
56
+ #
57
+ client.login
58
+ ```
59
+
60
+ |Resource|API endpoint|Description|
61
+ |:--|:--|:--|
62
+ |.login|||
63
+
64
+ ### Operations
65
+
66
+ Huntress endpoint implemented
67
+
68
+ |Resource|API endpoint|
69
+ |:--|:--|
70
+ |.account |/v1/account|
71
+ |.actor |/v1/actor|
72
+ |.agents, .agent(id) |/v1/agents/{id}|
73
+ |.billing_reports, .billing_report |/v1/billing_reports/{id}|
74
+ |.incident_reports, .incident_report(id) |/v1/incident_reports/{id}|
75
+ |.remediations(report_id), .remediation(report_id, id) |/v1incident_reports/{report_id}/remediations/{id}|
76
+ |.organizations, .organization(id) |/v1/organizations/{id}|
77
+ |.reports, .report(id) |/v1/reports/{id}|
78
+ |.signals, .signal(id) |/v1/signals/{id}|
79
+
80
+ ## Contributing
81
+
82
+ Bug reports and pull requests are welcome on [GitHub](https://github.com/jancotanis/huntress).
83
+
84
+ ## License
85
+
86
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'dotenv'
5
+ require 'rake/testtask'
6
+
7
+ Dotenv.load
8
+
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'test'
11
+ t.libs << 'lib'
12
+ t.test_files = FileList['test/**/*_test.rb']
13
+ at_exit do
14
+ system './bin/cc-test-reporter after-build'
15
+ end
16
+ end
17
+
18
+ require 'rubocop/rake_task'
19
+ RuboCop::RakeTask.new
20
+ task default: %i[test rubocop]
data/huntress.gemspec ADDED
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/huntress/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'huntress'
7
+ s.version = Huntress::VERSION
8
+ s.authors = ['Janco Tanis']
9
+ s.email = 'gems@jancology.com'
10
+ s.license = 'MIT'
11
+
12
+ s.summary = 'A Ruby wrapper for the Huntress APIs (readonly)'
13
+ s.homepage = 'https://rubygems.org/gems/huntress'
14
+
15
+ s.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
16
+
17
+ s.metadata['homepage_uri'] = s.homepage
18
+ s.metadata['source_code_uri'] = 'https://github.com/jancotanis/huntress'
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ s.files = Dir.chdir(File.expand_path(__dir__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
24
+ end
25
+ s.bindir = 'exe'
26
+ s.executables = s.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
27
+ s.require_paths = ['lib']
28
+
29
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
30
+ s.platform = Gem::Platform::RUBY
31
+ s.add_runtime_dependency 'faraday'
32
+ s.add_runtime_dependency 'wrapi', ">= 0.5.0"
33
+ s.add_development_dependency 'dotenv'
34
+ s.add_development_dependency 'minitest'
35
+ s.add_development_dependency 'simplecov'
36
+ s.add_development_dependency 'rubocop'
37
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'wrapi'
4
+ require File.expand_path('connection', __dir__)
5
+ require File.expand_path('authentication', __dir__)
6
+
7
+ module Huntress
8
+ # @private
9
+ class API
10
+ # @private
11
+ attr_accessor *WrAPI::Configuration::VALID_OPTIONS_KEYS
12
+
13
+ # Creates a new API and copies settings from singleton
14
+ def initialize(options = {})
15
+ options = Huntress.options.merge(options)
16
+ WrAPI::Configuration::VALID_OPTIONS_KEYS.each do |key|
17
+ send("#{key}=", options[key])
18
+ end
19
+ end
20
+
21
+ def config
22
+ conf = {}
23
+ WrAPI::Configuration::VALID_OPTIONS_KEYS.each do |key|
24
+ conf[key] = send key
25
+ end
26
+ conf
27
+ end
28
+
29
+ include WrAPI::Connection
30
+ include Connection
31
+ include WrAPI::Request
32
+ include WrAPI::Authentication
33
+ include Authentication
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require File.expand_path('error', __dir__)
5
+
6
+ module Huntress
7
+ # Deals with authentication flow and stores it within global configuration
8
+ module Authentication
9
+ #
10
+ # Authorize to the Hudu portal and return access_token
11
+ def login(options = {})
12
+ raise ArgumentError, 'client_id not set' unless client_id
13
+ raise ArgumentError, 'client_secret not set' unless client_secret
14
+
15
+ # pass api key (id) and secret using basic authentication/connection
16
+ self.token_type = 'Basic'
17
+ self.access_token = Base64.strict_encode64("#{client_id}:#{client_secret}")
18
+
19
+ # will do sanitty check if token if valid
20
+ get('/v1/account', options)
21
+ rescue Faraday::Error => e
22
+ raise AuthenticationError, e
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('api', __dir__)
4
+ #require File.expand_path('asset_helper', __dir__)
5
+
6
+ module Huntress
7
+ # The Client class serves as a wrapper for the Hudu REST API, providing methods to interact
8
+ # with various Hudu resources.
9
+ #
10
+ # This class dynamically defines methods to fetch, create, update, and manipulate Hudu resources
11
+ # such as companies, articles, assets, and more.
12
+ #
13
+ # @example Basic Usage
14
+ # client.companies # Fetch all companies
15
+ # client.company(1) # Fetch a company by ID
16
+ # client.update_company(1, { name: "Updated Company" }) # Update a company
17
+ # client.create_company({ name: "New Company" }) # Create a new company
18
+ class Client < API
19
+
20
+ # Dynamically defines methods for interacting with Hudu API resources.
21
+ #
22
+ # Depending on the arguments, this will define methods to:
23
+ # - Fetch all records for a resource
24
+ # - Fetch a specific record by ID
25
+ # - Update a record
26
+ # - Create a new record
27
+ #
28
+ # @param method [Symbol] The method name for fetching all records.
29
+ # @param singular_method [Symbol, nil] The method name for fetching a single record by ID. Optional.
30
+ # @param path [String] The API path for the resource. Defaults to the method name.
31
+ #
32
+ # @example Defining endpoints
33
+ # api_endpoint :companies, :company
34
+ # # Defines:
35
+ # # - `companies(params = {})` to fetch all companies.
36
+ # # - `company(id, params = {})` to fetch a single company by ID.
37
+ # # - `update_companies(id, params = {})` to update a company.
38
+ # # - `create_companies(params = {})` to create a new company.
39
+ def self.api_endpoint(method, singular_method = nil, path = method)
40
+ if singular_method
41
+ # Define method to fetch all records and one by id
42
+ send(:define_method, method) do |params = {}|
43
+ r = get_paged(api_url(path), params)
44
+ end
45
+ # Define method to fetch a single record by ID
46
+ send(:define_method, singular_method) do |id, params = {}|
47
+ r = get(api_url("#{path}/#{id}"), params)
48
+ end
49
+ else
50
+ # Define simple method to fetch data
51
+ send(:define_method, method) do |params = {}|
52
+ get(api_url(path), params)
53
+ end
54
+ end
55
+ end
56
+
57
+ def account(options = {})
58
+ get(api_url('account'), options)
59
+ end
60
+
61
+ def actor(options = {})
62
+ get(api_url('actor'), options)
63
+ end
64
+
65
+ def remediation(incident_report_id, remediation, options = {})
66
+ get_paged(api_url("incident_reports/#{incident_report_id}/remediations/#{remediation}"), options)
67
+ end
68
+
69
+ def remediations(incident_report_id, options = {})
70
+ #get_paged(api_url("incident_reports/#{incident_report_id}/remediations"), options)
71
+ remediation(incident_report_id, nil, options)
72
+ end
73
+
74
+ # Define API endpoints for various resources
75
+ api_endpoint :agents, :agent
76
+ api_endpoint :billing_reports, :billing_report
77
+ api_endpoint :incident_reports, :incident_report
78
+ api_endpoint :organizations, :organization
79
+ api_endpoint :reports, :report
80
+ api_endpoint :signals, :signal
81
+
82
+
83
+ # Constructs the full API URL for a given path.
84
+ #
85
+ # @param path [String] The API path.
86
+ # @return [String] The full API URL.
87
+ def api_url(path)
88
+ "/v1/#{path}"
89
+ end
90
+
91
+ end
92
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Huntress
4
+ # Create connection including and keep it persistent so we add the rate throtling middleware only once
5
+ module Connection
6
+ private
7
+
8
+ def connection
9
+ unless @connection
10
+ @connection = super
11
+ @connection.use WrAPI::RateThrottleMiddleware, limit: 60, period: 60
12
+ end
13
+ @connection
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Huntress
4
+ # Generic error to be able to rescue all Hudu errors
5
+ class HuntressError < StandardError; end
6
+
7
+ # Error when authentication fails
8
+ class AuthenticationError < HuntressError; end
9
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+ require 'json'
5
+
6
+ module Huntress
7
+ # Defines HTTP request methods
8
+ # @see https://api.huntress.io/docs
9
+ module RequestPagination
10
+ # The PaginationPager class provides a mechanism to handle pagination information for API responses.
11
+ #
12
+ # It manages the current page, page size, and provides utilities for determining if there are more pages to fetch.
13
+ #
14
+ # @example Basic Usage
15
+ # pager = PaginationPager.new(50)
16
+ # while pager.more_pages?
17
+ # response = api_client.get_data(pager.page_options)
18
+ # pager.next_page!(response.body)
19
+ # end
20
+ class PaginationPager
21
+ # Initializes a new PaginationPager instance.
22
+ #
23
+ # @param page_size [Integer] The number of records to fetch per page.
24
+ def initialize(page_size)
25
+ @page = 1
26
+ @page_token = @pagination_data = nil
27
+ @limit = page_size
28
+ end
29
+
30
+ # Provides the current pagination parameter options for each rest request.
31
+ #
32
+ # @return [Hash] A hash containing the current page and page size.
33
+ #
34
+ # @example
35
+ # pager.page_options # => { page_token: 'Mjadso43289', page_size: 50 }
36
+ def page_options
37
+ options = { limit: @limit }
38
+ options.merge!({ page_token: @page_token }) if @page_token
39
+ options
40
+ end
41
+
42
+ # Advances to the next page based on the response body and updates internal pagination state.
43
+ #
44
+ # @param body [Hash] The response body from the API, expected to contain a paginated resource.
45
+ # @return [Integer] The updated page total, typically the count of items on the current page.
46
+ #
47
+ # @example
48
+ # response_body = { "items" => [...] }
49
+ # pager.next_page!(response_body)
50
+ def next_page!(body)
51
+ @page += 1
52
+ @pagination_data = PaginationPager.pagination_data(body)
53
+ end
54
+
55
+ # Determines whether there are more pages to fetch.
56
+ #
57
+ # @return [Boolean] Returns `true` if the current page is full, indicating another page might exist.
58
+ #
59
+ # @example
60
+ # pager.more_pages? # => true or false
61
+ def more_pages?
62
+ # while full page we have next page
63
+ if @pagination_data
64
+ @page_token = @pagination_data["next_page_token"]
65
+ else
66
+ @page.eql? 1
67
+ end
68
+ end
69
+
70
+ # Extracts paginated data from the response body.
71
+ #
72
+ # @param body [Hash] The response body containing resource data, expected to be in a hash format.
73
+ # @return [Array, Hash, Object] Returns the extracted data, which could be an array, hash, or other object.
74
+ #
75
+ # @example
76
+ # response_body = { "items" => [1, 2, 3] }
77
+ # PaginationPager.data(response_body) # => [1, 2, 3]
78
+ def self.data(body)
79
+ # assume hash {"resource":[...]}, get first key and return array data
80
+ result = body
81
+ if result.is_a?(Hash)
82
+ _k, v = body.first
83
+ result = v if v.is_a?(Array) || v.is_a?(Hash)
84
+ end
85
+ result
86
+ end
87
+
88
+ # Extracts pagination information
89
+ #
90
+ # @param body [Hash] The response body containing resource data, and pagination infromation in a hash format.
91
+ # @return Hash Returns the extracted data, which could be an array, hash, or other object.
92
+ #
93
+ # @example
94
+ # response_body = {
95
+ # "items" => [1, 2, 3],
96
+ # "pagination" => {"current_page" => 1, "current_page_count": 10, "limit": 10, "total_count":60, "next_page": 2,
97
+ # "next_page_url": "https://api.xx.io/v1/signals?page_token=NjEyNjgxMzE%3D&limit=10", "next_page_token": "NjEyNjgxMzE=" } }
98
+ # PaginationPager.pagination_data(response_body) # => {"current_page" => 1, "current_page_count": 10, ...
99
+ def self.pagination_data(body)
100
+ # assume hash {"resource":[...], "pagination":{}}, return pagination data
101
+ result = nil
102
+ if body.is_a?(Hash)
103
+ result = body["pagination"]
104
+ end
105
+ result
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Huntress
4
+ VERSION = '0.1.0'
5
+ end
data/lib/huntress.rb ADDED
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'wrapi'
4
+ require File.expand_path('huntress/version', __dir__)
5
+ require File.expand_path('huntress/client', __dir__)
6
+ require File.expand_path('huntress/pagination', __dir__)
7
+
8
+ # The Huntress module provides utilities to manage and manipulate assets within the Huntress api
9
+ module Huntress
10
+ extend WrAPI::Configuration
11
+ extend WrAPI::RespondTo
12
+
13
+ # Default User-Agent header sent with API requests, including gem version information.
14
+ DEFAULT_UA = "Huntress Ruby API wrapper #{Huntress::VERSION}"
15
+ # Default api endpoint
16
+ DEFAULT_ENDPOINT = 'https://api.huntress.io'
17
+ DEFAULT_PAGINATION = RequestPagination::PaginationPager
18
+ DEFAULT_PAGE_SIZE = 25
19
+
20
+ #
21
+ # @return [Huntress::Client]
22
+ def self.client(options = {})
23
+ Huntress::Client.new({
24
+ endpoint: DEFAULT_ENDPOINT,
25
+ user_agent: DEFAULT_UA,
26
+ page_size: DEFAULT_PAGE_SIZE,
27
+ pagination_class: DEFAULT_PAGINATION
28
+ }.merge(options))
29
+ end
30
+
31
+ # Resets the Skykick configuration to default values.
32
+ #
33
+ # This method resets the configuration values to their defaults:
34
+ # - `DEFAULT_UA` for the User-Agent
35
+ #
36
+ # @example Reset the Huntress configuration:
37
+ # Huntress.reset
38
+ def self.reset
39
+ super
40
+ self.endpoint = DEFAULT_ENDPOINT
41
+ self.user_agent = DEFAULT_UA
42
+ self.page_size = DEFAULT_PAGE_SIZE
43
+ self.pagination_class = DEFAULT_PAGINATION
44
+ end
45
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: huntress
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Janco Tanis
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-10-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: wrapi
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.5.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.5.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: dotenv
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
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: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description:
98
+ email: gems@jancology.com
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - ".env.template"
104
+ - ".gitignore"
105
+ - CHANGELOG.md
106
+ - Gemfile
107
+ - README.md
108
+ - Rakefile
109
+ - huntress.gemspec
110
+ - lib/huntress.rb
111
+ - lib/huntress/api.rb
112
+ - lib/huntress/authentication.rb
113
+ - lib/huntress/client.rb
114
+ - lib/huntress/connection.rb
115
+ - lib/huntress/error.rb
116
+ - lib/huntress/pagination.rb
117
+ - lib/huntress/version.rb
118
+ homepage: https://rubygems.org/gems/huntress
119
+ licenses:
120
+ - MIT
121
+ metadata:
122
+ homepage_uri: https://rubygems.org/gems/huntress
123
+ source_code_uri: https://github.com/jancotanis/huntress
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: 2.4.0
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubygems_version: 3.1.6
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: A Ruby wrapper for the Huntress APIs (readonly)
143
+ test_files: []