Skip to content

Commit c51aee0

Browse files
committed
Add setting to check catalog encoding
If RSpec.configuration.strict_catalog_encoding is set to true, check whether the catalog contains binary strings or strings with an invalid encoding. This only checks resources, not other catalog metadata like `version`, `environment` or edges. Binary strings (aka ASCII_8BIT) commonly occur in facts that call Socket.gethostname, Windows registry or partial file reads. Strings with invalid encodings commonly occur when calling the `file` function to inline kerberos key tab files or DER encoded keys. Note this check can't detect cases where the underlying byte representation happens to be valid for UTF-8. For example, if a string contains the 3 bytes sequence 0xE2 0x82 0xAC, String#valid_encoding? will return true, since that happens to correspond to the € code point. But if the string contains 0xC0, then valid_encoding? will return false, since C0 must be followed by a second byte in UTF-8. By default the setting is false, because facter has historically produced facts with ASCII_8BIT and will be detected when running "puppet apply". The behavior can be opted into by setting this in your module's spec/spec_helper.rb: RSpec.configure do |c| c.strict_catalog_encoding = true end
1 parent 1f04a1d commit c51aee0

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

lib/rspec-puppet.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def self.current_example
5757
c.add_setting :fixture_hiera_configs, default: {}
5858
c.add_setting :use_fixture_spec_hiera, default: false
5959
c.add_setting :fallback_to_default_hiera, default: true
60+
c.add_setting :strict_catalog_encoding, default: false
6061

6162
c.before(:all) do
6263
RSpec::Puppet::Setup.safe_setup_directories(nil, false) if RSpec.configuration.setup_fixtures?

lib/rspec-puppet/adapters.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ def catalog(node, exported)
128128

129129
Puppet::Pops::Evaluator::DeferredResolver.resolve_and_replace(node.facts, catalog)
130130

131+
check_encoding(catalog)
132+
131133
catalog
132134
end
133135

@@ -179,6 +181,42 @@ def set_facter_impl(impl)
179181
impl = impl.call if impl.is_a?(Proc)
180182
Object.send(:const_set, :FacterImpl, impl)
181183
end
184+
185+
# Puppet expects source code to be UTF-8, but other inputs to the
186+
# compilation process can cause binary data to be added, which cause
187+
# problems later when serializing the catalog as JSON. Warn or raise if
188+
# there are any ASCII_8BIT strings or the byte representation does not
189+
# match its encoding.
190+
#
191+
def check_encoding(obj, path = '')
192+
case obj
193+
when Puppet::Resource::Catalog
194+
obj.resources.each do |r|
195+
check_encoding(r)
196+
end
197+
when Puppet::Resource
198+
obj.to_hash.each do |param, value|
199+
check_encoding(value, "#{obj.type}[#{obj.title}]/#{param}")
200+
end
201+
when Array
202+
obj.each_with_index do |elem, idx|
203+
check_encoding(elem, "#{path}[#{idx}]")
204+
end
205+
when Hash
206+
obj.each do |k, v|
207+
check_encoding(k, "#{path}/key")
208+
check_encoding(v, "#{path}/value")
209+
end
210+
when String
211+
meth = RSpec.configuration.strict_catalog_encoding ? :raise : :warn
212+
if obj.encoding == Encoding::ASCII_8BIT
213+
send(meth, "#{path} must be wrapped in a Binary data type, not encoded as #{obj.encoding}")
214+
elsif !obj.valid_encoding?
215+
send(meth, "#{path} is not a valid #{obj.encoding} encoded String")
216+
end
217+
end
218+
end
219+
private :check_encoding
182220
end
183221

184222
def self.get

0 commit comments

Comments
 (0)