inspec 0.32.0 → 0.33.0

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.
@@ -23,9 +23,9 @@ module Inspec
23
23
  # implementation of the fetcher being used.
24
24
  #
25
25
  class Resolver
26
- def self.resolve(dependencies, vendor_index, working_dir)
26
+ def self.resolve(dependencies, vendor_index, working_dir, backend)
27
27
  reqs = dependencies.map do |dep|
28
- req = Inspec::Requirement.from_metadata(dep, vendor_index, cwd: working_dir)
28
+ req = Inspec::Requirement.from_metadata(dep, vendor_index, cwd: working_dir, backend: backend)
29
29
  req || fail("Cannot initialize dependency: #{req}")
30
30
  end
31
31
  new.resolve(reqs)
data/lib/inspec/dsl.rb CHANGED
@@ -18,19 +18,6 @@ module Inspec::DSL
18
18
  alias require_rules require_controls
19
19
  alias include_rules include_controls
20
20
 
21
- def self.rule_from_check(m, a, b)
22
- if a.is_a?(Array) && !a.empty? &&
23
- a[0].respond_to?(:resource_skipped) &&
24
- !a[0].resource_skipped.nil?
25
- ::Inspec::Rule.__send__(m, *a) do
26
- it a[0].resource_skipped
27
- end
28
- else
29
- # execute the method
30
- ::Inspec::Rule.__send__(m, *a, &b)
31
- end
32
- end
33
-
34
21
  def self.load_spec_files_for_profile(bind_context, opts, &block)
35
22
  dependencies = opts[:dependencies]
36
23
  profile_id = opts[:profile_id]
@@ -43,25 +30,21 @@ of #{bind_context.profile_name}.
43
30
 
44
31
  Dependencies available from this context are:
45
32
 
46
- #{dependencies.list.keys.join("\n ")}
33
+ #{dependencies.list.keys.join("\n ")}
47
34
  EOF
48
35
  end
49
36
 
50
- context = load_profile_context(dep_entry.profile, opts[:backend])
51
-
37
+ context = dep_entry.profile.runner_context
52
38
  # if we don't want all the rules, then just make 1 pass to get all rule_IDs
53
39
  # that we want to keep from the original
54
40
  filter_included_controls(context, dep_entry.profile, &block) if !opts[:include_all]
55
-
56
41
  # interpret the block and skip/modify as required
57
42
  context.load(block) if block_given?
58
-
59
43
  bind_context.add_subcontext(context)
60
44
  end
61
45
 
62
46
  def self.filter_included_controls(context, profile, &block)
63
- mock = Inspec::Backend.create({ backend: 'mock' })
64
- include_ctx = Inspec::ProfileContext.for_profile(profile, mock)
47
+ include_ctx = profile.runner_context
65
48
  include_ctx.load(block) if block_given?
66
49
  # remove all rules that were not registered
67
50
  context.rules.keys.each do |id|
@@ -70,16 +53,4 @@ EOF
70
53
  end
71
54
  end
72
55
  end
73
-
74
- def self.load_profile_context(profile, backend)
75
- ctx = Inspec::ProfileContext.for_profile(profile, backend)
76
- profile.libraries.each do |path, content|
77
- ctx.load(content.to_s, path, 1)
78
- ctx.reload_dsl
79
- end
80
- profile.tests.each do |path, content|
81
- ctx.load(content.to_s, path, 1)
82
- end
83
- ctx
84
- end
85
56
  end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ module Inspec
