From 296158c4478c58d0d7099919face36cbdd7bfe2f Mon Sep 17 00:00:00 2001 From: Clinton Wolfe Date: Mon, 19 Aug 2019 19:08:28 -0400 Subject: [PATCH] Implementation and functional tests for the --input CLI option Signed-off-by: Clinton Wolfe --- lib/inspec/input_registry.rb | 27 ++++++++++ lib/inspec/profile.rb | 3 +- test/functional/inputs_test.rb | 50 +++++++++++++++++++ .../mock/profiles/inputs/cli/controls/cli.rb | 10 ++++ test/unit/mock/profiles/inputs/cli/inspec.yml | 6 +++ 5 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 test/unit/mock/profiles/inputs/cli/controls/cli.rb create mode 100644 test/unit/mock/profiles/inputs/cli/inspec.yml diff --git a/lib/inspec/input_registry.rb b/lib/inspec/input_registry.rb index ea23bcf72..0a0440bf8 100644 --- a/lib/inspec/input_registry.rb +++ b/lib/inspec/input_registry.rb @@ -135,10 +135,37 @@ module Inspec bind_inputs_from_metadata(profile_name, sources[:profile_metadata]) bind_inputs_from_input_files(profile_name, sources[:cli_input_files]) bind_inputs_from_runner_api(profile_name, sources[:runner_api]) + bind_inputs_from_cli_args(profile_name, sources[:cli_input_arg]) end private + def bind_inputs_from_cli_args(profile_name, input_list) + # TODO: move this into a core plugin + + return if input_list.nil? + return if input_list.empty? + + # These arrive as an array of "name=value" strings + # If the user used a comma, we'll see unfortunately see it as "name=value," pairs + input_list.each do |pair| + unless pair.include?("=") + if pair.end_with?(".yaml") + raise ArgumentError, "ERROR: --input is used for individual input values, as --input name=value. Use --input-file to load a YAML file." + else + raise ArgumentError, "ERROR: An '=' is required when using --input. Usage: --input input_name1=input_value1 input2=value2" + end + end + input_name, input_value = pair.split("=") + evt = Inspec::Input::Event.new( + value: input_value.sub(/,$/, ""), # Trim trailing comma if any + provider: :cli, + priority: 50 + ) + find_or_register_input(input_name, profile_name, event: evt) + end + end + def bind_inputs_from_runner_api(profile_name, input_hash) # TODO: move this into a core plugin diff --git a/lib/inspec/profile.rb b/lib/inspec/profile.rb index 4adf66e7a..fbdf1bd0f 100644 --- a/lib/inspec/profile.rb +++ b/lib/inspec/profile.rb @@ -137,7 +137,8 @@ module Inspec # Remaining args are possible sources of inputs cli_input_files: options[:runner_conf][:input_file], # From CLI --input-file profile_metadata: metadata, - runner_api: options[:runner_conf][:inputs] # 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 + cli_input_arg: options[:runner_conf][:input] # The --input name=value CLI option ) @runner_context = diff --git a/test/functional/inputs_test.rb b/test/functional/inputs_test.rb index 3e6f1d825..995634ff4 100644 --- a/test/functional/inputs_test.rb +++ b/test/functional/inputs_test.rb @@ -149,6 +149,56 @@ describe "inputs" do end end + describe "when using the --input inline raw input flag CLI option" do + let(:result) { run_inspec_process("exec #{inputs_profiles_path}/cli #{input_opt} #{control_opt}", json: true) } + let(:control_opt) { "" } + + describe "when the --input is used once with one value" do + let(:input_opt) { "--input test_input_01=value_from_cli_01" } + let(:control_opt) { "--controls test_control_01" } + it("correctly reads the input") { result.must_have_all_controls_passing } + end + + describe "when the --input is used once with two values" do + let(:input_opt) { "--input test_input_01=value_from_cli_01 test_input_02=value_from_cli_02" } + it("correctly reads the input") { result.must_have_all_controls_passing } + end + + describe "when the --input is used once with two values and a comma" do + let(:input_opt) { "--input test_input_01=value_from_cli_01, test_input_02=value_from_cli_02" } + it("correctly reads the input") { result.must_have_all_controls_passing } + end + + describe "when the --input is used twice with one value each" do + let(:input_opt) { "--input test_input_01=value_from_cli_01 --input test_input_02=value_from_cli_02" } + let(:control_opt) { "--controls test_control_02" } + # Expected, though unfortunate, behavior is to only notice the second input + it("correctly reads the input") { result.must_have_all_controls_passing } + end + + describe "when the --input is used with no equal sign" do + let(:input_opt) { "--input value_from_cli_01" } + it "does not run and provides an error message" do + output = result.stdout + assert_includes "ERROR", output + assert_includes "An '=' is required", output + assert_includes "input_name_1=input_value_1", output + assert_equal 1, result.exit_status + end + end + + describe "when the --input is used with a .yaml extension" do + let(:input_opt) { "--input myfile.yaml" } + it "does not run and provides an error message" do + output = result.stdout + assert_includes "ERROR", output + assert_includes "individual input values", output + assert_includes "Use --input-file", output + assert_equal 1, result.exit_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" diff --git a/test/unit/mock/profiles/inputs/cli/controls/cli.rb b/test/unit/mock/profiles/inputs/cli/controls/cli.rb new file mode 100644 index 000000000..77658b8f9 --- /dev/null +++ b/test/unit/mock/profiles/inputs/cli/controls/cli.rb @@ -0,0 +1,10 @@ +control "test_control_01" do + describe input("test_input_01", value: "value_from_dsl") do + it { should cmp "value_from_cli_01"} + end +end +control "test_control_02" do + describe input("test_input_02", value: "value_from_dsl") do + it { should cmp "value_from_cli_02"} + end +end diff --git a/test/unit/mock/profiles/inputs/cli/inspec.yml b/test/unit/mock/profiles/inputs/cli/inspec.yml new file mode 100644 index 000000000..d4935f8a4 --- /dev/null +++ b/test/unit/mock/profiles/inputs/cli/inspec.yml @@ -0,0 +1,6 @@ +name: cli +license: Apache-2.0 +summary: Profile to exercise setting inputs using the --input CLI option +version: 0.1.0 +supports: + platform: os \ No newline at end of file