inspec 1.48.0 → 1.49.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -0
  3. data/CHANGELOG.md +40 -16
  4. data/Rakefile +1 -1
  5. data/docs/resources/bond.md.erb +6 -1
  6. data/docs/resources/mysql_session.md.erb +24 -12
  7. data/docs/resources/passwd.md.erb +1 -1
  8. data/docs/resources/xml.md.erb +7 -2
  9. data/docs/shell.md +22 -0
  10. data/inspec.gemspec +1 -1
  11. data/lib/bundles/inspec-artifact/cli.rb +0 -2
  12. data/lib/bundles/inspec-compliance/api.rb +58 -3
  13. data/lib/bundles/inspec-compliance/cli.rb +1 -1
  14. data/lib/bundles/inspec-habitat/profile.rb +1 -1
  15. data/lib/fetchers/url.rb +1 -1
  16. data/lib/inspec/base_cli.rb +3 -1
  17. data/lib/inspec/cli.rb +11 -1
  18. data/lib/inspec/control_eval_context.rb +13 -2
  19. data/lib/inspec/dependencies/lockfile.rb +0 -2
  20. data/lib/inspec/dsl_shared.rb +8 -0
  21. data/lib/inspec/library_eval_context.rb +12 -1
  22. data/lib/inspec/metadata.rb +13 -44
  23. data/lib/inspec/objects/attribute.rb +1 -1
  24. data/lib/inspec/plugins/resource.rb +18 -2
  25. data/lib/inspec/profile.rb +17 -11
  26. data/lib/inspec/profile_context.rb +9 -3
  27. data/lib/inspec/profile_vendor.rb +1 -1
  28. data/lib/inspec/resource.rb +5 -0
  29. data/lib/inspec/rspec_json_formatter.rb +3 -3
  30. data/lib/inspec/rule.rb +1 -1
  31. data/lib/inspec/runner.rb +13 -5
  32. data/lib/inspec/schema.rb +1 -1
  33. data/lib/inspec/shell.rb +1 -1
  34. data/lib/inspec/version.rb +1 -1
  35. data/lib/resources/aide_conf.rb +0 -2
  36. data/lib/resources/apache_conf.rb +9 -2
  37. data/lib/resources/auditd.rb +0 -1
  38. data/lib/resources/auditd_rules.rb +0 -2
  39. data/lib/resources/bond.rb +4 -0
  40. data/lib/resources/crontab.rb +1 -1
  41. data/lib/resources/docker.rb +1 -1
  42. data/lib/resources/elasticsearch.rb +1 -1
  43. data/lib/resources/file.rb +2 -0
  44. data/lib/resources/groups.rb +29 -5
  45. data/lib/resources/grub_conf.rb +1 -1
  46. data/lib/resources/os.rb +8 -20
  47. data/lib/resources/package.rb +20 -21
  48. data/lib/resources/platform.rb +112 -0
  49. data/lib/resources/port.rb +1 -1
  50. data/lib/resources/processes.rb +1 -1
  51. data/lib/resources/registry_key.rb +1 -1
  52. data/lib/resources/service.rb +1 -1
  53. data/lib/resources/virtualization.rb +1 -1
  54. data/lib/resources/x509_certificate.rb +1 -1
  55. data/lib/resources/xml.rb +1 -0
  56. metadata +5 -10
@@ -13,7 +13,7 @@ module Inspec
13
13
  # as the basic DSL of the control files (describe, control, title,
14
14
  # etc).
15
15
  #
16
- class ControlEvalContext # rubocop:disable Metrics/ClassLength
16
+ class ControlEvalContext
17
17
  # Create the context for controls. This includes all components of the DSL,
18
18
  # including matchers and resources.
19
19
  #
@@ -117,10 +117,21 @@ module Inspec
117
117
  end
118
118
 
119
119
  define_method :register_control do |control, &block|
120
- if @skip_file || !profile_context_owner.profile_supports_os?
120
+ if @skip_file
121
121
  ::Inspec::Rule.set_skip_rule(control, true)
122
122
  end
123
123
 
124
+ unless profile_context_owner.profile_supports_platform?
125
+ platform = inspec.platform
126
+ msg = "Profile #{profile_context_owner.profile_id} is not supported on platform #{platform.name}/#{platform.release}."
127
+ ::Inspec::Rule.set_skip_rule(control, msg)
128
+ end
129
+
130
+ unless profile_context_owner.profile_supports_inspec_version?
131
+ msg = "Profile #{profile_context_owner.profile_id} is not supported on InSpec version (#{Inspec::VERSION})."
132
+ ::Inspec::Rule.set_skip_rule(control, msg)
133
+ end
134
+
124
135
  profile_context_owner.register_rule(control, &block) unless control.nil?