3
+ #
4
+ # Contains methods we would like in multiple DSL
5
+ #
6
+ module DSL
7
+ module RequireOverride
8
+ # Save the toplevel require method to load all ruby dependencies.
9
+ # It is used whenever the `require 'lib'` is not in libraries.
10
+ alias __ruby_require require
11
+
12
+ def require(path)
13
+ rbpath = path + '.rb'
14
+ return __ruby_require(path) if !@require_loader.exists?(rbpath)
15
+ return false if @require_loader.loaded?(rbpath)
16
+
17
+ # This is equivalent to calling `require 'lib'` with lib on disk.
18
+ # We cannot rely on libraries residing on disk however.
19
+ # TODO: Sandboxing.
20
+ content, path, line = @require_loader.load(rbpath)
21
+ eval(content, TOPLEVEL_BINDING, path, line) # rubocop:disable Lint/Eval
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+ # author: Steven Danna
3
+ # author: Victoria Jeffrey
4
+ require 'inspec/plugins/resource'
5
+ require 'inspec/dsl_shared'
6
+
7
+ module Inspec
8
+ #
9
+ # LibaryEvalContext constructs an instance of an anonymous class
10
+ # that library files will be instance_exec'd against.
11
+ #
12
+ # The anonymous class ensures that `Inspec.resource(1)` will return
13
+ # an anonymouse class that is suitable as the parent class of an
14
+ # inspec resource. The class returned will have the resource
15
+ # registry used by all dsl methods bound to the resource registry
16
+ # passed into the #create constructor.
17
+ #
18
+ #
19
+ class LibraryEvalContext
20
+ def self.create(registry, require_loader)
21
+ c = Class.new do
22
+ extend Inspec::ResourceDSL
23
+ include Inspec::ResourceBehaviors
24
+ define_singleton_method :__resource_registry do
25
+ registry
26
+ end
27
+ end
28
+
29
+ c2 = Class.new do
30
+ define_singleton_method :resource do |version|
31
+ Inspec.validate_resource_dsl_version!(version)
32
+ c
33
+ end
34
+ end
35
+
36
+ c3 = Class.new do
37
+ include Inspec::DSL::RequireOverride
38
+ def initialize(require_loader) # rubocop:disable Lint/NestedMethodDefinition
39
+ @require_loader = require_loader
40
+ end
41
+ end
42
+
43
+ c3.const_set(:Inspec, c2)
44
+ c3.new(require_loader)
45
+ end
46
+ end
47
+ end
@@ -3,83 +3,83 @@
3
3
  # author: Christoph Hartmann
4
4
 
5
5
  module Inspec
6
- module Plugins
7
- class Resource
8
- def self.name(name = nil)
9
- return if name.nil?
10
- @name = name
11
- Inspec::Plugins::Resource.__register(name, self)
12
- end
6
+ module ResourceBehaviors
7
+ def to_s
8
+ @__resource_name__
9
+ end
13
10
 
14
- def self.desc(description = nil)
15
- return if description.nil?
16
- Inspec::Resource.registry[@name].desc(description)
17
- end
11
+ # Overwrite inspect to provide better output to RSpec results.
12
+ #
13
+ # @return [String] full name of the resource
14
+ def inspect
15
+ to_s
16
+ end
17
+ end
18
18
 
19
- def self.example(example = nil)
20
- return if example.nil?
21
- Inspec::Resource.registry[@name].example(example)
22
- end
19
+ module ResourceDSL
20
+ def name(name = nil)
21
+ return if name.nil?
22
+ @name = name
23
+ __register(name, self)
24
+ end
23
25
 
24
- def self.__register(name, obj)
25
- # rubocop:disable Lint/NestedMethodDefinition, Lint/DuplicateMethods
26
- cl = Class.new(obj) do
27
- # add some common methods
28
- include Inspec::Plugins::ResourceCommon
29
- def initialize(backend, name, *args)
30
- # attach the backend to this instance
31
- @__backend_runner__ = backend
32
- @__resource_name__ = name
33
- # call the resource initializer
34
- super(*args)
35
- end
26
+ def desc(description = nil)
27
+ return if description.nil?
28
+ __resource_registry[@name].desc(description)
29
+ end
36
30
 
37
- def self.desc(description = nil)
38
- return @description if description.nil?
39
- @description = description
40
- end
31
+ def example(example = nil)
32
+ return if example.nil?
33
+ __resource_registry[@name].example(example)
34
+ end
41
35
 
42
- def self.example(example = nil)
43
- return @example if example.nil?
44
- @example = example
45
- end
36
+ def __resource_registry
37
+ Inspec::Resource.registry
38
+ end
46
39
 
