inspec 0.32.0 → 0.33.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +46 -2
- data/Gemfile +2 -1
- data/README.md +1 -1
- data/docs/dsl_inspec.rst +21 -0
- data/docs/resources.rst +3 -3
- data/docs/ruby_usage.rst +1 -1
- data/inspec.gemspec +1 -1
- data/lib/bundles/inspec-compliance/http.rb +2 -0
- data/lib/inspec/base_cli.rb +1 -1
- data/lib/inspec/control_eval_context.rb +145 -0
- data/lib/inspec/dependencies/dependency_set.rb +21 -6
- data/lib/inspec/dependencies/requirement.rb +13 -6
- data/lib/inspec/dependencies/resolver.rb +2 -2
- data/lib/inspec/dsl.rb +3 -32
- data/lib/inspec/dsl_shared.rb +25 -0
- data/lib/inspec/library_eval_context.rb +47 -0
- data/lib/inspec/plugins/resource.rb +63 -63
- data/lib/inspec/profile.rb +61 -31
- data/lib/inspec/profile_context.rb +48 -140
- data/lib/inspec/resource.rb +13 -7
- data/lib/inspec/rspec_json_formatter.rb +37 -6
- data/lib/inspec/rule.rb +4 -0
- data/lib/inspec/runner.rb +86 -86
- data/lib/inspec/version.rb +1 -1
- data/lib/matchers/matchers.rb +1 -1
- data/lib/resources/apache_conf.rb +1 -1
- data/lib/resources/mysql.rb +1 -1
- data/lib/resources/powershell.rb +3 -7
- data/lib/resources/service.rb +3 -3
- data/lib/resources/vbscript.rb +17 -1
- metadata +7 -4
@@ -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
|
-
|
33
|
+
#{dependencies.list.keys.join("\n ")}
|
47
34
|
EOF
|
48
35
|
end
|
49
36
|
|
50
|
-
context =
|
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
|
-
|
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
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
31
|
+
def example(example = nil)
|
32
|
+
return if example.nil?
|
33
|
+
__resource_registry[@name].example(example)
|
34
|
+
end
|
41
35
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
36
|
+
def __resource_registry
|
37
|
+
Inspec::Resource.registry
|
38
|
+
end
|
46
39
|
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
51
|
+
def self.desc(description = nil)
|
52
|
+
return @description if description.nil?
|
53
|
+
@description = description
|
54
|
+
end
|
58
55
|
|
59
|
-
|
60
|
-
|
56
|
+
def self.example(example = nil)
|
57
|
+
return @example if example.nil?
|
58
|
+
@example = example
|
59
|
+
end
|
61
60
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
61
|
+
def resource_skipped
|
62
|
+
@resource_skipped
|
63
|
+
end
|
66
64
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
def inspect
|
71
|
-
to_s
|
72
|
-
end
|
73
|
-
end
|
65
|
+
def skip_resource(message)
|
66
|
+
@resource_skipped = message
|
67
|
+
end
|
74
68
|
|
75
|
-
|
76
|
-
|
77
|
-
|
69
|
+
def inspec
|
70
|
+
@__backend_runner__
|
71
|
+
end
|
78
72
|
end
|
79
73
|
|
80
|
-
|
81
|
-
|
82
|
-
|
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
|
data/lib/inspec/profile.rb
CHANGED
@@ -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
|
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
|
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
|
-
@
|
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
|
-
|
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] =
|
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
|