puppet 4.9.4 → 4.10.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +6 -0
  3. data/ext/project_data.yaml +2 -2
  4. data/lib/hiera/puppet_function.rb +1 -1
  5. data/lib/puppet.rb +1 -0
  6. data/lib/puppet/application.rb +14 -0
  7. data/lib/puppet/application/inspect.rb +3 -0
  8. data/lib/puppet/defaults.rb +12 -2
  9. data/lib/puppet/etc.rb +125 -0
  10. data/lib/puppet/face/help.rb +1 -1
  11. data/lib/puppet/functions.rb +49 -4
  12. data/lib/puppet/functions/eyaml_lookup_key.rb +12 -3
  13. data/lib/puppet/functions/hocon_data.rb +9 -0
  14. data/lib/puppet/functions/json_data.rb +9 -0
  15. data/lib/puppet/functions/yaml_data.rb +9 -0
  16. data/lib/puppet/indirector/file_bucket_file/file.rb +69 -22
  17. data/lib/puppet/indirector/key/file.rb +2 -1
  18. data/lib/puppet/indirector/ssl_file.rb +24 -3
  19. data/lib/puppet/module.rb +28 -22
  20. data/lib/puppet/network/http/compression.rb +2 -1
  21. data/lib/puppet/parser/compiler.rb +15 -38
  22. data/lib/puppet/parser/functions/hiera.rb +1 -1
  23. data/lib/puppet/parser/functions/hiera_array.rb +1 -1
  24. data/lib/puppet/parser/functions/hiera_hash.rb +1 -1
  25. data/lib/puppet/parser/functions/hiera_include.rb +1 -1
  26. data/lib/puppet/parser/scope.rb +59 -17
  27. data/lib/puppet/pops/evaluator/callable_signature.rb +7 -0
  28. data/lib/puppet/pops/functions/dispatch.rb +18 -5
  29. data/lib/puppet/pops/functions/dispatcher.rb +7 -13
  30. data/lib/puppet/pops/issue_reporter.rb +1 -1
  31. data/lib/puppet/pops/issues.rb +84 -0
  32. data/lib/puppet/pops/loader/base_loader.rb +13 -5
  33. data/lib/puppet/pops/lookup/configured_data_provider.rb +8 -2
  34. data/lib/puppet/pops/lookup/data_dig_function_provider.rb +109 -19
  35. data/lib/puppet/pops/lookup/data_hash_function_provider.rb +19 -4
  36. data/lib/puppet/pops/lookup/data_provider.rb +43 -29
  37. data/lib/puppet/pops/lookup/environment_data_provider.rb +1 -1
  38. data/lib/puppet/pops/lookup/explainer.rb +1 -0
  39. data/lib/puppet/pops/lookup/function_provider.rb +36 -11
  40. data/lib/puppet/pops/lookup/global_data_provider.rb +18 -5
  41. data/lib/puppet/pops/lookup/hiera_config.rb +203 -84
  42. data/lib/puppet/pops/lookup/interpolation.rb +21 -6
  43. data/lib/puppet/pops/lookup/invocation.rb +14 -9
  44. data/lib/puppet/pops/lookup/location_resolver.rb +27 -0
  45. data/lib/puppet/pops/lookup/lookup_adapter.rb +59 -6
  46. data/lib/puppet/pops/lookup/lookup_key_function_provider.rb +9 -77
  47. data/lib/puppet/pops/lookup/module_data_provider.rb +27 -4
  48. data/lib/puppet/pops/parser/lexer2.rb +1 -1
  49. data/lib/puppet/pops/pcore.rb +3 -3
  50. data/lib/puppet/pops/types/p_object_type.rb +4 -6
  51. data/lib/puppet/pops/types/ruby_generator.rb +2 -2
  52. data/lib/puppet/pops/types/type_asserter.rb +3 -3
  53. data/lib/puppet/pops/types/type_mismatch_describer.rb +25 -7
  54. data/lib/puppet/pops/types/types.rb +20 -29
  55. data/lib/puppet/provider/exec.rb +4 -2
  56. data/lib/puppet/provider/nameservice.rb +8 -8
  57. data/lib/puppet/provider/selmodule/semodule.rb +20 -16
  58. data/lib/puppet/provider/service/src.rb +39 -39
  59. data/lib/puppet/provider/service/systemd.rb +1 -1
  60. data/lib/puppet/provider/user/aix.rb +7 -2
  61. data/lib/puppet/settings.rb +30 -17
  62. data/lib/puppet/ssl/base.rb +14 -1
  63. data/lib/puppet/ssl/certificate_authority.rb +4 -2
  64. data/lib/puppet/ssl/configuration.rb +4 -1
  65. data/lib/puppet/ssl/inventory.rb +10 -3
  66. data/lib/puppet/ssl/key.rb +7 -3
  67. data/lib/puppet/test/test_helper.rb +3 -0
  68. data/lib/puppet/type.rb +13 -1
  69. data/lib/puppet/type/exec.rb +16 -1
  70. data/lib/puppet/type/group.rb +17 -11
  71. data/lib/puppet/type/user.rb +3 -1
  72. data/lib/puppet/util.rb +1 -0
  73. data/lib/puppet/util/character_encoding.rb +95 -0
  74. data/lib/puppet/util/execution.rb +9 -6
  75. data/lib/puppet/util/reference.rb +4 -2
  76. data/lib/puppet/util/windows/file.rb +5 -1
  77. data/lib/puppet/version.rb +6 -2
  78. data/locales/config.yaml +1 -1
  79. data/locales/puppet.pot +18 -4
  80. data/spec/integration/ssl/autosign_spec.rb +18 -3
  81. data/spec/integration/ssl/key_spec.rb +104 -0
  82. data/spec/integration/type/user_spec.rb +13 -6
  83. data/spec/spec_helper.rb +7 -0
  84. data/spec/unit/application/inspect_spec.rb +9 -2
  85. data/spec/unit/data_providers/function_data_provider_spec.rb +2 -2
  86. data/spec/unit/etc_spec.rb +234 -0
  87. data/spec/unit/face/certificate_spec.rb +10 -2
  88. data/spec/unit/functions/dig_spec.rb +1 -1
  89. data/spec/unit/functions/hiera_spec.rb +40 -1
  90. data/spec/unit/functions/lookup_fixture_spec.rb +10 -10
  91. data/spec/unit/functions/lookup_spec.rb +1217 -357
  92. data/spec/unit/functions4_spec.rb +37 -1
  93. data/spec/unit/indirector/file_bucket_file/file_spec.rb +33 -2
  94. data/spec/unit/indirector/key/file_spec.rb +1 -1
  95. data/spec/unit/indirector/ssl_file_spec.rb +3 -3
  96. data/spec/unit/module_spec.rb +52 -59
  97. data/spec/unit/network/http/compression_spec.rb +39 -8
  98. data/spec/unit/parser/compiler_spec.rb +14 -0
  99. data/spec/unit/pops/loaders/loaders_spec.rb +21 -3
  100. data/spec/unit/pops/loaders/module_loaders_spec.rb +61 -0
  101. data/spec/unit/pops/lookup/context_spec.rb +56 -8
  102. data/spec/unit/pops/lookup/lookup_spec.rb +32 -1
  103. data/spec/unit/pops/parser/lexer2_spec.rb +8 -0
  104. data/spec/unit/pops/types/ruby_generator_spec.rb +48 -0
  105. data/spec/unit/pops/types/type_mismatch_describer_spec.rb +12 -3
  106. data/spec/unit/pops/types/types_spec.rb +6 -7
  107. data/spec/unit/provider/nameservice_spec.rb +12 -12
  108. data/spec/unit/provider/package/pkg_spec.rb +2 -0
  109. data/spec/unit/provider/service/src_spec.rb +5 -0
  110. data/spec/unit/ssl/base_spec.rb +9 -0
  111. data/spec/unit/ssl/certificate_authority_spec.rb +2 -2
  112. data/spec/unit/ssl/certificate_request_attributes_spec.rb +6 -0
  113. data/spec/unit/ssl/certificate_request_spec.rb +1 -1
  114. data/spec/unit/ssl/certificate_spec.rb +1 -1
  115. data/spec/unit/ssl/configuration_spec.rb +11 -2
  116. data/spec/unit/ssl/inventory_spec.rb +27 -3
  117. data/spec/unit/ssl/key_spec.rb +7 -7
  118. data/spec/unit/type/exec_spec.rb +41 -4
  119. data/spec/unit/type/file_spec.rb +4 -1
  120. data/spec/unit/util/character_encoding_spec.rb +88 -0
  121. data/spec/unit/util/execution_spec.rb +12 -0
  122. data/spec/unit/version_spec.rb +4 -0
  123. metadata +3803 -3808
  124. data/tasks/i18n.rake +0 -20
