From b9dde53e5410c4163466314aae01029a9f3fea7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Romain=20Tarti=C3=A8re?= Date: Fri, 24 Feb 2023 11:48:30 -1000 Subject: [PATCH] Unwrap sensitive values in error messages When sensitive values are compared and do not match, the produce error message does not help for debugging: ``` 1) postgresql::server::role with Password Datatype Sensitive[String] has alter role for "test" user with password as **** Failure/Error: is_expected.to contain_postgresql_psql('ALTER ROLE test ENCRYPTED PASSWORD ****') .with('command' => sensitive('ALTER ROLE "test" ENCRYPTED PASSWORD \'new-pa$s\''), 'sensitive' => 'true', 'unless' => sensitive("SELECT 1 FROM pg_shadow WHERE usename = 'test' AND passwd = 'new-pa$s'"), 'port' => '5432') expected that the catalogue would contain Postgresql_psql[ALTER ROLE test ENCRYPTED PASSWORD ****] with command set to Sensitive("ALTER ROLE \"test\" ENCRYPTED PASSWORD 'new-pa$s'") but it is set to #, and parameter unless set to Sensitive("SELECT 1 FROM pg_shadow WHERE usename = 'test' AND passwd = 'new-pa$s'") but it is set to # Diff: # ./spec/defines/server/role_spec.rb:56:in `block (3 levels) in ' # /usr/home/romain/.gem/ruby/3.0/bin/rspec:25:in `load' # /usr/home/romain/.gem/ruby/3.0/bin/rspec:25:in `
' ``` With this change, the sensitive values are unwrapped and allow to spot the missing unwraps in unit tests: ``` 1) postgresql::server::role with Password Datatype Sensitive[String] has alter role for "test" user with password as **** Failure/Error: is_expected.to contain_postgresql_psql('ALTER ROLE test ENCRYPTED PASSWORD ****') .with('command' => sensitive('ALTER ROLE "test" ENCRYPTED PASSWORD \'new-pa$s\''), 'sensitive' => 'true', 'unless' => sensitive("SELECT 1 FROM pg_shadow WHERE usename = 'test' AND passwd = 'new-pa$s'"), 'port' => '5432') expected that the catalogue would contain Postgresql_psql[ALTER ROLE test ENCRYPTED PASSWORD ****] with command set to Sensitive("ALTER ROLE \"test\" ENCRYPTED PASSWORD 'new-pa$s'") but it is set to Sensitive("ALTER ROLE \"test\" ENCRYPTED PASSWORD 'Sensitive [value redacted]'"), and parameter unless set to Sensitive("SELECT 1 FROM pg_shadow WHERE usename = 'test' AND passwd = 'new-pa$s'") but it is set to Sensitive("SELECT 1 FROM pg_shadow WHERE usename = 'test' AND passwd = 'Sensitive [value redacted]'") Diff: @@ -1,4 +1,4 @@ -Sensitive("ALTER ROLE \"test\" ENCRYPTED PASSWORD 'new-pa$s'") +Sensitive("ALTER ROLE \"test\" ENCRYPTED PASSWORD 'Sensitive [value redacted]'") -Sensitive("SELECT 1 FROM pg_shadow WHERE usename = 'test' AND passwd = 'new-pa$s'") +Sensitive("SELECT 1 FROM pg_shadow WHERE usename = 'test' AND passwd = 'Sensitive [value redacted]'") ``` --- .../matchers/parameter_matcher.rb | 2 ++ lib/rspec-puppet/sensitive.rb | 5 ++++ spec/unit/matchers/parameter_matcher_spec.rb | 29 +++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/lib/rspec-puppet/matchers/parameter_matcher.rb b/lib/rspec-puppet/matchers/parameter_matcher.rb index 64a7a5026..7d8495e1e 100644 --- a/lib/rspec-puppet/matchers/parameter_matcher.rb +++ b/lib/rspec-puppet/matchers/parameter_matcher.rb @@ -28,6 +28,8 @@ def matches?(resource) actual = resource[@parameter] expected = @value + actual = RSpec::Puppet::Sensitive.new(actual.unwrap) if actual.is_a?(Puppet::Pops::Types::PSensitiveType::Sensitive) + # Puppet flattens an array with a single value into just the value and # this can cause confusion when testing as people expect when you put # an array in, you'll get an array out. diff --git a/lib/rspec-puppet/sensitive.rb b/lib/rspec-puppet/sensitive.rb index c35962b37..cb9fb5d7a 100644 --- a/lib/rspec-puppet/sensitive.rb +++ b/lib/rspec-puppet/sensitive.rb @@ -24,6 +24,11 @@ def inspect "Sensitive(#{@value.inspect})" end + # @return the unwrapped value (needed to show diff) + def to_s + inspect + end + # Check for equality with another value. # If compared to Puppet Sensitive type, it compares the wrapped values. diff --git a/spec/unit/matchers/parameter_matcher_spec.rb b/spec/unit/matchers/parameter_matcher_spec.rb index 594c6dd15..b6001df3a 100644 --- a/spec/unit/matchers/parameter_matcher_spec.rb +++ b/spec/unit/matchers/parameter_matcher_spec.rb @@ -108,5 +108,34 @@ expect(subject.matches?(foo_parameter: nil)).to be(false) end end + + context 'with sensitive("foo") expected' do + subject do + described_class.new(:foo_parameter, RSpec::Puppet::Sensitive.new('foo'), :should) + end + + it 'matches sensitive("foo")' do + expect(subject.matches?(foo_parameter: RSpec::Puppet::Sensitive.new('foo'))).to be(true) + expect(subject.errors.size).to eq(0) + end + + it 'does not match sensitive("bar")' do + expect(subject.matches?(foo_parameter: RSpec::Puppet::Sensitive.new('bar'))).to be(false) + expect(subject.errors.size).to eq(1) + expect(subject.errors[0].message).to eq('foo_parameter set to Sensitive("foo") but it is set to Sensitive("bar")') + end + + it 'does not matches "foo"' do + expect(subject.matches?(foo_parameter: 'foo')).to be(false) + expect(subject.errors.size).to eq(1) + expect(subject.errors[0].message).to eq('foo_parameter set to Sensitive("foo") but it is set to "foo"') + end + + it 'does not matches "Sensitive [value redacted]"' do + expect(subject.matches?(foo_parameter: 'Sensitive [value redacted]')).to be(false) + expect(subject.errors.size).to eq(1) + expect(subject.errors[0].message).to eq('foo_parameter set to Sensitive("foo") but it is set to "Sensitive [value redacted]"') + end + end end end