inspec 4.16.0 → 4.17.7

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/lib/inspec.rb +0 -1
  3. data/lib/inspec/backend.rb +7 -0
  4. data/lib/inspec/base_cli.rb +2 -0
  5. data/lib/inspec/cli.rb +3 -10
  6. data/lib/inspec/config.rb +3 -4
  7. data/lib/inspec/control_eval_context.rb +5 -3
  8. data/lib/inspec/dsl.rb +24 -1
  9. data/lib/inspec/errors.rb +0 -26
  10. data/lib/inspec/file_provider.rb +33 -43
  11. data/lib/inspec/formatters/base.rb +1 -0
  12. data/lib/inspec/impact.rb +2 -0
  13. data/lib/inspec/input.rb +410 -0
  14. data/lib/inspec/input_registry.rb +10 -1
  15. data/lib/inspec/objects.rb +3 -1
  16. data/lib/inspec/objects/input.rb +5 -387
  17. data/lib/inspec/objects/tag.rb +1 -1
  18. data/lib/inspec/plugin/v1/plugin_types/resource.rb +16 -5
  19. data/lib/inspec/plugin/v2/activator.rb +4 -8
  20. data/lib/inspec/plugin/v2/loader.rb +19 -3
  21. data/lib/inspec/profile.rb +1 -1
  22. data/lib/inspec/profile_context.rb +1 -1
  23. data/lib/inspec/reporters/json.rb +70 -88
  24. data/lib/inspec/resource.rb +1 -0
  25. data/lib/inspec/resources.rb +9 -2
  26. data/lib/inspec/resources/aide_conf.rb +4 -0
  27. data/lib/inspec/resources/apt.rb +19 -19
  28. data/lib/inspec/resources/etc_fstab.rb +4 -0
  29. data/lib/inspec/resources/etc_hosts.rb +4 -0
  30. data/lib/inspec/resources/firewalld.rb +4 -0
  31. data/lib/inspec/resources/json.rb +10 -3
  32. data/lib/inspec/resources/mssql_session.rb +1 -1
  33. data/lib/inspec/resources/platform.rb +18 -13
  34. data/lib/inspec/resources/postfix_conf.rb +6 -2
  35. data/lib/inspec/resources/security_identifier.rb +4 -0
  36. data/lib/inspec/resources/sys_info.rb +65 -4
  37. data/lib/inspec/resources/user.rb +1 -0
  38. data/lib/inspec/rule.rb +68 -6
  39. data/lib/inspec/runner.rb +6 -1
  40. data/lib/inspec/runner_rspec.rb +1 -0
  41. data/lib/inspec/shell.rb +8 -1
  42. data/lib/inspec/utils/pkey_reader.rb +1 -1
  43. data/lib/inspec/version.rb +1 -1
  44. data/lib/matchers/matchers.rb +2 -0
  45. data/lib/plugins/inspec-plugin-manager-cli/test/functional/help_test.rb +23 -0
  46. data/lib/plugins/inspec-plugin-manager-cli/test/functional/helper.rb +62 -0
  47. data/lib/plugins/inspec-plugin-manager-cli/test/functional/install_test.rb +368 -0
  48. data/lib/plugins/inspec-plugin-manager-cli/test/functional/list_test.rb +101 -0
  49. data/lib/plugins/inspec-plugin-manager-cli/test/functional/search_test.rb +129 -0
  50. data/lib/plugins/inspec-plugin-manager-cli/test/functional/uninstall_test.rb +63 -0
  51. data/lib/plugins/inspec-plugin-manager-cli/test/functional/update_test.rb +84 -0
  52. metadata +11 -3
  53. data/lib/plugins/inspec-plugin-manager-cli/test/functional/inspec-plugin_test.rb +0 -845
@@ -31,8 +31,10 @@ module Inspec
31
31
  def supports(criteria = nil)
32
32
  return if criteria.nil?
33
33
 
34
- Inspec::Resource.supports[@name] ||= []
35
- Inspec::Resource.supports[@name].push(criteria)
34
+ key = @name.to_sym
35
+
36
+ Inspec::Resource.supports[key] ||= []
37
+ Inspec::Resource.supports[key].push(criteria)
36
38
  end
37
39
 
38
40
  def example(example = nil)
