inspec 4.1.4.preview → 4.2.0.preview

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: 7dd53f745c6f68b24d0b987f09258c973a6d4579
4
- data.tar.gz: f9b791e75517949b5007d0d6904c7d70752103b6
3
+ metadata.gz: 8114c17ed673de114cd1b869cffc981834e57abb
4
+ data.tar.gz: 5f4bdb0617548cee5b60ca0adf3a0f2c2d508285
5
5
  SHA512:
6
- metadata.gz: bcfdc38552520f03dcb738e3273d8cbee50ea35bb33d6f5f0e4bde0fae9b2b3b1dd36369b88a754fea078ddf23073400a81a914bb54468b0d573f5f471bec1e5
7
- data.tar.gz: 1ee7fdfc45f33bcbf182da86da273e2634825da4b6a218750ddbf77dfc150eb5f70484df22e524dead114dc8d4656784e00f402cdb49ebb8b2ce0c646bea6d58
6
+ metadata.gz: 9db1040f08a657def6c3a719eb8ce6c8eb0106024cda21395dc452f21eebfd8892b5e6779c501061cc12e3e19ade491bc3d272717fbb01cb8797b62fe4afc19b
7
+ data.tar.gz: 9b8863d0b896f9bc51c6b095ea373abd674ebb7e5464f16a7d0d2d0f2a055cc85ef97de8c53872a1110bcbdb43dad84e446adf1560b34b5fbe40789f78007acd
data/Gemfile CHANGED
@@ -8,6 +8,8 @@ gem 'ffi', '>= 1.9.14'
8
8
  group :omnibus do
9
9
  gem 'rb-readline'
10
10
  gem 'appbundler'
11
+ gem 'ed25519' # ed25519 ssh key support done here as its a native gem we can't put in the gemspec
12
+ gem 'bcrypt_pbkdf' # ed25519 ssh key support done here as its a native gem we can't put in the gemspec
11
13
  end
12
14
 
13
15
  group :test do
@@ -3,12 +3,12 @@
3
3
  "unknown_group_action": "ignore",