@@ -153,15 +153,18 @@ module Puppet::Util::Execution
153
153
  :squelch => false,
154
154
  :override_locale => true,
155
155
  :custom_environment => {},
156
+ :sensitive => false,
156
157
  }
157
158
 
158
159
  options = default_options.merge(options)
159
160
 
160
- if command.is_a?(Array)
161
+ if options[:sensitive]
162
+ command_str = '[redacted]'
163
+ elsif command.is_a?(Array)
161
164
  command = command.flatten.map(&:to_s)
162
- str = command.join(" ")
165
+ command_str = command.join(" ")
163
166
  elsif command.is_a?(String)
164
- str = command
167
+ command_str = command
165
168
  end
166
169
 
167
170
  user_log_s = ''
@@ -176,9 +179,9 @@ module Puppet::Util::Execution
176
179
  end
177
180
 
178
181
  if respond_to? :debug
179
- debug "Executing#{user_log_s}: '#{str}'"
182
+ debug "Executing#{user_log_s}: '#{command_str}'"
180
183
  else
181
- Puppet.debug "Executing#{user_log_s}: '#{str}'"
184
+ Puppet.debug "Executing#{user_log_s}: '#{command_str}'"
182
185
  end
183
186
 
184
187
  null_file = Puppet.features.microsoft_windows? ? 'NUL' : '/dev/null'
@@ -229,7 +232,7 @@ module Puppet::Util::Execution
229
232
  end
230
233
 
231
234
  if options[:failonfail] and exit_status != 0
232
- raise Puppet::ExecutionFailure, "Execution of '#{str}' returned #{exit_status}: #{output.strip}"
235
+ raise Puppet::ExecutionFailure, "Execution of '#{command_str}' returned #{exit_status}: #{output.strip}"
233
236
  end