@@ -80,14 +82,22 @@ module Inspec
80
82
  def initialize(backend, name, *args)
81
83
  @resource_skipped = false
82
84
  @resource_failed = false
83
- @supports = Inspec::Resource.supports[name]
85
+ @supports = Inspec::Resource.supports[name.to_sym]
84
86
  @resource_exception_message = nil
85
87
 
86
88
  # attach the backend to this instance
87
89
  @__backend_runner__ = backend
88
90
  @__resource_name__ = name
89
91
 
90
- check_supports unless @supports.nil? # this has side effects
92
+ # check resource supports
93
+ supported = @supports ? check_supports : true # check_supports has side effects!
94
+ test_backend = defined?(Train::Transports::Mock::Connection) && backend.backend.class == Train::Transports::Mock::Connection
95
+ # raise unless we are supported or in test
96
+ unless supported || test_backend
97
+ msg = "Unsupported resource/backend combination: %s / %s. Exiting." %
98
+ [name, backend.platform.name]
99
+ raise ArgumentError, msg
100
+ end
91
101
 
92
102
  # call the resource initializer
93
103
  begin
@@ -116,6 +126,7 @@ module Inspec
116
126
  end
117
127
 
118
128
  def check_supports
129
+ require "inspec/resources/platform"
119
130
  status = inspec.platform.supported?(@supports)
120
131
  fail_msg = "Resource `#{@__resource_name__}` is not supported on platform #{inspec.platform.name}/#{inspec.platform.release}."
121
132
  fail_resource(fail_msg) unless status
@@ -157,7 +168,7 @@ module Inspec
157
168
  end
158
169
 
159
170
  module Plugins
160
- class Resource
171
+ class Resource # TODO: possibly push up to inspec/resource.rb
161
172
  extend Inspec::ResourceDSL
162
173
  include Inspec::ResourceBehaviors
163
174
  end
@@ -3,21 +3,17 @@ module Inspec::Plugin::V2
3
3
  :plugin_name,
4
4
  :plugin_type,
5
5
  :activator_name,
6
- :activated?,
6
+ :activated,
7
7
  :exception,
8
8
  :activation_proc,
9
9
  :implementation_class
10
10
  ) do
11
11
  def initialize(*)
12
12
  super
13
- self[:'activated?'] = false
13
+ self[:activated] = false
14
14
  end
15
15
 
16
- def activated?(new_value = nil)
17
- return self[:activated?] if new_value.nil?
18
-
19
- self[:activated?] = new_value
20
- end
16
+ alias activated? activated
21
17
 
22
18
  # Load a plugin, but if an error is encountered, store it and continue
23
19
  def activate
@@ -26,7 +22,7 @@ module Inspec::Plugin::V2
26
22
  # rubocop: disable Lint/RescueException
27
23
  begin
28
24
  impl_class = self[:activation_proc].call
29
- self[:activated?] = true
25
+ self.activated = true
30
26
  self[:implementation_class] = impl_class
31
27
  rescue Exception => ex
32
28
  self[:exception] = ex
@@ -1,4 +1,5 @@
1
1
  require "inspec/log"
2
+ require "inspec/version"
2
3
  require "inspec/plugin/v2/config_file"
3
4
  require "inspec/plugin/v2/filter"
4
5
 
@@ -123,7 +124,9 @@ module Inspec::Plugin::V2
123
124
  require "rbconfig"
124
125
  ruby_abi_version = RbConfig::CONFIG["ruby_version"]
125
126
  # TODO: why are we installing under the api directory for plugins?
126
- File.join(Inspec.config_dir, "gems", ruby_abi_version)
127
+ base_dir = Inspec.config_dir
128
+ base_dir = File.realpath base_dir if File.exist? base_dir
129
+ File.join(base_dir, "gems", ruby_abi_version)
127
130
  end
128
131
 
129
132
  # Lists all gems found in the plugin_gem_path.
@@ -201,7 +204,7 @@ module Inspec::Plugin::V2
201
204
  status = registry[plugin_name]
202
205
  status.api_generation = 0
203
206
  act = Activator.new
204
- act.activated?(true)
207
+ act.activated = true
205
208
  act.plugin_type = :cli_command
206
209
  act.plugin_name = plugin_name
207
210
  act.activator_name = :default