4
4
  "groups": {
5
5
  "attrs_value_replaces_default": {
6
- "action": "ignore",
6
+ "action": "warn",
7
7
  "prefix": "The 'default' option for attributes is being replaced by 'value' - please use it instead."
8
8
  },
9
9
  "aws_resources_in_resource_pack": {
10
10
  "comment": "See #3822",
11
- "action": "ignore",
11
+ "action": "warn",
12
12
  "prefix": "AWS resources shipped with core InSpec are being to moved to a resource pack for faster iteration. Please update your profiles to depend on git@github.com:inspec/inspec-aws.git ."
13
13
  },
14
14
  "cli_option_json_config": {
@@ -17,11 +17,11 @@
17
17
  "comment": "See #3661"
18
18
  },
19
19
  "file_resource_be_mounted_matchers": {
20
- "action": "warn",
20
+ "action": "fail_control",
21
21
  "suffix": "This will not be supported in InSpec 4.0."
22
22
  },
23
23
  "host_resource_proto_usage": {
24
- "action": "warn",
24
+ "action": "fail_control",
25
25
  "suffix": "This will not be supported in InSpec 4.0."
26
26
  },
27
27
  "inspec_ui_methods": {
@@ -30,67 +30,67 @@
30
30
  "comment": "See #3715"
31
31
  },
32
32
  "mssql_session_pass_option": {
33
- "action": "warn",
33
+ "action": "exit",
34
34
  "suffix": "This will not be supported in InSpec 4.0."
35
35
  },
36
36
  "oracledb_session_pass_option": {
37
- "action": "warn",
38
- "suffix": "This will not be supported in InSpec 4.0."
37
+ "action": "exit",
38
+ "suffix": "This is not supported in InSpec 4.0."
39
39
  },
40
40
  "property_filesystem_size": {
41
- "action": "ignore",
41
+ "action": "warn",
42
42
  "comment": "See #3778"
43
43
  },
44
44
  "property_processes_list": {
45
- "action": "warn",
46
- "suffix": "This property will be removed in InSpec 4.0."
45
+ "action": "fail_control",
46
+ "suffix": "This property was removed in InSpec 4.0."
47
47
  },
48
48
  "properties_aws_iam_user": {
49
- "action": "warn",
50
- "suffix": "This property will be removed in InSpec 4.0."
49
+ "action": "fail_control",
50
+ "suffix": "This property was removed in InSpec 4.0."
51
51
  },
52
52
  "properties_shadow": {
53
- "action": "warn",
54
- "suffix": "This property will be removed in InSpec 4.0."
53
+ "action": "fail_control",
54
+ "suffix": "This property was removed in InSpec 4.0."
55
55
  },
56
56
  "rename_attributes_to_inputs": {
57
- "action": "ignore",
57
+ "action": "warn",
58
58
  "prefix": "InSpec Attributes are being renamed to InSpec Inputs to avoid confusion with Chef Attributes.",
59
59
  "comment": "See #3802"
60
60
  },
61
61
  "resource_apache": {
62
- "action": "warn",
63
- "suffix": "This resource will be removed in InSpec 4.0."
62
+ "action": "exit",
63
+ "suffix": "This resource was removed in InSpec 4.0."
64
64
  },
65
65
  "resource_azure_generic_resource": {
66
66
  "action": "warn",
67
67
  "prefix": "The azure_generic_resource is deprecated. Please use a specific resource. See: 'https://github.com/inspec/inspec/issues/3131'"
68
68
  },
69
69
  "resource_iis_website": {
70
- "action": "warn",
71
- "suffix": "This resource will be removed in InSpec 4.0.",
70
+ "action": "exit",
71
+ "suffix": "This resource was removed in InSpec 4.0.",
72
72
  "comment": "Needed for ServerSpec compatibility"
73
73
  },
74
74
  "resource_linux_kernel_parameter": {
75
- "action": "warn",
76
- "suffix": "This resource will be removed in InSpec 4.0.",
75
+ "action": "exit",
76
+ "suffix": "This resource was removed in InSpec 4.0.",
77
77
  "comment": "Needed for ServerSpec compatibility"
78
78
  },
79
79
  "resource_ppa": {
80
- "action": "warn",
81
- "suffix": "This resource will be removed in InSpec 4.0.",
80
+ "action": "exit",
81
+ "suffix": "This resource was removed in InSpec 4.0.",
82
82
  "comment": "Needed for ServerSpec compatibility"
83
83
  },
84
84
  "resource_script": {
85
- "action": "warn",
85
+ "action": "exit",
86
86
  "suffix": "This resource will be removed in InSpec 4.0"
87
87
  },
88
88
  "resource_user_serverspec_compat": {
89
- "action": "warn"
89
+ "action": "fail_control"
90
90
  },
91
91
  "resource_windows_registry_key": {
92
- "action": "warn",
93
- "suffix": "This resource will be removed in InSpec 4.0.",
92
+ "action": "exit",
93
+ "suffix": "This resource was removed in InSpec 4.0.",
94
94
  "comment": "Needed for ServerSpec compatibility"
95
95
  },
96
96
  "serverspec_compatibility": {
@@ -101,11 +101,11 @@
101
101
  "action": "warn"
102
102
  },
103
103
  "mount_parser_serverspec_compat": {
104
- "action": "warn"
104
+ "action": "fail_control"
105
105
  },
106
106
  "wmi_non_hash_usage": {
107
- "action": "warn",
108
- "suffix": "This property will be removed in InSpec 4.0."
107
+ "action": "fail_control",
108
+ "suffix": "This property was removed in InSpec 4.0."
109
109
  }
110
110
  }
111
111
  }
data/inspec.gemspec CHANGED
@@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
31
31
  spec.add_dependency 'train-aws', '~> 0.1'
32
32
 
33
33
  # Implementation dependencies
34
- spec.add_dependency 'license-acceptance', '~> 0.2'
34
+ spec.add_dependency 'license-acceptance', '>= 0.2.13', '< 2.0'
35
35
  spec.add_dependency 'thor', '~> 0.20'
36
36
  spec.add_dependency 'json', '>= 1.8', '< 3.0'
37
37
  spec.add_dependency 'method_source', '~> 0.8'
