mirror of
https://github.com/inspec/inspec
synced 2024-11-10 23:24:18 +00:00
Fixup behavior and add functional tests
This commit is contained in:
parent
01763d43ed
commit
039c760545
6 changed files with 217 additions and 60 deletions
|
@ -140,7 +140,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|||
def detect
|
||||
o = opts.dup
|
||||
o[:command] = 'os.params'
|
||||
res = run_command(o)
|
||||
(_, res) = run_command(o)
|
||||
if opts['format'] == 'json'
|
||||
puts res.to_json
|
||||
else
|
||||
|
@ -162,16 +162,23 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|||
diagnose
|
||||
o = opts.dup
|
||||
|
||||
log_device = opts['format'] == 'json' ? nil : STDOUT
|
||||
json_output = ['json', 'json-min'].include?(opts['format'])
|
||||
log_device = json_output ? nil : STDOUT
|
||||
o[:logger] = Logger.new(log_device)
|
||||
o[:logger].level = get_log_level(o.log_level)
|
||||
|
||||
if o[:command].nil?
|
||||
runner = Inspec::Runner.new(o)
|
||||
return Inspec::Shell.new(runner).start
|
||||
else
|
||||
exit run_command(o)
|
||||
end
|
||||
|
||||
run_type, res = run_command(o)
|
||||
exit res unless run_type == :ruby_eval
|
||||
|
||||
# No InSpec tests - just print evaluation output.
|
||||
res = (res.respond_to?(:to_json) ? res.to_json : JSON.dump(res)) if json_output
|
||||
puts res
|
||||
exit 0
|
||||
rescue RuntimeError, Train::UserError => e
|
||||
$stderr.puts e.message
|
||||
end
|
||||
|
@ -191,9 +198,13 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|||
|
||||
def run_command(opts)
|
||||
runner = Inspec::Runner.new(opts)
|
||||
content = { content: opts[:command], ref: nil, line: nil }
|
||||
runner.add_content(content, [])
|
||||
runner.run
|
||||
ctx = runner.create_context(opts)
|
||||
res = ctx.load(opts[:command])
|
||||
|
||||
return :ruby_eval, res if ctx.rules.empty?
|
||||
|
||||
runner.register_rules(ctx)
|
||||
return :rspec_run, runner.run # rubocop:disable Style/RedundantReturn
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -298,7 +298,7 @@ module Inspec
|
|||
|
||||
def load_dependencies
|
||||
cwd = @target.is_a?(String) && File.directory?(@target) ? @target : nil
|
||||
res = Inspec::Dependencies.new(cwd, nil)
|
||||
res = Inspec::DependencySet.new(cwd, nil)
|
||||
res.vendor(metadata.dependencies)
|
||||
res
|
||||
end
|
||||
|
|
|
@ -131,11 +131,6 @@ module Inspec
|
|||
profile.runner_context = ctx
|
||||
end
|
||||
|
||||
append_content(ctx, tests, libs, options)
|
||||
end
|
||||
|
||||
# Returns the profile context used to evaluate the given content.
|
||||
def append_content(ctx, tests, _libs, options = {})
|
||||
# evaluate the test content
|
||||
tests = [tests] unless tests.is_a? Array
|
||||
tests.each { |t| add_test_to_context(t, ctx) }
|
||||
|
@ -151,13 +146,12 @@ module Inspec
|
|||
ctx
|
||||
end
|
||||
|
||||
def reregister_rules(ctx)
|
||||
def register_rules(ctx)
|
||||
new_tests = false
|
||||
ctx.rules.each do |rule_id, rule|
|
||||
if yield rule_id, rule
|
||||
new_tests = true
|
||||
register_rule(rule_id, rule)
|
||||
end
|
||||
next if block_given? && !(yield rule_id, rule)
|
||||
new_tests = true
|
||||
register_rule(rule_id, rule)
|
||||
end
|
||||
new_tests
|
||||
end
|
||||
|
|
|
@ -18,8 +18,7 @@ module Inspec
|
|||
# Create an in-memory empty runner so that we can add tests to it later.
|
||||
# This context lasts for the duration of this "start" method call/pry
|
||||
# session.
|
||||
c = { content: '', ref: nil, line: nil }
|
||||
@ctx = @runner.add_content(c, [])
|
||||
@ctx = @runner.create_context
|
||||
configure_pry
|
||||
|
||||
# This will hold a single evaluation binding context as opened within
|
||||
|
@ -27,7 +26,7 @@ module Inspec
|
|||
# context creates to evaluate each individual test file. We want to
|
||||
# pretend like we are constantly appending to the same file and want
|
||||
# to capture the local variable context from inside said class.
|
||||
@ctx_binding = @ctx.load('binding', nil, nil)
|
||||
@ctx_binding = @ctx.load('binding')
|
||||
@ctx_binding.pry
|
||||
end
|
||||
|
||||
|
@ -62,7 +61,7 @@ module Inspec
|
|||
# test file, register all the rules it discovered.
|
||||
Pry.hooks.add_hook(:after_eval, 'inspec_after_eval') do
|
||||
@current_eval_new_tests =
|
||||
@runner.reregister_rules(@ctx) do |rule_id, rule|
|
||||
@runner.register_rules(@ctx) do |rule_id, rule|
|
||||
@current_eval_rules[rule_id] != Inspec::Rule.merge_count(rule)
|
||||
end
|
||||
@runner.run if @current_eval_new_tests
|
||||
|
|
191
test/functional/inspec_shell_test.rb
Normal file
191
test/functional/inspec_shell_test.rb
Normal file
|
@ -0,0 +1,191 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require 'functional/helper'
|
||||
|
||||
describe 'inspec shell tests' do
|
||||
include FunctionalHelper
|
||||
|
||||
describe 'cmd' do
|
||||
def do_shell_c(code, exit_status, json = false, stderr = '')
|
||||
json_suffix = " --format 'json'" if json
|
||||
out = inspec("shell -c '#{code.tr('\'','\\\'')}'#{json_suffix}")
|
||||
out.stderr.must_equal stderr
|
||||
out.exit_status.must_equal exit_status
|
||||
out
|
||||
end
|
||||
|
||||
it 'can run ruby expressions (json output)' do
|
||||
x = rand
|
||||
y = rand
|
||||
out = do_shell_c("#{x} + #{y}", 0, true)
|
||||
j = JSON.load(out.stdout)
|
||||
j.must_equal x+y
|
||||
end
|
||||
|
||||
it 'can run ruby expressions' do
|
||||
x = rand
|
||||
y = rand
|
||||
out = do_shell_c("#{x} + #{y}", 0)
|
||||
out.stdout.must_equal "#{x+y}\n"
|
||||
end
|
||||
|
||||
it 'can run arbitrary ruby (json output)' do
|
||||
out = do_shell_c('x = [1,2,3].inject(0) {|a,v| a + v*v}; x+10', 0, true)
|
||||
j = JSON.load(out.stdout)
|
||||
j.must_equal 24 # 1^2 + 2^2 + 3^2 + 10
|
||||
end
|
||||
|
||||
it 'can run arbitrary ruby' do
|
||||
out = do_shell_c('x = [1,2,3].inject(0) {|a,v| a + v*v}; x+10', 0)
|
||||
out.stdout.must_equal "24\n"
|
||||
end
|
||||
|
||||
it 'retrieves resources (json output)' do
|
||||
out = do_shell_c('os.params', 0, true)
|
||||
j = JSON.load(out.stdout)
|
||||
j.keys.must_include 'name'
|
||||
j.keys.must_include 'family'
|
||||
j.keys.must_include 'arch'
|
||||
j.keys.must_include 'release'
|
||||
end
|
||||
|
||||
it 'retrieves resources' do
|
||||
out = do_shell_c('os.params', 0)
|
||||
out.stdout.must_include 'name'
|
||||
out.stdout.must_include 'family'
|
||||
out.stdout.must_include 'arch'
|
||||
out.stdout.must_include 'release'
|
||||
end
|
||||
|
||||
it 'runs anonymous tests that succeed (json output)' do
|
||||
out = do_shell_c("describe file(\"#{__FILE__}\") do it { should exist } end", 0, true)
|
||||
j = JSON.load(out.stdout)
|
||||
j.keys.must_include 'version'
|
||||
j.keys.must_include 'profiles'
|
||||
j.keys.must_include 'other_checks'
|
||||
j.keys.must_include 'summary'
|
||||
j['summary']['example_count'].must_equal 1
|
||||
j['summary']['failure_count'].must_equal 0
|
||||
end
|
||||
|
||||
it 'runs anonymous tests that succeed' do
|
||||
out = do_shell_c("describe file(\"#{__FILE__}\") do it { should exist } end", 0)
|
||||
out.stdout.must_include '1 successful'
|
||||
out.stdout.must_include '0 failures'
|
||||
end
|
||||
|
||||
it 'runs anonymous tests that fail (json output)' do
|
||||
out = do_shell_c("describe file(\"foo/bar/baz\") do it { should exist } end", 1, true)
|
||||
j = JSON.load(out.stdout)
|
||||
j.keys.must_include 'version'
|
||||
j.keys.must_include 'profiles'
|
||||
j.keys.must_include 'other_checks'
|
||||
j.keys.must_include 'summary'
|
||||
j['summary']['example_count'].must_equal 1
|
||||
j['summary']['failure_count'].must_equal 1
|
||||
end
|
||||
|
||||
it 'runs anonymous tests that fail' do
|
||||
out = do_shell_c("describe file(\"foo/bar/baz\") do it { should exist } end", 1)
|
||||
out.stdout.must_include '0 successful'
|
||||
out.stdout.must_include '1 failures'
|
||||
end
|
||||
|
||||
it 'runs controls with tests (json output)' do
|
||||
out = do_shell_c("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end end", 0, true)
|
||||
j = JSON.load(out.stdout)
|
||||
j.keys.must_include 'version'
|
||||
j.keys.must_include 'profiles'
|
||||
j.keys.must_include 'other_checks'
|
||||
j.keys.must_include 'summary'
|
||||
j['summary']['example_count'].must_equal 1
|
||||
j['summary']['failure_count'].must_equal 0
|
||||
end
|
||||
|
||||
it 'runs controls with tests' do
|
||||
out = do_shell_c("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end end", 0)
|
||||
out.stdout.must_include '1 successful'
|
||||
out.stdout.must_include '0 failures'
|
||||
end
|
||||
|
||||
it 'runs controls with multiple tests (json output)' do
|
||||
out = do_shell_c("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end; describe file(\"foo/bar/baz\") do it { should exist } end end", 1, true)
|
||||
j = JSON.load(out.stdout)
|
||||
j.keys.must_include 'version'
|
||||
j.keys.must_include 'profiles'
|
||||
j.keys.must_include 'other_checks'
|
||||
j.keys.must_include 'summary'
|
||||
j['summary']['example_count'].must_equal 2
|
||||
j['summary']['failure_count'].must_equal 1
|
||||
end
|
||||
|
||||
it 'runs controls with multiple tests' do
|
||||
out = do_shell_c("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end; describe file(\"foo/bar/baz\") do it { should exist } end end", 1)
|
||||
out.stdout.must_include '1 successful'
|
||||
out.stdout.must_include '1 failures'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'shell' do
|
||||
def do_shell(code, exit_status = 0, stderr = '')
|
||||
cmd = "echo '#{code.tr('\'','\\\'')}' | #{exec_inspec} shell"
|
||||
out = CMD.run_command(cmd)
|
||||
#out.stderr.must_equal stderr
|
||||
out.exit_status.must_equal exit_status
|
||||
out
|
||||
end
|
||||
|
||||
it 'provides a help command' do
|
||||
out = do_shell('help')
|
||||
out.stdout.must_include 'Available commands:'
|
||||
out.stdout.must_include 'You are currently running on:'
|
||||
end
|
||||
|
||||
it 'exposes all resources' do
|
||||
out = do_shell('os')
|
||||
out.stdout.must_match /\=> .*Operating.* .*System.* .*Detection/
|
||||
end
|
||||
|
||||
it 'can run ruby expressions' do
|
||||
x = rand
|
||||
y = rand
|
||||
out = do_shell("#{x} + #{y}")
|
||||
out.stdout.must_include "#{x+y}"
|
||||
end
|
||||
|
||||
it 'can run arbitrary ruby' do
|
||||
out = do_shell('x = [1,2,3].inject(0) {|a,v| a + v*v}; x+10')
|
||||
out.stdout.must_include "24"
|
||||
end
|
||||
|
||||
it 'runs anonymous tests that succeed' do
|
||||
out = do_shell("describe file(\"#{__FILE__}\") do it { should exist } end")
|
||||
out.stdout.must_include '1 successful'
|
||||
out.stdout.must_include '0 failures'
|
||||
end
|
||||
|
||||
it 'runs anonymous tests that fail' do
|
||||
out = do_shell("describe file(\"foo/bar/baz\") do it { should exist } end")
|
||||
out.stdout.must_include '0 successful'
|
||||
out.stdout.must_include '1 failures'
|
||||
end
|
||||
|
||||
it 'runs controls with tests' do
|
||||
out = do_shell("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end end")
|
||||
out.stdout.must_include '1 successful'
|
||||
out.stdout.must_include '0 failures'
|
||||
end
|
||||
|
||||
it 'runs controls with multiple tests' do
|
||||
out = do_shell("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end; describe file(\"foo/bar/baz\") do it { should exist } end end")
|
||||
out.stdout.must_include '1 successful'
|
||||
out.stdout.must_include '1 failures'
|
||||
end
|
||||
|
||||
it 'reruns controls when redefined' do
|
||||
out = do_shell("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end end\ncontrol \"test\" do describe file(\"foo/bar/baz\") do it { should exist } end end")
|
||||
out.stdout.must_include '1 successful'
|
||||
out.stdout.must_include '1 failures'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -34,29 +34,6 @@ describe 'command tests' do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'cmd' do
|
||||
it 'can run arbitrary ruby' do
|
||||
x = rand
|
||||
y = rand
|
||||
out = inspec("shell -c '#{x} + #{y}' --format 'json'")
|
||||
out.stderr.must_equal ''
|
||||
out.exit_status.must_equal 0
|
||||
j = JSON.load(out.stdout)
|
||||
j.must_equal x+y
|
||||
end
|
||||
|
||||
it 'retrieves resources in JSON' do
|
||||
out = inspec("shell -c 'os.params' --format 'json'")
|
||||
out.stderr.must_equal ''
|
||||
out.exit_status.must_equal 0
|
||||
j = JSON.load(out.stdout)
|
||||
j.keys.must_include 'name'
|
||||
j.keys.must_include 'family'
|
||||
j.keys.must_include 'arch'
|
||||
j.keys.must_include 'release'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'version' do
|
||||
it 'provides the version number on stdout' do
|
||||
out = inspec('version')
|
||||
|
@ -66,21 +43,6 @@ describe 'command tests' do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'shell' do
|
||||
it 'provides a help command' do
|
||||
out = CMD.run_command("echo \"help\nexit\" | #{exec_inspec} shell")
|
||||
out.exit_status.must_equal 0
|
||||
out.stdout.must_include 'Available commands:'
|
||||
out.stdout.must_include 'You are currently running on:'
|
||||
end
|
||||
|
||||
it 'exposes all resources' do
|
||||
out = CMD.run_command("echo \"os\nexit\" | #{exec_inspec} shell")
|
||||
out.exit_status.must_equal 0
|
||||
out.stdout.must_match /^=> .*Operating.* .*System.* .*Detection.*$/
|
||||
end
|
||||
end
|
||||
|
||||
describe 'check' do
|
||||
it 'verifies that a profile is ok' do
|
||||
out = inspec('check ' + example_profile)
|
||||
|
|
Loading…
Reference in a new issue