@@ -272,9 +275,22 @@ module Inspec::Plugin::V2
272
275
  end
273
276
  end
274
277
 
278
+ def find_inspec_gemspec(name, ver)
279
+ Gem::Specification.find_by_name(name, ver)
280
+ rescue Gem::MissingSpecError
281
+ nil
282
+ end
283
+
275
284
  def detect_system_plugins
276
285
  # Find the gemspec for inspec
277
- inspec_gemspec = Gem::Specification.find_by_name("inspec", "=#{Inspec::VERSION}")
286
+ inspec_gemspec =
287
+ find_inspec_gemspec("inspec", "=#{Inspec::VERSION}") ||
288
+ find_inspec_gemspec("inspec-core", "=#{Inspec::VERSION}")
289
+
290
+ unless inspec_gemspec
291
+ Inspec::Log.warn "inspec gem not found, skipping detecting of system plugins"
292
+ return
293
+ end
278
294
 
279
295
  # Make a RequestSet that represents the dependencies of inspec
280
296
  inspec_deps_request_set = Gem::RequestSet.new(*inspec_gemspec.dependencies)
@@ -68,7 +68,7 @@ module Inspec
68
68
  end
69
69
 
70
70
  def self.for_target(target, opts = {})
71
- opts[:vendor_cache] = opts[:vendor_cache] || Cache.new
71
+ opts[:vendor_cache] ||= Cache.new
72
72
  fetcher = resolve_target(target, opts[:vendor_cache])
73
73
  for_fetcher(fetcher, opts)
74
74
  end
@@ -5,7 +5,7 @@ require "inspec/library_eval_context"
5
5
  require "inspec/control_eval_context"
6
6
  require "inspec/require_loader"
7
7
  require "securerandom"
8
- require "inspec/objects/input"
8
+ require "inspec/input_registry"
9
9
 
10
10
  module Inspec
11
11
  class ProfileContext
@@ -1,6 +1,7 @@
1
1
  require "json"
2
2
 
3
3
  module Inspec::Reporters
4
+ # rubocop:disable Layout/AlignHash, Style/BlockDelimiters
4
5
  class Json < Base
5
6
  def render
6
7
  output(report.to_json, false)
@@ -20,112 +21,93 @@ module Inspec::Reporters
20
21
  private
21
22
 
22
23
  def platform
23
- platform = {
24
- name: run_data[:platform][:name],
25
- release: run_data[:platform][:release],
26
- }
27
- platform[:target_id] = @config["target_id"] if @config["target_id"]
28
- platform
24
+ {
25
+ name: run_data[:platform][:name],
26
+ release: run_data[:platform][:release],
27
+ target_id: @config["target_id"],
28
+ }.reject { |_k, v| v.nil? }
29
29
  end
30
30
 
31
31
  def profile_results(control)
32
- results = []
33
- return results if control[:results].nil?
32
+ (control[:results] || []).map { |r|
33
+ {
34
+ status: r[:status],
35
+ code_desc: r[:code_desc],
36
+ run_time: r[:run_time],
37
+ start_time: r[:start_time],
38
+ resource: r[:resource],
39
+ skip_message: r[:skip_message],
40
+ message: r[:message],
41
+ exception: r[:exception],
42
+ backtrace: r[:backtrace],
43
+ waiver_data: r[:waiver_data],
44
+ }.reject { |_k, v| v.nil? }
45
+ }
46
+ end
34
47
 
35
- control[:results].each do |r|
36
- result = {
37
- status: r[:status],
38
- code_desc: r[:code_desc],
39
- run_time: r[:run_time],
40
- start_time: r[:start_time],
41
- }
42
- result[:resource] = r[:resource] if r[:resource]
43
- result[:skip_message] = r[:skip_message] if r[:skip_message]
44
- result[:message] = r[:message] if r[:message]
45
- result[:exception] = r[:exception] if r[:exception]
46
- result[:backtrace] = r[:backtrace] if r[:backtrace]
48
+ def profiles
49
+ run_data[:profiles].map { |p|
50
+ {
51
+ name: p[:name],
52
+ version: p[:version],
53
+ sha256: p[:sha256],
54
+ title: p[:title],
55
+ maintainer: p[:maintainer],
56
+ summary: p[:summary],
57
+ license: p[:license],
58
+ copyright: p[:copyright],
59
+ copyright_email: p[:copyright_email],
60
+ supports: p[:supports],
61
+ # TODO: rename exposed field to inputs, see #3802:
62
+ attributes: (p[:inputs] || p[:attributes]),
63
+ parent_profile: p[:parent_profile],
64
+ depends: p[:depends],
65
+ groups: profile_groups(p),
66
+ controls: profile_controls(p),
67
+ status: p[:status],
68
+ skip_message: p[:skip_message],
69
+ waiver_data: p[:waiver_data],
70
+ }.reject { |_k, v| v.nil? }
71
+ }
72
+ end
47
73
 