125
136
  end
126
137
 
@@ -28,7 +28,6 @@ module Inspec
28
28
  from_content(content)
29
29
  end
30
30
 
31
- # rubocop:disable Style/GuardClause
32
31
  def self.validate_lockfile_version!(version)
33
32
  if version < MINIMUM_SUPPORTED_VERSION
34
33
  raise <<~EOF
@@ -49,7 +48,6 @@ module Inspec
49
48
  EOF
50
49
  end
51
50
  end
52
- # rubocop:enable Style/GuardClause
53
51
 
54
52
  attr_reader :version, :deps
55
53
  def initialize(lockfile_content_hash)
@@ -18,6 +18,14 @@ module Inspec
18
18
  # We cannot rely on libraries residing on disk however.
19
19
  # TODO: Sandboxing.
20
20
  content, path, line = @require_loader.load(rbpath)
21
+
22
+ # If we are in the realm of libraries and the LibraryEvalContext
23
+ # we should have access to the __inspec_binding, which is a Binding
24
+ # context that provides the correct plane to evaluate all required files to.
25
+ # It will ensure that embedded calls to `require` still call this
26
+ # method and get loaded from their correct paths.
27
+ return __inspec_binding.eval(content, path, line) if defined?(__inspec_binding)
28
+
21
29
  eval(content, TOPLEVEL_BINDING, path, line) # rubocop:disable Security/Eval
22
30
  end
23
31
  end
@@ -37,11 +37,22 @@ module Inspec
37
37
  include Inspec::DSL::RequireOverride
38
38
  def initialize(require_loader)
39
39
  @require_loader = require_loader
40
+ @inspec_binding = nil
41
+ end
42
+
43
+ def __inspec_binding
44
+ @inspec_binding
40
45
  end
41
46
  end
42
47
 
43
48
  c3.const_set(:Inspec, c2)
44
- c3.new(require_loader)
49
+ res = c3.new(require_loader)
50
+
51
+ # Provide the local binding for this context which is necessary for
52
+ # calls to `require` to create all dependent objects in the correct
53
+ # context.
54
+ res.instance_variable_set('@inspec_binding', res.instance_eval('binding'))
55
+ res
45
56
  end
46
57
  end
47
58
  end
@@ -14,7 +14,7 @@ module Inspec
14
14
  # A Metadata object may be created and finalized with invalid data.
15
15
  # This allows the check CLI command to analyse the issues.
16
16
  # Use valid? to determine if the metadata is coherent.
17
- class Metadata # rubocop:disable Metrics/ClassLength
17
+ class Metadata
18
18
  attr_reader :ref
19
19
  attr_accessor :params, :content
20
20
  def initialize(ref, logger = nil)
@@ -36,6 +36,7 @@ module Inspec
36
36
  summary
37
37
  description
38
38
  version
39
+ inspec_version
39
40
  }.each do |name|
40
41
  define_method name.to_sym do |arg|
41
42
  params[name.to_sym] = arg
@@ -52,38 +53,16 @@ module Inspec
52
53
  # already.
53
54
  end
54
55
 
55
- def is_supported?(os, entry)
56
- name = entry[:'os-name'] || entry[:os]
57
- family = entry[:'os-family']
58
- release = entry[:release]
59
-
60
- # return true if the backend matches the supported OS's
61
- # fields act as masks, i.e. any value configured for os-name, os-family,
62
- # or release must be met by the backend; any field that is nil acts as
63
- # a glob expression i.e. is true
64
-
65
- # os name is both saved in :family and :name, so check both
66
- name_ok = name.nil? ||
67
- os[:name] == name || os[:family] == name
68
-
69
- family_check = family.to_s + '?'
70
- family_ok = family.nil? || os[:family] == family ||
71
- (
72
- os.respond_to?(family_check) &&
73
- # this call will return true if the family matches
74
- os.method(family_check).call
75
- )
76
-
77
- # ensure we do have a string if we have a non-nil value eg. 16.06
78
- release_ok = release.nil? || os[:release] == release
79
-
80
- # we want to make sure that all matchers are true
81
- name_ok && family_ok && release_ok
82
- end
83
-
84
56
  def inspec_requirement
