inspec 0.32.0 → 0.33.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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