47
- def inspec
48
- @__backend_runner__
49
- end
40
+ def __register(name, obj)
41
+ # rubocop:disable Lint/NestedMethodDefinition
42
+ cl = Class.new(obj) do
43
+ def initialize(backend, name, *args)
44
+ # attach the backend to this instance
45
+ @__backend_runner__ = backend
46
+ @__resource_name__ = name
47
+ # call the resource initializer
48
+ super(*args)
50
49
  end
51
- # rubocop:enable Lint/NestedMethodDefinition
52
50
 
53
- # add the resource to the registry by name with a newly-named registry class
54
- klass_name = name.split('_').map(&:capitalize).join
55
- Inspec::Resource::Registry.const_set(klass_name, cl)
56
- Inspec::Resource.registry[name] = Inspec::Resource::Registry.const_get(klass_name)
57
- end
51
+ def self.desc(description = nil)
52
+ return @description if description.nil?
53
+ @description = description
54
+ end
58
55
 
59
- # Define methods which are available to all resources
60
- # and may be overwritten.
56
+ def self.example(example = nil)
57
+ return @example if example.nil?
58
+ @example = example
59
+ end
61
60
 
62
- # Print the name of the resource
63
- def to_s
64
- @__resource_name__
65
- end
61
+ def resource_skipped
62
+ @resource_skipped
63
+ end
66
64
 
67
- # Overwrite inspect to provide better output to RSpec results.
68
- #
69
- # @return [String] full name of the resource
70
- def inspect
71
- to_s
72
- end
73
- end
65
+ def skip_resource(message)
66
+ @resource_skipped = message
67
+ end
74
68
 
75
- module ResourceCommon
76
- def resource_skipped
77
- @resource_skipped
69
+ def inspec
70
+ @__backend_runner__
71
+ end
78
72
  end
79
73
 
80
- def skip_resource(message)
81
- @resource_skipped = message
82
- end
74
+ # rubocop:enable Lint/NestedMethodDefinition
75
+ __resource_registry[name] = cl
76
+ end
77
+ end
78
+
79
+ module Plugins
80
+ class Resource
81
+ extend Inspec::ResourceDSL
82
+ include Inspec::ResourceBehaviors
83
83
  end
84
84
  end
85
85
  end
@@ -8,6 +8,9 @@ require 'inspec/polyfill'
8
8
  require 'inspec/fetcher'
9
9
  require 'inspec/source_reader'
10
10
  require 'inspec/metadata'
11
+ require 'inspec/backend'
12
+ require 'inspec/rule'
13
+ require 'inspec/profile_context'
11
14
  require 'inspec/dependencies/lockfile'
12
15
  require 'inspec/dependencies/dependency_set'
13
16
 
@@ -15,9 +18,8 @@ module Inspec
15
18
  class Profile # rubocop:disable Metrics/ClassLength
16
19
  extend Forwardable
17
20
 
18
- def self.resolve_target(target, opts)
21
+ def self.resolve_target(target)
19
22
  # Fetchers retrieve file contents
20
- opts[:target] = target
21
23
  fetcher = Inspec::Fetcher.resolve(target)
22
24
  if fetcher.nil?
23
25
  fail("Could not fetch inspec profile in #{target.inspect}.")
@@ -32,8 +34,8 @@ module Inspec
32
34
  reader
33
35
  end
34
36
 
35
- def self.for_target(target, opts)
36
- new(resolve_target(target, opts), opts)
37
+ def self.for_target(target, opts = {})
38
+ new(resolve_target(target), opts.merge(target: target))
37
39
  end
38
40
 
39
41
  attr_reader :source_reader
@@ -48,9 +50,14 @@ module Inspec
48
50
  @target = @options.delete(:target)
49
51
  @logger = @options[:logger] || Logger.new(nil)
50
52
  @source_reader = source_reader
53
+ if options[:dependencies]
54
+ @locked_dependencies = options[:dependencies]
55
+ end
56
+ @controls = options[:controls] || []
51
57
  @profile_id = @options[:id]
52
- @runner_context = nil
58
+ @backend = @options[:backend] || Inspec::Backend.create(options)
53
59
  Metadata.finalize(@source_reader.metadata, @profile_id)
