Accept regexes for --controls option to inspec exec (#3179)

* Functional tests for regex control selection
* Implementation for regex-based control filtering

Signed-off-by: Clinton Wolfe <clintoncwolfe@gmail.com>
This commit is contained in:
Clinton Wolfe 2018-07-05 15:44:30 -04:00 committed by Jared Quick
parent dc0c8b7cc0
commit 92e96ebedb
5 changed files with 46 additions and 8 deletions

View file

@ -73,7 +73,7 @@ module Inspec
target_options
profile_options
option :controls, type: :array,
desc: 'A list of controls to run. Ignore all other tests.'
desc: 'A list of control names to run, or a list of /regexes/ to match against control names. Ignore all other tests.'
option :format, type: :string,
desc: '[DEPRECATED] Please use --reporter - this will be removed in InSpec 3.0'
option :reporter, type: :array,

View file

@ -177,9 +177,29 @@ module Inspec
def filter_controls(controls_array, include_list)
return controls_array if include_list.nil? || include_list.empty?
# Check for anything that might be a regex in the list, and make it official
include_list.each_with_index do |inclusion, index|
next if inclusion.is_a?(Regexp)
# Insist the user wrap the regex in slashes to demarcate it as a regex
next unless inclusion.start_with?('/') && inclusion.end_with?('/')
inclusion = inclusion[1..-2] # Trim slashes
begin
re = Regexp.new(inclusion)
include_list[index] = re
rescue RegexpError => e
warn "Ignoring unparseable regex '/#{inclusion}/' in --control CLI option: #{e.message}"
include_list[index] = nil
end
end
include_list.compact!
controls_array.select do |c|
id = ::Inspec::Rule.rule_id(c)
include_list.include?(id)
include_list.any? do |inclusion|
# Try to see if the inclusion is a regex, and if it matches
inclusion == id || (inclusion.is_a?(Regexp) && inclusion =~ id)
end
end
end

View file

@ -117,7 +117,7 @@ describe '2370 lazy_load for filter table' do
it 'negative tests should fail but not abort' do
controls = [
'2370_proc_handle_exception',
'2370_fail_proc_handle_exception',
]
cmd = inspec('exec ' + File.join(profile_path, 'filter_table') + ' --reporter json --no-create-lockfile' + ' --controls ' + controls.join(' '))

View file

@ -82,13 +82,31 @@ Test Summary: 0 successful, 0 failures, 0 skipped
out.stdout.force_encoding(Encoding::UTF_8).must_include "Test Summary: \e[38;5;41m1 successful\e[0m, \e[38;5;9m1 failure\e[0m, \e[38;5;247m1 skipped\e[0m\n"
end
it 'executes only specified controls' do
out = inspec('exec ' + example_profile + ' --no-create-lockfile --controls tmp-1.0')
out.stderr.must_equal ''
it 'executes only specified controls when selecting passing controls by literal names' do
out = inspec('exec ' + File.join(profile_path, 'filter_table') + ' --no-create-lockfile --controls 2943_pass_undeclared_field_in_hash 2943_pass_irregular_row_key')
out.exit_status.must_equal 0
out.stdout.must_include "\nProfile Summary: \e[38;5;41m1 successful control\e[0m, 0 control failures, 0 controls skipped\n"
out.stdout.force_encoding(Encoding::UTF_8).must_include "\nProfile Summary: \e[38;5;41m2 successful controls\e[0m, 0 control failures, 0 controls skipped\n"
end
it 'executes only specified controls when selecting failing controls by literal names' do
out = inspec('exec ' + File.join(profile_path, 'filter_table') + ' --no-create-lockfile --controls 2943_fail_derail_check')
out.exit_status.must_equal 100
out.stdout.force_encoding(Encoding::UTF_8).must_include "\nProfile Summary: 0 successful controls, \e[38;5;9m1 control failure\e[0m, 0 controls skipped"
end
it 'executes only specified controls when selecting passing controls by regex' do
out = inspec('exec ' + File.join(profile_path, 'filter_table') + ' --no-create-lockfile --controls \'/^2943_pass/\'')
out.exit_status.must_equal 0
out.stdout.force_encoding(Encoding::UTF_8).must_include "Profile Summary: \e[38;5;41m4 successful controls\e[0m, 0 control failures, 0 controls skipped"
end
it 'executes only specified controls when selecting failing controls by regex' do
out = inspec('exec ' + File.join(profile_path, 'filter_table') + ' --no-create-lockfile --controls \'/^(2943|2370)_fail/\'')
out.exit_status.must_equal 100
out.stdout.force_encoding(Encoding::UTF_8).must_include "Profile Summary: 0 successful controls, \e[38;5;9m2 control failures\e[0m, 0 controls skipped"
end
it 'can execute a simple file with the default formatter' do
out = inspec('exec ' + example_control + ' --no-create-lockfile')
out.stderr.must_equal ''

View file

@ -117,7 +117,7 @@ control '2370_no_rows' do
end
end
control '2370_proc_handle_exception' do
control '2370_fail_proc_handle_exception' do
desc 'An exception in a Proc should not derail the run'
# TODO read exception
describe lazy_loader(fresh_data.call).lazy_4s do