diff --git a/lib/inspec/control_eval_context.rb b/lib/inspec/control_eval_context.rb index 0b87bcccc..df8ec4f73 100644 --- a/lib/inspec/control_eval_context.rb +++ b/lib/inspec/control_eval_context.rb @@ -52,6 +52,7 @@ module Inspec @conf = conf @dependencies = dependencies @require_loader = require_loader + @skip_file_message = nil @skip_file = false @skip_only_if_eval = skip_only_if_eval end @@ -118,18 +119,18 @@ module Inspec define_method :register_control do |control, &block| if @skip_file - ::Inspec::Rule.set_skip_rule(control, true) + ::Inspec::Rule.set_skip_rule(control, true, @skip_file_message) end unless profile_context_owner.profile_supports_platform? platform = inspec.platform msg = "Profile #{profile_context_owner.profile_id} is not supported on platform #{platform.name}/#{platform.release}." - ::Inspec::Rule.set_skip_rule(control, msg) + ::Inspec::Rule.set_skip_rule(control, true, msg) end unless profile_context_owner.profile_supports_inspec_version? msg = "Profile #{profile_context_owner.profile_id} is not supported on InSpec version (#{Inspec::VERSION})." - ::Inspec::Rule.set_skip_rule(control, msg) + ::Inspec::Rule.set_skip_rule(control, true, msg) end profile_context_owner.register_rule(control, &block) unless control.nil? @@ -144,19 +145,19 @@ module Inspec profile_context_owner.unregister_rule(id) end - define_method :only_if do |&block| + define_method :only_if do |message = nil, &block| return unless block return if @skip_file == true return if @skip_only_if_eval == true return if block.yield == true - # Apply `set_skip_rule` for other rules in the same file profile_context_owner.rules.values.each do |r| sources_match = r.source_file == block.source_location[0] - Inspec::Rule.set_skip_rule(r, true) if sources_match + Inspec::Rule.set_skip_rule(r, true, message) if sources_match end + @skip_file_message = message @skip_file = true end diff --git a/lib/inspec/rule.rb b/lib/inspec/rule.rb index 18da0d162..d3f45a75b 100644 --- a/lib/inspec/rule.rb +++ b/lib/inspec/rule.rb @@ -42,7 +42,7 @@ module Inspec @__rule_id = id @__profile_id = profile_id @__checks = [] - @__skip_rule = nil + @__skip_rule = {} @__merge_count = 0 @__merge_changes = [] @__skip_only_if_eval = opts[:skip_only_if_eval] @@ -118,11 +118,12 @@ module Inspec # # @param [Type] &block returns true if tests are added, false otherwise # @return [nil] - def only_if + def only_if(message = nil) return unless block_given? return if @__skip_only_if_eval == true - @__skip_rule ||= !yield + @__skip_rule[:result] ||= !yield + @__skip_rule[:message] = message end # Describe will add one or more tests to this control. There is 2 ways @@ -174,8 +175,9 @@ module Inspec rule.instance_variable_get(:@__skip_rule) end - def self.set_skip_rule(rule, value) - rule.instance_variable_set(:@__skip_rule, value) + def self.set_skip_rule(rule, value, message = nil) + rule.instance_variable_set(:@__skip_rule, + { result: value, message: message }) end def self.merge_count(rule) @@ -187,9 +189,13 @@ module Inspec end def self.prepare_checks(rule) - msg = skip_status(rule) - return checks(rule) unless msg - msg = 'Skipped control due to only_if condition.' if msg == true + skip_check = skip_status(rule) + return checks(rule) unless skip_check[:result].eql?(true) + if skip_check[:message] + msg = "Skipped control due to only_if condition: #{skip_check[:message]}" + else + msg = 'Skipped control due to only_if condition.' + end # TODO: we use os as the carrier here, but should consider # a separate resource to do skipping diff --git a/test/unit/profiles/profile_context_test.rb b/test/unit/profiles/profile_context_test.rb index 0859b0ec2..458fea22a 100644 --- a/test/unit/profiles/profile_context_test.rb +++ b/test/unit/profiles/profile_context_test.rb @@ -180,6 +180,15 @@ describe Inspec::ProfileContext do get_checks[0][1][0].resource_failed?.must_equal false end + it 'allows specifying a message with true only_if' do + profile.load("only_if('this is a only_if skipped message') { false }\n" + control) + get_checks.length.must_equal 1 + get_checks[0][1][0].resource_skipped?.must_equal true + get_checks[0][1][0].resource_exception_message.must_equal 'Skipped' \ + ' control due to only_if condition: this is a only_if skipped message' + get_checks[0][1][0].resource_failed?.must_equal false + end + it 'doesnt extend into other control files' do fake_control_file = if_false + control profile.load_control_file(fake_control_file, '(eval)', nil)