Merge pull request #4398 from inspec/cw/rename-runner-api

Accept input keys via the Runner API
This commit is contained in:
Clinton Wolfe 2019-08-27 16:34:54 -04:00 committed by GitHub
commit a849221b27
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 122 additions and 22 deletions

View file

@ -80,7 +80,7 @@ namespace :test do
missing.reject! { |f| ! File.file? f }
missing.reject! { |f| f =~ %r{test/(integration|cookbooks)} }
missing.reject! { |f| f =~ %r{test/unit/mock} }
missing.reject! { |f| f =~ %r{test.*helper} }
missing.reject! { |f| f =~ /test.*helper/ }
missing.reject! { |f| f =~ %r{test/docker} }
puts missing.sort

View file

@ -52,6 +52,7 @@ module Fetchers
# processing, but then again, if you passed a relative path
# to an on-disk repo, you probably expect it to exist.
return url_or_file_path unless File.exist?(url_or_file_path)
# It's important to expand this path, because it may be specified
# locally in the metadata files, and when we clone, we will be
# in a temp dir.
@ -97,6 +98,7 @@ module Fetchers
def cache_key
return resolved_ref unless @relative_path
OpenSSL::Digest::SHA256.hexdigest(resolved_ref + @relative_path)
end

View file

@ -124,8 +124,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI
else
%w{location profile controls timestamp valid}.each do |item|
prepared_string = format("%-12s %s",
"#{item.to_s.capitalize} :",
result[:summary][item.to_sym])
"#{item.to_s.capitalize} :",
result[:summary][item.to_sym])
ui.plain_line(prepared_string)
end
puts

View file

@ -64,6 +64,9 @@ module Inspec
#-------------------------------------------------------------#
def find_or_register_input(input_name, profile_name, options = {})
input_name = input_name.to_s
profile_name = profile_name.to_s
if profile_alias?(profile_name) && !profile_aliases[profile_name].nil?
alias_name = profile_name
profile_name = profile_aliases[profile_name]

View file

@ -116,9 +116,19 @@ module Inspec
# we can create any inputs that were provided by various mechanisms.
options[:runner_conf] ||= Inspec::Config.cached
# Catch legacy CLI input option usage
if options[:runner_conf].key?(:attrs)
Inspec.deprecate(:rename_attributes_to_inputs, "Use --input-file on the command line instead of --attrs.")
options[:runner_conf][:input_file] = options[:runner_conf].delete(:attrs)
elsif options[:runner_conf].key?(:input_files)
# The kitchen-inspec docs say to use plural. Our CLI and internal expectations are singular.
options[:runner_conf][:input_file] = options[:runner_conf].delete(:input_files)
end
# Catch legacy kitchen-inspec input usage
if options[:runner_conf].key?(:attributes)
Inspec.deprecate(:rename_attributes_to_inputs, "Use :inputs in your kitchen.yml verifier config instead of :attributes.")
options[:runner_conf][:inputs] = options[:runner_conf].delete(:attributes)
end
Inspec::InputRegistry.bind_profile_inputs(
@ -127,8 +137,7 @@ module Inspec
# Remaining args are possible sources of inputs
cli_input_files: options[:runner_conf][:input_file], # From CLI --input-file
profile_metadata: metadata,
# TODO: deprecation checks here
runner_api: options[:runner_conf][:attributes] # This is the route the audit_cookbook and kitchen-inspec take
runner_api: options[:runner_conf][:inputs] # This is the route the audit_cookbook and kitchen-inspec take
)
@runner_context =

View file

