puppet 5.5.17-x86-mingw32 → 5.5.18-x86-mingw32

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 (225) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +1 -1
  3. data/Gemfile +2 -3
  4. data/Gemfile.lock +35 -31
  5. data/ext/build_defaults.yaml +1 -0
  6. data/ext/cert_inspector +3 -3
  7. data/ext/puppet-test +2 -2
  8. data/ext/regexp_nodes/regexp_nodes.rb +4 -4
  9. data/ext/windows/service/daemon.rb +54 -8
  10. data/install.rb +6 -6
  11. data/lib/puppet/application.rb +1 -1
  12. data/lib/puppet/application/apply.rb +2 -2
  13. data/lib/puppet/application/describe.rb +3 -9
  14. data/lib/puppet/application/doc.rb +1 -1
  15. data/lib/puppet/application/lookup.rb +1 -1
  16. data/lib/puppet/application/script.rb +2 -2
  17. data/lib/puppet/configurer.rb +86 -28
  18. data/lib/puppet/configurer/downloader.rb +2 -6
  19. data/lib/puppet/defaults.rb +17 -4
  20. data/lib/puppet/error.rb +9 -1
  21. data/lib/puppet/external/nagios/base.rb +1 -1
  22. data/lib/puppet/face/ca.rb +1 -1
  23. data/lib/puppet/face/module/list.rb +5 -5
  24. data/lib/puppet/face/module/search.rb +1 -1
  25. data/lib/puppet/face/module/uninstall.rb +1 -1
  26. data/lib/puppet/face/module/upgrade.rb +1 -1
  27. data/lib/puppet/file_serving/http_metadata.rb +1 -1
  28. data/lib/puppet/file_system.rb +0 -8
  29. data/lib/puppet/file_system/memory_file.rb +1 -1
  30. data/lib/puppet/file_system/posix.rb +3 -2
  31. data/lib/puppet/forge.rb +3 -3
  32. data/lib/puppet/functions/epp.rb +4 -4
  33. data/lib/puppet/functions/inline_epp.rb +5 -5
  34. data/lib/puppet/gettext/module_translations.rb +1 -1
  35. data/lib/puppet/graph/rb_tree_map.rb +2 -2
  36. data/lib/puppet/graph/simple_graph.rb +6 -5
  37. data/lib/puppet/indirector/file_bucket_file/file.rb +1 -1
  38. data/lib/puppet/indirector/hiera.rb +2 -0
  39. data/lib/puppet/indirector/resource/ral.rb +1 -3
  40. data/lib/puppet/indirector/resource/validator.rb +1 -1
  41. data/lib/puppet/interface.rb +2 -1
  42. data/lib/puppet/loaders.rb +0 -1
  43. data/lib/puppet/metatype/manager.rb +1 -1
  44. data/lib/puppet/module.rb +1 -1
  45. data/lib/puppet/module_tool/applications/builder.rb +1 -1
  46. data/lib/puppet/module_tool/applications/installer.rb +1 -1
  47. data/lib/puppet/module_tool/applications/uninstaller.rb +3 -3
  48. data/lib/puppet/module_tool/metadata.rb +1 -1
  49. data/lib/puppet/module_tool/shared_behaviors.rb +4 -4
  50. data/lib/puppet/module_tool/tar/mini.rb +1 -1
  51. data/lib/puppet/network/http/api/indirected_routes.rb +12 -11
  52. data/lib/puppet/network/http/connection.rb +10 -12
  53. data/lib/puppet/network/http/pool.rb +2 -0
  54. data/lib/puppet/network/http/rack/rest.rb +2 -2
  55. data/lib/puppet/network/http/site.rb +1 -1
  56. data/lib/puppet/network/resolver.rb +2 -2
  57. data/lib/puppet/node/environment.rb +4 -2
  58. data/lib/puppet/parser/ast.rb +1 -1
  59. data/lib/puppet/parser/ast/resourceparam.rb +1 -1
  60. data/lib/puppet/parser/functions.rb +1 -1
  61. data/lib/puppet/parser/functions/epp.rb +3 -3
  62. data/lib/puppet/parser/functions/inline_epp.rb +5 -5
  63. data/lib/puppet/pops/evaluator/collectors/catalog_collector.rb +1 -1
  64. data/lib/puppet/pops/evaluator/collectors/exported_collector.rb +1 -1
  65. data/lib/puppet/pops/evaluator/external_syntax_support.rb +3 -2
  66. data/lib/puppet/pops/evaluator/runtime3_support.rb +4 -4
  67. data/lib/puppet/pops/loaders.rb +1 -1
  68. data/lib/puppet/pops/lookup/hiera_config.rb +1 -0
  69. data/lib/puppet/pops/lookup/sub_lookup.rb +1 -1
  70. data/lib/puppet/pops/merge_strategy.rb +22 -18
  71. data/lib/puppet/pops/parser/heredoc_support.rb +1 -1
  72. data/lib/puppet/pops/parser/interpolation_support.rb +4 -4
  73. data/lib/puppet/pops/parser/locator.rb +1 -1
  74. data/lib/puppet/pops/parser/pn_parser.rb +17 -16
  75. data/lib/puppet/pops/puppet_stack.rb +51 -48
  76. data/lib/puppet/pops/types/p_sensitive_type.rb +1 -1
  77. data/lib/puppet/pops/types/string_converter.rb +10 -10
  78. data/lib/puppet/pops/types/types.rb +3 -3
  79. data/lib/puppet/property.rb +1 -1
  80. data/lib/puppet/property/ensure.rb +1 -1
  81. data/lib/puppet/provider/augeas/augeas.rb +1 -1
  82. data/lib/puppet/provider/cron/crontab.rb +1 -1
  83. data/lib/puppet/provider/exec.rb +6 -2
  84. data/lib/puppet/provider/mount.rb +1 -1
  85. data/lib/puppet/provider/mount/parsed.rb +8 -8
  86. data/lib/puppet/provider/nameservice/directoryservice.rb +1 -1
  87. data/lib/puppet/provider/nameservice/pw.rb +2 -2
  88. data/lib/puppet/provider/package/dnfmodule.rb +87 -0
  89. data/lib/puppet/provider/package/dpkg.rb +3 -12
  90. data/lib/puppet/provider/package/openbsd.rb +1 -1
  91. data/lib/puppet/provider/package/pip.rb +34 -9
  92. data/lib/puppet/provider/package/portage.rb +4 -4
  93. data/lib/puppet/provider/package/rpm.rb +6 -6
  94. data/lib/puppet/provider/package/windows/package.rb +1 -1
  95. data/lib/puppet/provider/package/yum.rb +1 -1
  96. data/lib/puppet/provider/package_targetable.rb +5 -4
  97. data/lib/puppet/provider/parsedfile.rb +1 -1
  98. data/lib/puppet/provider/scheduled_task/win32_taskscheduler.rb +3 -3
  99. data/lib/puppet/provider/service/daemontools.rb +9 -9
  100. data/lib/puppet/provider/service/openbsd.rb +1 -1
  101. data/lib/puppet/provider/service/rcng.rb +2 -2
  102. data/lib/puppet/provider/service/runit.rb +2 -8
  103. data/lib/puppet/provider/service/systemd.rb +8 -8
  104. data/lib/puppet/provider/user/directoryservice.rb +1 -1
  105. data/lib/puppet/provider/user/hpux.rb +1 -1
  106. data/lib/puppet/provider/user/user_role_add.rb +1 -1
  107. data/lib/puppet/provider/user/useradd.rb +22 -13
  108. data/lib/puppet/provider/user/windows_adsi.rb +4 -5
  109. data/lib/puppet/provider/yumrepo/inifile.rb +2 -2
  110. data/lib/puppet/reference/indirection.rb +2 -2
  111. data/lib/puppet/reference/metaparameter.rb +1 -3
  112. data/lib/puppet/reference/providers.rb +1 -1
  113. data/lib/puppet/reference/type.rb +3 -9
  114. data/lib/puppet/reports.rb +1 -1
  115. data/lib/puppet/resource.rb +1 -1
  116. data/lib/puppet/resource/catalog.rb +1 -1
  117. data/lib/puppet/settings.rb +3 -3
  118. data/lib/puppet/settings/environment_conf.rb +1 -0
  119. data/lib/puppet/ssl/certificate_authority/interface.rb +1 -1
  120. data/lib/puppet/ssl/certificate_factory.rb +2 -2
  121. data/lib/puppet/ssl/host.rb +3 -3
  122. data/lib/puppet/ssl/oids.rb +1 -1
  123. data/lib/puppet/transaction/report.rb +1 -1
  124. data/lib/puppet/type.rb +2 -4
  125. data/lib/puppet/type/cron.rb +1 -1
  126. data/lib/puppet/type/exec.rb +7 -3
  127. data/lib/puppet/type/file.rb +1 -2
  128. data/lib/puppet/type/file/data_sync.rb +5 -1
  129. data/lib/puppet/type/group.rb +4 -2
  130. data/lib/puppet/type/interface.rb +1 -1
  131. data/lib/puppet/type/notify.rb +3 -2
  132. data/lib/puppet/type/package.rb +2 -2
  133. data/lib/puppet/type/schedule.rb +1 -1
  134. data/lib/puppet/type/selboolean.rb +17 -3
  135. data/lib/puppet/type/service.rb +1 -1
  136. data/lib/puppet/type/user.rb +4 -2
  137. data/lib/puppet/util.rb +35 -12
  138. data/lib/puppet/util/command_line/trollop.rb +1 -1
  139. data/lib/puppet/util/http_proxy.rb +8 -14
  140. data/lib/puppet/util/instance_loader.rb +1 -1
  141. data/lib/puppet/util/log.rb +1 -1
  142. data/lib/puppet/util/log/destinations.rb +2 -2
  143. data/lib/puppet/util/logging.rb +30 -18
  144. data/lib/puppet/util/metric.rb +2 -2
  145. data/lib/puppet/util/monkey_patches.rb +1 -1
  146. data/lib/puppet/util/nagios_maker.rb +2 -2
  147. data/lib/puppet/util/network_device/cisco/device.rb +1 -1
  148. data/lib/puppet/util/network_device/cisco/interface.rb +2 -2
  149. data/lib/puppet/util/network_device/transport/ssh.rb +1 -1
  150. data/lib/puppet/util/provider_features.rb +2 -4
  151. data/lib/puppet/util/rdoc.rb +1 -1
  152. data/lib/puppet/util/reference.rb +1 -1
  153. data/lib/puppet/util/resource_template.rb +1 -1
  154. data/lib/puppet/util/selinux.rb +3 -1
  155. data/lib/puppet/util/windows/adsi.rb +58 -28
  156. data/lib/puppet/util/windows/registry.rb +7 -5
  157. data/lib/puppet/vendor.rb +1 -1
  158. data/lib/puppet/version.rb +1 -1
  159. data/lib/puppet_pal.rb +2 -2
  160. data/locales/puppet.pot +115 -95
  161. data/man/man5/puppet.conf.5 +21 -5
  162. data/man/man8/puppet-agent.8 +1 -1
  163. data/man/man8/puppet-apply.8 +1 -1
  164. data/man/man8/puppet-ca.8 +1 -1
  165. data/man/man8/puppet-catalog.8 +1 -1
  166. data/man/man8/puppet-cert.8 +1 -1
  167. data/man/man8/puppet-certificate.8 +1 -1
  168. data/man/man8/puppet-certificate_request.8 +1 -1
  169. data/man/man8/puppet-certificate_revocation_list.8 +1 -1
  170. data/man/man8/puppet-config.8 +1 -1
  171. data/man/man8/puppet-describe.8 +1 -1
  172. data/man/man8/puppet-device.8 +1 -1
  173. data/man/man8/puppet-doc.8 +1 -1
  174. data/man/man8/puppet-epp.8 +1 -1
  175. data/man/man8/puppet-facts.8 +1 -1
  176. data/man/man8/puppet-filebucket.8 +1 -1
  177. data/man/man8/puppet-generate.8 +1 -1
  178. data/man/man8/puppet-help.8 +1 -1
  179. data/man/man8/puppet-key.8 +1 -1
  180. data/man/man8/puppet-lookup.8 +1 -1
  181. data/man/man8/puppet-man.8 +1 -1
  182. data/man/man8/puppet-master.8 +1 -1
  183. data/man/man8/puppet-module.8 +1 -1
  184. data/man/man8/puppet-node.8 +1 -1
  185. data/man/man8/puppet-parser.8 +1 -1
  186. data/man/man8/puppet-plugin.8 +1 -1
  187. data/man/man8/puppet-report.8 +1 -1
  188. data/man/man8/puppet-resource.8 +1 -1
  189. data/man/man8/puppet-script.8 +1 -1
  190. data/man/man8/puppet-status.8 +1 -1
  191. data/man/man8/puppet.8 +2 -2
  192. data/spec/fixtures/unit/provider/package/dnfmodule/dnf-module-list-installed.txt +11 -0
  193. data/spec/integration/configurer_spec.rb +52 -0
  194. data/spec/integration/type/notify_spec.rb +46 -0
  195. data/spec/unit/configurer_spec.rb +380 -397
  196. data/spec/unit/forge/forge_spec.rb +1 -3
  197. data/spec/unit/forge/repository_spec.rb +1 -3
  198. data/spec/unit/indirector/resource/ral_spec.rb +4 -4
  199. data/spec/unit/network/http/connection_spec.rb +26 -0
  200. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +8 -3
  201. data/spec/unit/provider/exec_spec.rb +209 -0
  202. data/spec/unit/provider/package/dnfmodule_spec.rb +186 -0
  203. data/spec/unit/provider/package/dpkg_spec.rb +15 -3
  204. data/spec/unit/provider/package/pip_spec.rb +51 -6
  205. data/spec/unit/provider/package/portage_spec.rb +4 -4
  206. data/spec/unit/provider/package_targetable_spec.rb +60 -0
  207. data/spec/unit/provider/service/daemontools_spec.rb +24 -0
  208. data/spec/unit/provider/service/runit_spec.rb +24 -0
  209. data/spec/unit/provider/service/systemd_spec.rb +22 -22
  210. data/spec/unit/provider/user/hpux_spec.rb +2 -2
  211. data/spec/unit/provider/user/useradd_spec.rb +46 -0
  212. data/spec/unit/type/exec_spec.rb +6 -12
  213. data/spec/unit/type/file/content_spec.rb +9 -3
  214. data/spec/unit/type/file_spec.rb +9 -4
  215. data/spec/unit/type/selboolean_spec.rb +4 -6
  216. data/spec/unit/util/execution_spec.rb +16 -0
  217. data/spec/unit/util/http_proxy_spec.rb +97 -0
  218. data/spec/unit/util/log/destinations_spec.rb +7 -3
  219. data/spec/unit/util/log_spec.rb +0 -138
  220. data/spec/unit/util/logging_spec.rb +200 -0
  221. data/spec/unit/util/windows/adsi_spec.rb +51 -0
  222. data/tasks/manpages.rake +1 -0
  223. metadata +12 -5
  224. data/lib/puppet/pops/loader/null_loader.rb +0 -60
  225. data/locales/ja/puppet.po +0 -12114