85
- inspec = params[:supports].find { |x| !x[:inspec].nil? } || {}
86
- Gem::Requirement.create(inspec[:inspec])
57
+ inspec_in_supports = params[:supports].find { |x| !x[:inspec].nil? }
58
+ if inspec_in_supports
59
+ Inspec::Log.warn '[DEPRECATED] The use of inspec.yml `supports:inspec` is deprecated and will be removed in InSpec 2.0. Please use `inspec_version` instead.'
60
+ Gem::Requirement.create(inspec_in_supports[:inspec])
61
+ else
62
+ # using Gem::Requirement here to allow nil values which
63
+ # translate to [">= 0"]
64
+ Gem::Requirement.create(params[:inspec_version])
65
+ end
87
66
  end
88
67
 
89
68
  def supports_runtime?
@@ -91,18 +70,8 @@ module Inspec
91
70
  inspec_requirement.satisfied_by?(running)
92
71
  end
93
72
 
94
- def supports_transport?(backend)
95
- # with no supports specified, always return true, as there are no
96
- # constraints on the supported backend; it is equivalent to putting
97
- # all fields into accept-all mode
98
- return true if params[:supports].empty?
99
-
100
- found = params[:supports].find do |entry|
101
- is_supported?(backend.os, entry)
102
- end
103
-
104
- # finally, if we found a supported entry, we are good to go
105
- !found.nil?
73
+ def supports_platform?(backend)
74
+ backend.platform.supported?(params[:supports])
106
75
  end
107
76
 
108
77
  # return all warn and errors
@@ -27,7 +27,7 @@ module Inspec
27
27
  end
28
28
 
29
29
  def default
30
- @opts[:default] || DEFAULT_ATTRIBUTE.new
30
+ @opts.key?(:default) ? @opts[:default] : DEFAULT_ATTRIBUTE.new
31
31
  end
32
32
 
33
33
  def title
@@ -28,6 +28,12 @@ module Inspec
28
28
  __resource_registry[@name].desc(description)
29
29
  end
30
30
 
31
+ def supports(criteria = nil)
32
+ return if criteria.nil?
33
+ Inspec::Resource.supports[@name] ||= []
34
+ Inspec::Resource.supports[@name].push(criteria)
35
+ end
36
+
31
37
  def example(example = nil)
32
38
  return if example.nil?
33
39
  __resource_registry[@name].example(example)
@@ -37,18 +43,22 @@ module Inspec
37
43
  Inspec::Resource.registry
38
44
  end
39
45
 
40
- def __register(name, obj) # rubocop:disable Metrics/MethodLength
41
- cl = Class.new(obj) do
46
+ def __register(name, obj) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
47
+ cl = Class.new(obj) do # rubocop:disable Metrics/BlockLength
42
48
  attr_reader :resource_exception_message
43
49
 
44
50
  def initialize(backend, name, *args)
45
51
  @resource_skipped = false
46
52
  @resource_failed = false
53
+ @supports = Inspec::Resource.supports[name]
47
54
 
48
55
  # attach the backend to this instance
49
56
  @__backend_runner__ = backend
50
57
  @__resource_name__ = name
51
58
 
59
+ # check resource supports
60
+ check_supports unless @supports.nil?
61
+
52
62
  # call the resource initializer
53
63
  begin
54
64
  super(*args)
@@ -69,6 +79,12 @@ module Inspec
69
79
  @example = example
70
80
  end
71
81
 
82
+ def check_supports
83
+ status = inspec.platform.supported?(@supports)
84
+ skip_msg = "Resource #{@__resource_name__.capitalize} is not supported on platform #{inspec.platform.name}/#{inspec.platform.release}."
85
+ skip_resource(skip_msg) unless status
86
+ end
87
+
72
88
  def skip_resource(message)
73
89
  @resource_skipped = true
74
90
  @resource_exception_message = message
@@ -21,7 +21,7 @@ require 'inspec/dependencies/lockfile'
21
21
  require 'inspec/dependencies/dependency_set'
22
22
 
23
23
  module Inspec
24
- class Profile # rubocop:disable Metrics/ClassLength
24
+ class Profile
25
25
  extend Forwardable
26
26
 
27
27
  def self.resolve_target(target, cache)
@@ -43,7 +43,7 @@ module Inspec
43
43
  next if content[key].nil?
44
44
  # remove prefix
45
45
  rel = Pathname.new(key).relative_path_from(Pathname.new('vendor')).to_s
