From 2d118cbd4217edf90b15502bbe7acbcc336297fb Mon Sep 17 00:00:00 2001 From: Michael Hashizume Date: Wed, 3 Apr 2024 11:03:54 -0700 Subject: [PATCH] Evaluate confine block in case-insensitive way Prior to this commit when a user provided a confine block, Facter would downcase the value when evaluating it. For example: confine :kernel do |value| value == "Linux" end While Facter's public documentation states that this is a valid way to write a confine block, it would incorrectly and unexpectedly evaluate as false on Linux systems. However, these other styles of confine would return true: confine :kernel => "Linux" confine kernel: "Linux" This downcasing behavior was introduced in 7a81945 as a way of comparing values in a case-insensitive way. However when block confines were introduced in e4c8689, it added block evaluation before value comparison, making the case-insensitive comparison moot with blocks. This commit retains existing behavior of evaluating a confine block with a downcased fact value, while adding evaluation with the raw fact value to ensure expected behavior. --- lib/facter/custom_facts/util/confine.rb | 6 ++++-- spec/custom_facts/util/confine_spec.rb | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/facter/custom_facts/util/confine.rb b/lib/facter/custom_facts/util/confine.rb index d4bd144efb..f2f0fe454a 100644 --- a/lib/facter/custom_facts/util/confine.rb +++ b/lib/facter/custom_facts/util/confine.rb @@ -35,7 +35,7 @@ def to_s end # Evaluate the fact, returning true or false. - # if we have a block paramter then we only evaluate that instead + # if we have a block parameter then we only evaluate that instead def true? if @block && !@fact begin @@ -54,9 +54,11 @@ def true? return false if value.nil? + # We call the block with both the downcased and raw fact value for + # backwards-compatibility. if @block begin - return !!@block.call(value) + return !!@block.call(value) || !!@block.call(fact.value) # rubocop:disable Style/DoubleNegation rescue StandardError => e log.debug "Confine raised #{e.class} #{e}" return false diff --git a/spec/custom_facts/util/confine_spec.rb b/spec/custom_facts/util/confine_spec.rb index 0b1bdf628e..24021eab88 100755 --- a/spec/custom_facts/util/confine_spec.rb +++ b/spec/custom_facts/util/confine_spec.rb @@ -126,6 +126,20 @@ def confined(fact_value, *confines) expect(confine.true?).to be true end + it 'accepts and evaluate a block argument against the fact while respecting case' do + allow(fact).to receive(:value).and_return 'Foo' + confine = LegacyFacter::Util::Confine.new(:yay) { |f| f == 'Foo' } + expect(confine.true?).to be true + end + + it 'accepts and evaluate multiple block arguments' do + allow(fact).to receive(:value).and_return 'bar' + first_confine = LegacyFacter::Util::Confine.new(:yay) { |f| f == 'foo' } + second_confine = LegacyFacter::Util::Confine.new(:yay) { |f| f == 'bar' } + expect(first_confine.true?).to be false + expect(second_confine.true?).to be true + end + it 'returns false if the block raises a StandardError when checking a fact' do allow(fact).to receive(:value).and_return 'foo' confine = LegacyFacter::Util::Confine.new(:yay) { |_f| raise StandardError }