@@ -97,10 +97,8 @@ describe Puppet::Forge do
97
97
  def mock_proxy(port, proxy_args, result, &block)
98
98
  http = double("http client")
99
99
  proxy = double("http proxy")
100
- proxy_class = double("http proxy class")
101
100
 
102
- expect(Net::HTTP).to receive(:Proxy).with(*proxy_args).and_return(proxy_class)
103
- expect(proxy_class).to receive(:new).with(host, port).and_return(proxy)
101
+ expect(Net::HTTP).to receive(:new).with(host, port, *proxy_args).and_return(proxy)
104
102
 
105
103
  expect(proxy).to receive(:open_timeout=)
106
104
  expect(proxy).to receive(:read_timeout=)
@@ -234,10 +234,8 @@ describe Puppet::Forge::Repository do
234
234
  def mock_proxy(port, proxy_args, result, &block)
235
235
  http = double("http client")
236
236
  proxy = double("http proxy")
237
- proxy_class = double("http proxy class")
238
237
 
239
- expect(Net::HTTP).to receive(:Proxy).with(*proxy_args).and_return(proxy_class)
240
- expect(proxy_class).to receive(:new).with("fake.com", port).and_return(proxy)
238
+ expect(Net::HTTP).to receive(:new).with("fake.com", port, *proxy_args).and_return(proxy)
241
239
 