46
- tar = Pathname.new(opts[:cache].path).join(rel)
46
+ tar = Pathname.new(opts[:vendor_cache].path).join(rel)
47
47
 
48
48
  FileUtils.mkdir_p tar.dirname.to_s
49
49
  Inspec::Log.debug "Copy #{tar} to cache directory"
@@ -56,7 +56,7 @@ module Inspec
56
56
  rp = file_provider.relative_provider
57
57
 
58
58
  # copy embedded dependecies into global cache
59
- copy_deps_into_cache(rp, opts) unless opts[:cache].nil?
59
+ copy_deps_into_cache(rp, opts) unless opts[:vendor_cache].nil?
60
60
 
61
61
  reader = Inspec::SourceReader.resolve(rp)
62
62
  if reader.nil?
@@ -67,14 +67,14 @@ module Inspec
67
67
  end
68
68
 
69
69
  def self.for_fetcher(fetcher, opts)
70
- opts[:cache] = opts[:cache] || Cache.new
70
+ opts[:vendor_cache] = opts[:vendor_cache] || Cache.new
71
71
  path, writable = fetcher.fetch
72
72
  for_path(path, opts.merge(target: fetcher.target, writable: writable))
73
73
  end
74
74
 
75
75
  def self.for_target(target, opts = {})
76
- opts[:cache] = opts[:cache] || Cache.new
77
- fetcher = resolve_target(target, opts[:cache])
76
+ opts[:vendor_cache] = opts[:vendor_cache] || Cache.new
77
+ fetcher = resolve_target(target, opts[:vendor_cache])
78
78
  for_fetcher(fetcher, opts)
79
79
  end
80
80
 
@@ -92,7 +92,7 @@ module Inspec
92
92
  @controls = options[:controls] || []
93
93
  @writable = options[:writable] || false
94
94
  @profile_id = options[:id]
95
- @cache = options[:cache] || Cache.new
95
+ @cache = options[:vendor_cache] || Cache.new
96
96
  @attr_values = options[:attributes]
97
97
  @tests_collected = false
98
98
  @libraries_loaded = false
@@ -136,15 +136,21 @@ module Inspec
136
136
  # @returns [TrueClass, FalseClass]
137
137
  #
138
138
  def supported?
139
- supports_os? && supports_runtime?
139
+ supports_platform? && supports_runtime?
140
140
  end
141
141
 
142
- def supports_os?
143
- metadata.supports_transport?(@backend)
142
+ def supports_platform?
143
+ if @supports_platform.nil?
144
+ @supports_platform = metadata.supports_platform?(@backend)
145
+ end
146
+ @supports_platform
144
147
  end
145
148
 
146
149
  def supports_runtime?
147
- metadata.supports_runtime?
150
+ if @supports_runtime.nil?
151
+ @supports_runtime = metadata.supports_runtime?
152
+ end
153
+ @supports_runtime
148
154
  end
149
155
 
150
156
  def params
@@ -11,7 +11,7 @@ require 'securerandom'
11
11
  require 'inspec/objects/attribute'
12
12
 
13
13
  module Inspec
14
- class ProfileContext # rubocop:disable Metrics/ClassLength
14
+ class ProfileContext
15
15
  def self.for_profile(profile, backend, attributes)
