diff --git a/lib/inspec/input.rb b/lib/inspec/input.rb index 6c1987418..62df7ea79 100644 --- a/lib/inspec/input.rb +++ b/lib/inspec/input.rb @@ -98,15 +98,15 @@ module Inspec # not been assigned a value. This allows a user to explicitly assign nil # to an input. class NO_VALUE_SET # rubocop: disable Naming/ClassAndModuleCamelCase - def initialize(name) + def initialize(name, warn_on_create = true) @name = name # output warn message if we are in a exec call - if Inspec::BaseCLI.inspec_cli_command == :exec + if warn_on_create && Inspec::BaseCLI.inspec_cli_command == :exec Inspec::Log.warn( "Input '#{@name}' does not have a value. "\ - "Use --input-file to provide a value for '#{@name}' or specify a "\ - "value with `attribute('#{@name}', value: 'somevalue', ...)`." + "Use --input-file or --input to provide a value for '#{@name}' or specify a "\ + "value with `input('#{@name}', value: 'somevalue', ...)`." ) end end @@ -277,7 +277,7 @@ module Inspec end # Determine the current winning value, but don't validate it - def current_value + def current_value(warn_on_missing = true) # Examine the events to determine highest-priority value. Tie-break # by using the last one set. events_that_set_a_value = events.select(&:value_has_been_set?) @@ -287,7 +287,7 @@ module Inspec if winning_event.nil? # No value has been set - return special no value object - NO_VALUE_SET.new(name) + NO_VALUE_SET.new(name, warn_on_missing) else winning_event.value # May still be nil end @@ -315,7 +315,7 @@ module Inspec end def has_value? - !current_value.is_a? NO_VALUE_SET + !current_value(false).is_a? NO_VALUE_SET end def to_hash @@ -348,7 +348,7 @@ module Inspec # skip if we are not doing an exec call (archive/vendor/check) return unless Inspec::BaseCLI.inspec_cli_command == :exec - proposed_value = current_value + proposed_value = current_value(false) if proposed_value.nil? || proposed_value.is_a?(NO_VALUE_SET) error = Inspec::Input::RequiredError.new error.input_name = name @@ -363,7 +363,7 @@ module Inspec type_req = type return if type_req == "Any" - proposed_value = current_value + proposed_value = current_value(false) invalid_type = false if type_req == "Regexp" diff --git a/test/fixtures/profiles/inputs/required/controls/required.rb b/test/fixtures/profiles/inputs/required/controls/required.rb new file mode 100644 index 000000000..438b51a0e --- /dev/null +++ b/test/fixtures/profiles/inputs/required/controls/required.rb @@ -0,0 +1,14 @@ + +control 'start_marker' do + describe('dummy_test_01') do + it { should cmp 'dummy_test_01'} + end +end + +discard_me = input('required_01') + +control 'end_marker' do + describe('dummy_test_04') do + it { should cmp 'dummy_test_04'} + end +end diff --git a/test/fixtures/profiles/inputs/required/files/inputs.yaml b/test/fixtures/profiles/inputs/required/files/inputs.yaml new file mode 100644 index 000000000..46945bfcf --- /dev/null +++ b/test/fixtures/profiles/inputs/required/files/inputs.yaml @@ -0,0 +1 @@ +required_01: "required_01" diff --git a/test/fixtures/profiles/inputs/required/inspec.yml b/test/fixtures/profiles/inputs/required/inspec.yml new file mode 100644 index 000000000..f0009c8c9 --- /dev/null +++ b/test/fixtures/profiles/inputs/required/inspec.yml @@ -0,0 +1,13 @@ +name: required_inputs +title: InSpec Profile +maintainer: The Authors +copyright: The Authors +copyright_email: you@example.com +license: Apache-2.0 +summary: A profile mentioning an input in a control file that is required +version: 0.1.0 + +inputs: + - name: required_01 + required: true + type: string diff --git a/test/fixtures/profiles/inputs/undeclared/controls/undeclared.rb b/test/fixtures/profiles/inputs/undeclared/controls/undeclared.rb index 815c666df..ba0fe5e66 100644 --- a/test/fixtures/profiles/inputs/undeclared/controls/undeclared.rb +++ b/test/fixtures/profiles/inputs/undeclared/controls/undeclared.rb @@ -1,3 +1,6 @@ +# Note this one is outside a control block +discard_me = input('undeclared_00') + control 'start_marker' do describe('dummy_test_01') do it { should cmp 'dummy_test_01'} diff --git a/test/functional/inputs_test.rb b/test/functional/inputs_test.rb index 26dd75233..f13cd122b 100644 --- a/test/functional/inputs_test.rb +++ b/test/functional/inputs_test.rb @@ -293,4 +293,39 @@ describe "inputs" do assert_json_controls_passing(result) end end + + # Addresses https://github.com/inspec/inspec/issues/4769 + describe "when using a profile with required inputs" do + describe "when the values are not provided" do + it "should emit an error and exit code 1" do + cmd = "exec #{inputs_profiles_path}/required" + + result = run_inspec_process(cmd, json: true) + + _(result.stderr).must_include "Input 'required_01'" + _(result.stderr).must_include "does not have a value" + assert_exit_code 1, result + end + end + describe "when the values are provided by an input file" do + it "should not warn and run normally" do + cmd = "exec #{inputs_profiles_path}/required --input-file #{inputs_profiles_path}/required/files/inputs.yaml" + + result = run_inspec_process(cmd, json: true) + + _(result.stderr).must_be_empty + assert_json_controls_passing(result) + end + end + describe "when the values are provided by a CLI flag" do + it "should not warn and run normally" do + cmd = "exec #{inputs_profiles_path}/required --input required_01=anything" + + result = run_inspec_process(cmd, json: true) + + _(result.stderr).must_be_empty + assert_json_controls_passing(result) + end + end + end end