controls 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3d97c792ec22e7db59c7f591f023942e40b9cf6c
4
- data.tar.gz: 59d3fafbcb9633a88a43935c72e90c5d66ea8878
3
+ metadata.gz: f428c9a710108971da0e6995f4f0ca0032caeed4
4
+ data.tar.gz: e727ddbd5d77bc6afdfd84ef51a81bc57bc8dfc4
5
5
  SHA512:
6
- metadata.gz: eee56d732f6779946baa87cc77afeb38587d5abe8ac004cad782da8c5f9d6ee39ce711d932da15cfe1ab51bbb13ac5daa24fecf8edac6e7e6bc1e17c660c594b
7
- data.tar.gz: 6e6a7ae9442977487ba0d449a0fc5ecd500360b038c920f4477b1f5e2f15d818eb766dbbe4ab68edc057c947a3cf13884c80d9e9648562bcff69a0fd3fbab1e4
6
+ metadata.gz: 1455b974d58516093e986277014a653b157ab5f1a0da5d22742b7554a5671074f001ae458ab14cff15cf18ffdc7a5b7c1742c713aea4eb0a41b21bae8466d111
7
+ data.tar.gz: fd418654c0932982591cd8d717354796194dd376a7214397fb553f348b1d742f5cedd64cddc18237bd6e2eb3dbf280a4c890a05fb36d2901f1c9d18595efb99d
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # controlsinsight client gem
2
- The **controls**insight (controls) gem interfaces with [Rapid7's **controls**insight API](http://rapid7.viewdocs.io/controlsinsight.rb).
2
+ The **controls**insight (controls) gem interfaces with [Rapid7's **controls**insight API](http://rapid7.github.io/controlsinsight.rb).
3
3
 
4
4
  ## Installation
5
5
  Add this line to your application's Gemfile:
@@ -15,7 +15,7 @@ Or install it yourself as:
15
15
  $ gem install controls
16
16
 
17
17
  ## Documentation
18
- * [viewdocs.io API documentation](http://rapid7.viewdocs.io/controlsinsight.rb)
18
+ * [API documentation](http://rapid7.github.io/controlsinsight.rb)
19
19
  * [YARD documentation for the Ruby client](http://www.rubydoc.info/github/rapid7/controlsinsight.rb)
20
20
 
21
21
  ## Basic Resources
@@ -101,4 +101,4 @@ Controls.configuration_trends('configuration-name-here')
101
101
  ```
102
102
 
103
103
  ## License
104
- This project was created by [Erran Carey (@ipwnstuff)](http://ipwnstuff.github.io) and licensed under [the MIT License](LICENSE.md).
104
+ This project was created by [Erran Carey (@erran)](http://erran.github.io) and licensed under [the MIT License](LICENSE.md).
data/controls.gemspec CHANGED
@@ -18,9 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = %w[lib]
20
20
 
21
- spec.add_dependency 'activesupport'
21
+ spec.add_dependency 'dish'
22
22
  spec.add_dependency 'faraday', '< 0.9'
23
- spec.add_dependency 'nokogiri'
23
+ spec.add_dependency 'rack'
24
24
 
25
25
  spec.add_development_dependency 'bundler', '~> 1.3'
26
26
  spec.add_development_dependency 'netrc'
data/lib/controls.rb CHANGED
@@ -3,6 +3,8 @@ require 'controls/default'
3
3
 
4
4
  # A Ruby client for the **controls**insight API
5
5
  module Controls
6
+ Error = Class.new(StandardError)
7
+
6
8
  class << self
7
9
  include Controls::Configurable
8
10
 
@@ -1,6 +1,7 @@
1
- require 'faraday'
2
1
  require 'json'
2
+ require 'faraday'
3
3
  require 'nokogiri'
4
+ require 'rack/utils'
4
5
  require 'controls/authentication'
5
6
  require 'controls/configurable'
6
7
  require 'controls/client/assessments'
@@ -88,8 +89,16 @@ module Controls
88
89
  headers = connection_options[:headers].merge(headers)
89
90
  url = URI.escape(File.join(api_endpoint, path))
90
91
  resp = middleware.get(url, params, headers)
92
+ @_last_request = {
93
+ response: resp,
94
+ path: path
95
+ }
96
+
97
+ if !resp.headers['content-type'].eql?("application/json;charset=UTF-8")
98
+ fail exception('Invalid content-type error')
99
+ end
91
100
 
92
- Response.parse(resp.body)
101
+ Response.parse(resp.body, path)
93
102
  rescue Faraday::Error::ConnectionFailed => e
94
103
  if e.message =~ /^SSL_connect/
95
104
  warn(*SSL_WARNING)
@@ -105,8 +114,16 @@ module Controls
105
114
  headers = connection_options[:headers].merge(headers)
106
115
  url = URI.escape(File.join(api_endpoint, path))
107
116
  resp = middleware.put(url, body, headers, &block)
117
+ @_last_request = {
118
+ response: resp,
119
+ path: path
120
+ }
108
121
 
109
- Response.parse(resp.body)
122
+ if !resp.headers['content-type'].eql?("application/json;charset=UTF-8")
123
+ fail exception('Invalid content-type error')
124
+ end
125
+
126
+ Response.parse(resp.body, path)
110
127
  rescue Faraday::Error::ConnectionFailed => e
111
128
  if e.message =~ /^SSL_connect/
112
129
  warn(*SSL_WARNING)
@@ -134,11 +151,7 @@ module Controls
134
151
  # @param [String] version the API version to collect documentation from
135
152
  def references(version = '1.0')
136
153
  version = '1.0' unless version =~ /\d.\d/
137
-
138
- web_get "/api/#{version}"
139
-
140
- # [review] - Use Response#generate_ruby
141
- @references = Hash[Response.parse(resp.body).sort]
154
+ web_get "/api/#{version}"
142
155
  rescue Faraday::Error::ConnectionFailed => e
143
156
  if e.message =~ /^SSL_connect/
144
157
  warn(*SSL_WARNING)
@@ -176,8 +189,16 @@ module Controls
176
189
  headers = connection_options[:headers].merge(headers)
177
190
  url = URI.escape(File.join(web_endpoint, path))
178
191
  resp = middleware.get(url, params, headers)
192
+ @_last_request = {
193
+ response: resp,
194
+ path: path
195
+ }
179
196
 
180
- Response.parse(resp.body)
197
+ if !resp.headers['content-type'].eql?("application/json;charset=UTF-8")
198
+ fail exception('Invalid content-type error')
199
+ end
200
+
201
+ JSON.parse(resp.body)
181
202
  rescue Faraday::Error::ConnectionFailed => e
182
203
  if e.message =~ /^SSL_connect/
183
204
  warn(*SSL_WARNING)
@@ -185,5 +206,19 @@ module Controls
185
206
  raise e
186
207
  end
187
208
  end
209
+
210
+ def exception(message = "HTTP Error")
211
+ last_request = _last_request
212
+ if last_request
213
+ message << ": #{last_request[:response].status} #{Rack::Utils::HTTP_STATUS_CODES[last_request[:response].status]} #{last_request[:path]}"
214
+ else
215
+ message = 'Unknown error'
216
+ end
217
+
218
+ Controls::Error.new(message)
219
+ end
220
+
221
+ private
222
+ attr_reader :_last_request
188
223
  end
189
224
  end
@@ -65,7 +65,6 @@ module Controls
65
65
  @middleware ||= Faraday.new(api_endpoint, connection_options) do |conn|
66
66
  conn.adapter Faraday.default_adapter
67
67
  conn.response :logger if ENV['CONTROLS_DEBUG']
68
- conn.use Controls::Response::RaiseError
69
68
  end
70
69
  end
71
70
 
@@ -0,0 +1,46 @@
1
+ module Dish
2
+ class Plate
3
+ def method_missing(method, *args, &block)
4
+ method = method.to_s
5
+ camel_case_key = method.split('_').map(&:capitalize).join
6
+ camel_case_key[0] = camel_case_key[0].downcase
7
+
8
+ if method.end_with?('?')
9
+ key = camel_case_key[0..-2]
10
+ _check_for_presence(key)
11
+ else
12
+ value = _get_value(camel_case_key)
13
+ if value.nil?
14
+ super(method.to_sym, *args, &block)
15
+ else
16
+ value
17
+ end
18
+ end
19
+ end
20
+
21
+ def methods()
22
+ valid_keys = as_hash.keys.map do |key|
23
+ key.to_s.gsub(/([^A-Z])([A-Z]+)/, '\1_\2').downcase.to_sym
24
+ end
25
+
26
+ valid_keys + super
27
+ end
28
+
29
+ def inspect
30
+ hash = as_hash
31
+ keys_to_snake_case = hash.keys.map { |key|
32
+ [key, key.to_s.gsub(/([^A-Z])([A-Z]+)/, '\1_\2').downcase]
33
+ }.to_h
34
+
35
+ vars = hash.map do |key, value|
36
+ "#{keys_to_snake_case[key]}: #{_get_value(key)}"
37
+ end
38
+
39
+ "#<#{self.class}: #{vars.join(', ')}>"
40
+ end
41
+
42
+ def to_json(*args)
43
+ as_hash.to_json(*args)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,11 @@
1
+ require 'dish'
2
+ require 'controls/ext/dish/plate'
3
+ require 'controls/objects/assessment'
4
+ require 'controls/objects/asset'
5
+ require 'controls/objects/configuration'
6
+ require 'controls/objects/guidance'
7
+ require 'controls/objects/security_control'
8
+ require 'controls/objects/security_control_coverage'
9
+ require 'controls/objects/threat'
10
+ require 'controls/objects/threat_vector'
11
+ require 'controls/objects/trend'
@@ -0,0 +1,9 @@
1
+ module Controls
2
+ class Assessment < Dish::Plate
3
+ coerce :timestamp, ->(value) { Time.at(value / 1000) if value }
4
+
5
+ def to_s
6
+ id.to_s
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,36 @@
1
+ require 'controls/objects/security_control_finding'
2
+
3
+ module Controls
4
+ class Asset < Dish::Plate
5
+ coerce :discoveredAt, ->(value) { Time.at(value / 1000) if value }
6
+ coerce :securityControlFindings, Controls::SecurityControlFinding
7
+
8
+ def to_s
9
+ %(#{host_name} (#{ipaddress}) - #{operating_system})
10
+ end
11
+ end
12
+
13
+ class AssetCollection < Dish::Plate
14
+ coerce :resources, Asset
15
+
16
+ def map(*args, &block)
17
+ resources.map(*args, &block)
18
+ end
19
+
20
+ def first
21
+ resources.first
22
+ end
23
+
24
+ def last
25
+ resources.last
26
+ end
27
+
28
+ def [](index)
29
+ resources[index]
30
+ end
31
+
32
+ def to_s
33
+ resources.sort_by(&:ipaddress).map(&:to_s).join("\n")
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,9 @@
1
+ module Controls
2
+ class Configuration < Dish::Plate
3
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
4
+
5
+ def to_s
6
+ title
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Controls
2
+ class ConfigurationFinding < Dish::Plate
3
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
4
+
5
+ def to_s
6
+ "#{state}: #{reason.strip}"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ module Controls
2
+ Guidance = Class.new(Dish::Plate)
3
+ Guidance::Reference = Class.new(Dish::Plate)
4
+ Guidance::Section = Class.new(Dish::Plate)
5
+
6
+ class Guidance
7
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
8
+ coerce :references, Reference
9
+ coerce :sections, Section
10
+
11
+ def to_s
12
+ title
13
+ end
14
+ end
15
+
16
+ PrioritizedGuidance = Class.new(Guidance)
17
+ end
@@ -0,0 +1,7 @@
1
+ module Controls
2
+ class SecurityControl < Dish::Plate
3
+ def to_s
4
+ name
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ module Controls
2
+ class SecurityControlCoverage < Dish::Plate
3
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
4
+
5
+ def to_s
6
+ title
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ require 'controls/objects/configuration_finding'
2
+
3
+ module Controls
4
+ class SecurityControlFinding < Dish::Plate
5
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
6
+ coerce :configurationFindings, Controls::ConfigurationFinding
7
+
8
+ def to_s
9
+ "#{security_control_name}: #{configuration_findings.map { |finding| "\n #{finding}" }.join}"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ module Controls
2
+ class Threat < Dish::Plate
3
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
4
+
5
+ def to_s
6
+ title
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Controls
2
+ class ThreatVector < Dish::Plate
3
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
4
+
5
+ def to_s
6
+ title
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Controls
2
+ class Trend < Dish::Plate
3
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
4
+
5
+ def to_s
6
+ format('%05.2f', grade)
7
+ end
8
+ end
9
+ end
@@ -1,76 +1,32 @@
1
- require 'active_support/core_ext/string/inflections'
2
- require 'active_support/core_ext/hash/keys'
3
- require 'controls/response/raise_error'
1
+ require 'controls/objects'
4
2
 
5
3
  module Controls
6
- # A namespace for response related classes
4
+ # A module to encapsulate middleware customization
7
5
  module Response
8
- # @param [String] response the response body as a JSON String provided by
9
- # the ControlsInsight API
10
- # @return [Array,Hash] the response after being parsed into an Array or
11
- # Hash
12
- def self.parse(response)
13
- response = JSON.parse(response)
14
- end
6
+ def self.parse(obj, path = nil)
7
+ hash_or_array = JSON.parse(obj)
15
8
 
16
- # @param [Array,Hash] response the Array or Hash to convert into a ruby
17
- # style object
18
- def self.generate_ruby(response)
19
- if response.is_a? String
20
- response = JSON.parse(response)
9
+ if hash_or_array.is_a?(Hash) && hash_or_array.key?('message') && hash_or_array.key?('documentationUrl')
10
+ type = Controls::Error
21
11
  end
22
12
 
23
- # TODO: Determine the specific format, or create a new, recursive (w/
24
- # array support) deep method
25
- # NOTE: If the ControlsInsight API begins returning more complex JSON
26
- # this conditional must be updated.
27
- if response.is_a? Hash
28
- response.deep_transform_keys! { |key| key.underscore }
29
-
30
- if response.has_key? 'resources'
31
- response['resources'].each do |hash|
32
- hash.deep_transform_keys! { |key| key.underscore }
33
-
34
- if hash.has_key? 'security_control_findings'
35
- hash['security_control_findings'].each do |subhash|
36
- subhash.deep_transform_keys! { |key| key.underscore }
37
-
38
- if subhash.has_key? 'configuration_findings'
39
- subhash['configuration_findings'].each do |subhash_two|
40
- subhash_two.deep_transform_keys! { |key| key.underscore }
41
- end
42
- end
43
- end
44
- end
45
- end
13
+ type ||=
14
+ case path
15
+ when %r(^(?:/\d.\d)?/coverage/security_controls)
16
+ Controls::SecurityControlCoverage
17
+ when /(configuration|event|guidance|prioritized_guidance|security_control|threat_vector|trend)s?$/
18
+ Controls.const_get(Regexp.last_match[1].split('_').map(&:capitalize).join)
19
+ when %r(^(?:/\d.\d)?\/(assessment|configuration|threat|threat_vector)s)
20
+ Controls.const_get(Regexp.last_match[1].split('_').map(&:capitalize).join)
21
+ when /((?:applicable|miconfigured|uncovered|undefended)?_?asset)s$/
22
+ Controls.const_get('AssetCollection')
23
+ when %r(^/((?:applicable|miconfigured|uncovered|undefended)?_?asset)s/)
24
+ Controls.const_get('Asset')
25
+ else
26
+ Dish::Plate
46
27
  end
47
- elsif response.is_a? Array
48
- response.each do |element|
49
- if element.is_a? Hash
50
- element.deep_transform_keys! { |key| key.underscore }
51
-
52
- if element.has_key? 'resources'
53
- element['resources'].each do |hash|
54
- hash.deep_transform_keys! { |key| key.underscore }
55
-
56
- if hash.has_key? 'security_control_findings'
57
- hash['security_control_findings'].each do |subhash|
58
- subhash.deep_transform_keys! { |key| key.underscore }
59
-
60
- if subhash.has_key? 'configuration_findings'
61
- subhash['configuration_findings'].each do |subhash_two|
62
- subhash_two.deep_transform_keys! { |key| key.underscore }
63
- end
64
- end
65
- end
66
- end
67
- end
68
- end
69
- end
70
- end
71
- end
72
28
 
73
- response
29
+ Dish(hash_or_array, type)
74
30
  end
75
31
  end
76
32
  end
@@ -1,4 +1,4 @@
1
1
  module Controls
2
2
  # The version of the Controls gem
3
- VERSION = '1.2.0'
3
+ VERSION = '1.3.0'
4
4
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: controls
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Erran Carey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-04 00:00:00.000000000 Z
11
+ date: 2014-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: activesupport
14
+ name: dish
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.9'
41
41
  - !ruby/object:Gem::Dependency
42
- name: nokogiri
42
+ name: rack
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -175,9 +175,20 @@ files:
175
175
  - lib/controls/client/trends.rb
176
176
  - lib/controls/configurable.rb
177
177
  - lib/controls/default.rb
178
- - lib/controls/error.rb
178
+ - lib/controls/ext/dish/plate.rb
179
+ - lib/controls/objects.rb
180
+ - lib/controls/objects/assessment.rb
181
+ - lib/controls/objects/asset.rb
182
+ - lib/controls/objects/configuration.rb
183
+ - lib/controls/objects/configuration_finding.rb
184
+ - lib/controls/objects/guidance.rb
185
+ - lib/controls/objects/security_control.rb
186
+ - lib/controls/objects/security_control_coverage.rb
187
+ - lib/controls/objects/security_control_finding.rb
188
+ - lib/controls/objects/threat.rb
189
+ - lib/controls/objects/threat_vector.rb
190
+ - lib/controls/objects/trend.rb
179
191
  - lib/controls/response.rb
180
- - lib/controls/response/raise_error.rb
181
192
  - lib/controls/version.rb
182
193
  - spec/controls_spec.rb
183
194
  - spec/helper.rb
@@ -1,132 +0,0 @@
1
- module Controls
2
- # A namespace for errors in the Controls module
3
- class Error < StandardError
4
- # @!attribute [r] error_message
5
- # @return [String] the error message
6
- # @!attribute [r] error_status
7
- # @return [Fixnum] the error message
8
- # @!attribute [r] error_json
9
- # @return [Hash] the JSON body from the error message
10
- attr_reader :error_json
11
- attr_reader :error_message
12
- attr_reader :error_status
13
-
14
- # @raise [BadRequest,Unauthorized,NotFound,InternalServerError] a subclass
15
- # of {Controls::Error}
16
- # @return [nil] if no error was raised
17
- def self.from_response(response)
18
- error = case response[:status].to_i
19
- when 302
20
- # TODO: Nexpose/ControlsInsight returns 302 when you either visit a
21
- # none existant path (Nexpose) or unauthenticated
22
- # (ControlsInsight).
23
- Found # if response[:body].empty?
24
- when 400 then BadRequest
25
- when 401 then Unauthorized
26
- when 404 then NotFound
27
- when 500 then InternalServerError
28
- end
29
-
30
- error.new(response) if error
31
- end
32
-
33
- # @return [self] generates an error and passes it to super
34
- def initialize(response = nil)
35
- @response = response
36
- super(generate_error)
37
- end
38
-
39
- private
40
-
41
- # @return [String] an error message to be used by {#generate_error}
42
- def response_message
43
- return @response_message if @response_message
44
-
45
- resp = @response[:response]
46
-
47
- if resp.headers['content-type']
48
- resp.headers['content-type'][/(\S+);charset=utf-8/i]
49
- html = Regexp.last_match && Regexp.last_match[1].eql?('text/html')
50
- end
51
-
52
- @response_message = if html
53
- doc = Nokogiri::XML.parse(resp.body)
54
-
55
- if doc.css('title').text.eql? 'ControlsInsight'
56
- message = ['message'].zip(doc.css('h1').map(&:text))
57
- reason = ['reason'].zip([doc.css('p').map(&:text)])
58
- Hash[message + reason]
59
- else
60
- Hash[doc.css('HR').children.map { |elem| elem.text.split(' ', 2) }]
61
- end
62
- else
63
- if resp.body.empty?
64
- @error_json = {}
65
- else
66
- @error_json = JSON.parse(resp.body)
67
- @error_message = @error_json['message']
68
- @error_status = @error_json['status'].to_i
69
-
70
- @error_json
71
- end
72
- end
73
- end
74
-
75
- # @return [String] the error message passed to super on {#initialize}
76
- def generate_error
77
- return unless @response
78
-
79
- message = "#{@response[:method]} ".upcase
80
- message << "#{@response[:url].path}"
81
-
82
- if response_message.is_a? Hash
83
- message << ": #{response_message['message']}\n" if response_message['message']
84
-
85
- if response_message['reason'].respond_to?(:join)
86
- message << response_message['reason'].join("\n")
87
- elsif response_message['reason']
88
- message << response_message['reason'].to_s
89
- end
90
- elsif response_message.is_a? String
91
- message << response_message
92
- else
93
- message << "#{@response[:status]} -"
94
- message << self.class.to_s.split('::', 2).last
95
- end
96
-
97
- message.strip
98
- end
99
- end
100
-
101
- # @!group Generic errors
102
-
103
- # TODO REVIEW: To be raised when a user hasn't explicitly supplied credentials or set up
104
- # any environment defaults.
105
- Unauthenticated = Class.new(StandardError)
106
-
107
- # @!endgroup
108
-
109
- # @!group HTTP errors
110
-
111
- # @return [Found] an error to be raised when a status code of 401 is
112
- # returned by the API
113
- Found = Class.new(Error)
114
-
115
- # @return [Unauthorized] an error to be raised when a status code of 401 is
116
- # returned by the API
117
- Unauthorized = Class.new(Error)
118
-
119
- # @return [BadRequest] an error to be raised when a status code of 400 is
120
- # returned by the API
121
- BadRequest = Class.new(Error)
122
-
123
- # @return [NotFound] an error to be raised when a status code of 404 is
124
- # returned by the API
125
- NotFound = Class.new(Error)
126
-
127
- # @return [InternalServerError] an error to be raised when a status code of
128
- # 500 is returned by the API
129
- InternalServerError = Class.new(Error)
130
-
131
- # @!endgroup
132
- end
@@ -1,21 +0,0 @@
1
- require 'controls/error'
2
-
3
- module Controls
4
- module Response
5
- # A middleware plugin that hooks into the Faraday client used by this gem
6
- class RaiseError < Faraday::Response::Middleware
7
- private
8
-
9
- # Implements the {#on_complete} hook used by Faraday's middleware
10
- #
11
- # @raise [Controls::Error] a subclass of Controls::Error if any errors
12
- # were encountered
13
- # @return [nil] if no error was found
14
- def on_complete(response)
15
- if error = Controls::Error.from_response(response)
16
- raise error
17
- end
18
- end
19
- end
20
- end
21
- end