-
Notifications
You must be signed in to change notification settings - Fork 683
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Minor refactor and explanatory comments #987
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,20 @@ | |
# spec requirements | ||
|
||
module Inspec | ||
# | ||
# Inspec::Runner coordinates the running of tests and is the main | ||
# entry point to the application. | ||
# | ||
# Users are expected to insantiate a runner, add targets to be run, | ||
# and then call the run method: | ||
# | ||
# ``` | ||
# r = Inspec::Runner.new() | ||
# r.add_target("/path/to/some/profile") | ||
# r.add_target("http://url/to/some/profile") | ||
# r.run | ||
# ``` | ||
# | ||
class Runner # rubocop:disable Metrics/ClassLength | ||
extend Forwardable | ||
attr_reader :backend, :rules, :attributes | ||
|
@@ -66,83 +80,114 @@ def load_attributes(options) | |
options['attributes'] = attributes | ||
end | ||
|
||
# Returns the profile context used the profile at this target. | ||
# | ||
# add_target allows the user to add a target whose tests will be | ||
# run when the user calls the run method. This is the main entry | ||
# point to profile loading. | ||
# | ||
# A target is a path or URL that points to a profile. Using this | ||
# target we generate a Profile and a ProfileContext. The content | ||
# (libraries, tests, and attributes) from the Profile are loaded | ||
# into the ProfileContext. | ||
# | ||
# If the profile depends on other profiles, those profiles will be | ||
# loaded on-demand when include_content or required_content are | ||
# called using similar code in Inspec::DSL. | ||
# | ||
# Once the we've loaded all of the tests files in the profile, we | ||
# query the profile for the full list of rules. Those rules are | ||
# registered with the @test_collector which is ultimately | ||
# responsible for actually running the tests. | ||
# | ||
# TODO: Deduplicate/clarify the loading code that exists in here, | ||
# the ProfileContext, the Profile, and Inspec::DSL | ||
# | ||
# TODO: Libraries of dependent profiles should be loaded even when | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 right, that is essential for resource packs aka profiles without any test, but only libraries |
||
# include_content/required_content aren't called. | ||
# | ||
# @params target [String] A path or URL to a profile or raw test. | ||
# | ||
# @params options [Hash] An options hash. The relevant options | ||
# considered by this call path are: | ||
# | ||
# - `:ignore_supports`: A boolean that controls whether to ignore | ||
# the profile's metadata regarding supported Inspec versions or | ||
# platforms. | ||
# | ||
# - `:controls`: An array of controls to run from this | ||
# profile. Any returned rules that are not part of these | ||
# controls will be filtered before being passed to @test_collector. | ||
# | ||
# @eturns [Inspec::ProfileContext] | ||
# | ||
def add_target(target, options = {}) | ||
profile = Inspec::Profile.for_target(target, options) | ||
fail "Could not resolve #{target} to valid input." if profile.nil? | ||
add_profile(profile, options) | ||
end | ||
|
||
def supports_profile?(profile) | ||
return true if profile.metadata.nil? | ||
|
||
if !profile.metadata.supports_runtime? | ||
fail 'This profile requires InSpec version '\ | ||
"#{profile.metadata.inspec_requirement}. You are running "\ | ||
"InSpec v#{Inspec::VERSION}.\n" | ||
end | ||
|
||
if !profile.metadata.supports_transport?(@backend) | ||
os_info = @backend.os[:name].to_s | ||
fail "This OS/platform (#{os_info}) is not supported by this profile." | ||
end | ||
|
||
true | ||
end | ||
|
||
# Returns the profile context used to initialize this profile. | ||
def add_profile(profile, options = {}) | ||
return if !options[:ignore_supports] && !supports_profile?(profile) | ||
|
||
@test_collector.add_profile(profile) | ||
options[:metadata] = profile.metadata | ||
options[:profile] = profile | ||
add_content_from_profile(profile, options[:controls]) | ||
end | ||
|
||
def add_content_from_profile(profile, controls) | ||
return if profile.tests.nil? || profile.tests.empty? | ||
|
||
ctx = Inspec::ProfileContext.for_profile(profile, @backend) | ||
profile.runner_context = ctx | ||
|
||
libs = profile.libraries.map do |k, v| | ||
{ ref: k, content: v } | ||
[v, k] | ||
end | ||
|
||
tests = profile.tests.map do |ref, content| | ||
r = profile.source_reader.target.abs_path(ref) | ||
{ ref: r, content: content } | ||
end | ||
|
||
add_content(tests, libs, options) | ||
ctx.load_libraries(libs) | ||
ctx.load_tests(tests) | ||
@attributes |= ctx.attributes | ||
|
||
filter_controls(ctx.all_rules, controls).each do |rule| | ||
register_rule(rule) | ||
end | ||
|
||
ctx | ||
end | ||
|
||
# | ||
# This is used by inspec-shell and inspec-detect. This should | ||
# probably be cleaned up a bit. | ||
# | ||
# @params [Hash] Options | ||
# @returns [Inspec::ProfileContext] | ||
# | ||
def create_context(options = {}) | ||
meta = options[:metadata] | ||
profile_id = nil | ||
profile_id = meta.params[:name] unless meta.nil? | ||
Inspec::ProfileContext.new(profile_id, @backend, @conf.merge(options)) | ||
end | ||
|
||
# Returns the profile context used to evaluate the given content. | ||
# Calling this method again will use a different context each time. | ||
def add_content(tests, libs, options = {}) | ||
return if tests.nil? || tests.empty? | ||
|
||
# load all libraries | ||
ctx = create_context(options) | ||
ctx.load_libraries(libs.map { |x| [x[:content], x[:ref], x[:line]] }) | ||
def supports_profile?(profile) | ||
return true if profile.metadata.nil? | ||
|
||
# hand the context to the profile for further evaluation | ||
unless (profile = options[:profile]).nil? | ||
profile.runner_context = ctx | ||
if !profile.metadata.supports_runtime? | ||
fail 'This profile requires InSpec version '\ | ||
"#{profile.metadata.inspec_requirement}. You are running "\ | ||
"InSpec v#{Inspec::VERSION}.\n" | ||
end | ||
|
||
# evaluate the test content | ||
Array(tests).each { |t| add_test_to_context(t, ctx) } | ||
|
||
# merge and collect all attributes | ||
@attributes |= ctx.attributes | ||
|
||
# process the resulting rules | ||
filter_controls(ctx.all_rules, options[:controls]).each do |rule| | ||
register_rule(rule) | ||
if !profile.metadata.supports_transport?(@backend) | ||
os_info = @backend.os[:name].to_s | ||
fail "This OS/platform (#{os_info}) is not supported by this profile." | ||
end | ||
|
||
ctx | ||
true | ||
end | ||
|
||
# In some places we read the rules off of the runner, in other | ||
|
@@ -168,12 +213,6 @@ def register_rules(ctx) | |
|
||
private | ||
|
||
def add_test_to_context(test, ctx) | ||
content = test[:content] | ||
return if content.nil? || content.empty? | ||
ctx.load(content, test[:ref], test[:line]) | ||
end | ||
|
||
def filter_controls(controls_array, include_list) | ||
return controls_array if include_list.nil? || include_list.empty? | ||
controls_array.select do |c| | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