242
240
  expect(proxy).to receive(:open_timeout=)
243
241
  expect(proxy).to receive(:read_timeout=)
@@ -47,7 +47,7 @@ describe "Puppet::Resource::Ral" do
47
47
  end
48
48
 
49
49
  it "should convert ral resources into regular resources" do
50
- my_resource = double("my user resource")
50
+ my_resource = double("my user resource", :title => "my user resource")
51
51
  my_instance = double("my user", :name => "root", :to_resource => my_resource)
52
52
 
53
53
  expect(Puppet::Type::User).to receive(:instances).and_return([ my_instance ])
@@ -55,7 +55,7 @@ describe "Puppet::Resource::Ral" do
55
55
  end
56
56
 
57
57
  it "should filter results by name if there's a name in the key" do
58
- my_resource = double("my user resource")
58
+ my_resource = double("my user resource", title: "my user resource")
59
59
  allow(my_resource).to receive(:to_resource).and_return(my_resource)
60
60
  allow(my_resource).to receive(:[]).with(:name).and_return("root")
61
61
 
@@ -73,11 +73,11 @@ describe "Puppet::Resource::Ral" do
73
73
  end
74
74
 
75
75
  it "should filter results by query parameters" do
76
- wrong_resource = double("my user resource")
76
+ wrong_resource = double("my user resource", title: "my user resource")
77
77
  allow(wrong_resource).to receive(:to_resource).and_return(wrong_resource)