234
237
  ensure
235
238
  if !options[:squelch] && stdout
@@ -13,7 +13,8 @@ class Puppet::Util::Reference
13
13
  instance_load(:reference, 'puppet/reference')
14
14
 
15
15
  def self.footer
16
- "\n\n----------------\n\n*This page autogenerated on #{Time.now}*\n"
16
+ #TRANSLATORS message accompanied by date of generation
17
+ "\n\n----------------\n\n*" + _("This page autogenerated on ") + "#{Time.now}*\n"
17
18
  end
18
19
 
19
20
  def self.modes
@@ -111,7 +112,8 @@ class Puppet::Util::Reference
111
112
  def to_markdown(withcontents = true)
112
113
  # First the header
113
114
  text = markdown_header(@title, 1)
114
- text << "\n\n**This page is autogenerated; any changes will get overwritten** *(last generated on #{Time.now.to_s})*\n\n"
115
+ #TRANSLATORS message accompanied by date of generation
116
+ text << _("\n\n**This page is autogenerated; any changes will get overwritten** *(last generated on ") + "#{Time.now.to_s})*\n\n"
115
117
 
116
118
  text << @header
117
119
 
@@ -48,11 +48,15 @@ module Puppet::Util::Windows::File
48
48
  FILE_EXECUTE |
49
49
  SYNCHRONIZE
50
50
 
51
+ REPLACEFILE_WRITE_THROUGH = 0x1
52
+ REPLACEFILE_IGNORE_MERGE_ERRORS = 0x2
53
+ REPLACEFILE_IGNORE_ACL_ERRORS = 0x3
54
+
51
55
  def replace_file(target, source)
52
56
  target_encoded = wide_string(target.to_s)
53
57
  source_encoded = wide_string(source.to_s)
54
58
 
55
- flags = 0x1
59
+ flags = REPLACEFILE_IGNORE_MERGE_ERRORS
56
60
  backup_file = nil
