inspec 4.1.4.preview → 4.2.0.preview

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 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