78
78
  allow(wrong_resource).to receive(:[]).with(:name).and_return("root")
79
79
 
80
- my_resource = double("wrong resource")
80
+ my_resource = double("wrong resource", title: "wrong resource")
81
81
  allow(my_resource).to receive(:to_resource).and_return(my_resource)
82
82
  allow(my_resource).to receive(:[]).with(:name).and_return("bob")
83
83
 
@@ -266,4 +266,30 @@ describe Puppet::Network::HTTP::Connection do
266
266
 
267
267
  subject.get('/path')
268
268
  end
269
+
270
+ describe 'connection request errors' do
271
+ it "logs and raises generic http errors" do
272
+ generic_error = Net::HTTPError.new('generic error', double("response"))
273
+ expect_any_instance_of(Net::HTTP).to receive(:request).and_raise(generic_error)
274
+
275
+ expect(Puppet).to receive(:log_exception).with(anything, /^.*failed: generic error$/)
276
+ expect { subject.get('/foo') }.to raise_error(generic_error)
277
+ end
278
+
279
+ it "logs and raises timeout errors" do
280
+ timeout_error = Timeout::Error.new
281
+ expect_any_instance_of(Net::HTTP).to receive(:request).and_raise(timeout_error)
282
+
283
+ expect(Puppet).to receive(:log_exception).with(anything, /^.*timed out after .* seconds$/)
284
+ expect { subject.get('/foo') }.to raise_error(timeout_error)
285
+ end
286
+
287
+ it "logs and raises eof errors" do
288
+ eof_error = EOFError
289
+ expect_any_instance_of(Net::HTTP).to receive(:request).and_raise(eof_error)
290
+
291
+ expect(Puppet).to receive(:log_exception).with(anything, /^.*interrupted after .* seconds$/)
292
+ expect { subject.get('/foo') }.to raise_error(eof_error)
293
+ end
294
+ end
269
295
  end
@@ -442,21 +442,26 @@ describe 'Puppet::Pops::Evaluator::EvaluatorImpl' do
442
442
  }.each do |source, coerced_val|
443
443
  it "should warn about numeric coercion in '#{source}' when strict = warning" do
