inspec-core 4.16.0 → 4.17.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) 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. metadata +4 -2
@@ -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