inspec-core 2.2.78 → 2.2.101
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 +4 -4
- data/CHANGELOG.md +44 -14
- data/docs/profiles.md +106 -8
- data/examples/inheritance/inspec.yml +2 -1
- data/examples/profile/controls/gordon.rb +1 -1
- data/examples/profile/controls/meta.rb +2 -0
- data/examples/profile/inspec.yml +2 -1
- data/inspec-core.gemspec +2 -1
- data/lib/bundles/inspec-compliance/cli.rb +13 -1
- data/lib/bundles/inspec-compliance/http.rb +9 -18
- data/lib/bundles/inspec-compliance/target.rb +3 -3
- data/lib/fetchers/local.rb +60 -17
- data/lib/inspec.rb +4 -0
- data/lib/inspec/attribute_registry.rb +83 -0
- data/lib/inspec/base_cli.rb +10 -1
- data/lib/inspec/cli.rb +12 -1
- data/lib/inspec/control_eval_context.rb +13 -4
- data/lib/inspec/dependencies/cache.rb +1 -1
- data/lib/inspec/dependencies/dependency_set.rb +1 -1
- data/lib/inspec/dependencies/requirement.rb +2 -1
- data/lib/inspec/errors.rb +27 -0
- data/lib/inspec/file_provider.rb +38 -1
- data/lib/inspec/globals.rb +5 -0
- data/lib/inspec/impact.rb +34 -0
- data/lib/inspec/objects/attribute.rb +92 -7
- data/lib/inspec/profile.rb +33 -4
- data/lib/inspec/profile_context.rb +7 -7
- data/lib/inspec/profile_vendor.rb +21 -1
- data/lib/inspec/reporters/automate.rb +7 -2
- data/lib/inspec/reporters/cli.rb +12 -4
- data/lib/inspec/reporters/json.rb +3 -1
- data/lib/inspec/rspec_extensions.rb +12 -0
- data/lib/inspec/rule.rb +6 -1
- data/lib/inspec/runner.rb +2 -2
- data/lib/inspec/schema.rb +16 -2
- data/lib/inspec/version.rb +1 -1
- data/lib/resources/mysql_session.rb +1 -0
- metadata +22 -4
data/lib/inspec.rb
CHANGED
@@ -15,6 +15,10 @@ require 'inspec/runner'
|
|
15
15
|
require 'inspec/shell'
|
16
16
|
require 'inspec/formatters'
|
17
17
|
require 'inspec/reporters'
|
18
|
+
require 'inspec/attribute_registry'
|
19
|
+
require 'inspec/rspec_extensions'
|
20
|
+
require 'inspec/globals'
|
21
|
+
require 'inspec/impact'
|
18
22
|
|
19
23
|
require 'inspec/plugin/v2'
|
20
24
|
require 'inspec/plugin/v1'
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'singleton'
|
3
|
+
require 'inspec/objects/attribute'
|
4
|
+
|
5
|
+
module Inspec
|
6
|
+
class AttributeRegistry
|
7
|
+
include Singleton
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
attr_reader :list
|
11
|
+
def_delegator :list, :each
|
12
|
+
def_delegator :list, :[]
|
13
|
+
def_delegator :list, :key?, :profile_exist?
|
14
|
+
def_delegator :list, :select
|
15
|
+
|
16
|
+
# These self methods are convenience methods so you dont always
|
17
|
+
# have to specify instance when calling the registry
|
18
|
+
def self.find_attribute(name, profile)
|
19
|
+
instance.find_attribute(name, profile)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.register_attribute(name, profile, options = {})
|
23
|
+
instance.register_attribute(name, profile, options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.register_profile_alias(name, alias_name)
|
27
|
+
instance.register_profile_alias(name, alias_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.list_attributes_for_profile(profile)
|
31
|
+
instance.list_attributes_for_profile(profile)
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize
|
35
|
+
# this is a collection of profiles which have a value of attribute objects
|
36
|
+
@list = {}
|
37
|
+
|
38
|
+
# this is a list of optional profile name overrides set in the inspec.yml
|
39
|
+
@profile_aliases = {}
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_attribute(name, profile)
|
43
|
+
profile = @profile_aliases[profile] if !profile_exist?(profile) && @profile_aliases[profile]
|
44
|
+
unless profile_exist?(profile)
|
45
|
+
error = Inspec::AttributeRegistry::ProfileError.new
|
46
|
+
error.profile_name = profile
|
47
|
+
raise error, "Profile '#{error.profile_name}' does not have any attributes"
|
48
|
+
end
|
49
|
+
|
50
|
+
unless list[profile].key?(name)
|
51
|
+
error = Inspec::AttributeRegistry::AttributeError.new
|
52
|
+
error.attribute_name = name
|
53
|
+
error.profile_name = profile
|
54
|
+
raise error, "Profile '#{error.profile_name}' does not have a attribute with name '#{error.attribute_name}'"
|
55
|
+
end
|
56
|
+
list[profile][name]
|
57
|
+
end
|
58
|
+
|
59
|
+
def register_attribute(name, profile, options = {})
|
60
|
+
# check for a profile override name
|
61
|
+
if profile_exist?(profile) && list[profile][name] && options.empty?
|
62
|
+
list[profile][name]
|
63
|
+
else
|
64
|
+
list[profile] = {} unless profile_exist?(profile)
|
65
|
+
list[profile][name] = Inspec::Attribute.new(name, options)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def register_profile_alias(name, alias_name)
|
70
|
+
@profile_aliases[name] = alias_name
|
71
|
+
end
|
72
|
+
|
73
|
+
def list_attributes_for_profile(profile)
|
74
|
+
list[profile] = {} unless profile_exist?(profile)
|
75
|
+
list[profile]
|
76
|
+
end
|
77
|
+
|
78
|
+
def __reset
|
79
|
+
@list = {}
|
80
|
+
@profile_aliases = {}
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/inspec/base_cli.rb
CHANGED
@@ -8,6 +8,10 @@ require 'inspec/profile_vendor'
|
|
8
8
|
|
9
9
|
module Inspec
|
10
10
|
class BaseCLI < Thor
|
11
|
+
class << self
|
12
|
+
attr_accessor :inspec_cli_command
|
13
|
+
end
|
14
|
+
|
11
15
|
# https://github.com/erikhuda/thor/issues/244
|
12
16
|
def self.exit_on_failure?
|
13
17
|
true
|
@@ -62,6 +66,8 @@ module Inspec
|
|
62
66
|
desc: 'Specifies the bastion port if applicable'
|
63
67
|
option :insecure, type: :boolean, default: false,
|
64
68
|
desc: 'Disable SSL verification on select targets'
|
69
|
+
option :target_id, type: :string,
|
70
|
+
desc: 'Provide a ID which will be included on reports'
|
65
71
|
end
|
66
72
|
|
67
73
|
def self.profile_options
|
@@ -134,7 +140,7 @@ module Inspec
|
|
134
140
|
if opts['reporter'].is_a?(Array)
|
135
141
|
reports = {}
|
136
142
|
opts['reporter'].each do |report|
|
137
|
-
reporter_name, target = report.split(':')
|
143
|
+
reporter_name, target = report.split(':', 2)
|
138
144
|
if target.nil? || target.strip == '-'
|
139
145
|
reports[reporter_name] = { 'stdout' => true }
|
140
146
|
else
|
@@ -142,6 +148,7 @@ module Inspec
|
|
142
148
|
'file' => target,
|
143
149
|
'stdout' => false,
|
144
150
|
}
|
151
|
+
reports[reporter_name]['target_id'] = opts['target_id'] if opts['target_id']
|
145
152
|
end
|
146
153
|
end
|
147
154
|
opts['reporter'] = reports
|
@@ -152,6 +159,7 @@ module Inspec
|
|
152
159
|
opts['reporter'].each do |reporter_name, config|
|
153
160
|
opts['reporter'][reporter_name] = {} if config.nil?
|
154
161
|
opts['reporter'][reporter_name]['stdout'] = true if opts['reporter'][reporter_name].empty?
|
162
|
+
opts['reporter'][reporter_name]['target_id'] = opts['target_id'] if opts['target_id']
|
155
163
|
end
|
156
164
|
end
|
157
165
|
|
@@ -295,6 +303,7 @@ module Inspec
|
|
295
303
|
# start with default options if we have any
|
296
304
|
opts = BaseCLI.default_options[type] unless type.nil? || BaseCLI.default_options[type].nil?
|
297
305
|
opts['type'] = type unless type.nil?
|
306
|
+
Inspec::BaseCLI.inspec_cli_command = type
|
298
307
|
|
299
308
|
# merge in any options from json-config
|
300
309
|
json_config = options_json
|
data/lib/inspec/cli.rb
CHANGED
@@ -35,6 +35,9 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
35
35
|
def json(target)
|
36
36
|
o = opts.dup
|
37
37
|
diagnose(o)
|
38
|
+
o['log_location'] = STDERR
|
39
|
+
configure_logger(o)
|
40
|
+
|
38
41
|
o[:backend] = Inspec::Backend.create(target: 'mock://')
|
39
42
|
o[:check_mode] = true
|
40
43
|
o[:vendor_cache] = Inspec::Cache.new(o[:vendor_cache])
|
@@ -119,6 +122,10 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
119
122
|
desc: 'Overwrite existing vendored dependencies and lockfile.'
|
120
123
|
def vendor(path = nil)
|
121
124
|
o = opts.dup
|
125
|
+
configure_logger(o)
|
126
|
+
o[:logger] = Logger.new(STDOUT)
|
127
|
+
o[:logger].level = get_log_level(o.log_level)
|
128
|
+
|
122
129
|
vendor_deps(path, o)
|
123
130
|
end
|
124
131
|
|
@@ -141,7 +148,11 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
141
148
|
o[:logger] = Logger.new(STDOUT)
|
142
149
|
o[:logger].level = get_log_level(o.log_level)
|
143
150
|
o[:backend] = Inspec::Backend.create(target: 'mock://')
|
144
|
-
|
151
|
+
|
152
|
+
# Force vendoring with overwrite when archiving
|
153
|
+
vendor_options = o.dup
|
154
|
+
vendor_options[:overwrite] = true
|
155
|
+
vendor_deps(path, vendor_options)
|
145
156
|
|
146
157
|
profile = Inspec::Profile.for_target(path, o)
|
147
158
|
result = profile.check
|
@@ -19,11 +19,16 @@ module Inspec
|
|
19
19
|
#
|
20
20
|
# @param [ResourcesDSL] resources_dsl which has all resources to attach
|
21
21
|
# @return [RuleContext] the inner context of rules
|
22
|
-
def self.rule_context(resources_dsl)
|
22
|
+
def self.rule_context(resources_dsl, profile_id)
|
23
23
|
require 'rspec/core/dsl'
|
24
24
|
Class.new(Inspec::Rule) do
|
25
25
|
include RSpec::Core::DSL
|
26
26
|
with_resource_dsl resources_dsl
|
27
|
+
|
28
|
+
# allow attributes to be accessed within control blocks
|
29
|
+
define_method :attribute do |name|
|
30
|
+
Inspec::AttributeRegistry.find_attribute(name, profile_id).value
|
31
|
+
end
|
27
32
|
end
|
28
33
|
end
|
29
34
|
|
@@ -36,9 +41,9 @@ module Inspec
|
|
36
41
|
# @param outer_dsl [OuterDSLClass]
|
37
42
|
# @return [ProfileContextClass]
|
38
43
|
def self.create(profile_context, resources_dsl) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
39
|
-
rule_class = rule_context(resources_dsl)
|
40
44
|
profile_context_owner = profile_context
|
41
45
|
profile_id = profile_context.profile_id
|
46
|
+
rule_class = rule_context(resources_dsl, profile_id)
|
42
47
|
|
43
48
|
Class.new do # rubocop:disable Metrics/BlockLength
|
44
49
|
include Inspec::DSL
|
@@ -137,8 +142,12 @@ module Inspec
|
|
137
142
|
end
|
138
143
|
|
139
144
|
# method for attributes; import attribute handling
|
140
|
-
define_method :attribute do |name, options|
|
141
|
-
|
145
|
+
define_method :attribute do |name, options = {}|
|
146
|
+
if options.empty?
|
147
|
+
Inspec::AttributeRegistry.find_attribute(name, profile_id).value
|
148
|
+
else
|
149
|
+
profile_context_owner.register_attribute(name, options)
|
150
|
+
end
|
142
151
|
end
|
143
152
|
|
144
153
|
define_method :skip_control do |id|
|
@@ -18,7 +18,7 @@ module Inspec
|
|
18
18
|
class Cache
|
19
19
|
attr_reader :path
|
20
20
|
def initialize(path = nil)
|
21
|
-
@path = path || File.join(
|
21
|
+
@path = path || File.join(Inspec.config_dir, 'cache')
|
22
22
|
FileUtils.mkdir_p(@path) unless File.directory?(@path)
|
23
23
|
end
|
24
24
|
|
@@ -121,8 +121,9 @@ module Inspec
|
|
121
121
|
if !@dependencies.nil? && !@dependencies.empty?
|
122
122
|
opts[:dependencies] = Inspec::DependencySet.from_array(@dependencies, @cwd, @cache, @backend)
|
123
123
|
end
|
124
|
+
opts[:profile_name] = @name
|
125
|
+
opts[:parent_profile] = @parent_profile
|
124
126
|
@profile = Inspec::Profile.for_fetcher(fetcher, opts)
|
125
|
-
@profile.parent_profile = @parent_profile
|
126
127
|
@profile
|
127
128
|
end
|
128
129
|
end
|
data/lib/inspec/errors.rb
CHANGED
@@ -11,4 +11,31 @@ module Inspec
|
|
11
11
|
class DuplicateDep < Error; end
|
12
12
|
class FetcherFailure < Error; end
|
13
13
|
class ReporterError < Error; end
|
14
|
+
class ImpactError < Error; end
|
15
|
+
|
16
|
+
class Attribute
|
17
|
+
class Error < Inspec::Error; end
|
18
|
+
class ValidationError < Error
|
19
|
+
attr_accessor :attribute_name
|
20
|
+
attr_accessor :attribute_value
|
21
|
+
attr_accessor :attribute_type
|
22
|
+
end
|
23
|
+
class TypeError < Error
|
24
|
+
attr_accessor :attribute_type
|
25
|
+
end
|
26
|
+
class RequiredError < Error
|
27
|
+
attr_accessor :attribute_name
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class AttributeRegistry
|
32
|
+
class Error < Inspec::Error; end
|
33
|
+
class ProfileError < Error
|
34
|
+
attr_accessor :profile_name
|
35
|
+
end
|
36
|
+
class AttributeError < Error
|
37
|
+
attr_accessor :profile_name
|
38
|
+
attr_accessor :attribute_name
|
39
|
+
end
|
40
|
+
end
|
14
41
|
end
|
data/lib/inspec/file_provider.rb
CHANGED
@@ -105,6 +105,22 @@ module Inspec
|
|
105
105
|
end
|
106
106
|
end
|
107
107
|
|
108
|
+
def extract(destination_path = '.')
|
109
|
+
FileUtils.mkdir_p(destination_path)
|
110
|
+
|
111
|
+
Zip::File.open(@path) do |archive|
|
112
|
+
archive.each do |file|
|
113
|
+
final_path = File.join(destination_path, file.name)
|
114
|
+
|
115
|
+
# This removes the top level directory (and any other files) to ensure
|
116
|
+
# extracted files do not conflict.
|
117
|
+
FileUtils.remove_entry(final_path) if File.exist?(final_path)
|
118
|
+
|
119
|
+
archive.extract(file, final_path)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
108
124
|
def read(file)
|
109
125
|
@contents[file] ||= read_from_zip(file)
|
110
126
|
end
|
@@ -150,6 +166,24 @@ module Inspec
|
|
150
166
|
end
|
151
167
|
end
|
152
168
|
|
169
|
+
def extract(destination_path = '.')
|
170
|
+
FileUtils.mkdir_p(destination_path)
|
171
|
+
|
172
|
+
walk_tar(@path) do |files|
|
173
|
+
files.each do |file|
|
174
|
+
next unless @files.include?(file.full_name)
|
175
|
+
final_path = File.join(destination_path, file.full_name)
|
176
|
+
|
177
|
+
# This removes the top level directory (and any other files) to ensure
|
178
|
+
# extracted files do not conflict.
|
179
|
+
FileUtils.remove_entry(final_path) if File.exist?(final_path)
|
180
|
+
|
181
|
+
FileUtils.mkdir_p(File.dirname(final_path))
|
182
|
+
File.open(final_path, 'wb') { |f| f.write(file.read) }
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
153
187
|
def read(file)
|
154
188
|
@contents[file] ||= read_from_tar(file)
|
155
189
|
end
|
@@ -157,7 +191,10 @@ module Inspec
|
|
157
191
|
private
|
158
192
|
|
159
193
|
def walk_tar(path, &callback)
|
160
|
-
|
194
|
+
tar_file = Zlib::GzipReader.open(path)
|
195
|
+
Gem::Package::TarReader.new(tar_file, &callback)
|
196
|
+
ensure
|
197
|
+
tar_file.close
|
161
198
|
end
|
162
199
|
|
163
200
|
def read_from_tar(file)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Impact scores based off CVSS 3.0
|
4
|
+
module Inspec::Impact
|
5
|
+
IMPACT_SCORES = {
|
6
|
+
'none' => 0.0,
|
7
|
+
'low' => 0.01,
|
8
|
+
'medium' => 0.4,
|
9
|
+
'high' => 0.7,
|
10
|
+
'critical' => 0.9,
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
def self.impact_from_string(value)
|
14
|
+
# return if its a number
|
15
|
+
return value if is_number?(value)
|
16
|
+
raise Inspec::ImpactError, "'#{value}' is not a valid impact name. Valid impact names: none, low, medium, high, critical." unless IMPACT_SCORES.key?(value.downcase)
|
17
|
+
IMPACT_SCORES[value]
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.is_number?(value)
|
21
|
+
Float(value)
|
22
|
+
true
|
23
|
+
rescue
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.string_from_impact(value)
|
28
|
+
value = value.to_f
|
29
|
+
raise Inspec::ImpactError, "'#{value}' is not a valid impact score. Valid impact scores: [0.0 - 1.0]." if value < 0 || value > 1
|
30
|
+
IMPACT_SCORES.reverse_each do |name, impact|
|
31
|
+
return name if value >= impact
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -3,7 +3,16 @@
|
|
3
3
|
module Inspec
|
4
4
|
class Attribute
|
5
5
|
attr_accessor :name
|
6
|
-
|
6
|
+
|
7
|
+
VALID_TYPES = %w{
|
8
|
+
String
|
9
|
+
Numeric
|
10
|
+
Regexp
|
11
|
+
Array
|
12
|
+
Hash
|
13
|
+
Boolean
|
14
|
+
Any
|
15
|
+
}.freeze
|
7
16
|
|
8
17
|
DEFAULT_ATTRIBUTE = Class.new do
|
9
18
|
def initialize(name)
|
@@ -16,7 +25,6 @@ module Inspec
|
|
16
25
|
"Use --attrs to provide a value for '#{@name}' or specify a default "\
|
17
26
|
"value with `attribute('#{@name}', default: 'somedefault', ...)`.",
|
18
27
|
)
|
19
|
-
|
20
28
|
self
|
21
29
|
end
|
22
30
|
|
@@ -28,16 +36,22 @@ module Inspec
|
|
28
36
|
def initialize(name, options = {})
|
29
37
|
@name = name
|
30
38
|
@opts = options
|
39
|
+
validate_value_type(default) if @opts.key?(:type) && @opts.key?(:default)
|
31
40
|
@value = nil
|
32
41
|
end
|
33
42
|
|
34
|
-
|
35
|
-
|
36
|
-
@value
|
43
|
+
def value=(new_value)
|
44
|
+
validate_value_type(new_value) if @opts.key?(:type)
|
45
|
+
@value = new_value
|
37
46
|
end
|
38
47
|
|
39
|
-
def
|
40
|
-
@
|
48
|
+
def value
|
49
|
+
if @value.nil?
|
50
|
+
validate_required(@value) if @opts[:required] == true
|
51
|
+
@value = default
|
52
|
+
else
|
53
|
+
@value
|
54
|
+
end
|
41
55
|
end
|
42
56
|
|
43
57
|
def title
|
@@ -71,5 +85,76 @@ module Inspec
|
|
71
85
|
def to_s
|
72
86
|
"Attribute #{@name} with #{@value}"
|
73
87
|
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def validate_required(value)
|
92
|
+
# value will be set already if a secrets file was passed in
|
93
|
+
if (!@opts.key?(:default) && value.nil?) || (@opts[:default].nil? && value.nil?)
|
94
|
+
error = Inspec::Attribute::RequiredError.new
|
95
|
+
error.attribute_name = @name
|
96
|
+
raise error, "Attribute '#{error.attribute_name}' is required and does not have a value."
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def validate_type(type)
|
101
|
+
type = type.capitalize
|
102
|
+
abbreviations = {
|
103
|
+
'Num' => 'Numeric',
|
104
|
+
'Regex' => 'Regexp',
|
105
|
+
}
|
106
|
+
type = abbreviations[type] if abbreviations.key?(type)
|
107
|
+
if !VALID_TYPES.include?(type)
|
108
|
+
error = Inspec::Attribute::TypeError.new
|
109
|
+
error.attribute_type = type
|
110
|
+
raise error, "Type '#{error.attribute_type}' is not a valid attribute type."
|
111
|
+
end
|
112
|
+
type
|
113
|
+
end
|
114
|
+
|
115
|
+
def valid_numeric?(value)
|
116
|
+
Float(value)
|
117
|
+
true
|
118
|
+
rescue
|
119
|
+
false
|
120
|
+
end
|
121
|
+
|
122
|
+
def valid_regexp?(value)
|
123
|
+
# check for invalid regex syntex
|
124
|
+
Regexp.new(value)
|
125
|
+
true
|
126
|
+
rescue
|
127
|
+
false
|
128
|
+
end
|
129
|
+
|
130
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
131
|
+
def validate_value_type(value)
|
132
|
+
type = validate_type(@opts[:type])
|
133
|
+
return if type == 'Any'
|
134
|
+
|
135
|
+
invalid_type = false
|
136
|
+
if type == 'Regexp'
|
137
|
+
invalid_type = true if !value.is_a?(String) || !valid_regexp?(value)
|
138
|
+
elsif type == 'Numeric'
|
139
|
+
invalid_type = true if !valid_numeric?(value)
|
140
|
+
elsif type == 'Boolean'
|
141
|
+
invalid_type = true if ![true, false].include?(value)
|
142
|
+
elsif value.is_a?(Module.const_get(type)) == false
|
143
|
+
invalid_type = true
|
144
|
+
end
|
145
|
+
|
146
|
+
if invalid_type == true
|
147
|
+
error = Inspec::Attribute::ValidationError.new
|
148
|
+
error.attribute_name = @name
|
149
|
+
error.attribute_value = value
|
150
|
+
error.attribute_type = type
|
151
|
+
raise error, "Attribute '#{error.attribute_name}' with value '#{error.attribute_value}' does not validate to type '#{error.attribute_type}'."
|
152
|
+
end
|
153
|
+
end
|
154
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
155
|
+
|
156
|
+
def default
|
157
|
+
@opts.key?(:default) ? @opts[:default] : DEFAULT_ATTRIBUTE.new(@name)
|
158
|
+
end
|
74
159
|
end
|
75
160
|
end
|