444
444
  Puppet[:strict] = :warning
445
+ expect(Puppet::Pops::Evaluator::Runtime3Support::EvaluationError).not_to receive(:new)
445
446
  collect_notices(source)
446
447
  expect(warnings).to include(/The string '#{coerced_val}' was automatically coerced to the numerical value #{coerced_val}/)
447
448
  end
448
449
 
449
450
  it "should not warn about numeric coercion in '#{source}' if strict = off" do
450
451
  Puppet[:strict] = :off
452
+ expect(Puppet::Pops::Evaluator::Runtime3Support::EvaluationError).not_to receive(:new)
451
453
  collect_notices(source)
452
454
  expect(warnings).to_not include(/The string '#{coerced_val}' was automatically coerced to the numerical value #{coerced_val}/)
453
455
  end
454
456
 
455
457
  it "should error when finding numeric coercion in '#{source}' if strict = error" do
456
458
  Puppet[:strict] = :error
457
- expect { parser.evaluate_string(scope, source, __FILE__) }.to raise_error(
458
- /The string '#{coerced_val}' was automatically coerced to the numerical value #{coerced_val}/
459
- )
459
+ expect {
460
+ parser.evaluate_string(scope, source, __FILE__)
461
+ }.to raise_error {|error|
462
+ expect(error.message).to match(/The string '#{coerced_val}' was automatically coerced to the numerical value #{coerced_val}/)
463
+ expect(error.backtrace.first).to match(/runtime3_support\.rb.+optionally_fail/)
464
+ }
460
465
  end
461
466
  end
462
467
 
@@ -1,7 +1,12 @@
1
1
  require 'spec_helper'
2
2
  require 'puppet/provider/exec'
3
+ require 'puppet_spec/compiler'
4
+ require 'puppet_spec/files'
3
5
 
4
6
  describe Puppet::Provider::Exec do
7
+ include PuppetSpec::Compiler
8
+ include PuppetSpec::Files
9
+
5
10
  describe "#extractexe" do
6
11
  it "should return the first element of an array" do
7
12
  expect(subject.extractexe(['one', 'two'])).to eq('one')
@@ -31,4 +36,208 @@ describe Puppet::Provider::Exec do
31
36
  end
32
37
  end
33
38
  end
39
+
40
+ context "when handling sensitive data" do
41
+ before :each do
42
+ Puppet[:log_level] = 'debug'
43
+ end
44
+
45
+ let(:supersecret) { 'supersecret' }
46
+ let(:path) do
47
+ if Puppet::Util::Platform.windows?
48
+ # The `apply_compiled_manifest` helper doesn't add the `path` fact, so
49
+ # we can't reference that in our manifest. Windows PATHs can contain
50
+ # double quotes and trailing backslashes, which confuse HEREDOC
51
+ # interpolation below. So sanitize it:
52
+ ENV['PATH'].split(File::PATH_SEPARATOR).map do |dir|
53
+ dir.gsub(/"/, '\"').gsub(/\\$/, '')
54
+ end.join(File::PATH_SEPARATOR)
55
+ else
56
+ ENV['PATH']
57
+ end
58
+ end
59
+
60
+ def ruby_exit_0
61
+ "ruby -e 'exit 0'"
62
+ end
63
+
64
+ def echo_from_ruby_exit_0(message)
65
+ # Escape double quotes due to HEREDOC interpolation below
66
+ "ruby -e 'puts \"#{message}\"; exit 0'".gsub(/"/, '\"')
67
+ end
68
+
69
+ def echo_from_ruby_exit_1(message)
70
+ # Escape double quotes due to HEREDOC interpolation below
71
+ "ruby -e 'puts \"#{message}\"; exit 1'".gsub(/"/, '\"')
72
+ end
73
+
74
+ context "when validating the command" do
75
+ it "redacts the arguments if the command is relative" do
76
+ expect {
77
+ apply_compiled_manifest(<<-MANIFEST)
78
+ exec { 'echo':
79
+ command => Sensitive.new('echo #{supersecret}')
80
+ }
81
+ MANIFEST
82
+ }.to raise_error do |err|
83
+ expect(err).to be_a(Puppet::Error)
84
+ expect(err.message).to match(/'echo' is not qualified and no path was specified. Please qualify the command or specify a path./)
85
+ expect(err.message).to_not match(/#{supersecret}/)
86
+ end
87
+ end
88
+
89
+ it "redacts the arguments if the command is a directory" do
90
+ dir = tmpdir('exec')
91
+ apply_compiled_manifest(<<-MANIFEST)
92
+ exec { 'echo':
93
+ command => Sensitive.new('#{dir} #{supersecret}'),
94
+ }
95
+ MANIFEST
96
+ expect(@logs).to include(an_object_having_attributes(level: :err, message: /'#{dir}' is a directory, not a file/))
97
+ expect(@logs).to_not include(an_object_having_attributes(message: /#{supersecret}/))
98
+ end
99
+
100
+ it "redacts the arguments if the command isn't executable" do
101
+ file = tmpfile('exec')
102
+ Puppet::FileSystem.touch(file)
103
+ Puppet::FileSystem.chmod(0644, file)
104
+
105
+ apply_compiled_manifest(<<-MANIFEST)
106
+ exec { 'echo':
107
+ command => Sensitive.new('#{file} #{supersecret}'),
108
+ }
109
+ MANIFEST
110
+ # Execute permission works differently on Windows, but execute will fail since the
111
+ # file doesn't have a valid extension and isn't a valid executable. The raised error
112
+ # will be Errno::EIO, which is not useful. The Windows execute code needs to raise
113
+ # Puppet::Util::Windows::Error so the Win32 error message is preserved.
114
+ pending("PUP-3561 Needs to raise a meaningful Puppet::Error") if Puppet::Util::Platform.windows?
115
+ expect(@logs).to include(an_object_having_attributes(level: :err, message: /'#{file}' is not executable/))
116
+ expect(@logs).to_not include(an_object_having_attributes(message: /#{supersecret}/))
117
+ end
118
+
119
+ it "redacts the arguments if the relative command cannot be resolved using the path parameter" do
120
+ file = File.basename(tmpfile('exec'))
121
+ dir = tmpdir('exec')
122
+
123
+ apply_compiled_manifest(<<-MANIFEST)
124
+ exec { 'echo':
125
+ command => Sensitive.new('#{file} #{supersecret}'),
126
+ path => "#{dir}",
127
+ }
128
+ MANIFEST
129
+ expect(@logs).to include(an_object_having_attributes(level: :err, message: /Could not find command '#{file}'/))
130
+ expect(@logs).to_not include(an_object_having_attributes(message: /#{supersecret}/))
131
+ end
132
+ end
133
+
134
+ it "redacts the command on success" do
135
+ command = echo_from_ruby_exit_0(supersecret)
136
+
137
+ apply_compiled_manifest(<<-MANIFEST)
138
+ exec { 'true':
139
+ command => Sensitive.new("#{command}"),
140
+ path => "#{path}",
141
+ }
142
+ MANIFEST
143
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing '[redacted]'", source: /Exec\[true\]/))
144
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing: '[redacted]'", source: "Puppet"))
145
+ expect(@logs).to include(an_object_having_attributes(level: :notice, message: "executed successfully"))
146
+ expect(@logs).to_not include(an_object_having_attributes(message: /#{supersecret}/))
147
+ end
148
+
149
+ it "redacts the command on failure" do
150
+ command = echo_from_ruby_exit_1(supersecret)
151
+
152
+ apply_compiled_manifest(<<-MANIFEST)
153
+ exec { 'false':
154
+ command => Sensitive.new("#{command}"),
155
+ path => "#{path}",
156
+ }
157
+ MANIFEST
158
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing '[redacted]'", source: /Exec\[false\]/))
159
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing: '[redacted]'", source: "Puppet"))
160
+ expect(@logs).to include(an_object_having_attributes(level: :err, message: "[command redacted] returned 1 instead of one of [0]"))
161
+ expect(@logs).to_not include(an_object_having_attributes(message: /#{supersecret}/))
162
+ end
163
+
164
+ context "when handling checks" do
165
+ let(:onlyifsecret) { "onlyifsecret" }
166
+ let(:unlesssecret) { "unlesssecret" }
167
+
168
+ it "redacts command and onlyif outputs" do
169
+ onlyif = echo_from_ruby_exit_0(onlyifsecret)
170
+
171
+ apply_compiled_manifest(<<-MANIFEST)
172
+ exec { 'true':
173
+ command => Sensitive.new("#{ruby_exit_0}"),
174
+ onlyif => Sensitive.new("#{onlyif}"),
175
+ path => "#{path}",
176
+ }
177
+ MANIFEST
178
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing check '[redacted]'"))
179
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing '[redacted]'", source: /Exec\[true\]/))
180
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing: '[redacted]'", source: "Puppet"))
181
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "[output redacted]"))
182
+ expect(@logs).to include(an_object_having_attributes(level: :notice, message: "executed successfully"))
183
+ expect(@logs).to_not include(an_object_having_attributes(message: /#{onlyifsecret}/))
184
+ end
185
+
186
+ it "redacts the command that would have been executed but didn't due to onlyif" do
187
+ command = echo_from_ruby_exit_0(supersecret)
188
+ onlyif = echo_from_ruby_exit_1(onlyifsecret)
189
+
190
+ apply_compiled_manifest(<<-MANIFEST)
191
+ exec { 'true':
192
+ command => Sensitive.new("#{command}"),
193
+ onlyif => Sensitive.new("#{onlyif}"),
194
+ path => "#{path}",
195
+ }
196
+ MANIFEST
197
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing check '[redacted]'"))
198
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing: '[redacted]'", source: "Puppet"))
199
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "[output redacted]"))
200
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "'[command redacted]' won't be executed because of failed check 'onlyif'"))
201
+ expect(@logs).to_not include(an_object_having_attributes(message: /#{supersecret}/))
202
+ expect(@logs).to_not include(an_object_having_attributes(message: /#{onlyifsecret}/))
203
+ end
204
+
205
+ it "redacts command and unless outputs" do
206
+ unlesscmd = echo_from_ruby_exit_1(unlesssecret)
207
+
208
+ apply_compiled_manifest(<<-MANIFEST)
209
+ exec { 'true':
210
+ command => Sensitive.new("#{ruby_exit_0}"),
211
+ unless => Sensitive.new("#{unlesscmd}"),
212
+ path => "#{path}",
213
+ }
214
+ MANIFEST
215
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing check '[redacted]'"))
216
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing '[redacted]'", source: /Exec\[true\]/))
217
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing: '[redacted]'", source: "Puppet"))
218
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "[output redacted]"))
219
+ expect(@logs).to include(an_object_having_attributes(level: :notice, message: "executed successfully"))
220
+ expect(@logs).to_not include(an_object_having_attributes(message: /#{unlesssecret}/))
221
+ end
222
+
223
+ it "redacts the command that would have been executed but didn't due to unless" do
224
+ command = echo_from_ruby_exit_0(supersecret)
225
+ unlesscmd = echo_from_ruby_exit_0(unlesssecret)
226
+
227
+ apply_compiled_manifest(<<-MANIFEST)
228
+ exec { 'true':
229
+ command => Sensitive.new("#{command}"),
230
+ unless => Sensitive.new("#{unlesscmd}"),
231
+ path => "#{path}",
232
+ }
233
+ MANIFEST
234
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing check '[redacted]'"))
235
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing: '[redacted]'", source: "Puppet"))
236
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "[output redacted]"))
237
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "'[command redacted]' won't be executed because of failed check 'unless'"))
238
+ expect(@logs).to_not include(an_object_having_attributes(message: /#{supersecret}/))
239
+ expect(@logs).to_not include(an_object_having_attributes(message: /#{unlesssecret}/))
240
+ end
241
+ end
242
+ end
34
243
  end
@@ -0,0 +1,186 @@
1
+ require 'spec_helper'
2
+
3
+ describe Puppet::Type.type(:package).provider(:dnfmodule) do
4
+ include PuppetSpec::Fixtures
5
+
6
+ let(:dnf_version) do
7
+ <<-DNF_OUTPUT
8
+ 4.0.9
9
+ Installed: dnf-0:4.0.9.2-5.el8.noarch at Wed 29 May 2019 07:05:05 AM GMT
10
+ Built : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla> at Thu 14 Feb 2019 12:04:07 PM GMT
11
+
12
+ Installed: rpm-0:4.14.2-9.el8.x86_64 at Wed 29 May 2019 07:04:33 AM GMT
13
+ Built : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla> at Thu 20 Dec 2018 01:30:03 PM GMT
14
+ DNF_OUTPUT
15
+ end
16
+
17
+ let(:execute_options) do
18
+ {:failonfail => true, :combine => true, :custom_environment => {}}
19
+ end
20
+
21
+ let(:packages) { File.read(my_fixture("dnf-module-list-installed.txt")) }
22
+ let(:dnf_path) { '/usr/bin/dnf' }
23
+
24
+ before(:each) { allow(Puppet::Util).to receive(:which).with('/usr/bin/dnf').and_return(dnf_path) }
25
+
26
+ it "should have lower specificity" do
27
+ allow(Facter).to receive(:value).with(:osfamily).and_return(:redhat)
28
+ allow(Facter).to receive(:value).with(:operatingsystem).and_return(:redhat)
29
+ allow(Facter).to receive(:value).with(:operatingsystemmajrelease).and_return('8')
30
+ expect(described_class.specificity).to be < 200
31
+ end
32
+
33
+ describe "should be an opt-in provider" do
34
+ Array(4..8).each do |ver|
35
+ it "should not be default for redhat #{ver}" do
36
+ allow(Facter).to receive(:value).with(:operatingsystem).and_return('redhat')
37
+ allow(Facter).to receive(:value).with(:osfamily).and_return('redhat')
38
+ allow(Facter).to receive(:value).with(:operatingsystemmajrelease).and_return(ver.to_s)
39
+ expect(described_class).not_to be_default
40
+ end
41
+ end
42
+ end
43
+
44
+ describe "handling dnf versions" do
45
+ before(:each) do
46
+ expect(Puppet::Type::Package::ProviderDnfmodule).to receive(:execute)
47
+ .with(["/usr/bin/dnf", "--version"])
48
+ .and_return(dnf_version).at_most(:once)
49
+ expect(Puppet::Util::Execution).to receive(:execute)
50
+ .with(["/usr/bin/dnf", "--version"], execute_options)
51
+ .and_return(Puppet::Util::Execution::ProcessOutput.new(dnf_version, 0))
52
+ end
53
+
54
+ describe "with a supported dnf version" do
55
+ it "correctly parses the version" do
56
+ expect(described_class.current_version).to eq('4.0.9')
57
+ end
58
+ end
59
+
60
+ describe "with an unsupported dnf version" do
61
+ let(:dnf_version) do
62
+ <<-DNF_OUTPUT
63
+ 2.7.5
64
+ Installed: dnf-0:2.7.5-12.fc28.noarch at Mon 13 Aug 2018 11:05:27 PM GMT
65
+ Built : Fedora Project at Wed 18 Apr 2018 02:29:51 PM GMT
66
+
67
+ Installed: rpm-0:4.14.1-7.fc28.x86_64 at Mon 13 Aug 2018 11:05:25 PM GMT
68
+ Built : Fedora Project at Mon 19 Feb 2018 09:29:01 AM GMT
69
+ DNF_OUTPUT
70
+ end
71
+
72
+ before(:each) { described_class.instance_variable_set("@current_version", nil) }
73
+
74
+ it "correctly parses the version" do
75
+ expect(described_class.current_version).to eq('2.7.5')
76
+ end
77
+
78
+ it "raises an error when attempting prefetch" do
79
+ expect { described_class.prefetch('anything') }.to raise_error(Puppet::Error, "Modules are not supported on DNF versions lower than 3.0.1")
80
+ end
81
+ end
82
+ end
83
+
84
+ describe "when installing a module" do
85
+ let(:name) { 'baz' }
86
+
87
+ let(:resource) do
88
+ Puppet::Type.type(:package).new(
89
+ :name => name,
90
+ :provider => 'dnfmodule',
91
+ )
92
+ end
93
+
94
+ let(:provider) do
95
+ provider = described_class.new
96
+ provider.resource = resource
97
+ provider
98
+ end
99
+
100
+ describe 'provider features' do
101
+ it { is_expected.to be_versionable }
102
+ it { is_expected.to be_installable }
103
+ it { is_expected.to be_uninstallable }
104
+ end
105
+
106
+ context "when installing a new module" do
107
+ before do
108
+ provider.instance_variable_get('@property_hash')[:ensure] = :absent
109
+ end
110
+
111
+ it "should not reset the module stream when package is absent" do
112
+ resource[:ensure] = :present
113
+ expect(provider).not_to receive(:uninstall)
114
+ expect(provider).to receive(:execute)
115
+ provider.install
116
+ end
117
+
118
+ it "should not reset the module stream when package is purged" do
119
+ provider.instance_variable_get('@property_hash')[:ensure] = :purged
120
+ resource[:ensure] = :present
121
+ expect(provider).not_to receive(:uninstall)
122
+ expect(provider).to receive(:execute)
123
+ provider.install
124
+ end
125
+
126
+ it "should install the default stream and flavor" do
127
+ resource[:ensure] = :present
128
+ expect(provider).to receive(:execute).with(array_including('baz'))
129
+ provider.install
130
+ end
131
+
132
+ it "should install a specific stream" do
133
+ resource[:ensure] = '9.6'
134
+ expect(provider).to receive(:execute).with(array_including('baz:9.6'))
135
+ provider.install
136
+ end
137
+
138
+ it "should install a specific flavor" do
139
+ resource[:ensure] = :present
140
+ resource[:flavor] = 'minimal'
141
+ expect(provider).to receive(:execute).with(array_including('baz/minimal'))
142
+ provider.install
143
+ end
144
+
145
+ it "should install a specific flavor and stream" do
146
+ resource[:ensure] = '9.6'
147
+ resource[:flavor] = 'minimal'
148
+ expect(provider).to receive(:execute).with(array_including('baz:9.6/minimal'))
149
+ provider.install
150
+ end
151
+ end
152
+
153
+ context "when ensuring a specific version on top of another stream" do
154
+ before do
155
+ provider.instance_variable_get('@property_hash')[:ensure] = '9.6'
156
+ end
157
+
158
+ it "should remove existing packages and reset the module stream before installing" do
159
+ resource[:ensure] = '10'
160
+ expect(provider).to receive(:execute).thrice.with(array_including(/remove|reset|install/))
161
+ provider.install
162
+ end
163
+ end
164
+ end
165
+
166
+ context "parsing the output of module list --installed" do
167
+ before { allow(described_class).to receive(:command).with(:dnf).and_return(dnf_path) }
168
+
169
+ it "returns an array of installed modules" do
170
+ allow(Puppet::Util::Execution).to receive(:execute)
171
+ .with("/usr/bin/dnf module list --installed -d 0 -e 1")
172
+ .and_return(packages)
173
+
174
+ installed_packages = described_class.instances.map { |package| package.properties }
175
+ expected_packages = [{name: "gimp", ensure: "2.8", flavor: "devel", :provider => :dnfmodule},
176
+ {name: "mariadb", ensure: "10.3", flavor: "client", :provider => :dnfmodule},
177
+ {name: "nodejs", ensure: "10", flavor: "minimal", :provider => :dnfmodule},
178
+ {name: "perl", ensure: "5.26", flavor: "minimal", :provider => :dnfmodule},
179
+ {name: "postgresql", ensure: "10", flavor: "server", :provider => :dnfmodule},
180
+ {name: "rust-toolset", ensure: "rhel8", flavor: "common", :provider => :dnfmodule},
181
+ {name: "subversion", ensure: "1.10", flavor: "server", :provider => :dnfmodule}]
182
+
183
+ expect(installed_packages).to eql(expected_packages)
184
+ end
185
+ end
186
+ end