data/lib/inspec/cli.rb CHANGED
@@ -392,7 +392,11 @@ require 'license_acceptance/acceptor'
392
392
  begin
393
393
  if (commands_exempt_from_license_check & ARGV.map(&:downcase)).empty? && # Did they use a non-exempt command?
394
394
  !ARGV.empty? # Did they supply at least one command?
395
- LicenseAcceptance::Acceptor.check_and_persist('inspec', Inspec::VERSION)
395
+ LicenseAcceptance::Acceptor.check_and_persist(
396
+ 'inspec',
397
+ Inspec::VERSION,
398
+ logger: Inspec::Log,
399
+ )
396
400
  end
397
401
  rescue LicenseAcceptance::LicenseNotAcceptedError
398
402
  Inspec::Log.error 'InSpec cannot execute without accepting the license'
@@ -26,8 +26,23 @@ module Inspec
26
26
  with_resource_dsl resources_dsl
27
27
 
28
28
  # allow attributes to be accessed within control blocks
29
- define_method :attribute do |name|
30
- Inspec::InputRegistry.find_input(name, profile_id).value
29
+ # TODO: deprecate name, use input()
30
+ define_method :attribute do |input_name, options = {}|
31
+ if options.empty?
32
+ # Simply an access, no event here
33
+ Inspec::InputRegistry.find_or_register_input(input_name, profile_id).value
34
+ else
35
+ options[:priority] = 20
36
+ options[:provider] = :inline_control_code
37
+ evt = Inspec::Input.infer_event(options)
38
+ Inspec::InputRegistry.find_or_register_input(input_name, profile_name, event: evt).value
39
+ end
40
+ end
41
+
42
+ # Find the Input object, but don't collapse to a value.
43
+ # Will return nil on a miss.
44
+ define_method :input_object do |input_name|
45
+ Inspec::InputRegistry.find_or_register_input(input_name, profile_id)
31
46
  end
32
47
 
33
48
  # Support for Control DSL plugins.
@@ -168,14 +183,25 @@ module Inspec
168
183
  end
169
184
 
170
185
  # method for inputs; import input handling
171
- define_method :attribute do |name, options = nil|
172
- if options.nil?
173
- Inspec::InputRegistry.find_input(name, profile_id).value
186
+ # TODO: deprecate name, use input()
187
+ define_method :attribute do |input_name, options = {}|
188
+ if options.empty?
189
+ # Simply an access, no event here
190
+ Inspec::InputRegistry.find_or_register_input(input_name, profile_id).value
174
191
  else
175
- profile_context_owner.register_input(name, options)
192
+ options[:priority] = 20
193
+ options[:provider] = :inline_control_code
194
+ evt = Inspec::Input.infer_event(options)
195
+ Inspec::InputRegistry.find_or_register_input(input_name, profile_name, event: evt).value
176
196
  end
177
197
  end
178
198
 
199
+ # Find the Input object, but don't collapse to a value.
200
+ # Will return nil on a miss.
201
+ define_method :input_object do |input_name|
202
+ Inspec::InputRegistry.find_or_register_input(input_name, profile_id)
203
+ end
204
+
179
205
  define_method :skip_control do |id|
180
206
  profile_context_owner.unregister_rule(id)
181
207
  end
@@ -118,6 +118,7 @@ module Inspec
118
118
  return @profile unless @profile.nil?
119
119
  opts = @opts.dup
120
120
  opts[:backend] = @backend
121
+ opts[:runner_conf] = Inspec::Config.cached
121
122
  if !@dependencies.nil? && !@dependencies.empty?
122
123
  opts[:dependencies] = Inspec::DependencySet.from_array(@dependencies, @cwd, @cache, @backend)
123
124
  end
@@ -23,6 +23,7 @@ module Inspec
23
23
  # implementation of the fetcher being used.
24
24
  #
25
25
  class Resolver
26
+ # Here deps is an Array of Hashes
26
27
  def self.resolve(dependencies, cache, working_dir, backend)
27
28
  reqs = dependencies.map do |dep|
28
29
  req = Inspec::Requirement.from_metadata(dep, cache, cwd: working_dir, backend: backend)