57
61
  result = ReplaceFileW(
58
62
  target_encoded,
@@ -5,9 +5,8 @@
5
5
  # The version can be set programmatically because we want to allow the
6
6
  # Raketasks and such to set the version based on the output of `git describe`
7
7
 
8
-
9
8
  module Puppet
10
- PUPPETVERSION = '4.9.4'
9
+ PUPPETVERSION = '4.10.0'
11
10
 
12
11
  ##
13
12
  # version is a public API method intended to always provide a fast and
@@ -68,6 +67,11 @@ module Puppet
68
67
  @puppet_version ||= PUPPETVERSION
69
68
  end
70
69
 
70
+ # @return [String] containing the puppet version to minor specificity, e.g. "3.0"
71
+ def self.minor_version
72
+ self.version.split('.')[0..1].join('.')
73
+ end
74
+
71
75
  def self.version=(version)
72
76
  @puppet_version = version
73
77
  end
data/locales/config.yaml CHANGED
@@ -26,4 +26,4 @@ gettext:
26
26
  - 'lib/puppet/pops/types/type_formatter.rb'
27
27
  # The semantic_puppet gem is temporarily vendored (PUP-7114), and it
28
28
  # handles its own translation.
29
- - 'lib/semantic_puppet/**/*.rb'
29
+ - 'lib/puppet/vendor/**/*.rb'
data/locales/puppet.pot CHANGED
@@ -6,11 +6,11 @@
6
6
  #, fuzzy
7
7
  msgid ""
8
8
  msgstr ""
9
- "Project-Id-Version: Puppet automation framework 4.8.2-338-g562b302\n"
9
+ "Project-Id-Version: Puppet automation framework 4.9.4-162-g7637326\n"
10
10
  "\n"
11
11
  "Report-Msgid-Bugs-To: https://tickets.puppetlabs.com\n"
12
- "POT-Creation-Date: 2017-01-25 09:32-0800\n"
13
- "PO-Revision-Date: 2017-01-25 09:32-0800\n"
12
+ "POT-Creation-Date: 2017-03-22 13:57-0700\n"
13
+ "PO-Revision-Date: 2017-03-22 13:57-0700\n"
14
14
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
15
15
  "Language-Team: LANGUAGE <LL@li.org>\n"
16
16
  "Language: \n"
@@ -40,7 +40,7 @@ msgid ""
40
40
  " $ puppet help\n"
41
41
  msgstr ""
42
42
 
43
- msgid "--version VERSION"
43
+ msgid "VERSION"
44
44
  msgstr ""
45
45
 
46
46
  msgid "The version of the subcommand for which to show help."
@@ -77,3 +77,17 @@ msgstr ""
77
77
 
78
78
  msgid "! Subcommand unavailable due to error. Check error logs."
79
79
  msgstr ""
80
+
81
+ msgid "%{error}: %{value} is not valid UTF-8 and cannot be transcoded by Puppet."
82
+ msgstr ""
83
+
84
+ #. TRANSLATORS message accompanied by date of generation
85
+ msgid "This page autogenerated on "
86
+ msgstr ""
87
+
88
+ #. TRANSLATORS message accompanied by date of generation
89
+ msgid ""
90
+ "\n"
91
+ "\n"
92
+ "**This page is autogenerated; any changes will get overwritten** *(last generated on "
93
+ msgstr ""
@@ -4,6 +4,8 @@ describe "autosigning" do
4
4
  include PuppetSpec::Files
5
5
 
6
6
  let(:puppet_dir) { tmpdir("ca_autosigning") }
7
+ let(:utf8_value) { "utf8_\u06FF\u16A0\u{2070E}" }
8
+ let(:utf8_value_binary_string) { utf8_value.force_encoding(Encoding::BINARY) }
7
9
  let(:csr_attributes_content) do
8
10
  {
9
11
  'custom_attributes' => {
@@ -12,10 +14,16 @@ describe "autosigning" do
12
14
  '1.3.6.1.4.1.34380.2.2' => # system IPs in hex
13
15
  [ 0xC0A80001, # 192.168.0.1
14
16
  0xC0A80101 ], # 192.168.1.1
17
+ # different UTF-8 widths
18
+ # 1-byte A
19
+ # 2-byte ۿ - http://www.fileformat.info/info/unicode/char/06ff/index.htm - 0xDB 0xBF / 219 191
20
+ # 3-byte ᚠ - http://www.fileformat.info/info/unicode/char/16A0/index.htm - 0xE1 0x9A 0xA0 / 225 154 160
21
+ # 4-byte 𠜎 - http://www.fileformat.info/info/unicode/char/2070E/index.htm - 0xF0 0xA0 0x9C 0x8E / 240 160 156 142
22
+ '1.2.840.113549.1.9.7' => utf8_value,
15
23
  },
16
24
  'extension_requests' => {
17
25
  'pp_uuid' => 'abcdef',
18
- '1.3.6.1.4.1.34380.1.1.2' => '1234', # pp_instance_id
26
+ '1.3.6.1.4.1.34380.1.1.2' => utf8_value, # pp_instance_id
19
27
  '1.3.6.1.4.1.34380.1.2.1' => 'some-value', # private extension
20
28
  },
21
29
  }
@@ -107,14 +115,20 @@ describe "autosigning" do
107
115
  csr = Puppet::SSL::CertificateRequest.indirection.find(host.name)
108
116
  expect(csr.request_extensions).to have(3).items
109
117
  expect(csr.request_extensions).to include('oid' => 'pp_uuid', 'value' => 'abcdef')
110
- expect(csr.request_extensions).to include('oid' => 'pp_instance_id', 'value' => '1234')
118
+ expect(csr.request_extensions).to include('oid' => 'pp_instance_id', 'value' => utf8_value_binary_string)
111
119
  expect(csr.request_extensions).to include('oid' => '1.3.6.1.4.1.34380.1.2.1', 'value' => 'some-value')
112
120
  end
113
121
 
122
+ it "pulls custom attributes from the csr_attributes file into the certificate" do
123
+ csr = Puppet::SSL::CertificateRequest.indirection.find(host.name)
124
+ expect(csr.custom_attributes).to have(4).items
125
+ expect(csr.custom_attributes).to include('oid' => 'challengePassword', 'value' => utf8_value_binary_string)
126
+ end
127
+
114
128
  it "copies extension requests to certificate" do
115
129
  cert = ca.sign(host.name)
116
130
  expect(cert.custom_extensions).to include('oid' => 'pp_uuid', 'value' => 'abcdef')
117
- expect(cert.custom_extensions).to include('oid' => 'pp_instance_id', 'value' => '1234')
131
+ expect(cert.custom_extensions).to include('oid' => 'pp_instance_id', 'value' => utf8_value_binary_string)
118
132
  expect(cert.custom_extensions).to include('oid' => '1.3.6.1.4.1.34380.1.2.1', 'value' => 'some-value')
119
133
  end
120
134
 
@@ -122,6 +136,7 @@ describe "autosigning" do
122
136
  cert = ca.sign(host.name)
123
137
  cert.custom_extensions.each do |ext|
124
138
  expect(Puppet::SSL::Oids.subtree_of?('1.3.6.1.4.1.34380.2', ext['oid'])).to be_falsey
139
+ expect(ext['oid']).to_not eq('1.2.840.113549.1.9.7')
125
140
  end
126
141
  end
127
142
  end
@@ -0,0 +1,104 @@
1
+ #! /usr/bin/env ruby
2
+ require 'spec_helper'
3
+
4
+ require 'puppet/ssl/key'
5
+
6
+ describe Puppet::SSL::Key do
7
+ include PuppetSpec::Files
8
+
9
+ # different UTF-8 widths
10
+ # 1-byte A
11
+ # 2-byte ۿ - http://www.fileformat.info/info/unicode/char/06ff/index.htm - 0xDB 0xBF / 219 191
12
+ # 3-byte ᚠ - http://www.fileformat.info/info/unicode/char/16A0/index.htm - 0xE1 0x9A 0xA0 / 225 154 160
13
+ # 4-byte ܎ - http://www.fileformat.info/info/unicode/char/2070E/index.htm - 0xF0 0xA0 0x9C 0x8E / 240 160 156 142
14
+ let (:mixed_utf8) { "A\u06FF\u16A0\u{2070E}" } # Aۿᚠ܎
15
+
16
+ before do
17
+ # Get a safe temporary file
18
+ dir = tmpdir('key_integration_testing')
19
+
20
+ Puppet.settings[:confdir] = dir
21
+ Puppet.settings[:vardir] = dir
22
+
23
+ # This is necessary so the terminus instances don't lie around.
24
+ # and so that Puppet::SSL::Key.indirection.save may be used
25
+ Puppet::SSL::Key.indirection.termini.clear
26
+ end
27
+
28
+ describe 'with a custom user-specified passfile' do
29
+
30
+ before do
31
+ # write custom password file to where Puppet expects
32
+ password_file = tmpfile('passfile')
33
+ Puppet[:passfile] = password_file
34
+ Puppet::FileSystem.open(password_file, nil, 'w:UTF-8') { |f| f.print(mixed_utf8) }
35
+ end
36
+
37
+ it 'should use the configured password file if it is not the CA key' do
38
+ key = Puppet::SSL::Key.new('test')
39
+ expect(key.password_file).to eq(Puppet[:passfile])
40
+ expect(key.password).to eq(mixed_utf8.force_encoding(Encoding::BINARY))
41
+ end
42
+
43
+ it "should be able to read an existing private key given the correct password" do
44
+ Puppet[:keylength] = '50'
45
+
46
+ key_name = 'test'
47
+ # use OpenSSL APIs to generate a private key
48
+ private_key = OpenSSL::PKey::RSA.generate(512)
49
+
50
+ # stash it in Puppets private key directory
51
+ FileUtils.mkdir_p(Puppet[:privatekeydir])
52
+ pem_path = File.join(Puppet[:privatekeydir], "#{key_name}.pem")
53
+ Puppet::FileSystem.open(pem_path, nil, 'w:UTF-8') do |f|
54
+ # with password protection enabled
55
+ pem = private_key.to_pem(OpenSSL::Cipher::DES.new(:EDE3, :CBC), mixed_utf8)
56
+ f.print(pem)
57
+ end
58
+
59
+ # indirector loads existing .pem off disk instead of replacing it
60
+ host = Puppet::SSL::Host.new(key_name)
61
+ host.generate
62
+
63
+ # newly loaded host private key matches the manually created key
64
+ # Private-Key: (512 bit) style data
65
+ expect(host.key.content.to_text).to eq(private_key.to_text)
66
+ # -----BEGIN RSA PRIVATE KEY-----
67
+ expect(host.key.content.to_s).to eq(private_key.to_s)
68
+ expect(host.key.password).to eq(mixed_utf8.force_encoding(Encoding::BINARY))
69
+ end
70
+
71
+ it 'should export the private key to PEM using the password' do
72
+ Puppet[:keylength] = '50'
73
+
74
+ key_name = 'test'
75
+
76
+ # uses specified :passfile when writing the private key
77
+ key = Puppet::SSL::Key.new(key_name)
78
+ key.generate
79
+ Puppet::SSL::Key.indirection.save(key)
80
+
81
+ # indirector writes file here
82
+ pem_path = File.join(Puppet[:privatekeydir], "#{key_name}.pem")
83
+
84
+ # note incorrect password is an error
85
+ expect do
86
+ Puppet::FileSystem.open(pem_path, nil, 'r:ASCII') do |f|
87
+ reloaded_key = OpenSSL::PKey::RSA.new(f.read, 'invalid_password')
88
+ end
89
+ end.to raise_error(OpenSSL::PKey::RSAError)
90
+
91
+ # but when specifying the correct password
92
+ reloaded_key = nil
93
+ Puppet::FileSystem.open(pem_path, nil, 'r:ASCII') do |f|
94
+ reloaded_key = OpenSSL::PKey::RSA.new(f.read, mixed_utf8)
95
+ end
96
+
97
+ # the original key matches the manually reloaded key
98
+ # Private-Key: (512 bit) style data
99
+ expect(key.content.to_text).to eq(reloaded_key.to_text)
100
+ # -----BEGIN RSA PRIVATE KEY-----
101
+ expect(key.content.to_s).to eq(reloaded_key.to_s)
102
+ end
103
+ end
104
+ end
@@ -8,9 +8,16 @@ describe Puppet::Type.type(:user), '(integration)', :unless => Puppet.features.m
8
8
  include PuppetSpec::Compiler
9
9
 
10
10
  context "when set to purge ssh keys from a file" do
11
+ # different UTF-8 widths
12
+ # 1-byte A
13
+ # 2-byte ۿ - http://www.fileformat.info/info/unicode/char/06ff/index.htm - 0xDB 0xBF / 219 191
14
+ # 3-byte ᚠ - http://www.fileformat.info/info/unicode/char/16A0/index.htm - 0xE1 0x9A 0xA0 / 225 154 160
15
+ # 4-byte 𠜎 - http://www.fileformat.info/info/unicode/char/2070E/index.htm - 0xF0 0xA0 0x9C 0x8E / 240 160 156 142
16
+ let (:mixed_utf8) { "A\u06FF\u16A0\u{2070E}" } # Aۿᚠ𠜎
17
+
11
18
  let(:tempfile) do
12
19
  file_containing('user_spec', <<-EOF)
13
- # comment
20
+ # comment #{mixed_utf8}
14
21
  ssh-rsa KEY-DATA key-name
15
22
  ssh-rsa KEY-DATA key name
16
23
  EOF
@@ -22,12 +29,12 @@ describe Puppet::Type.type(:user), '(integration)', :unless => Puppet.features.m
22
29
 
23
30
  it "should purge authorized ssh keys" do
24
31
  apply_compiled_manifest(manifest)
25
- expect(File.read(tempfile)).not_to match(/key-name/)
32
+ expect(File.read(tempfile, :encoding => Encoding::UTF_8)).not_to match(/key-name/)
26
33
  end
27
34
 
28
35
  it "should purge keys with spaces in the comment string" do
29
36
  apply_compiled_manifest(manifest)
30
- expect(File.read(tempfile)).not_to match(/key name/)
37
+ expect(File.read(tempfile, :encoding => Encoding::UTF_8)).not_to match(/key name/)
31
38
  end
32
39
 
33
40
  context "with other prefetching resources evaluated first" do
@@ -35,14 +42,14 @@ describe Puppet::Type.type(:user), '(integration)', :unless => Puppet.features.m
35
42
 
36
43
  it "should purge authorized ssh keys" do
37
44
  apply_compiled_manifest(manifest)
38
- expect(File.read(tempfile)).not_to match(/key-name/)
45
+ expect(File.read(tempfile, :encoding => Encoding::UTF_8)).not_to match(/key-name/)
39
46
  end
40
47
  end
41
48
 
42
49
  context "with multiple unnamed keys" do
43
50
  let(:tempfile) do
44
51
  file_containing('user_spec', <<-EOF)
45
- # comment
52
+ # comment #{mixed_utf8}
46
53
  ssh-rsa KEY-DATA1
47
54
  ssh-rsa KEY-DATA2
48
55
  EOF
@@ -50,7 +57,7 @@ describe Puppet::Type.type(:user), '(integration)', :unless => Puppet.features.m
50
57
 
51
58
  it "should purge authorized ssh keys" do
52
59
  apply_compiled_manifest(manifest)
53
- expect(File.read(tempfile)).not_to match(/KEY-DATA/)
60
+ expect(File.read(tempfile, :encoding => Encoding::UTF_8)).not_to match(/KEY-DATA/)
54
61
  end
55
62
  end
56
63
  end
data/spec/spec_helper.rb CHANGED
@@ -8,6 +8,13 @@ $LOAD_PATH.unshift File.join(dir, 'lib')
8
8
  # Don't want puppet getting the command line arguments for rake or autotest
9
9
  ARGV.clear
10
10
 
11
+ # Stub out gettext's `_` method, which attempts to load translations.
12
+ # Several of our mocks (mostly around file system interaction) are broken by
13
+ # FastGettext's implementation of this method.
14
+ def _(msg)
15
+ msg
16
+ end
17
+
11
18
  begin
12
19
  require 'rubygems'
13
20
  rescue LoadError
@@ -42,6 +42,11 @@ describe Puppet::Application::Inspect do
42
42
  Puppet::Resource::Catalog.indirection.expects(:terminus_class=).with(:yaml)
43
43
  expect { @inspect.setup }.not_to raise_error
44
44
  end
45
+
46
+ it "should be marked as deprecated" do
47
+ @inspect.setup
48
+ expect(@inspect.deprecated?).to be true
49
+ end
45
50
  end
46
51
 
47
52
  describe "when executing", :uses_checksums => true do
@@ -193,8 +198,10 @@ describe Puppet::Application::Inspect do
193
198
 
194
199
  @inspect.run_command
195
200
 
196
- expect(@report.logs.first).not_to eq(nil)
197
- expect(@report.logs.first.message).to match(/Could not back up/)
201
+ # First several errors are deprecation warnings, find correct log message
202
+ expect(@report.logs).to be_any { |l|
203
+ /Could not back up/.match(l.message)
204
+ }
198
205
  end
199
206
  end
200
207
 
@@ -90,7 +90,7 @@ describe "when using function data provider" do
90
90
  env_loader.add_entry(:function, 'environment::data', f.new(compiler.topscope, env_loader), nil)
91
91
  expect do
92
92
  compiler.compile()
93
- end.to raise_error(/Value returned from deprecated API function "environment::data" has wrong type/)
93
+ end.to raise_error(/Value returned from deprecated API function 'environment::data' has wrong type/)
94
94
  end
95
95
 
96
96
  it 'raises an error if the module data function does not return a hash' do
@@ -109,7 +109,7 @@ describe "when using function data provider" do
109
109
  module_loader.add_entry(:function, 'abc::data', f.new(compiler.topscope, module_loader), nil)
110
110
  expect do
111
111
  compiler.compile()
112
- end.to raise_error(/Value returned from deprecated API function "abc::data" has wrong type/)
112
+ end.to raise_error(/Value returned from deprecated API function 'abc::data' has wrong type/)
113
113
  end
114
114
 
115
115
  def parent_fixture(dir_name)
@@ -0,0 +1,234 @@
1
+ require 'puppet'
2
+ require 'spec_helper'
3
+
4
+ # The Ruby::Etc module is largely non-functional on Windows - many methods
5
+ # simply return nil regardless of input, the Etc::Group struct is not defined,
6
+ # and Etc::Passwd is missing fields
7
+ describe Puppet::Etc, :if => !Puppet.features.microsoft_windows? do
8
+ let(:bin) { 'bin'.force_encoding(Encoding::ISO_8859_1) }
9
+ let(:root) { 'root'.force_encoding(Encoding::ISO_8859_1) }
10
+ let(:x) { 'x'.force_encoding(Encoding::ISO_8859_1) }
11
+ let(:daemon) { 'daemon'.force_encoding(Encoding::ISO_8859_1) }
12
+ let(:root_comment) { 'i am the root user'.force_encoding(Encoding::ISO_8859_1) }
13
+ let(:user_struct_iso_8859_1) { Etc::Passwd.new(root, x, 0, 0, root_comment) }
14
+ let(:group_struct_iso_8859_1) { Etc::Group.new(bin, x, 1, [root, bin, daemon]) }
15
+
16
+ # http://www.fileformat.info/info/unicode/char/5e0c/index.htm
17
+ # 希 Han Character 'rare; hope, expect, strive for'
18
+ # In EUC_KR: \xfd \xf1 - 253 241
19
+ # Not convertible to UTF-8, likely to be read in as BINARY by Ruby unless system is in EUC_KR
20
+ let(:not_convertible) { [254, 241].pack('C*') }
21
+
22
+ # characters representing different UTF-8 widths
23
+ # 1-byte A
24
+ # 2-byte ۿ - http://www.fileformat.info/info/unicode/char/06ff/index.htm - 0xDB 0xBF / 219 191
25
+ # 3-byte ᚠ - http://www.fileformat.info/info/unicode/char/16A0/index.htm - 0xE1 0x9A 0xA0 / 225 154 160
26
+ # 4-byte 𠜎 - http://www.fileformat.info/info/unicode/char/2070E/index.htm - 0xF0 0xA0 0x9C 0x8E / 240 160 156 142
27
+ #
28
+ # Should all convert cleanly to UTF-8
29
+ # Unless the system is in UTF-8, these will likely be read in as BINARY by Ruby
30
+ let(:convertible_utf8) { "A\u06FF\u16A0\u{2070E}" } # Aۿᚠ𠜎
31
+ let(:convertible_binary) { "A\u06FF\u16A0\u{2070E}".force_encoding(Encoding::BINARY) }
32
+
33
+ # For the methods described which actually expect an encoding conversion, we
34
+ # only superficially test via #force_encoding - the deeper level testing is in
35
+ # character_encoding_spec.rb which handles testing transcoding etc.
36
+
37
+ describe "getgrent" do
38
+ context "given an original system Etc Group struct with ISO-8850-1 string values" do
39
+ before { Etc.expects(:getgrent).returns(group_struct_iso_8859_1) }
40
+ let(:converted) { Puppet::Etc.getgrent }
41
+
42
+ it "should return a struct with :name and :passwd field values converted to UTF-8" do
43
+ [converted.name, converted.passwd].each do |value|
44
+ expect(value.encoding).to eq(Encoding::UTF_8)
45
+ end
46
+ end
47
+
48
+ it "should return a struct with a :mem array with all field values converted to UTF-8" do
49
+ converted.mem.each { |elem| expect(elem.encoding).to eq(Encoding::UTF_8) }
50
+ end
51
+ end
52
+
53
+ context "given an original Etc::Group struct with field values that cannot be converted to UTF-8" do
54
+ let(:group) { Etc::Group.new }
55
+ before do
56
+ # group membership contains valid and invalid UTF-8
57
+ group.mem = [convertible_binary, not_convertible]
58
+ # group name contains a value that is invalid UTF-8
59
+ group.name = not_convertible
60
+ # group passwd field is valid UTF-8
61
+ group.passwd = convertible_binary
62
+
63
+ Etc.expects(:getgrent).returns(group)
64
+ end
65
+
66
+ let(:converted) { Puppet::Etc.getgrent }
67
+
68
+ it "should convert convertible values in arrays to UTF-8" do
69
+ expect(converted.mem[0]).to eq("A\u06FF\u16A0\u{2070E}")
70
+ expect(converted.mem[0].encoding).to eq(Encoding::UTF_8) # just being explicit
71
+ end
72
+
73
+ it "should leave the unconvertible values unmodified" do
74
+ expect(converted.name).to eq([254, 241].pack('C*'))
75
+ expect(converted.name.encoding).to eq(Encoding::BINARY) # just being explicit
76
+ end
77
+
78
+ it "should leave unconvertible values in arrays unmodifed" do
79
+ expect(converted.mem[1]).to eq([254, 241].pack('C*'))
80
+ expect(converted.mem[1].encoding).to eq(Encoding::BINARY) # just being explicit
81
+ end
82
+
83
+ it "should convert values that can be converted to UTf-8" do
84
+ expect(converted.passwd).to eq("A\u06FF\u16A0\u{2070E}")
85
+ expect(converted.passwd.encoding).to eq(Encoding::UTF_8) # just being explicit
86
+ end
87
+ end
88
+ end
89
+
90
+ describe "endgrent" do
91
+ it "should call Etc.getgrent" do
92
+ Etc.expects(:getgrent)
93
+ Puppet::Etc.getgrent
94
+ end
95
+ end
96
+
97
+ describe "setgrent" do
98
+ it "should call Etc.setgrent" do
99
+ Etc.expects(:setgrent)
100
+ Puppet::Etc.setgrent
101
+ end
102
+ end
103
+
104
+ describe "getpwent" do
105
+ context "given an original system Etc Passwd struct with ISO-8859-1 string values" do
106
+ before { Etc.expects(:getpwent).returns(user_struct_iso_8859_1) }
107
+ let(:converted) { Puppet::Etc.getpwent }
108
+
109
+ it "should return an Etc Passwd struct with field values converted to UTF-8" do
110
+ [converted.name, converted.passwd, converted.gecos].each do |value|
111
+ expect(value.encoding).to eq(Encoding::UTF_8)
112
+ end
113
+ end
114
+ end
115
+
116
+ context "given an original Etc::Passwd struct with field values that cannot be converted to UTF-8" do
117
+ let(:user) { Etc::Passwd.new }
118
+ before do
119
+ # user comment field cannot be converted to UTF-8
120
+ user.gecos = not_convertible
121
+ # user passwd field is valid UTF-8
122
+ user.passwd = convertible_binary
123
+
124
+ Etc.expects(:getpwent).returns(user)
125
+ end
126
+
127
+ let(:converted) { Puppet::Etc.getpwent }
128
+
129
+ it "should leave the unconvertible values unmodified" do
130
+ expect(converted.gecos).to eq([254, 241].pack('C*'))
131
+ expect(converted.gecos.encoding).to eq(Encoding::BINARY) # just being explicit
132
+ end
133
+
134
+ it "should convert values that can be converted to UTf-8" do
135
+ expect(converted.passwd).to eq("A\u06FF\u16A0\u{2070E}")
136
+ expect(converted.passwd.encoding).to eq(Encoding::UTF_8) # just being explicit
137
+ end
138
+ end
139
+ end
140
+
141
+ describe "endpwent" do
142
+ it "should call Etc.endpwent" do
143
+ Etc.expects(:endpwent)
144
+ Puppet::Etc.endpwent
145
+ end
146
+ end
147
+
148
+ describe "setpwent" do
149
+ it "should call Etc.setpwent" do
150
+ Etc.expects(:setpwent)
151
+ Puppet::Etc.setpwent
152
+ end
153
+ end
154
+
155
+ describe "getpwnam" do
156
+ context "given a username to query" do
157
+ it "should call Etc.getpwnam with that username" do
158
+ Etc.expects(:getpwnam).with('foo')
159
+ Puppet::Etc.getpwnam('foo')
160
+ end
161
+ end
162
+
163
+ context "given an original system Etc Passwd struct with ISO-8859-1 string values" do
164
+ it "should return an Etc Passwd struct with field values converted to UTF-8" do
165
+ Etc.expects(:getpwnam).with('root').returns(user_struct_iso_8859_1)
166
+ converted = Puppet::Etc.getpwnam('root')
167
+ [converted.name, converted.passwd, converted.gecos].each do |value|
168
+ expect(value.encoding).to eq(Encoding::UTF_8)
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ describe "getgrnam" do
175
+ context "given a group name to query" do
176
+ it "should call Etc.getgrnam with that group name" do
177
+ Etc.expects(:getgrnam).with('foo')
178
+ Puppet::Etc.getgrnam('foo')
179
+ end
180
+ end
181
+
182
+ context "given an original system Etc Group struct with ISO-8859-1 string values" do
183
+ it "should return an Etc Group struct with field values converted to UTF-8" do
184
+ Etc.expects(:getgrnam).with('bin').returns(group_struct_iso_8859_1)
185
+ converted = Puppet::Etc.getgrnam('bin')
186
+ [converted.name, converted.passwd].each do |value|
187
+ expect(value.encoding).to eq(Encoding::UTF_8)
188
+ end
189
+ converted.mem.each { |elem| expect(elem.encoding).to eq(Encoding::UTF_8) }
190
+ end
191
+ end
192
+ end
193
+
194
+ describe "getgrgid" do
195
+ context "given a group ID to query" do
196
+ it "should call Etc.getgrgid with the id" do
197
+ Etc.expects(:getgrgid).with(0)
198
+ Puppet::Etc.getgrgid(0)
199
+ end
200
+ end
201
+
202
+ context "given an original Etc Group struct with field values in ISO-8859-1" do
203
+ it "should return an Etc Group struct with field values converted to UTF-8" do
204
+ Etc.expects(:getgrgid).with(1).returns(group_struct_iso_8859_1)
205
+ converted = Puppet::Etc.getgrgid(1)
206
+ [converted.name, converted.passwd].each do |value|
207
+ expect(value.encoding).to eq(Encoding::UTF_8)
208
+ end
209
+ converted.mem.each { |elem| expect(elem.encoding).to eq(Encoding::UTF_8) }
210
+ end
211
+ end
212
+ end
213
+
214
+ describe "getpwid" do
215
+ context "given a UID to query" do
216
+ it "should call Etc.getpwuid with the id" do
217
+ Etc.expects(:getpwuid).with(2)
218
+ Puppet::Etc.getpwuid(2)
219
+ end
220
+ end
221
+ end
222
+
223
+ context "given an orginal Etc Passwd struct with field values in ISO-8859-1" do
224
+ it "should return an Etc Passwd struct with field values converted to UTF-8" do
225
+ Etc.expects(:getpwuid).with(0).returns(user_struct_iso_8859_1)
226
+ converted = Puppet::Etc.getpwuid(0)
227
+ [converted.name, converted.passwd, converted.gecos].each do |value|
228
+ expect(value.encoding).to eq(Encoding::UTF_8)
229
+ end
230
+ end
231
+ end
232
+
233
+
234
+ end