48
- results << result
49
- end
50
- results
74
+ def profile_groups(profile)
75
+ (profile[:groups] || []).map { |g|
76
+ {
77
+ id: g[:id],
78
+ controls: g[:controls],
79
+ title: g[:title],
80
+ }.reject { |_k, v| v.nil? }
81
+ }
51
82
  end
52
83
 
53
84
  def profile_controls(profile)
54
- controls = []
55
- return controls if profile[:controls].nil?
56
-
57
- profile[:controls].each do |c|
58
- control = {
59
- id: c[:id],
60
- title: c[:title],
61
- desc: c.dig(:descriptions, :default),
85
+ (profile[:controls] || []).map { |c|
86
+ {
87
+ id: c[:id],
88
+ title: c[:title],
89
+ desc: c.dig(:descriptions, :default),
62
90
  descriptions: convert_descriptions(c[:descriptions]),
63
91
  impact: c[:impact],
64
- refs: c[:refs],
65
- tags: c[:tags],
66
- code: c[:code],
92
+ refs: c[:refs],
93
+ tags: c[:tags],
94
+ code: c[:code],
67
95
  source_location: {
68
96
  line: c[:source_location][:line],
69
- ref: c[:source_location][:ref],
97
+ ref: c[:source_location][:ref],
70
98
  },
71
99
  results: profile_results(c),
72
100
  }
73
- controls << control
74
- end
75
- controls
76
- end
77
-
78
- def profile_groups(profile)
79
- groups = []
80
- return groups if profile[:groups].nil?
81
-
82
- profile[:groups].each do |g|
83
- group = {
84
- id: g[:id],
85
- controls: g[:controls],
86
- }
87
- group[:title] = g[:title] if g[:title]
88
-
89
- groups << group
90
- end
91
- groups
92
- end
93
-
94
- def profiles
95
- profiles = []
96
- run_data[:profiles].each do |p|
97
- profile = {
98
- name: p[:name],
99
- version: p[:version],
100
- sha256: p[:sha256],
101
- title: p[:title],
102
- maintainer: p[:maintainer],
103
- summary: p[:summary],
104
- license: p[:license],
105
- copyright: p[:copyright],
106
- copyright_email: p[:copyright_email],
107
- supports: p[:supports],
108
- attributes: (p[:inputs] ? p[:inputs] : p[:attributes]), # TODO: rename exposed field to inputs, see #3802
109
- parent_profile: p[:parent_profile],
110
- depends: p[:depends],
111
- groups: profile_groups(p),
112
- controls: profile_controls(p),
113
- status: p[:status],
114
- skip_message: p[:skip_message],
115
- }
116
- profiles << profile.reject { |_k, v| v.nil? }
117
- end
118
- profiles
101
+ }
119
102
  end
120
103
 
121
104
  def convert_descriptions(data)
122
- return [] if data.nil?
123
-
124
- results = []
125
- data.each do |label, text|
126
- results.push({ label: label.to_s, data: text })
127
- end
128
- results
105
+ (data || []).map { |label, text|
106
+ {
107
+ label: label.to_s,
108
+ data: text,
109
+ }
110
+ }
129
111
  end
130
112
  end
131
113
  end
@@ -74,6 +74,7 @@ module Inspec
74
74
  # @return [Resource] base class for creating a new resource
75
75
  def self.resource(version)
76
76
  validate_resource_dsl_version!(version)
77
+ require "inspec/plugin/v1/plugin_types/resource"
77
78
  Inspec::Plugins::Resource
78
79
  end
79
80
 
@@ -1,11 +1,18 @@
1
+ ##
2
+ # Now that resources are lazily loaded, this file is ONLY here for one
3
+ # reason at this point, to load all the resources in order to populate
4
+ # the registry for `inspec shell`'s `help commands`. There has to be a
5
+ # cheaper way to do this, but this will do for now.
6
+ #
7
+ # NOTE: I intentionally didn't convert this to a loop over a simple
8
+ # glob so this remains a sort of manifest for our resources.
9
+
1
10
  require "inspec/resource"
2
11
 
3
12
  # Detect if we are running the stripped-down inspec-core
4
13
  # This relies on AWS being stripped from the inspec-core gem
5
14
  inspec_core_only = ENV["NO_AWS"] || !File.exist?(File.join(File.dirname(__FILE__), "..", "resource_support", "aws.rb"))
6
15
 
7
- require "rspec/matchers"
8
-
9
16
  # Do not attempt to load cloud resources if we are in inspec-core mode
10
17
  unless inspec_core_only
11
18
  require "resource_support/aws"
@@ -48,6 +48,10 @@ module Inspec::Resources
48
48
 
49
49
  filter.install_filter_methods_on_resource(self, :params)
50
50
 
51
+ def to_s
52
+ "AIDE Config"
53
+ end
54
+
51
55
  private
52
56
 
53
57
  def read_content
@@ -71,9 +71,9 @@ module Inspec::Resources
71
71
  read_debs.select { |repo| repo[:url] == @deb_url && repo[:type] == "deb" }
72
72
  end
73
73
 
74
+ # TODO: remove this. just see if it is valid w/ URI.parse
74
75
  HTTP_URL_RE = /\A#{URI::DEFAULT_PARSER.make_regexp(%w{http https})}\z/.freeze
75
76
 
76
- # read
77
77
  def read_debs
78
78
  return @repo_cache if defined?(@repo_cache)
79
79
 
@@ -81,32 +81,32 @@ module Inspec::Resources
81
81
  cmd = inspec.command("find /etc/apt/ -name \*.list -exec sh -c 'cat {} || echo -n' \\;")
82
82
 
83
83
  # @see https://help.ubuntu.com/community/Repositories/CommandLine#Explanation_of_the_Repository_Format
84
- @repo_cache = cmd.stdout.chomp.split("\n").each_with_object([]) do |raw_line, lines|
85
- active = true
86
-
84
+ @repo_cache = cmd.stdout.lines.map do |raw_line|
87
85
  # detect if the repo is commented out
88
86
  line = raw_line.gsub(/^(#\s*)*/, "")
89
- active = false if raw_line != line
87
+ active = raw_line == line
88
+
89
+ # formats:
90
+ # deb http://archive.ubuntu.com/ubuntu/ wily main restricted ...
91
+ # deb [trusted=yes] http://archive.ubuntu.com/ubuntu/ wily main restricted ...
90
92
 
91
- # eg.: deb http://archive.ubuntu.com/ubuntu/ wily main restricted
92
- # or : deb [trusted=yes] http://archive.ubuntu.com/ubuntu/ wily main restricted
93
- parse_repo = /^\s*(\S+)\s+(?:\[\S+\])?\s*"?([^ "\t\r\n\f]+)"?\s+(\S+)\s+(.*)$/.match(line)
93
+ words = line.split
94
+ words.delete 1 if words[1] && words[1].start_with?("[")
95
+ type, url, distro, *components = words
94
96
 
95
- # check if we got any result and the second param is an url
96
- next if parse_repo.nil? || !parse_repo[2] =~ HTTP_URL_RE
97
+ next if components.empty?
98
+ next unless URI::HTTP === URI.parse(url)
99
+ next unless %w{deb deb-src}.include? type
97
100
 
98
101
  # map data
99
- repo = {
100
- type: parse_repo[1],
101
- url: parse_repo[2],
102
- distro: parse_repo[3],
103
- components: parse_repo[4].chomp.split(" "),
102
+ {
103
+ type: type,
104
+ url: url,
105
+ distro: distro,
106
+ components: components,
104
107
  active: active,
105
108
  }
106
- next unless %w{deb deb-src}.include? repo[:type]
107
-
108
- lines.push(repo)
109
- end
109
+ end.compact
110
110
  end
111
111
 
112
112
  # resolves ppa urls