mirror of
https://github.com/inspec/inspec
synced 2024-11-27 07:00:39 +00:00
Merge pull request #4398 from inspec/cw/rename-runner-api
Accept input keys via the Runner API
This commit is contained in:
commit
a849221b27
11 changed files with 122 additions and 22 deletions
2
Rakefile
2
Rakefile
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
6
test/unit/mock/profiles/inputs/via-runner/inspec.yml
Normal file
6
test/unit/mock/profiles/inputs/via-runner/inspec.yml
Normal 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
|
Loading…
Reference in a new issue