60
+ @runner_context = @options[:profile_context] || Inspec::ProfileContext.for_profile(self, @backend)
54
61
  end
55
62
 
56
63
  def name
@@ -61,6 +68,46 @@ module Inspec
61
68
  @params ||= load_params
62
69
  end
63
70
 
71
+ def collect_tests(include_list = @controls)
72
+ if !@tests_collected
73
+ locked_dependencies.each(&:collect_tests)
74
+
75
+ tests.each do |path, content|
76
+ next if content.nil? || content.empty?
77
+ abs_path = source_reader.target.abs_path(path)
78
+ @runner_context.load_control_file(content, abs_path, nil)
79
+ end
80
+ @tests_collected = true
81
+ end
82
+ filter_controls(@runner_context.all_rules, include_list)
83
+ end
84
+
85
+ def filter_controls(controls_array, include_list)
86
+ return controls_array if include_list.nil? || include_list.empty?
87
+ controls_array.select do |c|
88
+ id = ::Inspec::Rule.rule_id(c)
89
+ include_list.include?(id)
90
+ end
91
+ end
92
+
93
+ def load_libraries
94
+ locked_dependencies.each do |d|
95
+ c = d.load_libraries
96
+ @runner_context.add_resources(c)
97
+ end
98
+
99
+ libs = libraries.map do |path, content|
100
+ [content, path]
101
+ end
102
+
103
+ @runner_context.load_libraries(libs)
104
+ @runner_context
105
+ end
106
+
107
+ def to_s
108
+ "Inspec::Profile<#{name}>"
109
+ end
110
+
64
111
  def info
65
112
  res = params.dup
66
113
  # add information about the controls
@@ -249,11 +296,15 @@ module Inspec
249
296
  # @return [Inspec::Lockfile]
250
297
  #
251
298
  def generate_lockfile(vendor_path = nil)
252
- res = Inspec::DependencySet.new(cwd, vendor_path)
299
+ res = Inspec::DependencySet.new(cwd, vendor_path, nil, @backend)
253
300
  res.vendor(metadata.dependencies)
254
301
  Inspec::Lockfile.from_dependency_set(res)
255
302
  end
256
303
 
304
+ def load_dependencies
305
+ Inspec::DependencySet.from_lockfile(lockfile, cwd, nil, @backend)
306
+ end
307
+
257
308
  private
258
309
 
259
310
  # Create an archive name for this profile and an additional options
@@ -282,34 +333,17 @@ module Inspec
282
333
  params
283
334
  end
284
335
 
285
- #
286
- # Returns a new runner for the current profile.
287
- #
288
- # @params [Symbol] The type of backend to use when constructing a
289
- # new runner.
290
- # @returns [Inspec::Runner]
291
- #
292
- def runner_for_profile(backend = :mock)
293
- opts = @options.dup
294
- opts[:ignore_supports] = true
295
- r = Runner.new(id: @profile_id,
296
- backend: backend,
297
- test_collector: opts.delete(:test_collector))
298
- r.add_profile(self, opts)
299
- r
300
- end
301
-
302
336
  def load_checks_params(params)
337
+ load_libraries
338
+ tests = collect_tests
303
339
  params[:controls] = controls = {}
304
340
  params[:groups] = groups = {}
305
341
  prefix = @source_reader.target.prefix || ''
306
- # Load from the runner_context if it exists
307
- runner = @runner_context || runner_for_profile
308
- runner.all_rules.each do |rule|
342
+ tests.each do |rule|
309
343
  f = load_rule_filepath(prefix, rule)
310
344
  load_rule(rule, f, controls, groups)
311
345
  end
312
- params[:attributes] = runner.attributes
346
+ params[:attributes] = @runner_context.attributes
313
347
  params
314
348
  end
315
349
 
@@ -338,9 +372,5 @@ module Inspec
338
372
  }
339
373
  groups[file][:controls].push(id)
340
374
  end
341
-
342
- def load_dependencies
343
- Inspec::DependencySet.from_lockfile(lockfile, cwd, nil)
344
- end
345
375
  end
346
376
  end