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
@@ -3,7 +3,9 @@
|
|
3
3
|
# author: Christoph Hartmann
|
4
4
|
require 'inspec/log'
|
5
5
|
require 'inspec/rule'
|
6
|
-
require 'inspec/
|
6
|
+
require 'inspec/resource'
|
7
|
+
require 'inspec/library_eval_context'
|
8
|
+
require 'inspec/control_eval_context'
|
7
9
|
require 'inspec/require_loader'
|
8
10
|
require 'securerandom'
|
9
11
|
require 'inspec/objects/attribute'
|
@@ -14,7 +16,7 @@ module Inspec
|
|
14
16
|
new(profile.name, backend, { 'profile' => profile })
|
15
17
|
end
|
16
18
|
|
17
|
-
attr_reader :attributes, :rules, :profile_id
|
19
|
+
attr_reader :attributes, :rules, :profile_id, :resource_registry
|
18
20
|
def initialize(profile_id, backend, conf)
|
19
21
|
if backend.nil?
|
20
22
|
fail 'ProfileContext is initiated with a backend == nil. ' \
|
@@ -25,17 +27,35 @@ module Inspec
|
|
25
27
|
@conf = conf.dup
|
26
28
|
@rules = {}
|
27
29
|
@subcontexts = []
|
28
|
-
@dependencies = {}
|
29
|
-
@dependencies = conf['profile'].locked_dependencies unless conf['profile'].nil?
|
30
30
|
@require_loader = ::Inspec::RequireLoader.new
|
31
31
|
@attributes = []
|
32
|
-
|
32
|
+
# A local resource registry that only contains resources defined
|
33
|
+
# in the transitive dependency tree of the loaded profile.
|
34
|
+
@resource_registry = Inspec::Resource.new_registry
|
35
|
+
@library_eval_context = Inspec::LibraryEvalContext.create(@resource_registry, @require_loader)
|
36
|
+
end
|
37
|
+
|
38
|
+
def dependencies
|
39
|
+
if @conf['profile'].nil?
|
40
|
+
{}
|
41
|
+
else
|
42
|
+
@conf['profile'].locked_dependencies
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_resources_dsl
|
47
|
+
Inspec::Resource.create_dsl(@backend, @resource_registry)
|
48
|
+
end
|
49
|
+
|
50
|
+
def control_eval_context
|
51
|
+
@control_eval_context ||= begin
|
52
|
+
ctx = Inspec::ControlEvalContext.create(self, to_resources_dsl)
|
53
|
+
ctx.new(@backend, @conf, dependencies, @require_loader)
|
54
|
+
end
|
33
55
|
end
|
34
56
|
|
35
57
|
def reload_dsl
|
36
|
-
|
37
|
-
ctx = create_context(resources_dsl, rule_context(resources_dsl))
|
38
|
-
@profile_context = ctx.new(@backend, @conf, @dependencies, @require_loader)
|
58
|
+
@control_eval_context = nil
|
39
59
|
end
|
40
60
|
|
41
61
|
def all_rules
|
@@ -44,6 +64,12 @@ module Inspec
|
|
44
64
|
ret
|
45
65
|
end
|
46
66
|
|
67
|
+
def add_resources(context)
|
68
|
+
@resource_registry.merge!(context.resource_registry)
|
69
|
+
control_eval_context.add_resources(context)
|
70
|
+
reload_dsl
|
71
|
+
end
|
72
|
+
|
47
73
|
def add_subcontext(context)
|
48
74
|
@subcontexts << context
|
49
75
|
end
|
@@ -65,21 +91,29 @@ module Inspec
|
|
65
91
|
# load all files directly that are flat inside the libraries folder
|
66
92
|
autoloads.each do |path|
|
67
93
|
next unless path.end_with?('.rb')
|
68
|
-
|
94
|
+
load_library_file(*@require_loader.load(path)) unless @require_loader.loaded?(path)
|
69
95
|
end
|
70
|
-
|
71
96
|
reload_dsl
|
72
97
|
end
|
73
98
|
|
74
|
-
def
|
99
|
+
def load_control_file(*args)
|
100
|
+
load_with_context(control_eval_context, *args)
|
101
|
+
end
|
102
|
+
alias load load_control_file
|
103
|
+
|
104
|
+
def load_library_file(*args)
|
105
|
+
load_with_context(@library_eval_context, *args)
|
106
|
+
end
|
107
|
+
|
108
|
+
def load_with_context(context, content, source = nil, line = nil)
|
75
109
|
Inspec::Log.debug("Loading #{source || '<anonymous content>'} into #{self}")
|
76
110
|
@current_load = { file: source }
|
77
111
|
if content.is_a? Proc
|
78
|
-
|
112
|
+
context.instance_eval(&content)
|
79
113
|
elsif source.nil? && line.nil?
|
80
|
-
|
114
|
+
context.instance_eval(content)
|
81
115
|
else
|
82
|
-
|
116
|
+
context.instance_eval(content, source || 'unknown', line || 1)
|
83
117
|
end
|
84
118
|
end
|
85
119
|
|
@@ -121,131 +155,5 @@ module Inspec
|
|
121
155
|
return rid.to_s if pid.to_s.empty?
|
122
156
|
pid.to_s + '/' + rid.to_s
|
123
157
|
end
|
124
|
-
|
125
|
-
# Create the context for controls. This includes all components of the DSL,
|
126
|
-
# including matchers and resources.
|
127
|
-
#
|
128
|
-
# @param [ResourcesDSL] resources_dsl which has all resources to attach
|
129
|
-
# @return [RuleContext] the inner context of rules
|
130
|
-
def rule_context(resources_dsl)
|
131
|
-
require 'rspec/core/dsl'
|
132
|
-
Class.new(Inspec::Rule) do
|
133
|
-
include RSpec::Core::DSL
|
134
|
-
include resources_dsl
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
# Creates the heart of the profile context:
|
139
|
-
# An instantiated object which has all resources registered to it
|
140
|
-
# and exposes them to the a test file. The profile context serves as a
|
141
|
-
# container for all profiles which are registered. Within the context
|
142
|
-
# profiles get access to all DSL calls for creating tests and controls.
|
143
|
-
#
|
144
|
-
# @param outer_dsl [OuterDSLClass]
|
145
|
-
# @return [ProfileContextClass]
|
146
|
-
def create_context(resources_dsl, rule_class) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
147
|
-
profile_context_owner = self
|
148
|
-
profile_id = @profile_id
|
149
|
-
|
150
|
-
# rubocop:disable Lint/NestedMethodDefinition
|
151
|
-
Class.new do
|
152
|
-
include Inspec::DSL
|
153
|
-
include resources_dsl
|
154
|
-
|
155
|
-
def initialize(backend, conf, dependencies, require_loader) # rubocop:disable Lint/NestedMethodDefinition, Lint/DuplicateMethods
|
156
|
-
@backend = backend
|
157
|
-
@conf = conf
|
158
|
-
@dependencies = dependencies
|
159
|
-
@require_loader = require_loader
|
160
|
-
@skip_profile = false
|
161
|
-
end
|
162
|
-
|
163
|
-
# Save the toplevel require method to load all ruby dependencies.
|
164
|
-
# It is used whenever the `require 'lib'` is not in libraries.
|
165
|
-
alias_method :__ruby_require, :require
|
166
|
-
|
167
|
-
def require(path)
|
168
|
-
rbpath = path + '.rb'
|
169
|
-
return __ruby_require(path) if !@require_loader.exists?(rbpath)
|
170
|
-
return false if @require_loader.loaded?(rbpath)
|
171
|
-
|
172
|
-
# This is equivalent to calling `require 'lib'` with lib on disk.
|
173
|
-
# We cannot rely on libraries residing on disk however.
|
174
|
-
# TODO: Sandboxing.
|
175
|
-
content, path, line = @require_loader.load(rbpath)
|
176
|
-
eval(content, TOPLEVEL_BINDING, path, line) # rubocop:disable Lint/Eval
|
177
|
-
end
|
178
|
-
|
179
|
-
define_method :title do |arg|
|
180
|
-
profile_context_owner.set_header(:title, arg)
|
181
|
-
end
|
182
|
-
|
183
|
-
def to_s
|
184
|
-
"Profile Context Run #{profile_name}"
|
185
|
-
end
|
186
|
-
|
187
|
-
define_method :profile_name do
|
188
|
-
profile_id
|
189
|
-
end
|
190
|
-
|
191
|
-
define_method :control do |*args, &block|
|
192
|
-
id = args[0]
|
193
|
-
opts = args[1] || {}
|
194
|
-
register_control(rule_class.new(id, profile_id, opts, &block))
|
195
|
-
end
|
196
|
-
|
197
|
-
define_method :describe do |*args, &block|
|
198
|
-
loc = block_location(block, caller[0])
|
199
|
-
id = "(generated from #{loc} #{SecureRandom.hex})"
|
200
|
-
|
201
|
-
res = nil
|
202
|
-
rule = rule_class.new(id, profile_id, {}) do
|
203
|
-
res = describe(*args, &block)
|
204
|
-
end
|
205
|
-
register_control(rule, &block)
|
206
|
-
|
207
|
-
res
|
208
|
-
end
|
209
|
-
|
210
|
-
define_method :add_subcontext do |context|
|
211
|
-
profile_context_owner.add_subcontext(context)
|
212
|
-
end
|
213
|
-
|
214
|
-
define_method :register_control do |control, &block|
|
215
|
-
::Inspec::Rule.set_skip_rule(control, true) if @skip_profile
|
216
|
-
|
217
|
-
profile_context_owner.register_rule(control, &block) unless control.nil?
|
218
|
-
end
|
219
|
-
|
220
|
-
# method for attributes; import attribute handling
|
221
|
-
define_method :attribute do |name, options|
|
222
|
-
profile_context_owner.register_attribute(name, options)
|
223
|
-
end
|
224
|
-
|
225
|
-
define_method :skip_control do |id|
|
226
|
-
profile_context_owner.unregister_rule(id)
|
227
|
-
end
|
228
|
-
|
229
|
-
def only_if
|
230
|
-
return unless block_given?
|
231
|
-
@skip_profile ||= !yield
|
232
|
-
end
|
233
|
-
|
234
|
-
alias_method :rule, :control
|
235
|
-
alias_method :skip_rule, :skip_control
|
236
|
-
|
237
|
-
private
|
238
|
-
|
239
|
-
def block_location(block, alternate_caller)
|
240
|
-
if block.nil?
|
241
|
-
alternate_caller[/^(.+:\d+):in .+$/, 1] || 'unknown'
|
242
|
-
else
|
243
|
-
path, line = block.source_location
|
244
|
-
"#{File.basename(path)}:#{line}"
|
245
|
-
end
|
246
|
-
end
|
247
|
-
end
|
248
|
-
# rubocop:enable all
|
249
|
-
end
|
250
158
|
end
|
251
159
|
end
|
data/lib/inspec/resource.rb
CHANGED
@@ -3,17 +3,20 @@
|
|
3
3
|
# license: All rights reserved
|
4
4
|
# author: Dominik Richter
|
5
5
|
# author: Christoph Hartmann
|
6
|
-
|
7
6
|
require 'inspec/plugins'
|
8
7
|
|
9
8
|
module Inspec
|
10
9
|
class Resource
|
11
|
-
|
12
|
-
|
10
|
+
def self.default_registry
|
11
|
+
@default_registry ||= {}
|
13
12
|
end
|
14
13
|
|
15
14
|
def self.registry
|
16
|
-
@registry ||=
|
15
|
+
@registry ||= default_registry
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.new_registry
|
19
|
+
default_registry.dup
|
17
20
|
end
|
18
21
|
|
19
22
|
# Creates the inner DSL which includes all resources for
|
@@ -22,9 +25,8 @@ module Inspec
|
|
22
25
|
#
|
23
26
|
# @param backend [BackendRunner] exposing the target to resources
|
24
27
|
# @return [ResourcesDSL]
|
25
|
-
def self.create_dsl(backend)
|
28
|
+
def self.create_dsl(backend, my_registry = registry)
|
26
29
|
# need the local name, to use it in the module creation further down
|
27
|
-
my_registry = registry
|
28
30
|
Module.new do
|
29
31
|
my_registry.each do |id, r|
|
30
32
|
define_method id.to_sym do |*args|
|
@@ -41,10 +43,14 @@ module Inspec
|
|
41
43
|
# @param [int] version the resource version to use
|
42
44
|
# @return [Resource] base class for creating a new resource
|
43
45
|
def self.resource(version)
|
46
|
+
validate_resource_dsl_version!(version)
|
47
|
+
Inspec::Plugins::Resource
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.validate_resource_dsl_version!(version)
|
44
51
|
if version != 1
|
45
52
|
fail 'Only resource version 1 is supported!'
|
46
53
|
end
|
47
|
-
Inspec::Plugins::Resource
|
48
54
|
end
|
49
55
|
end
|
50
56
|
|
@@ -164,10 +164,32 @@ class InspecRspecJson < InspecRspecMiniJson
|
|
164
164
|
[info[:name], info]
|
165
165
|
end
|
166
166
|
|
167
|
+
#
|
168
|
+
# TODO(ssd+vj): We should probably solve this by either ensuring the example has
|
169
|
+
# the profile_id of the top level profile when it is included as a dependency, or
|
170
|
+
# by registrying all dependent profiles with the formatter. The we could remove
|
171
|
+
# this heuristic matching.
|
172
|
+
#
|
173
|
+
def example2profile(example, profiles)
|
174
|
+
profiles.values.find { |p| profile_contains_example?(p, example) }
|
175
|
+
end
|
176
|
+
|
177
|
+
def profile_contains_example?(profile, example)
|
178
|
+
# Heuristic for finding the profile an example came from:
|
179
|
+
# Case 1: The profile_id on the example matches the name of the profile
|
180
|
+
# Case 2: The profile contains a control that matches the id of the example
|
181
|
+
if profile[:name] == example[:profile_id]
|
182
|
+
true
|
183
|
+
elsif profile[:controls] && profile[:controls].key?(example[:id])
|
184
|
+
true
|
185
|
+
else
|
186
|
+
false
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
167
190
|
def example2control(example, profiles)
|
168
|
-
|
169
|
-
|
170
|
-
profile[:controls][example[:id]]
|
191
|
+
p = example2profile(example, profiles)
|
192
|
+
p[:controls][example[:id]] if p && p[:controls]
|
171
193
|
end
|
172
194
|
|
173
195
|
def format_example(example)
|
@@ -240,7 +262,7 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
240
262
|
print_line(
|
241
263
|
color: '', indicator: @indicators['empty'], id: '', profile: '',
|
242
264
|
summary: 'No tests executed.'
|
243
|
-
)
|
265
|
+
) if @current_control.nil?
|
244
266
|
output.puts('')
|
245
267
|
end
|
246
268
|
|
@@ -348,7 +370,7 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
348
370
|
test_status = x[:status_type]
|
349
371
|
test_color = @colors[test_status]
|
350
372
|
indicator = @indicators[x[:status]]
|
351
|
-
indicator = @indicators['empty'] if
|
373
|
+
indicator = @indicators['empty'] if indicator.nil?
|
352
374
|
msg = x[:message] || x[:skip_message] || x[:code_desc]
|
353
375
|
print_line(
|
354
376
|
color: test_color,
|
@@ -364,9 +386,18 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
364
386
|
control_result = control[:results]
|
365
387
|
title = control_result[0][:code_desc].split[0..1].join(' ')
|
366
388
|
puts ' ' + title
|
389
|
+
# iterate over all describe blocks in anonoymous control block
|
367
390
|
control_result.each do |test|
|
368
391
|
control_id = ''
|
369
|
-
|
392
|
+
# display exceptions
|
393
|
+
unless test[:exception].nil?
|
394
|
+
test_result = test[:message]
|
395
|
+
else
|
396
|
+
# determine title
|
397
|
+
test_result = test[:code_desc].split[2..-1].join(' ')
|
398
|
+
# show error message
|
399
|
+
test_result += "\n" + test[:message] unless test[:message].nil?
|
400
|
+
end
|
370
401
|
status_indicator = test[:status_type]
|
371
402
|
print_line(
|
372
403
|
color: @colors[status_indicator] || '',
|
data/lib/inspec/rule.rb
CHANGED
data/lib/inspec/runner.rb
CHANGED
@@ -14,13 +14,34 @@ require 'inspec/secrets'
|
|
14
14
|
# spec requirements
|
15
15
|
|
16
16
|
module Inspec
|
17
|
+
#
|
18
|
+
# Inspec::Runner coordinates the running of tests and is the main
|
19
|
+
# entry point to the application.
|
20
|
+
#
|
21
|
+
# Users are expected to insantiate a runner, add targets to be run,
|
22
|
+
# and then call the run method:
|
23
|
+
#
|
24
|
+
# ```
|
25
|
+
# r = Inspec::Runner.new()
|
26
|
+
# r.add_target("/path/to/some/profile")
|
27
|
+
# r.add_target("http://url/to/some/profile")
|
28
|
+
# r.run
|
29
|
+
# ```
|
30
|
+
#
|
17
31
|
class Runner # rubocop:disable Metrics/ClassLength
|
18
32
|
extend Forwardable
|
33
|
+
|
34
|
+
def_delegator :@test_collector, :report
|
35
|
+
def_delegator :@test_collector, :reset
|
36
|
+
|
19
37
|
attr_reader :backend, :rules, :attributes
|
20
38
|
def initialize(conf = {})
|
21
39
|
@rules = []
|
22
40
|
@conf = conf.dup
|
23
41
|
@conf[:logger] ||= Logger.new(nil)
|
42
|
+
@target_profiles = []
|
43
|
+
@controls = @conf[:controls] || []
|
44
|
+
@ignore_supports = @conf[:ignore_supports]
|
24
45
|
|
25
46
|
@test_collector = @conf.delete(:test_collector) || begin
|
26
47
|
require 'inspec/runner_rspec'
|
@@ -38,19 +59,31 @@ module Inspec
|
|
38
59
|
@test_collector.tests
|
39
60
|
end
|
40
61
|
|
41
|
-
def normalize_map(hm)
|
42
|
-
res = {}
|
43
|
-
hm.each {|k, v|
|
44
|
-
res[k.to_s] = v
|
45
|
-
}
|
46
|
-
res
|
47
|
-
end
|
48
|
-
|
49
62
|
def configure_transport
|
50
63
|
@backend = Inspec::Backend.create(@conf)
|
51
64
|
@test_collector.backend = @backend
|
52
65
|
end
|
53
66
|
|
67
|
+
def run(with = nil)
|
68
|
+
Inspec::Log.debug "Starting run with targets: #{@target_profiles.map(&:to_s)}"
|
69
|
+
Inspec::Log.debug "Backend is #{@backend}"
|
70
|
+
all_controls = []
|
71
|
+
|
72
|
+
@target_profiles.each do |profile|
|
73
|
+
@test_collector.add_profile(profile)
|
74
|
+
profile.locked_dependencies
|
75
|
+
profile.load_libraries
|
76
|
+
@attributes |= profile.runner_context.attributes
|
77
|
+
all_controls += profile.collect_tests
|
78
|
+
end
|
79
|
+
|
80
|
+
all_controls.each do |rule|
|
81
|
+
register_rule(rule)
|
82
|
+
end
|
83
|
+
|
84
|
+
@test_collector.run(with)
|
85
|
+
end
|
86
|
+
|
54
87
|
# determine all attributes before the execution, fetch data from secrets backend
|
55
88
|
def load_attributes(options)
|
56
89
|
attributes = {}
|
@@ -66,15 +99,54 @@ module Inspec
|
|
66
99
|
options['attributes'] = attributes
|
67
100
|
end
|
68
101
|
|
69
|
-
#
|
70
|
-
|
71
|
-
|
102
|
+
#
|
103
|
+
# add_target allows the user to add a target whose tests will be
|
104
|
+
# run when the user calls the run method.
|
105
|
+
#
|
106
|
+
# A target is a path or URL that points to a profile. Using this
|
107
|
+
# target we generate a Profile and a ProfileContext. The content
|
108
|
+
# (libraries, tests, and attributes) from the Profile are loaded
|
109
|
+
# into the ProfileContext.
|
110
|
+
#
|
111
|
+
# If the profile depends on other profiles, those profiles will be
|
112
|
+
# loaded on-demand when include_content or required_content are
|
113
|
+
# called using similar code in Inspec::DSL.
|
114
|
+
#
|
115
|
+
# Once the we've loaded all of the tests files in the profile, we
|
116
|
+
# query the profile for the full list of rules. Those rules are
|
117
|
+
# registered with the @test_collector which is ultimately
|
118
|
+
# responsible for actually running the tests.
|
119
|
+
#
|
120
|
+
# TODO: Deduplicate/clarify the loading code that exists in here,
|
121
|
+
# the ProfileContext, the Profile, and Inspec::DSL
|
122
|
+
#
|
123
|
+
# @params target [String] A path or URL to a profile or raw test.
|
124
|
+
# @params _opts [Hash] Unused, but still here to avoid breaking kitchen-inspec
|
125
|
+
#
|
126
|
+
# @eturns [Inspec::ProfileContext]
|
127
|
+
#
|
128
|
+
def add_target(target, _opts = [])
|
129
|
+
profile = Inspec::Profile.for_target(target, backend: @backend, controls: @controls)
|
72
130
|
fail "Could not resolve #{target} to valid input." if profile.nil?
|
73
|
-
|
131
|
+
@target_profiles << profile if supports_profile?(profile)
|
132
|
+
end
|
133
|
+
|
134
|
+
#
|
135
|
+
# This is used by inspec-shell and inspec-detect. This should
|
136
|
+
# probably be cleaned up a bit.
|
137
|
+
#
|
138
|
+
# @params [Hash] Options
|
139
|
+
# @returns [Inspec::ProfileContext]
|
140
|
+
#
|
141
|
+
def create_context(options = {})
|
142
|
+
meta = options[:metadata]
|
143
|
+
profile_id = nil
|
144
|
+
profile_id = meta.params[:name] unless meta.nil?
|
145
|
+
Inspec::ProfileContext.new(profile_id, @backend, @conf.merge(options))
|
74
146
|
end
|
75
147
|
|
76
148
|
def supports_profile?(profile)
|
77
|
-
return true if profile.metadata.nil?
|
149
|
+
return true if profile.metadata.nil? || @ignore_supports
|
78
150
|
|
79
151
|
if !profile.metadata.supports_runtime?
|
80
152
|
fail 'This profile requires InSpec version '\
|
@@ -90,61 +162,6 @@ module Inspec
|
|
90
162
|
true
|
91
163
|
end
|
92
164
|
|
93
|
-
# Returns the profile context used to initialize this profile.
|
94
|
-
def add_profile(profile, options = {})
|
95
|
-
return if !options[:ignore_supports] && !supports_profile?(profile)
|
96
|
-
|
97
|
-
@test_collector.add_profile(profile)
|
98
|
-
options[:metadata] = profile.metadata
|
99
|
-
options[:profile] = profile
|
100
|
-
|
101
|
-
libs = profile.libraries.map do |k, v|
|
102
|
-
{ ref: k, content: v }
|
103
|
-
end
|
104
|
-
|
105
|
-
tests = profile.tests.map do |ref, content|
|
106
|
-
r = profile.source_reader.target.abs_path(ref)
|
107
|
-
{ ref: r, content: content }
|
108
|
-
end
|
109
|
-
|
110
|
-
add_content(tests, libs, options)
|
111
|
-
end
|
112
|
-
|
113
|
-
def create_context(options = {})
|
114
|
-
meta = options[:metadata]
|
115
|
-
profile_id = nil
|
116
|
-
profile_id = meta.params[:name] unless meta.nil?
|
117
|
-
Inspec::ProfileContext.new(profile_id, @backend, @conf.merge(options))
|
118
|
-
end
|
119
|
-
|
120
|
-
# Returns the profile context used to evaluate the given content.
|
121
|
-
# Calling this method again will use a different context each time.
|
122
|
-
def add_content(tests, libs, options = {})
|
123
|
-
return if tests.nil? || tests.empty?
|
124
|
-
|
125
|
-
# load all libraries
|
126
|
-
ctx = create_context(options)
|
127
|
-
ctx.load_libraries(libs.map { |x| [x[:content], x[:ref], x[:line]] })
|
128
|
-
|
129
|
-
# hand the context to the profile for further evaluation
|
130
|
-
unless (profile = options[:profile]).nil?
|
131
|
-
profile.runner_context = ctx
|
132
|
-
end
|
133
|
-
|
134
|
-
# evaluate the test content
|
135
|
-
Array(tests).each { |t| add_test_to_context(t, ctx) }
|
136
|
-
|
137
|
-
# merge and collect all attributes
|
138
|
-
@attributes |= ctx.attributes
|
139
|
-
|
140
|
-
# process the resulting rules
|
141
|
-
filter_controls(ctx.all_rules, options[:controls]).each do |rule|
|
142
|
-
register_rule(rule)
|
143
|
-
end
|
144
|
-
|
145
|
-
ctx
|
146
|
-
end
|
147
|
-
|
148
165
|
# In some places we read the rules off of the runner, in other
|
149
166
|
# places we read it off of the profile context. To keep the API's
|
150
167
|
# the same, we provide an #all_rules method here as well.
|
@@ -162,26 +179,8 @@ module Inspec
|
|
162
179
|
new_tests
|
163
180
|
end
|
164
181
|
|
165
|
-
def_delegator :@test_collector, :run
|
166
|
-
def_delegator :@test_collector, :report
|
167
|
-
def_delegator :@test_collector, :reset
|
168
|
-
|
169
182
|
private
|
170
183
|
|
171
|
-
def add_test_to_context(test, ctx)
|
172
|
-
content = test[:content]
|
173
|
-
return if content.nil? || content.empty?
|
174
|
-
ctx.load(content, test[:ref], test[:line])
|
175
|
-
end
|
176
|
-
|
177
|
-
def filter_controls(controls_array, include_list)
|
178
|
-
return controls_array if include_list.nil? || include_list.empty?
|
179
|
-
controls_array.select do |c|
|
180
|
-
id = ::Inspec::Rule.rule_id(c)
|
181
|
-
include_list.include?(id)
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
184
|
def block_source_info(block)
|
186
185
|
return {} if block.nil? || !block.respond_to?(:source_location)
|
187
186
|
opts = {}
|
@@ -226,6 +225,7 @@ module Inspec
|
|
226
225
|
end
|
227
226
|
|
228
227
|
def register_rule(rule)
|
228
|
+
Inspec::Log.debug "Registering rule #{rule}"
|
229
229
|
@rules << rule
|
230
230
|
checks = ::Inspec::Rule.prepare_checks(rule)
|
231
231
|
examples = checks.map do |m, a, b|
|