16
16
  new(profile.name, backend, { 'profile' => profile,
17
17
  'attributes' => attributes,
@@ -63,10 +63,16 @@ module Inspec
63
63
  @control_eval_context = nil
64
64
  end
65
65
 
66
- def profile_supports_os?
66
+ def profile_supports_platform?
67
67
  return true if @conf['profile'].nil?
68
68
 
69
- @conf['profile'].supports_os?
69
+ @conf['profile'].supports_platform?
70
+ end
71
+
72
+ def profile_supports_inspec_version?
73
+ return true if @conf['profile'].nil?
74
+
75
+ @conf['profile'].supports_runtime?
70
76
  end
71
77
 
72
78
  def remove_rule(id)
@@ -48,7 +48,7 @@ module Inspec
48
48
 
49
49
  def profile_opts
50
50
  {
51
- cache: Inspec::Cache.new(cache_path.to_s),
51
+ vendor_cache: Inspec::Cache.new(cache_path.to_s),
52
52
  backend: Inspec::Backend.create(target: 'mock://'),
53
53
  }
54
54
  end
@@ -16,6 +16,10 @@ module Inspec
16
16
  @registry ||= default_registry
17
17
  end
18
18
 
19
+ def self.supports
20
+ @supports ||= {}
21
+ end
22
+
19
23
  def self.new_registry
20
24
  default_registry.dup
21
25
  end
@@ -131,6 +135,7 @@ require 'resources/packages'
131
135
  require 'resources/parse_config'
132
136
  require 'resources/passwd'
133
137
  require 'resources/pip'
138
+ require 'resources/platform'
134
139
  require 'resources/port'
135
140
  require 'resources/postgres'
136
141
  require 'resources/postgres_conf'
@@ -110,7 +110,7 @@ class InspecRspecMiniJson < RSpec::Core::Formatters::JsonFormatter
110
110
  end
111
111
  end
112
112
 
113
- class InspecRspecJson < InspecRspecMiniJson # rubocop:disable Metrics/ClassLength
113
+ class InspecRspecJson < InspecRspecMiniJson
114
114
  RSpec::Core::Formatters.register self, :stop, :dump_summary
115
115
  attr_writer :backend
116
116
 
@@ -279,7 +279,7 @@ class InspecRspecJson < InspecRspecMiniJson # rubocop:disable Metrics/ClassLengt
279
279
  end
280
280
  end
281
281
 
282
- class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
282
+ class InspecRspecCli < InspecRspecJson
283
283
  RSpec::Core::Formatters.register self, :close
284
284
 
285
285
  case RUBY_PLATFORM
@@ -685,7 +685,7 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
685
685
  # This class wraps a control hash object to provide a useful inteface for
686
686
  # maintaining the associated profile, ids, results, title, etc.
687
687
  #
688
- class Control # rubocop:disable Metrics/ClassLength
688
+ class Control
689
689
  include Comparable
690
690
 
691
691
  STATUS_TYPES = {
@@ -8,7 +8,7 @@ require 'inspec/describe'
8
8
  require 'inspec/expect'
9
9
 
10
10
  module Inspec
11
- class Rule # rubocop:disable Metrics/ClassLength
11
+ class Rule
12
12
  include ::RSpec::Matchers
13
13
 
14
14
  #
@@ -28,7 +28,7 @@ module Inspec
28
28
  # r.run
29
29
  # ```
30
30
  #
31
- class Runner # rubocop:disable Metrics/ClassLength
31
+ class Runner
32
32
  extend Forwardable
33
33
 
34
34
  def_delegator :@test_collector, :report
@@ -40,9 +40,10 @@ module Inspec
40
40
  @conf[:logger] ||= Logger.new(nil)
41
41
  @target_profiles = []
42
42
  @controls = @conf[:controls] || []
43
+ @depends = @conf[:depends] || []
43
44
  @ignore_supports = @conf[:ignore_supports]
44
45
  @create_lockfile = @conf[:create_lockfile]
45
- @cache = Inspec::Cache.new(@conf[:cache])
46
+ @cache = Inspec::Cache.new(@conf[:vendor_cache])
46
47
  @test_collector = @conf.delete(:test_collector) || begin
47
48
  require 'inspec/runner_rspec'
48
49
  RunnerRspec.new(@conf)
@@ -168,7 +169,7 @@ module Inspec
168
169
  #
169
170
  def add_target(target, _opts = [])
170
171
  profile = Inspec::Profile.for_target(target,
171
- cache: @cache,
172
+ vendor_cache: @cache,
172
173
  backend: @backend,
173
174
  controls: @controls,
174
175
  attributes: @conf[:attributes])
@@ -185,8 +186,8 @@ module Inspec
185
186
  "InSpec v#{Inspec::VERSION}.\n"
186
187
  end
187
188
 
188
- if !profile.supports_os?
189
- raise "This OS/platform (#{@backend.os[:name]}) is not supported by this profile."
189
+ if !profile.supports_platform?
190
+ raise "This OS/platform (#{@backend.platform.name}/#{@backend.platform.release}) is not supported by this profile."
190
191
  end
191
192
 
192
193
  true
@@ -214,6 +215,13 @@ module Inspec
214
215
  add_target({ 'inspec.yml' => 'name: inspec-shell' })
215
216
  our_profile = @target_profiles.first
216
217
  ctx = our_profile.runner_context
218
+
219
+ # Load local profile dependencies. This is used in inspec shell
220
+ # to provide access to local profiles that add resources.
221
+ @depends
222
+ .map { |x| Inspec::Profile.for_path(x, { profile_context: ctx }) }
223
+ .each(&:load_libraries)
224
+
217
225
  ctx.load(command)
218
226
  end
219
227