@ -25,9 +25,9 @@ module InspecPlugins
ui.line
plugin_statuses.sort_by(&:name).each do |status|
ui.plain(format(" %-30s%-10s%-8s%-6s", status.name,
make_pretty_version(status),
status.installation_type,
status.api_generation.to_s))
make_pretty_version(status),
status.installation_type,
status.api_generation.to_s))
end
ui.line
ui.plain(" #{plugin_statuses.count} plugin(s) total")
@ -118,7 +118,7 @@ module InspecPlugins
begin
installer.update(plugin_name)
rescue Inspec::Plugin::V2::UpdateError => ex
ui.plain("#{ui.red('Update error:')} #{ex.message} - update failed")
ui.plain("#{ui.red("Update error:")} #{ex.message} - update failed")
ui.exit Inspec::UI::EXIT_USAGE_ERROR
end
post_update_versions = installer.list_installed_plugin_gems.select { |spec| spec.name == plugin_name }.map { |spec| spec.version.to_s }
@ -144,7 +144,7 @@ module InspecPlugins
def uninstall(plugin_name)
status = Inspec::Plugin::V2::Registry.instance[plugin_name.to_sym]
unless status
ui.plain("#{ui.red('No such plugin installed:')} #{plugin_name} is not " \
ui.plain("#{ui.red("No such plugin installed:")} #{plugin_name} is not " \
"installed - uninstall failed")
ui.exit Inspec::UI::EXIT_USAGE_ERROR
end
@ -375,7 +375,7 @@ module InspecPlugins
# There are existing versions installed, but none of them are what was requested
ui.red("Update required - plugin #{plugin_name}, requested " \
"#{requested_version}, have " \
"#{pre_installed_versions.join(', ')}; use `inspec " \
"#{pre_installed_versions.join(", ")}; use `inspec " \
"plugin update` - refusing to install.")
end
@ -420,10 +420,10 @@ module InspecPlugins
# Check for path install
status = Inspec::Plugin::V2::Registry.instance[plugin_name.to_sym]
if !status
ui.plain("#{ui.red('No such plugin installed:')} #{plugin_name} - update failed")
ui.plain("#{ui.red("No such plugin installed:")} #{plugin_name} - update failed")
ui.exit Inspec::UI::EXIT_USAGE_ERROR
elsif status.installation_type == :path
ui.plain("#{ui.red('Cannot update path-based install:')} " \
ui.plain("#{ui.red("Cannot update path-based install:")} " \
"#{plugin_name} is installed via path reference; " \
"use `inspec plugin uninstall` to remove - refusing to" \
"update")
@ -436,7 +436,7 @@ module InspecPlugins
latest_version = latest_version[plugin_name]&.last
if pre_update_versions.include?(latest_version)
ui.plain("#{ui.red('Already installed at latest version:')} " \
ui.plain("#{ui.red("Already installed at latest version:")} " \
"#{plugin_name} is at #{latest_version}, which the " \
"latest - refusing to update")
ui.exit Inspec::UI::EXIT_PLUGIN_ERROR

View file

@ -52,15 +52,15 @@ module SourceReaders
end
def load_tests
load_all(/^controls\/.*\.rb$/)
load_all(%r{^controls/.*\.rb$})
end
def load_libs
load_all(/^libraries\/.*\.rb$/)
load_all(%r{^libraries/.*\.rb$})
end
def load_data_files
load_all(/^files\//)
load_all(%r{^files/})
end
end
end

View file

@ -1,4 +1,5 @@
require "functional/helper"
require "tempfile"
# For tests related to reading inputs from plugins, see plugins_test.rb
@ -67,6 +68,80 @@ describe "inputs" do
end
end
describe "when being passed inputs via the Runner API" do
let(:run_result) { run_runner_api_process(runner_options) }
let(:common_options) do
{
profile: "#{inputs_profiles_path}/via-runner",
reporter: ["json"],
}
end
# options:
# profile: path to profile to run
# All other opts passed to InSpec::Runner.new(...)
# then add.target is called
def run_runner_api_process(options)
# Remove profile from options. All other are passed to Runner.
profile = options.delete(:profile)
# Make a tmpfile
Tempfile.open(mode: 0700) do |script| # 0700 - -rwx------
# Clear and concat - can't just assign, it's readonly
script.puts <<~EOSCRIPT
# Ruby load path
$LOAD_PATH.clear
$LOAD_PATH.concat(#{$LOAD_PATH})
# require inspec
require "inspec"
require "inspec/runner"
# inject pretty-printed runner opts
runner_args = #{options.inspect}
# Profile to run:
profile_location = "#{profile}"
# Run Execution
runner = Inspec::Runner.new(runner_args)
runner.add_target profile_location
runner.run
EOSCRIPT
script.flush
# TODO - portability - this does not have windows compat stuff from the inspec()
# method in functional/helper.rb - it is not portable to windows at this point yet.
# https://github.com/inspec/inspec/issues/4416
CMD.run_command("ruby #{script.path}")
end
end
describe "when using the current :inputs key" do
let(:runner_options) { common_options.merge({ inputs: { test_input_01: "value_from_api" } }) }
it "finds the values and does not issue any warnings" do
output = run_result.stdout
skip_windows!
refute_includes output, "DEPRECATION"
structured_output = JSON.parse(output)
assert_equal "passed", structured_output["profiles"][0]["controls"][0]["results"][0]["status"]
end
end
describe "when using the legacy :attributes key" do
let(:runner_options) { common_options.merge({ attributes: { test_input_01: "value_from_api" } }) }
it "finds the values but issues a DEPRECATION warning" do
output = run_result.stdout
skip_windows!
assert_includes output, "DEPRECATION"
structured_output = JSON.parse(output.lines.reject { |l| l.include? "DEPRECATION" }.join("\n") )
assert_equal "passed", structured_output["profiles"][0]["controls"][0]["results"][0]["status"]
end
end
end
describe "when accessing inputs in a variety of scopes using the DSL" do
it "is able to read the inputs using the input keyword" do
cmd = "exec #{inputs_profiles_path}/scoping"

View file

@ -100,7 +100,7 @@ describe Inspec::InputRegistry do
describe "when a CLI --attrs file is provided and has inputs" do
let(:sources) { { cli_input_files: ["file1.yaml"] } }
it "returns a hash containing the inputs" do
fixture_inputs = { foo: "bar" }
fixture_inputs = { "foo" => "bar" }
secrets = mock
secrets.stubs(:inputs).returns(fixture_inputs)
Inspec::SecretsBackend.expects(:resolve).with("file1.yaml").returns(secrets)
@ -124,7 +124,7 @@ describe Inspec::InputRegistry do
let(:sources) { { cli_input_files: ["file1.yaml", "file2.yaml"] } }
it "returns a hash containing the inputs from the valid files" do
inputs = { foo: "bar" }
inputs = { "foo" => "bar" }
secrets1 = mock
secrets1.stubs(:inputs).returns(nil)
secrets2 = mock
@ -139,12 +139,12 @@ describe Inspec::InputRegistry do
let(:sources) { { cli_input_files: ["file1.yaml", "file2.yaml"] } }
it "returns a hash containing all the inputs" do
secrets1 = mock
secrets1.stubs(:inputs).returns({ key1: "value1" })
secrets1.stubs(:inputs).returns({ "key1" => "value1" })
secrets2 = mock
secrets2.stubs(:inputs).returns({ key2: "value2" })
secrets2.stubs(:inputs).returns({ "key2" => "value2" })
Inspec::SecretsBackend.expects(:resolve).with("file1.yaml").returns(secrets1)
Inspec::SecretsBackend.expects(:resolve).with("file2.yaml").returns(secrets2)
seen_inputs.must_equal({ key1: "value1", key2: "value2" })
seen_inputs.must_equal({ "key1" => "value1", "key2" => "value2" })
end
end
end

View file

@ -0,0 +1,5 @@
control "test_control_01" do
describe input("test_input_01", value: "value_from_dsl") do
it { should cmp "value_from_api" }
end
end

View file

@ -0,0 +1,6 @@
name: via-runner
license: Apache-2.0
summary: Profile to test inspec loading inputs via the Runner API (audit cookbook / kitchen inspec)
version: 0.1.0
supports:
platform: os