@@ -47,6 +48,7 @@ module Inspec
47
48
  end
48
49
  end
49
50
 
51
+ # Here deps is an Array of Inspec::Requirement
50
52
  def resolve(deps, top_level = true, seen_items = {}, path_string = '') # rubocop:disable Metrics/AbcSize
51
53
  graph = {}
52
54
  if top_level
data/lib/inspec/dsl.rb CHANGED
@@ -79,7 +79,7 @@ module Inspec::DSL
79
79
 
80
80
  def self.filter_included_controls(context, profile, &block)
81
81
  mock = Inspec::Backend.create(Inspec::Config.mock)
82
- include_ctx = Inspec::ProfileContext.for_profile(profile, mock, {})
82
+ include_ctx = Inspec::ProfileContext.for_profile(profile, mock)
83
83
  include_ctx.load(block) if block_given?
84
84
  # remove all rules that were not registered
85
85
  context.all_rules.each do |r|
data/lib/inspec/impact.rb CHANGED
@@ -4,7 +4,7 @@
4
4
  module Inspec::Impact
5
5
  IMPACT_SCORES = {
6
6
  'none' => 0.0,
7
- 'low' => 0.01,
7
+ 'low' => 0.1,
8
8
  'medium' => 0.4,
9
9
  'high' => 0.7,
10
10
  'critical' => 0.9,
@@ -1,83 +1,224 @@
1
1
  require 'forwardable'
2
2
  require 'singleton'
3
3
  require 'inspec/objects/input'
4
+ require 'inspec/secrets'
5
+ require 'inspec/exceptions'
4
6
 
5
7
  module Inspec
8
+ # The InputRegistry's responsibilities include:
9
+ # - maintaining a list of Input objects that are bound to profiles
10
+ # - assisting in the lookup and creation of Inputs
6
11
  class InputRegistry
7
12
  include Singleton
8
13
  extend Forwardable
9
14
 
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
+ attr_reader :inputs_by_profile, :profile_aliases
16
+ def_delegator :inputs_by_profile, :each
17
+ def_delegator :inputs_by_profile, :[]
18
+ def_delegator :inputs_by_profile, :key?, :profile_known?
19
+ def_delegator :inputs_by_profile, :select
20
+ def_delegator :profile_aliases, :key?, :profile_alias?
15
21
 
16
- # These self methods are convenience methods so you dont always
17
- # have to specify instance when calling the registry
18
- def self.find_input(name, profile)
19
- instance.find_input(name, profile)
20
- end
22
+ def initialize
23
+ # Keyed on String profile_name => Hash of String input_name => Input object
24
+ @inputs_by_profile = {}
21
25
 
22
- def self.register_input(name, profile, options = {})
23
- instance.register_input(name, profile, options)
26
+ # this is a list of optional profile name overrides set in the inspec.yml
27
+ @profile_aliases = {}
24
28
  end
25
29
 
26
- def self.register_profile_alias(name, alias_name)
27
- instance.register_profile_alias(name, alias_name)
30
+ #-------------------------------------------------------------#
31
+ # Support for Profiles
32
+ #-------------------------------------------------------------#
33
+
34
+ def register_profile_alias(name, alias_name)
35
+ @profile_aliases[name] = alias_name
28
36
  end
29
37
 
30
- def self.list_inputs_for_profile(profile)
31
- instance.list_inputs_for_profile(profile)
38
+ def list_inputs_for_profile(profile)
39
+ inputs_by_profile[profile] = {} unless profile_known?(profile)
40
+ inputs_by_profile[profile]
32
41
  end
33
42
 
34
- def initialize
35
- # this is a collection of profiles which have a value of input objects
36
- @list = {}
43
+ #-------------------------------------------------------------#
44
+ # Support for Individual Inputs
45
+ #-------------------------------------------------------------#
37
46
 
38
- # this is a list of optional profile name overrides set in the inspec.yml
39
- @profile_aliases = {}
47
+ def find_or_register_input(input_name, profile_name, options = {})
48
+ if profile_alias?(profile_name)
49
+ alias_name = profile_name
50
+ profile_name = profile_aliases[profile_name]
51
+ handle_late_arriving_alias(alias_name, profile_name) if profile_known?(alias_name)
52
+ end
53
+
54
+ inputs_by_profile[profile_name] ||= {}
55
+ if inputs_by_profile[profile_name].key?(input_name)
56
+ inputs_by_profile[profile_name][input_name].update(options)
57
+ else
58
+ inputs_by_profile[profile_name][input_name] = Inspec::Input.new(input_name, options)
59
+ end
60
+
61
+ inputs_by_profile[profile_name][input_name]
40
62
  end
41
63
 
42
- def find_input(name, profile)
43
- profile = @profile_aliases[profile] if !profile_exist?(profile) && @profile_aliases[profile]
44
- unless profile_exist?(profile)
45
- error = Inspec::InputRegistry::ProfileLookupError.new
46
- error.profile_name = profile
47
- raise error, "Profile '#{error.profile_name}' does not have any inputs"
64
+ # It is possible for a wrapper profile to create an input in metadata,
65
+ # referring to the child profile by an alias that has not yet been registered.
66
+ # The registry will then store the inputs under the alias, as if the alias
67
+ # were a true profile.
68
+ # If that happens and the child profile also mentions the input, we will
69
+ # need to move some things - all inputs should be stored under the true
70
+ # profile name, and no inputs should be stored under the alias.
71
+ def handle_late_arriving_alias(alias_name, profile_name)
72
+ inputs_by_profile[profile_name] ||= {}
73
+ inputs_by_profile[alias_name].each do |input_name, input_from_alias|
74
+ # Move the inpuut, or if it exists, merge events
75
+ existing = inputs_by_profile[profile_name][input_name]
76
+ if existing
77
+ existing.events.concat(input_from_alias.events)
78
+ else
79
+ inputs_by_profile[profile_name][input_name] = input_from_alias
80
+ end
48
81
  end
82
+ # Finally, delete the (now copied-out) entry for the alias
83
+ inputs_by_profile.delete(alias_name)
84
+ end
85
+ #-------------------------------------------------------------#
86
+ # Support for Binding Inputs
87
+ #-------------------------------------------------------------#
88
+
89
+ # This method is called by the Profile as soon as it has
90
+ # enough context to allow binding inputs to it.
91
+ def bind_profile_inputs(profile_name, sources = {})
92
+ inputs_by_profile[profile_name] ||= {}
93
+
94
+ # In a more perfect world, we could let the core plugins choose
95
+ # self-determine what to do; but as-is, the APIs that call this
96
+ # are a bit over-constrained.
97
+ bind_inputs_from_metadata(profile_name, sources[:profile_metadata])
98
+ bind_inputs_from_input_files(profile_name, sources[:cli_input_files])
99
+ bind_inputs_from_runner_api(profile_name, sources[:runner_api])
100
+ end
101
+
102
+ private
49
103
 
50
- unless list[profile].key?(name)
51
- error = Inspec::InputRegistry::InputLookupError.new
52
- error.input_name = name
53
- error.profile_name = profile
54
- raise error, "Profile '#{error.profile_name}' does not have an input with name '#{error.input_name}'"
104
+ def bind_inputs_from_runner_api(profile_name, input_hash)
105
+ # TODO: move this into a core plugin
106
+
107
+ return if input_hash.nil?
108
+ return if input_hash.empty?
109
+
110
+ # These arrive as a bare hash - values are raw values, not options
111
+ input_hash.each do |input_name, input_value|
112
+ loc = Inspec::Input::Event.probe_stack # TODO: likely modify this to look for a kitchen.yml, if that is realistic
113
+ evt = Inspec::Input::Event.new(
114
+ value: input_value,
115
+ provider: :runner_api, # TODO: suss out if audit cookbook or kitchen-inspec or something unknown
116
+ priority: 40,
117
+ file: loc.path,
118
+ line: loc.lineno,
119
+ )
120
+ find_or_register_input(input_name, profile_name, event: evt)
55
121
  end
56
- list[profile][name]
57
122
  end
58
123
 
59
- def register_input(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::Input.new(name, options)
124
+ def bind_inputs_from_input_files(profile_name, file_list)
125
+ # TODO: move this into a core plugin
126
+
127
+ return if file_list.nil?
128
+ return if file_list.empty?
129
+
130
+ file_list.each do |path|
131
+ validate_inputs_file_readability!(path)
132
+
133
+ # TODO: drop this SecretsBackend stuff, will be handled by plugin system
134
+ data = Inspec::SecretsBackend.resolve(path)
135
+ if data.nil?
136
+ raise Inspec::Exceptions::SecretsBackendNotFound,
137
+ "Cannot find parser for inputs file '#{path}'. " \
138
+ 'Check to make sure file has the appropriate extension.'
139
+ end
140
+
141
+ next if data.inputs.nil?
142
+ data.inputs.each do |input_name, input_value|
143
+ evt = Inspec::Input::Event.new(
144
+ value: input_value,
145
+ provider: :cli_files,
146
+ priority: 40,
147
+ file: path,
148
+ # TODO: any way we could get a line number?
149
+ )
150
+ find_or_register_input(input_name, profile_name, event: evt)
151
+ end
66
152
  end
67
153
  end
68
154
 
69
- def register_profile_alias(name, alias_name)
70
- @profile_aliases[name] = alias_name
155
+ def validate_inputs_file_readability!(path)
156
+ unless File.exist?(path)
157
+ raise Inspec::Exceptions::InputsFileDoesNotExist,
158
+ "Cannot find input file '#{path}'. " \
159
+ 'Check to make sure file exists.'
160
+ end
161
+
162
+ unless File.readable?(path)
163
+ raise Inspec::Exceptions::InputsFileNotReadable,
164
+ "Cannot read input file '#{path}'. " \
165
+ 'Check to make sure file is readable.'
166
+ end
167
+
168
+ true
71
169
  end
72
170
 
73
- def list_inputs_for_profile(profile)
74
- list[profile] = {} unless profile_exist?(profile)
75
- list[profile]
171
+ def bind_inputs_from_metadata(profile_name, profile_metadata_obj)
172
+ # TODO: move this into a core plugin
173
+ # TODO: add deprecation stuff
174
+ return if profile_metadata_obj.nil? # Metadata files are technically optional
175
+
176
+ if profile_metadata_obj.params.key?(:attributes) && profile_metadata_obj.params[:attributes].is_a?(Array)
177
+ profile_metadata_obj.params[:attributes].each do |input_orig|
178
+ input_options = input_orig.dup
179
+ input_name = input_options.delete(:name)
180
+ input_options.merge!({ priority: 30, provider: :profile_metadata, file: File.join(profile_name, 'inspec.yml') })
181
+ evt = Inspec::Input.infer_event(input_options)
182
+
183
+ # Profile metadata may set inputs in other profiles by naming them.
184
+ if input_options[:profile]
185
+ profile_name = input_options[:profile] || profile_name
186
+ # Override priority to force this to win. Allow user to set their own priority.
187
+ evt.priority = input_orig[:priority] || 35
188
+ end
189
+ find_or_register_input(input_name,
190
+ profile_name,
191
+ type: input_options[:type],
192
+ required: input_options[:required],
193
+ event: evt)
194
+ end
195
+ elsif profile_metadata_obj.params.key?(:attributes)
196
+ Inspec::Log.warn 'Inputs must be defined as an Array. Skipping current definition.'
197
+ end
76
198
  end
77
199
 
200
+ #-------------------------------------------------------------#
201
+ # Other Support
202
+ #-------------------------------------------------------------#
203
+ public
204
+
205
+ # Used in testing
78
206
  def __reset
79
- @list = {}
207
+ @inputs_by_profile = {}
80
208
  @profile_aliases = {}
81
209
  end
210
+
211
+ # These class methods are convenience methods so you don't always
212
+ # have to call #instance when calling the registry
213
+ [
214
+ :find_or_register_input,
215
+ :register_profile_alias,
216
+ :list_inputs_for_profile,
217
+ :bind_profile_inputs,
218
+ ].each do |meth|
219
+ define_singleton_method(meth) do |*args|
220
+ instance.send(meth, *args)
221
+ end
222
+ end
82
223
  end
83
224
  end