mirror of
https://github.com/inspec/inspec
synced 2024-12-19 01:23:50 +00:00
36ce34be98
Signed-off-by: Clinton Wolfe <clintoncwolfe@gmail.com>
282 lines
13 KiB
Ruby
282 lines
13 KiB
Ruby
# Functional tests related to plugin facility
|
|
require 'functional/helper'
|
|
|
|
|
|
#=========================================================================================#
|
|
# Loader Errors
|
|
#=========================================================================================#
|
|
describe 'plugin loader' do
|
|
include FunctionalHelper
|
|
|
|
it 'handles an unloadable plugin correctly' do
|
|
outcome = inspec_with_env('version', INSPEC_CONFIG_DIR: File.join(config_dir_path, 'plugin_error_on_load'))
|
|
outcome.exit_status.must_equal 2
|
|
outcome.stdout.must_include('ERROR', 'Have an error on stdout')
|
|
outcome.stdout.must_include('Could not load plugin inspec-divide-by-zero', 'Name the plugin in the stdout error')
|
|
outcome.stdout.wont_include('ZeroDivisionError', 'No stacktrace in error by default')
|
|
outcome.stdout.must_include('Errors were encountered while loading plugins', 'Friendly message in error')
|
|
outcome.stdout.must_include('Plugin name: inspec-divide-by-zero', 'Plugin named in error')
|
|
outcome.stdout.must_include('divided by 0', 'Exception message in error')
|
|
|
|
outcome = inspec_with_env('version --debug', INSPEC_CONFIG_DIR: File.join(config_dir_path, 'plugin_error_on_load'))
|
|
outcome.exit_status.must_equal 2
|
|
outcome.stdout.must_include('ZeroDivisionError', 'Include stacktrace in error with --debug')
|
|
end
|
|
end
|
|
|
|
#=========================================================================================#
|
|
# Disabling Plugins
|
|
#=========================================================================================#
|
|
describe 'when disabling plugins' do
|
|
include FunctionalHelper
|
|
|
|
describe 'when disabling the core plugins' do
|
|
it 'should not be able to use core-provided commands' do
|
|
run_result = run_inspec_process('--disable-core-plugins habitat')
|
|
run_result.stderr.must_include 'Could not find command "habitat".'
|
|
# One might think that this should be code 2 (plugin error)
|
|
# But because the core plugins are not loaded, 'habitat' is not
|
|
# a known command, which makes it a usage error, code 1.
|
|
run_result.exit_status.must_equal 1
|
|
end
|
|
end
|
|
|
|
describe 'when disabling the user plugins' do
|
|
it 'should not be able to use user commands' do
|
|
run_result = run_inspec_process('--disable-user-plugins meaningoflife answer', env: { INSPEC_CONFIG_DIR: File.join(config_dir_path, 'meaning_by_path') })
|
|
run_result.stderr.must_include 'Could not find command "meaningoflife"'
|
|
run_result.exit_status.must_equal 1
|
|
end
|
|
end
|
|
end
|
|
|
|
#=========================================================================================#
|
|
# CliCommand plugin type
|
|
#=========================================================================================#
|
|
describe 'cli command plugins' do
|
|
include FunctionalHelper
|
|
|
|
it 'is able to respond to a plugin-based cli subcommand' do
|
|
outcome = inspec_with_env('meaningoflife answer', INSPEC_CONFIG_DIR: File.join(config_dir_path, 'meaning_by_path'))
|
|
outcome.stderr.wont_include 'Could not find command "meaningoflife"'
|
|
outcome.stderr.must_equal ''
|
|
outcome.stdout.must_equal ''
|
|
outcome.exit_status.must_equal 42
|
|
end
|
|
|
|
it 'is able to respond to [help subcommand] invocations' do
|
|
outcome = inspec_with_env('help meaningoflife', INSPEC_CONFIG_DIR: File.join(config_dir_path, 'meaning_by_path'))
|
|
outcome.exit_status.must_equal 0
|
|
outcome.stderr.must_equal ''
|
|
outcome.stdout.must_include 'inspec meaningoflife answer'
|
|
# Full text:
|
|
# 'Exits immediately with an exit code reflecting the answer to life the universe, and everything.'
|
|
# but Thor will ellipsify based on the terminal width
|
|
outcome.stdout.must_include 'Exits immediately'
|
|
end
|
|
|
|
# This is an important test; usually CLI plugins are only activated when their name is present in ARGV
|
|
it 'includes plugin-based cli commands in top-level help' do
|
|
outcome = inspec_with_env('help', INSPEC_CONFIG_DIR: File.join(config_dir_path, 'meaning_by_path'))
|
|
outcome.exit_status.must_equal 0
|
|
outcome.stdout.must_include 'inspec meaningoflife'
|
|
end
|
|
end
|
|
|
|
#=========================================================================================#
|
|
# inspec plugin command
|
|
#=========================================================================================#
|
|
# See lib/plugins/inspec-plugin-manager-cli/test
|
|
|
|
#=========================================================================================#
|
|
# Plugin Disable Messaging
|
|
#=========================================================================================#
|
|
describe 'disable plugin usage message integration' do
|
|
include FunctionalHelper
|
|
|
|
it "mentions the --disable-{user,core}-plugins options" do
|
|
outcome = inspec('help')
|
|
['--disable-user-plugins', '--disable-core-plugins'].each do |option|
|
|
outcome.stdout.must_include(option)
|
|
end
|
|
end
|
|
end
|
|
|
|
#=========================================================================================#
|
|
# DSL Plugin Support
|
|
#=========================================================================================#
|
|
|
|
describe 'DSL plugin types support' do
|
|
include PluginFunctionalHelper
|
|
|
|
let(:fixture_path) { File.join(profile_path, 'dsl_plugins', 'controls', profile_file)}
|
|
let(:dsl_plugin_path) { File.join(mock_path, 'plugins', 'inspec-dsl-test', 'lib', 'inspec-dsl-test.rb')}
|
|
let(:run_result) { run_inspec_with_plugin("exec #{fixture_path}", plugin_path: dsl_plugin_path) }
|
|
let(:json_result) { run_result.payload.json }
|
|
|
|
describe 'outer profile dsl plugin type support' do
|
|
let(:profile_file) { 'outer_profile_dsl.rb' }
|
|
it 'works correctly with outer_profile dsl extensions' do
|
|
run_result.stderr.must_equal ''
|
|
|
|
# The outer_profile_dsl.rb file has control-01, then a call to favorite_grain
|
|
# (which generates a control), then control-03.
|
|
# If the plugin exploded, we'd see control-01 but not control-03
|
|
controls = json_result['profiles'][0]['controls']
|
|
controls.count.must_equal 3
|
|
|
|
# We expect the second controls id to be 'sorghum'
|
|
# (this is the functionality of the outer_profile_dsl we installed)
|
|
generated_control = json_result['profiles'][0]['controls'][1]
|
|
generated_control['id'].must_equal 'sorghum'
|
|
generated_control['results'][0]['status'].must_equal 'passed'
|
|
end
|
|
end
|
|
|
|
describe 'control dsl plugin type support' do
|
|
|
|
let(:profile_file) { 'control_dsl.rb' }
|
|
it 'works correctly with control dsl extensions' do
|
|
run_result.stderr.must_equal ''
|
|
|
|
# The control_dsl.rb file has one control, with a describe-01, then a call to favorite_fruit, then describe-02
|
|
# If the plugin exploded, we'd see describe-01 but not describe-02
|
|
results = json_result['profiles'][0]['controls'][0]['results']
|
|
results.count.must_equal 2
|
|
|
|
# We expect the descriptions to include that the favorite fruit is banana
|
|
# (this is the functionality of the control_dsl we installed)
|
|
first_description_section = json_result['profiles'][0]['controls'][0]['descriptions'].first
|
|
first_description_section.wont_be_nil
|
|
first_description_section['label'].must_equal 'favorite_fruit'
|
|
first_description_section['data'].must_equal 'Banana'
|
|
end
|
|
end
|
|
|
|
describe 'describe dsl plugin type support' do
|
|
let(:profile_file) { 'describe_dsl.rb' }
|
|
it 'works correctly with describe dsl extensions' do
|
|
run_result.stderr.must_equal ''
|
|
|
|
# The describe_dsl.rb file has one control, with
|
|
# describe-01, describe-02 which contains a call to favorite_vegetable, then describe-03
|
|
# If the plugin exploded, we'd see describe-01 but not describe-02
|
|
results = json_result['profiles'][0]['controls'][0]['results']
|
|
results.count.must_equal 3
|
|
|
|
# We expect the description of describe-02 to include the word aubergine
|
|
# (this is the functionality of the describe_dsl we installed)
|
|
second_result = json_result['profiles'][0]['controls'][0]['results'][1]
|
|
second_result.wont_be_nil
|
|
second_result['code_desc'].must_include 'aubergine'
|
|
end
|
|
end
|
|
|
|
describe 'test dsl plugin type support' do
|
|
let(:profile_file) { 'test_dsl.rb' }
|
|
it 'works correctly with test dsl extensions' do
|
|
run_result.stderr.must_equal ''
|
|
|
|
# The test_dsl.rb file has one control, with
|
|
# describe-01, describe-02 which contains a call to favorite_legume, then describe-03
|
|
# If the plugin exploded, we'd see describe-01 but not describe-02
|
|
results = json_result['profiles'][0]['controls'][0]['results']
|
|
results.count.must_equal 3
|
|
|
|
# I spent a while trying to find a way to get the test to alter its name;
|
|
# that won't work for various setup reasons.
|
|
# So, it just throws an exception with the word 'edemame' in it.
|
|
second_result = json_result['profiles'][0]['controls'][0]['results'][1]
|
|
second_result.wont_be_nil
|
|
second_result['status'].must_equal 'failed'
|
|
second_result['message'].must_include 'edemame'
|
|
end
|
|
end
|
|
|
|
describe 'resource dsl plugin type support' do
|
|
let(:profile_file) { 'unused' }
|
|
it 'works correctly with test dsl extensions' do
|
|
# We have to build a custom command line - need to load the whole profile,
|
|
# so the libraries get loaded.
|
|
cmd = 'exec '
|
|
cmd += File.join(profile_path, 'dsl_plugins')
|
|
cmd += ' --controls=/^rdsl-control/ '
|
|
run_result = run_inspec_with_plugin(cmd, plugin_path: dsl_plugin_path)
|
|
run_result.stderr.must_equal ''
|
|
|
|
# We should have three controls; 01 and 03 just do a string match.
|
|
# 02 uses the custom resource, which relies on calls to the resource DSL.
|
|
# If the plugin exploded, we'd see rdsl-control-01 but not rdsl-control-02
|
|
json_result = run_result.payload.json
|
|
results = json_result['profiles'][0]['controls']
|
|
results.count.must_equal 3
|
|
|
|
# Control 2 has 2 describes; one uses a simple explicit matcher,
|
|
# while the second uses a matcher defined via a macro provided by the resource DSL.
|
|
control2_results = results[1]['results']
|
|
control2_results[0]['status'].must_equal 'passed'
|
|
control2_results[0]['code_desc'].must_include 'favorite_berry'
|
|
control2_results[0]['code_desc'].must_include 'blendable'
|
|
|
|
control2_results[1]['status'].must_equal 'passed'
|
|
control2_results[1]['code_desc'].must_include 'favorite_berry'
|
|
control2_results[1]['code_desc'].must_include 'have drupals'
|
|
end
|
|
end
|
|
end
|
|
|
|
#=========================================================================================#
|
|
# Train Plugin Support
|
|
#=========================================================================================#
|
|
|
|
describe 'train plugin support' do
|
|
describe 'when a train plugin is installed' do
|
|
include FunctionalHelper
|
|
it 'can run inspec detect against a URL target' do
|
|
outcome = inspec_with_env('detect -t test-fixture://', INSPEC_CONFIG_DIR: File.join(config_dir_path, 'train-test-fixture'))
|
|
outcome.exit_status.must_equal(0)
|
|
outcome.stderr.must_be_empty
|
|
lines = outcome.stdout.split("\n")
|
|
lines.grep(/Name/).first.must_include('test-fixture')
|
|
lines.grep(/Name/).first.wont_include('train-test-fixture')
|
|
lines.grep(/Release/).first.must_include('0.1.0')
|
|
lines.grep(/Families/).first.must_include('os')
|
|
lines.grep(/Families/).first.must_include('windows')
|
|
lines.grep(/Families/).first.must_include('unix')
|
|
lines.grep(/Arch/).first.must_include('mock')
|
|
end
|
|
|
|
it 'can run inspec detect against a test-fixture backend' do
|
|
outcome = inspec_with_env('detect -b test-fixture', INSPEC_CONFIG_DIR: File.join(config_dir_path, 'train-test-fixture'))
|
|
outcome.exit_status.must_equal(0)
|
|
outcome.stderr.must_be_empty
|
|
lines = outcome.stdout.split("\n")
|
|
lines.grep(/Name/).first.must_include('test-fixture')
|
|
lines.grep(/Name/).first.wont_include('train-test-fixture')
|
|
lines.grep(/Release/).first.must_include('0.1.0')
|
|
lines.grep(/Families/).first.must_include('os')
|
|
lines.grep(/Families/).first.must_include('windows')
|
|
lines.grep(/Families/).first.must_include('unix')
|
|
lines.grep(/Arch/).first.must_include('mock')
|
|
end
|
|
|
|
it 'can run inspec shell and read a file' do
|
|
outcome = inspec_with_env("shell -t test-fixture:// -c 'file(\"any-path\").content'", INSPEC_CONFIG_DIR: File.join(config_dir_path, 'train-test-fixture'))
|
|
outcome.exit_status.must_equal(0)
|
|
outcome.stderr.must_be_empty
|
|
outcome.stdout.chomp.must_equal 'Lorem Ipsum'
|
|
end
|
|
|
|
it 'can run inspec shell and run a command' do
|
|
outcome = inspec_with_env("shell -t test-fixture:// -c 'command(\"echo hello\").exit_status'", INSPEC_CONFIG_DIR: File.join(config_dir_path, 'train-test-fixture'))
|
|
outcome.exit_status.must_equal(0)
|
|
outcome.stderr.must_be_empty
|
|
outcome.stdout.chomp.must_equal "17"
|
|
|
|
outcome = inspec_with_env("shell -t test-fixture:// -c 'command(\"echo hello\").stdout'", INSPEC_CONFIG_DIR: File.join(config_dir_path, 'train-test-fixture'))
|
|
outcome.exit_status.must_equal(0)
|
|
outcome.stderr.must_be_empty
|
|
outcome.stdout.chomp.must_equal "Mock Command Result stdout"
|
|
end
|
|
end
|
|
end
|