puppet 6.4.5-universal-darwin → 6.5.0-universal-darwin

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 (329) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +10 -10
  3. data/Gemfile +6 -6
  4. data/Gemfile.lock +46 -52
  5. data/ext/build_defaults.yaml +0 -1
  6. data/ext/project_data.yaml +3 -3
  7. data/ext/regexp_nodes/regexp_nodes.rb +4 -4
  8. data/ext/solaris/smf/puppet.xml +0 -2
  9. data/ext/windows/eventlog/Rakefile +32 -0
  10. data/ext/windows/eventlog/puppetres.dll +0 -0
  11. data/ext/windows/eventlog/puppetres.mc +18 -0
  12. data/ext/windows/service/daemon.rb +8 -38
  13. data/install.rb +24 -6
  14. data/lib/puppet.rb +3 -1
  15. data/lib/puppet/application.rb +1 -1
  16. data/lib/puppet/application/agent.rb +11 -34
  17. data/lib/puppet/application/apply.rb +6 -6
  18. data/lib/puppet/application/describe.rb +9 -3
  19. data/lib/puppet/application/device.rb +4 -14
  20. data/lib/puppet/application/doc.rb +1 -1
  21. data/lib/puppet/application/lookup.rb +2 -2
  22. data/lib/puppet/application/resource.rb +4 -4
  23. data/lib/puppet/application/script.rb +2 -2
  24. data/lib/puppet/application/ssl.rb +10 -9
  25. data/lib/puppet/configurer.rb +30 -86
  26. data/lib/puppet/configurer/downloader.rb +6 -2
  27. data/lib/puppet/defaults.rb +50 -44
  28. data/lib/puppet/error.rb +14 -9
  29. data/lib/puppet/face/catalog.rb +20 -1
  30. data/lib/puppet/face/config.rb +48 -10
  31. data/lib/puppet/face/facts.rb +1 -1
  32. data/lib/puppet/face/help.rb +1 -1
  33. data/lib/puppet/face/module/list.rb +5 -5
  34. data/lib/puppet/face/module/search.rb +1 -1
  35. data/lib/puppet/face/module/uninstall.rb +1 -1
  36. data/lib/puppet/face/module/upgrade.rb +1 -1
  37. data/lib/puppet/face/parser.rb +48 -9
  38. data/lib/puppet/face/plugin.rb +2 -9
  39. data/lib/puppet/file_serving/http_metadata.rb +1 -1
  40. data/lib/puppet/file_system.rb +12 -2
  41. data/lib/puppet/file_system/file_impl.rb +6 -3
  42. data/lib/puppet/file_system/memory_file.rb +1 -1
  43. data/lib/puppet/file_system/posix.rb +2 -3
  44. data/lib/puppet/forge.rb +3 -3
  45. data/lib/puppet/functions.rb +2 -1
  46. data/lib/puppet/functions/camelcase.rb +2 -2
  47. data/lib/puppet/functions/epp.rb +4 -4
  48. data/lib/puppet/functions/find_file.rb +9 -9
  49. data/lib/puppet/functions/inline_epp.rb +5 -5
  50. data/lib/puppet/functions/regsubst.rb +6 -8
  51. data/lib/puppet/gettext/module_translations.rb +1 -1
  52. data/lib/puppet/graph/rb_tree_map.rb +2 -2
  53. data/lib/puppet/graph/simple_graph.rb +3 -4
  54. data/lib/puppet/indirector/catalog/compiler.rb +5 -11
  55. data/lib/puppet/indirector/file_bucket_file/file.rb +1 -1
  56. data/lib/puppet/indirector/hiera.rb +0 -2
  57. data/lib/puppet/indirector/resource/ral.rb +3 -1
  58. data/lib/puppet/indirector/resource/validator.rb +1 -1
  59. data/lib/puppet/interface.rb +1 -2
  60. data/lib/puppet/loaders.rb +1 -0
  61. data/lib/puppet/metatype/manager.rb +1 -1
  62. data/lib/puppet/module.rb +1 -1
  63. data/lib/puppet/module/task.rb +4 -20
  64. data/lib/puppet/module_tool/applications/installer.rb +1 -1
  65. data/lib/puppet/module_tool/applications/uninstaller.rb +3 -3
  66. data/lib/puppet/module_tool/metadata.rb +1 -1
  67. data/lib/puppet/module_tool/shared_behaviors.rb +4 -4
  68. data/lib/puppet/module_tool/tar/mini.rb +2 -12
  69. data/lib/puppet/network/http/api/indirected_routes.rb +11 -12
  70. data/lib/puppet/network/http/connection.rb +12 -10
  71. data/lib/puppet/network/http/factory.rb +11 -1
  72. data/lib/puppet/network/http/pool.rb +0 -2
  73. data/lib/puppet/network/http/site.rb +1 -1
  74. data/lib/puppet/network/resolver.rb +2 -2
  75. data/lib/puppet/node/environment.rb +2 -4
  76. data/lib/puppet/pal/pal_impl.rb +2 -2
  77. data/lib/puppet/parser/ast.rb +1 -1
  78. data/lib/puppet/parser/ast/resourceparam.rb +1 -1
  79. data/lib/puppet/parser/functions.rb +1 -1
  80. data/lib/puppet/parser/functions/epp.rb +3 -3
  81. data/lib/puppet/parser/functions/fail.rb +8 -1
  82. data/lib/puppet/parser/functions/inline_epp.rb +5 -5
  83. data/lib/puppet/parser/scope.rb +7 -8
  84. data/lib/puppet/pops/evaluator/collectors/catalog_collector.rb +1 -1
  85. data/lib/puppet/pops/evaluator/collectors/exported_collector.rb +1 -1
  86. data/lib/puppet/pops/evaluator/external_syntax_support.rb +2 -3
  87. data/lib/puppet/pops/evaluator/runtime3_support.rb +4 -4
  88. data/lib/puppet/pops/loader/null_loader.rb +60 -0
  89. data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +6 -4
  90. data/lib/puppet/pops/loader/task_instantiator.rb +0 -4
  91. data/lib/puppet/pops/loaders.rb +1 -1
  92. data/lib/puppet/pops/lookup/hiera_config.rb +0 -1
  93. data/lib/puppet/pops/lookup/sub_lookup.rb +1 -1
  94. data/lib/puppet/pops/merge_strategy.rb +18 -22
  95. data/lib/puppet/pops/parser/heredoc_support.rb +1 -1
  96. data/lib/puppet/pops/parser/interpolation_support.rb +4 -4
  97. data/lib/puppet/pops/parser/locator.rb +1 -1
  98. data/lib/puppet/pops/parser/pn_parser.rb +16 -17
  99. data/lib/puppet/pops/puppet_stack.rb +49 -51
  100. data/lib/puppet/pops/types/p_sensitive_type.rb +1 -1
  101. data/lib/puppet/pops/types/string_converter.rb +10 -10
  102. data/lib/puppet/pops/types/types.rb +6 -5
  103. data/lib/puppet/property.rb +1 -1
  104. data/lib/puppet/property/ensure.rb +1 -1
  105. data/lib/puppet/provider/exec.rb +2 -6
  106. data/lib/puppet/provider/file/posix.rb +0 -5
  107. data/lib/puppet/provider/nameservice.rb +3 -10
  108. data/lib/puppet/provider/nameservice/directoryservice.rb +1 -1
  109. data/lib/puppet/provider/nameservice/pw.rb +2 -2
  110. data/lib/puppet/provider/package.rb +0 -2
  111. data/lib/puppet/provider/package/apt.rb +1 -5
  112. data/lib/puppet/provider/package/dnf.rb +1 -1
  113. data/lib/puppet/provider/package/dpkg.rb +18 -34
  114. data/lib/puppet/provider/package/openbsd.rb +1 -1
  115. data/lib/puppet/provider/package/pip.rb +13 -37
  116. data/lib/puppet/provider/package/portage.rb +4 -4
  117. data/lib/puppet/provider/package/puppet_gem.rb +1 -1
  118. data/lib/puppet/provider/package/rpm.rb +18 -56
  119. data/lib/puppet/provider/package/windows/package.rb +1 -1
  120. data/lib/puppet/provider/package/yum.rb +5 -9
  121. data/lib/puppet/provider/package_targetable.rb +4 -7
  122. data/lib/puppet/provider/parsedfile.rb +1 -1
  123. data/lib/puppet/provider/service/daemontools.rb +9 -9
  124. data/lib/puppet/provider/service/launchd.rb +5 -20
  125. data/lib/puppet/provider/service/openbsd.rb +1 -1
  126. data/lib/puppet/provider/service/rcng.rb +2 -2
  127. data/lib/puppet/provider/service/runit.rb +8 -2
  128. data/lib/puppet/provider/service/systemd.rb +19 -14
  129. data/lib/puppet/provider/service/windows.rb +0 -8
  130. data/lib/puppet/provider/user/directoryservice.rb +1 -1
  131. data/lib/puppet/provider/user/hpux.rb +1 -1
  132. data/lib/puppet/provider/user/pw.rb +3 -12
  133. data/lib/puppet/provider/user/user_role_add.rb +1 -5
  134. data/lib/puppet/provider/user/useradd.rb +20 -45
  135. data/lib/puppet/provider/user/windows_adsi.rb +5 -4
  136. data/lib/puppet/reference/configuration.rb +3 -3
  137. data/lib/puppet/reference/indirection.rb +2 -2
  138. data/lib/puppet/reference/metaparameter.rb +3 -1
  139. data/lib/puppet/reference/providers.rb +3 -1
  140. data/lib/puppet/reference/type.rb +9 -3
  141. data/lib/puppet/reports.rb +1 -1
  142. data/lib/puppet/resource.rb +1 -18
  143. data/lib/puppet/resource/catalog.rb +1 -1
  144. data/lib/puppet/rest/routes.rb +30 -17
  145. data/lib/puppet/settings.rb +3 -43
  146. data/lib/puppet/settings/environment_conf.rb +0 -1
  147. data/lib/puppet/ssl/certificate_request.rb +12 -2
  148. data/lib/puppet/ssl/host.rb +2 -2
  149. data/lib/puppet/ssl/oids.rb +1 -1
  150. data/lib/puppet/ssl/ssl_provider.rb +11 -5
  151. data/lib/puppet/ssl/state_machine.rb +102 -98
  152. data/lib/puppet/test/test_helper.rb +1 -0
  153. data/lib/puppet/transaction.rb +11 -33
  154. data/lib/puppet/transaction/report.rb +1 -1
  155. data/lib/puppet/type.rb +4 -2
  156. data/lib/puppet/type/exec.rb +17 -23
  157. data/lib/puppet/type/file.rb +39 -11
  158. data/lib/puppet/type/file/data_sync.rb +1 -5
  159. data/lib/puppet/type/group.rb +2 -4
  160. data/lib/puppet/type/notify.rb +3 -4
  161. data/lib/puppet/type/package.rb +3 -20
  162. data/lib/puppet/type/schedule.rb +1 -1
  163. data/lib/puppet/type/service.rb +3 -8
  164. data/lib/puppet/type/user.rb +2 -4
  165. data/lib/puppet/util.rb +29 -39
  166. data/lib/puppet/util/command_line/trollop.rb +1 -1
  167. data/lib/puppet/util/execution.rb +3 -4
  168. data/lib/puppet/util/http_proxy.rb +19 -27
  169. data/lib/puppet/util/log.rb +2 -2
  170. data/lib/puppet/util/log/destinations.rb +2 -2
  171. data/lib/puppet/util/logging.rb +20 -32
  172. data/lib/puppet/util/metric.rb +2 -2
  173. data/lib/puppet/util/monkey_patches.rb +33 -0
  174. data/lib/puppet/util/pidlock.rb +2 -3
  175. data/lib/puppet/util/provider_features.rb +4 -2
  176. data/lib/puppet/util/rdoc.rb +1 -1
  177. data/lib/puppet/util/reference.rb +1 -1
  178. data/lib/puppet/util/resource_template.rb +1 -1
  179. data/lib/puppet/util/selinux.rb +2 -8
  180. data/lib/puppet/util/skip_tags.rb +4 -0
  181. data/lib/puppet/util/windows/adsi.rb +18 -48
  182. data/lib/puppet/util/windows/process.rb +8 -8
  183. data/lib/puppet/util/windows/registry.rb +5 -7
  184. data/lib/puppet/util/windows/security.rb +0 -2
  185. data/lib/puppet/util/windows/service.rb +4 -149
  186. data/lib/puppet/util/windows/sid.rb +0 -1
  187. data/lib/puppet/vendor.rb +1 -1
  188. data/lib/puppet/version.rb +1 -1
  189. data/lib/puppet/x509/cert_provider.rb +81 -24
  190. data/locales/puppet.pot +462 -482
  191. data/man/man5/puppet.conf.5 +43 -44
  192. data/man/man8/puppet-agent.8 +1 -1
  193. data/man/man8/puppet-apply.8 +3 -3
  194. data/man/man8/puppet-catalog.8 +31 -3
  195. data/man/man8/puppet-config.8 +1 -1
  196. data/man/man8/puppet-describe.8 +1 -1
  197. data/man/man8/puppet-device.8 +1 -1
  198. data/man/man8/puppet-doc.8 +1 -1
  199. data/man/man8/puppet-epp.8 +1 -1
  200. data/man/man8/puppet-facts.8 +1 -1
  201. data/man/man8/puppet-filebucket.8 +1 -1
  202. data/man/man8/puppet-generate.8 +1 -1
  203. data/man/man8/puppet-help.8 +1 -1
  204. data/man/man8/puppet-key.8 +1 -1
  205. data/man/man8/puppet-lookup.8 +1 -1
  206. data/man/man8/puppet-man.8 +1 -1
  207. data/man/man8/puppet-module.8 +1 -1
  208. data/man/man8/puppet-node.8 +1 -1
  209. data/man/man8/puppet-parser.8 +1 -1
  210. data/man/man8/puppet-plugin.8 +1 -1
  211. data/man/man8/puppet-report.8 +1 -1
  212. data/man/man8/puppet-resource.8 +1 -1
  213. data/man/man8/puppet-script.8 +1 -1
  214. data/man/man8/puppet-ssl.8 +1 -1
  215. data/man/man8/puppet-status.8 +1 -1
  216. data/man/man8/puppet.8 +3 -3
  217. data/spec/fixtures/ssl/127.0.0.1-key.pem +56 -56
  218. data/spec/fixtures/ssl/127.0.0.1.pem +27 -27
  219. data/spec/fixtures/ssl/bad-basic-constraints.pem +32 -32
  220. data/spec/fixtures/ssl/bad-int-basic-constraints.pem +30 -30
  221. data/spec/fixtures/ssl/ca.pem +30 -30
  222. data/spec/fixtures/ssl/crl.pem +15 -15
  223. data/spec/fixtures/ssl/ec-key.pem +18 -0
  224. data/spec/fixtures/ssl/ec.pem +40 -0
  225. data/spec/fixtures/ssl/encrypted-ec-key.pem +21 -0
  226. data/spec/fixtures/ssl/encrypted-key.pem +57 -57
  227. data/spec/fixtures/ssl/intermediate-agent-crl.pem +16 -16
  228. data/spec/fixtures/ssl/intermediate-agent.pem +33 -33
  229. data/spec/fixtures/ssl/intermediate-crl.pem +17 -17
  230. data/spec/fixtures/ssl/intermediate.pem +31 -31
  231. data/spec/fixtures/ssl/pluto-key.pem +56 -56
  232. data/spec/fixtures/ssl/pluto.pem +28 -28
  233. data/spec/fixtures/ssl/request-key.pem +56 -56
  234. data/spec/fixtures/ssl/request.pem +24 -24
  235. data/spec/fixtures/ssl/revoked-key.pem +56 -56
  236. data/spec/fixtures/ssl/revoked.pem +25 -25
  237. data/spec/fixtures/ssl/signed-key.pem +56 -56
  238. data/spec/fixtures/ssl/signed.pem +25 -25
  239. data/spec/fixtures/ssl/tampered-cert.pem +27 -27
  240. data/spec/fixtures/ssl/tampered-csr.pem +24 -24
  241. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/func_with_syntax_error.rb +9 -0
  242. data/spec/fixtures/vcr/cassettes/Puppet_Network_HTTP_Connection/when_handling_requests/_request_get/should_yield_to_the_block.yml +24 -0
  243. data/spec/fixtures/vcr/cassettes/Puppet_Network_HTTP_Connection/when_handling_requests/_request_head/should_yield_to_the_block.yml +24 -0
  244. data/spec/fixtures/vcr/cassettes/Puppet_Network_HTTP_Connection/when_handling_requests/_request_post/should_yield_to_the_block.yml +24 -0
  245. data/spec/integration/configurer_spec.rb +0 -52
  246. data/spec/integration/provider/service/init_spec.rb +1 -0
  247. data/spec/integration/provider/service/systemd_spec.rb +5 -8
  248. data/spec/integration/type/file_spec.rb +38 -28
  249. data/spec/integration/util/execution_spec.rb +0 -27
  250. data/spec/lib/puppet/certificate_factory.rb +2 -2
  251. data/spec/lib/puppet/test_ca.rb +17 -4
  252. data/spec/lib/puppet_spec/fixtures.rb +4 -0
  253. data/spec/spec_helper.rb +0 -28
  254. data/spec/unit/application/agent_spec.rb +34 -67
  255. data/spec/unit/application/device_spec.rb +1 -27
  256. data/spec/unit/application/ssl_spec.rb +60 -35
  257. data/spec/unit/configurer_spec.rb +399 -395
  258. data/spec/unit/defaults_spec.rb +4 -4
  259. data/spec/unit/face/facts_spec.rb +0 -9
  260. data/spec/unit/face/parser_spec.rb +69 -22
  261. data/spec/unit/face/plugin_spec.rb +0 -8
  262. data/spec/unit/file_system_spec.rb +30 -1
  263. data/spec/unit/forge/forge_spec.rb +3 -1
  264. data/spec/unit/forge/repository_spec.rb +3 -1
  265. data/spec/unit/indirector/catalog/compiler_spec.rb +5 -62
  266. data/spec/unit/indirector/resource/ral_spec.rb +4 -4
  267. data/spec/unit/module_tool/tar/mini_spec.rb +1 -1
  268. data/spec/unit/network/http/api/indirected_routes_spec.rb +10 -25
  269. data/spec/unit/network/http/connection_spec.rb +145 -119
  270. data/spec/unit/network/http/factory_spec.rb +5 -27
  271. data/spec/unit/parser/scope_spec.rb +0 -10
  272. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +3 -8
  273. data/spec/unit/pops/loaders/loaders_spec.rb +4 -0
  274. data/spec/unit/pops/loaders/module_loaders_spec.rb +0 -37
  275. data/spec/unit/pops/types/types_spec.rb +27 -0
  276. data/spec/unit/provider/exec_spec.rb +0 -209
  277. data/spec/unit/provider/package/aptrpm_spec.rb +1 -1
  278. data/spec/unit/provider/package/dnf_spec.rb +0 -7
  279. data/spec/unit/provider/package/dpkg_spec.rb +80 -240
  280. data/spec/unit/provider/package/pip_spec.rb +8 -61
  281. data/spec/unit/provider/package/portage_spec.rb +4 -4
  282. data/spec/unit/provider/package/rpm_spec.rb +16 -150
  283. data/spec/unit/provider/package/yum_spec.rb +0 -7
  284. data/spec/unit/provider/service/daemontools_spec.rb +0 -24
  285. data/spec/unit/provider/service/launchd_spec.rb +0 -28
  286. data/spec/unit/provider/service/runit_spec.rb +0 -24
  287. data/spec/unit/provider/service/systemd_spec.rb +25 -39
  288. data/spec/unit/provider/service/windows_spec.rb +0 -20
  289. data/spec/unit/provider/user/hpux_spec.rb +2 -2
  290. data/spec/unit/provider/user/pw_spec.rb +0 -37
  291. data/spec/unit/provider/user/useradd_spec.rb +0 -88
  292. data/spec/unit/resource_spec.rb +1 -26
  293. data/spec/unit/ssl/host_spec.rb +5 -0
  294. data/spec/unit/ssl/ssl_provider_spec.rb +36 -11
  295. data/spec/unit/ssl/state_machine_spec.rb +233 -158
  296. data/spec/unit/transaction_spec.rb +0 -64
  297. data/spec/unit/type/exec_spec.rb +12 -15
  298. data/spec/unit/type/file/content_spec.rb +3 -9
  299. data/spec/unit/type/file/source_spec.rb +4 -4
  300. data/spec/unit/type/file_spec.rb +15 -11
  301. data/spec/unit/type/package_spec.rb +0 -5
  302. data/spec/unit/type/schedule_spec.rb +1 -3
  303. data/spec/unit/type/service_spec.rb +0 -16
  304. data/spec/unit/util/execution_spec.rb +0 -16
  305. data/spec/unit/util/http_proxy_spec.rb +21 -151
  306. data/spec/unit/util/ldap/manager_spec.rb +0 -15
  307. data/spec/unit/util/log/destinations_spec.rb +3 -7
  308. data/spec/unit/util/log_spec.rb +138 -0
  309. data/spec/unit/util/logging_spec.rb +0 -200
  310. data/spec/unit/util/pidlock_spec.rb +0 -26
  311. data/spec/unit/util/skip_tags_spec.rb +14 -0
  312. data/spec/unit/util/windows/adsi_spec.rb +0 -51
  313. data/spec/unit/util/windows/service_spec.rb +0 -9
  314. data/spec/unit/util_spec.rb +10 -0
  315. data/spec/unit/x509/cert_provider_spec.rb +82 -43
  316. data/tasks/generate_cert_fixtures.rake +13 -1
  317. data/tasks/manpages.rake +0 -1
  318. metadata +26 -20
  319. data/ext/cert_inspector +0 -140
  320. data/ext/envpuppet +0 -139
  321. data/ext/envpuppet.bat +0 -14
  322. data/ext/puppet-test +0 -476
  323. data/ext/pure_ruby_dsl/dsl_test.rb +0 -7
  324. data/ext/upload_facts.rb +0 -119
  325. data/lib/puppet/provider/package/dnfmodule.rb +0 -87
  326. data/spec/fixtures/unit/provider/package/dnfmodule/dnf-module-list-installed.txt +0 -11
  327. data/spec/integration/type/notify_spec.rb +0 -46
  328. data/spec/unit/provider/package/dnfmodule_spec.rb +0 -186
  329. data/spec/unit/provider/package_targetable_spec.rb +0 -60
@@ -747,8 +747,7 @@ describe Puppet::Resource do
747
747
  @resource = Puppet::Resource.new("one::two", "/my/file",
748
748
  :parameters => {
749
749
  :noop => true,
750
- :foo => [:one, "two"],
751
- :bar => 'a\'b',
750
+ :foo => %w{one two},
752
751
  :ensure => 'present',
753
752
  }
754
753
  )
@@ -758,34 +757,10 @@ describe Puppet::Resource do
758
757
  expect(@resource.to_hierayaml).to eq(<<-HEREDOC.gsub(/^\s{8}/, ''))
759
758
  /my/file:
760
759
  ensure: 'present'
761
- bar : 'a\\'b'
762
760
  foo : ['one', 'two']
763
761
  noop : true
764
762
  HEREDOC
765
763
  end
766
-
767
- it "should convert some types to String" do
768
- expect(@resource.to_hiera_hash).to eq(
769
- "/my/file" => {
770
- 'ensure' => "present",
771
- 'bar' => "a'b",
772
- 'foo' => ["one", "two"],
773
- 'noop' => true
774
- }
775
- )
776
- end
777
-
778
- it "accepts symbolic titles" do
779
- res = Puppet::Resource.new(:file, "/my/file", :parameters => { 'ensure' => "present" })
780
-
781
- expect(res.to_hiera_hash.keys).to eq(["/my/file"])
782
- end
783
-
784
- it "emits an empty parameters hash" do
785
- res = Puppet::Resource.new(:file, "/my/file")
786
-
787
- expect(res.to_hiera_hash).to eq({"/my/file" => {}})
788
- end
789
764
  end
790
765
 
791
766
  describe "when converting to json" do
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'webmock/rspec'
2
3
  require 'puppet/test_ca'
3
4
 
4
5
  require 'puppet/ssl/host'
@@ -307,6 +308,10 @@ describe Puppet::SSL::Host, if: !Puppet::Util::Platform.jruby? do
307
308
  allow(@host).to receive(:validate_certificate_with_key)
308
309
  allow(@host).to receive(:http_client).and_return(@http)
309
310
  allow(@host).to receive(:ssl_store).and_return(double("ssl store"))
311
+
312
+ WebMock.disable_net_connect!
313
+ allow_any_instance_of(Net::HTTP).to receive(:start)
314
+ allow_any_instance_of(Net::HTTP).to receive(:finish)
310
315
  end
311
316
 
312
317
  let(:ca_cert_response) { @pki[:ca_bundle] }
@@ -7,12 +7,6 @@ describe Puppet::SSL::SSLProvider do
7
7
  let(:global_crls) { [ crl_fixture('crl.pem'), crl_fixture('intermediate-crl.pem') ] }
8
8
  let(:wrong_key) { OpenSSL::PKey::RSA.new(512) }
9
9
 
10
- def as_pem_file(x509)
11
- path = tmpfile('ssl_provider_pem')
12
- File.write(path, x509.to_pem)
13
- path
14
- end
15
-
16
10
  context 'when creating an insecure context' do
17
11
  let(:sslctx) { subject.create_insecure_context }
18
12
 
@@ -141,11 +135,18 @@ describe Puppet::SSL::SSLProvider do
141
135
  expect(sslctx.private_key).to eq(private_key)
142
136
  end
143
137
 
138
+ it 'accepts EC keys' do
139
+ ec_key = ec_key_fixture('ec-key.pem')
140
+ ec_cert = cert_fixture('ec.pem')
141
+ sslctx = subject.create_context(config.merge(client_cert: ec_cert, private_key: ec_key))
142
+ expect(sslctx.private_key).to eq(ec_key)
143
+ end
144
+
144
145
  it 'raises if private key is unsupported' do
145
- ec_key = OpenSSL::PKey::EC.new
146
+ dsa_key = OpenSSL::PKey::DSA.new
146
147
  expect {
147
- subject.create_context(config.merge(private_key: ec_key))
148
- }.to raise_error(Puppet::SSL::SSLError, /Unsupported key 'OpenSSL::PKey::EC'/)
148
+ subject.create_context(config.merge(private_key: dsa_key))
149
+ }.to raise_error(Puppet::SSL::SSLError, /Unsupported key 'OpenSSL::PKey::DSA'/)
149
150
  end
150
151
 
151
152
  it 'resolves the client chain from leaf to root' do
@@ -352,8 +353,8 @@ describe Puppet::SSL::SSLProvider do
352
353
  let(:doesnt_exist) { '/does/not/exist' }
353
354
 
354
355
  before :each do
355
- Puppet[:localcacert] = as_pem_file(global_cacerts.first)
356
- Puppet[:hostcrl] = as_pem_file(global_crls.first)
356
+ Puppet[:localcacert] = file_containing('global_cacerts', global_cacerts.first.to_pem)
357
+ Puppet[:hostcrl] = file_containing('global_crls', global_crls.first.to_pem)
357
358
 
358
359
  Puppet[:certname] = 'signed'
359
360
  Puppet[:privatekeydir] = tmpdir('privatekeydir')
@@ -400,6 +401,30 @@ describe Puppet::SSL::SSLProvider do
400
401
  subject.load_context
401
402
  }.to raise_error(Puppet::Error, /The client certificate is missing from/)
402
403
  end
404
+
405
+ it 'loads the private key and client cert' do
406
+ ssl_context = subject.load_context
407
+
408
+ expect(ssl_context.private_key).to be_an(OpenSSL::PKey::RSA)
409
+ expect(ssl_context.client_cert).to be_an(OpenSSL::X509::Certificate)
410
+ end
411
+
412
+ it 'loads a password protected key and client cert' do
413
+ FileUtils.cp(File.join(PuppetSpec::FIXTURE_DIR, 'ssl', 'encrypted-key.pem'), File.join(Puppet[:privatekeydir], 'signed.pem'))
414
+
415
+ ssl_context = subject.load_context(password: '74695716c8b6')
416
+
417
+ expect(ssl_context.private_key).to be_an(OpenSSL::PKey::RSA)
418
+ expect(ssl_context.client_cert).to be_an(OpenSSL::X509::Certificate)
419
+ end
420
+
421
+ it 'raises if the password is incorrect' do
422
+ FileUtils.cp(File.join(PuppetSpec::FIXTURE_DIR, 'ssl', 'encrypted-key.pem'), File.join(Puppet[:privatekeydir], 'signed.pem'))
423
+
424
+ expect {
425
+ subject.load_context(password: 'wrongpassword')
426
+ }.to raise_error(Puppet::SSL::SSLError, /Failed to load private key for host 'signed': Could not parse PKey/)
427
+ end
403
428
  end
404
429
 
405
430
  context 'when verifying requests' do
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'webmock/rspec'
2
3
  require 'puppet_spec/files'
3
4
 
4
5
  require 'puppet/ssl'
@@ -6,11 +7,7 @@ require 'puppet/ssl'
6
7
  describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
7
8
  include PuppetSpec::Files
8
9
 
9
- let(:privatekeydir) { tmpdir('privatekeydir') }
10
- let(:certdir) { tmpdir('certdir') }
11
- let(:requestdir) { tmpdir('requestdir') }
12
- let(:machine) { described_class.new }
13
- let(:cert_provider) { Puppet::X509::CertProvider.new(privatekeydir: privatekeydir, certdir: certdir, requestdir: requestdir) }
10
+ let(:cert_provider) { Puppet::X509::CertProvider.new }
14
11
  let(:ssl_provider) { Puppet::SSL::SSLProvider.new }
15
12
  let(:machine) { described_class.new(cert_provider: cert_provider, ssl_provider: ssl_provider) }
16
13
  let(:cacert_pem) { cacert.to_pem }
@@ -24,10 +21,13 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
24
21
  let(:private_key) { key_fixture('signed-key.pem') }
25
22
  let(:client_cert) { cert_fixture('signed.pem') }
26
23
 
27
- let(:refused_message) { %r{Connection refused|No connection could be made because the target machine actively refused it} }
28
-
29
24
  before(:each) do
30
- allow(Kernel).to receive(:sleep)
25
+ WebMock.disable_net_connect!
26
+
27
+ allow_any_instance_of(Net::HTTP).to receive(:start)
28
+ allow_any_instance_of(Net::HTTP).to receive(:finish)
29
+
30
+ Puppet[:ssl_lockfile] = tmpfile('ssllock')
31
31
  end
32
32
 
33
33
  context 'when ensuring CA certs and CRLs' do
@@ -41,48 +41,6 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
41
41
  expect(ssl_context[:crls]).to eq(crls)
42
42
  expect(ssl_context[:verify_peer]).to eq(true)
43
43
  end
44
-
45
- context 'when exceptions occur' do
46
- it 'raises in onetime mode' do
47
- stub_request(:get, %r{puppet-ca/v1/certificate/ca})
48
- .to_raise(Errno::ECONNREFUSED)
49
-
50
- machine = described_class.new(cert_provider: cert_provider, ssl_provider: ssl_provider, onetime: true)
51
- expect {
52
- machine.ensure_ca_certificates
53
- }.to raise_error(Puppet::Error, refused_message)
54
- end
55
-
56
- it 'retries CA cert download' do
57
- # allow cert to be saved to disk
58
- FileUtils.mkdir_p(Puppet[:certdir])
59
- allow(cert_provider).to receive(:load_crls).and_return(crls)
60
-
61
- req = stub_request(:get, %r{puppet-ca/v1/certificate/ca})
62
- .to_raise(Errno::ECONNREFUSED).then
63
- .to_return(status: 200, body: cacert_pem)
64
-
65
- machine.ensure_ca_certificates
66
-
67
- expect(req).to have_been_made.twice
68
- expect(@logs).to include(an_object_having_attributes(message: refused_message))
69
- end
70
-
71
- it 'retries CRL download' do
72
- # allow crl to be saved to disk
73
- FileUtils.mkdir_p(Puppet[:ssldir])
74
- allow(cert_provider).to receive(:load_cacerts).and_return(cacerts)
75
-
76
- req = stub_request(:get, %r{puppet-ca/v1/certificate_revocation_list/ca})
77
- .to_raise(Errno::ECONNREFUSED).then
78
- .to_return(status: 200, body: crl_pem)
79
-
80
- machine.ensure_ca_certificates
81
-
82
- expect(req).to have_been_made.twice
83
- expect(@logs).to include(an_object_having_attributes(message: refused_message))
84
- end
85
- end
86
44
  end
87
45
 
88
46
  context 'when ensuring a client cert' do
@@ -100,71 +58,73 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
100
58
  expect(ssl_context[:private_key]).to eq(private_key)
101
59
  expect(ssl_context[:client_cert]).to eq(client_cert)
102
60
  end
61
+ end
103
62
 
104
- context 'when exceptions occur' do
105
- before :each do
106
- allow(cert_provider).to receive(:load_cacerts).and_return(cacerts)
107
- allow(cert_provider).to receive(:load_crls).and_return(crls)
108
- end
63
+ context 'when locking' do
64
+ let(:lockfile) { double('ssllockfile') }
65
+ let(:machine) { described_class.new(cert_provider: cert_provider, ssl_provider: ssl_provider, lockfile: lockfile) }
109
66
 
110
- it 'retries CSR submission' do
111
- allow(cert_provider).to receive(:load_private_key).and_return(private_key)
112
- allow($stdout).to receive(:puts).with(/Couldn't fetch certificate from CA server; you might still need to sign this agent's certificate/)
67
+ # lockfile is deleted before `ensure_ca_certificates` returns, so
68
+ # verify lockfile contents while state machine is running
69
+ def expect_lockfile_to_contain(pid)
70
+ allow(cert_provider).to receive(:load_cacerts) do
71
+ expect(File.read(Puppet[:ssl_lockfile])).to eq(pid.to_s)
72
+ end.and_return(cacerts)
73
+ allow(cert_provider).to receive(:load_crls).and_return(crls)
74
+ end
113
75
 
114
- stub_request(:get, %r{puppet-ca/v1/certificate/#{Puppet[:certname]}})
115
- .to_return(status: 200, body: client_cert.to_pem)
116
- # first request raises, second succeeds
117
- req = stub_request(:put, %r{puppet-ca/v1/certificate_request/#{Puppet[:certname]}})
118
- .to_raise(Errno::ECONNREFUSED).then
119
- .to_return(status: 200)
76
+ it 'locks the file prior to running the state machine and unlocks when done' do
77
+ expect(lockfile).to receive(:lock).and_return(true).ordered
78
+ expect(cert_provider).to receive(:load_cacerts).and_return(cacerts).ordered
79
+ expect(cert_provider).to receive(:load_crls).and_return(crls).ordered
80
+ expect(lockfile).to receive(:unlock).ordered
120
81
 
121
- machine.ensure_client_certificate
82
+ machine.ensure_ca_certificates
83
+ end
122
84
 
123
- expect(req).to have_been_made.twice
124
- expect(@logs).to include(an_object_having_attributes(message: refused_message))
125
- end
85
+ it 'deletes the lockfile when finished' do
86
+ allow(cert_provider).to receive(:load_cacerts).and_return(cacerts)
87
+ allow(cert_provider).to receive(:load_crls).and_return(crls)
126
88
 
127
- it 'retries client cert download' do
128
- allow(cert_provider).to receive(:load_private_key).and_return(private_key)
89
+ machine = described_class.new(cert_provider: cert_provider, ssl_provider: ssl_provider)
90
+ machine.ensure_ca_certificates
129
91
 
130
- # first request raises, second succeeds
131
- req = stub_request(:get, %r{puppet-ca/v1/certificate/#{Puppet[:certname]}})
132
- .to_raise(Errno::ECONNREFUSED).then
133
- .to_return(status: 200, body: client_cert.to_pem)
134
- stub_request(:put, %r{puppet-ca/v1/certificate_request/#{Puppet[:certname]}}).to_return(status: 200)
92
+ expect(File).to_not be_exist(Puppet[:ssl_lockfile])
93
+ end
135
94
 
136
- machine.ensure_client_certificate
95
+ it 'raises an exception when locking fails' do
96
+ allow(lockfile).to receive(:lock).and_return(false)
97
+ expect {
98
+ machine.ensure_ca_certificates
99
+ }.to raise_error(Puppet::Error, /Another puppet instance is already running; exiting/)
100
+ end
137
101
 
138
- expect(req).to have_been_made.twice
139
- expect(@logs).to include(an_object_having_attributes(message: refused_message))
140
- end
102
+ it 'acquires an empty lockfile' do
103
+ Puppet::FileSystem.touch(Puppet[:ssl_lockfile])
141
104
 
142
- it 'retries when client cert and private key are mismatched' do
143
- allow(cert_provider).to receive(:load_private_key).and_return(private_key)
105
+ expect_lockfile_to_contain(Process.pid)
144
106
 
145
- # return mismatched cert the first time, correct cert second time
146
- req = stub_request(:get, %r{puppet-ca/v1/certificate/#{Puppet[:certname]}})
147
- .to_return(status: 200, body: cert_fixture('pluto.pem').to_pem)
148
- .to_return(status: 200, body: client_cert.to_pem)
149
- stub_request(:put, %r{puppet-ca/v1/certificate_request/#{Puppet[:certname]}}).to_return(status: 200)
107
+ machine = described_class.new(cert_provider: cert_provider, ssl_provider: ssl_provider)
108
+ machine.ensure_ca_certificates
109
+ end
150
110
 
151
- machine.ensure_client_certificate
111
+ it 'acquires its own lockfile' do
112
+ File.write(Puppet[:ssl_lockfile], Process.pid.to_s)
152
113
 
153
- expect(req).to have_been_made.twice
154
- expect(@logs).to include(an_object_having_attributes(message: %r{The certificate for 'CN=pluto' does not match its private key}))
155
- end
114
+ expect_lockfile_to_contain(Process.pid)
156
115
 
157
- it 'raises in onetime mode' do
158
- stub_request(:get, %r{puppet-ca/v1/certificate/#{Puppet[:certname]}})
159
- .to_raise(Errno::ECONNREFUSED)
160
- stub_request(:put, %r{puppet-ca/v1/certificate_request/#{Puppet[:certname]}})
161
- .to_return(status: 200)
116
+ machine = described_class.new(cert_provider: cert_provider, ssl_provider: ssl_provider)
117
+ machine.ensure_ca_certificates
118
+ end
162
119
 
163
- machine = described_class.new(cert_provider: cert_provider, ssl_provider: ssl_provider, onetime: true)
164
- expect {
165
- machine.ensure_client_certificate
166
- }.to raise_error(Puppet::Error, refused_message)
167
- end
120
+ it 'overwrites a stale lockfile' do
121
+ # 2**31 - 1 chosen to not conflict with existing pid
122
+ File.write(Puppet[:ssl_lockfile], "2147483647")
123
+
124
+ expect_lockfile_to_contain(Process.pid)
125
+
126
+ machine = described_class.new(cert_provider: cert_provider, ssl_provider: ssl_provider)
127
+ machine.ensure_ca_certificates
168
128
  end
169
129
  end
170
130
 
@@ -207,29 +167,29 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
207
167
  state.next_state
208
168
  end
209
169
 
210
- it 'returns an Error if the server returns 404' do
170
+ it 'raises if the server returns 404' do
211
171
  stub_request(:get, %r{puppet-ca/v1/certificate/ca}).to_return(status: 404)
212
172
 
213
- st = state.next_state
214
- expect(st).to be_an_instance_of(Puppet::SSL::StateMachine::Error)
215
- expect(st.message).to eq("CA certificate is missing from the server")
173
+ expect {
174
+ state.next_state
175
+ }.to raise_error(Puppet::Error, /CA certificate is missing from the server/)
216
176
  end
217
177
 
218
- it 'returns an Error if there is a different exception' do
178
+ it 'raises if there is a different error' do
219
179
  stub_request(:get, %r{puppet-ca/v1/certificate/ca}).to_return(status: [500, 'Internal Server Error'])
220
180
 
221
- st = state.next_state
222
- expect(st).to be_an_instance_of(Puppet::SSL::StateMachine::Error)
223
- expect(st.message).to eq("Could not download CA certificate: Internal Server Error")
181
+ expect {
182
+ state.next_state
183
+ }.to raise_error(Puppet::Error, /Could not download CA certificate: Internal Server Error/)
224
184
  end
225
185
 
226
- it 'returns an Error if CA certs are invalid' do
186
+ it 'raises if CA certs are invalid' do
227
187
  allow(cert_provider).to receive(:load_cacerts).and_return(nil)
228
188
  stub_request(:get, %r{puppet-ca/v1/certificate/ca}).to_return(status: 200, body: '')
229
189
 
230
- st = state.next_state
231
- expect(st).to be_an_instance_of(Puppet::SSL::StateMachine::Error)
232
- expect(st.error).to be_an_instance_of(OpenSSL::X509::CertificateError)
190
+ expect {
191
+ state.next_state
192
+ }.to raise_error(OpenSSL::X509::CertificateError)
233
193
  end
234
194
 
235
195
  it 'does not save invalid CA certs' do
@@ -284,29 +244,29 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
284
244
  state.next_state
285
245
  end
286
246
 
287
- it 'returns an Error if the server returns 404' do
247
+ it 'raises if the server returns 404' do
288
248
  stub_request(:get, %r{puppet-ca/v1/certificate_revocation_list/ca}).to_return(status: 404)
289
249
 
290
- st = state.next_state
291
- expect(st).to be_an_instance_of(Puppet::SSL::StateMachine::Error)
292
- expect(st.message).to eq("CRL is missing from the server")
250
+ expect {
251
+ state.next_state
252
+ }.to raise_error(Puppet::Error, /CRL is missing from the server/)
293
253
  end
294
254
 
295
- it 'returns an Error if there is a different exception' do
255
+ it 'raises if there is a different error' do
296
256
  stub_request(:get, %r{puppet-ca/v1/certificate_revocation_list/ca}).to_return(status: [500, 'Internal Server Error'])
297
257
 
298
- st = state.next_state
299
- expect(st).to be_an_instance_of(Puppet::SSL::StateMachine::Error)
300
- expect(st.message).to eq("Could not download CRLs: Internal Server Error")
258
+ expect {
259
+ state.next_state
260
+ }.to raise_error(Puppet::Error, /Could not download CRLs: Internal Server Error/)
301
261
  end
302
262
 
303
- it 'returns an Error if CRLs are invalid' do
263
+ it 'raises if CRLs are invalid' do
304
264
  allow(cert_provider).to receive(:load_crls).and_return(nil)
305
265
  stub_request(:get, %r{puppet-ca/v1/certificate_revocation_list/ca}).to_return(status: 200, body: '')
306
266
 
307
- st = state.next_state
308
- expect(st).to be_an_instance_of(Puppet::SSL::StateMachine::Error)
309
- expect(st.error).to be_an_instance_of(OpenSSL::X509::CRLError)
267
+ expect {
268
+ state.next_state
269
+ }.to raise_error(OpenSSL::X509::CRLError)
310
270
  end
311
271
 
312
272
  it 'does not save invalid CRLs' do
@@ -330,6 +290,69 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
330
290
 
331
291
  expect(File).to_not exist(Puppet[:hostcrl])
332
292
  end
293
+
294
+ it 'skips CRL refresh by default' do
295
+ allow_any_instance_of(Puppet::X509::CertProvider).to receive(:load_crls).and_return(crls)
296
+
297
+ state.next_state
298
+ end
299
+
300
+ it 'skips CRL refresh if it has not expired' do
301
+ Puppet[:crl_refresh_interval] = '1y'
302
+ Puppet::FileSystem.touch(Puppet[:hostcrl], mtime: Time.now)
303
+
304
+ allow_any_instance_of(Puppet::X509::CertProvider).to receive(:load_crls).and_return(crls)
305
+
306
+ state.next_state
307
+ end
308
+
309
+ context 'when refreshing a CRL' do
310
+ before :each do
311
+ Puppet[:crl_refresh_interval] = '1s'
312
+ allow_any_instance_of(Puppet::X509::CertProvider).to receive(:load_crls).and_return(crls)
313
+
314
+ yesterday = Time.now - (24 * 60 * 60)
315
+ allow_any_instance_of(Puppet::X509::CertProvider).to receive(:crl_last_update).and_return(yesterday)
316
+ end
317
+
318
+ let(:new_crl_bundle) do
319
+ # add intermediate crl to the bundle
320
+ int_crl = crl_fixture('intermediate-crl.pem')
321
+ [crl, int_crl].map(&:to_pem)
322
+ end
323
+
324
+ it 'uses the local crl if it has not been modified' do
325
+ stub_request(:get, %r{puppet-ca/v1/certificate_revocation_list/ca}).to_return(status: 304)
326
+
327
+ expect(state.next_state.ssl_context.crls).to eq(crls)
328
+ end
329
+
330
+ it 'uses the local crl if refreshing fails in HTTP layer' do
331
+ stub_request(:get, %r{puppet-ca/v1/certificate_revocation_list/ca}).to_return(status: 503)
332
+
333
+ expect(state.next_state.ssl_context.crls).to eq(crls)
334
+ end
335
+
336
+ it 'uses the local crl if refreshing fails in TCP layer' do
337
+ stub_request(:get, %r{puppet-ca/v1/certificate_revocation_list/ca}).to_raise(Errno::ECONNREFUSED)
338
+
339
+ expect(state.next_state.ssl_context.crls).to eq(crls)
340
+ end
341
+
342
+ it 'uses the updated crl for the future requests' do
343
+ stub_request(:get, %r{puppet-ca/v1/certificate_revocation_list/ca}).to_return(status: 200, body: new_crl_bundle.join)
344
+
345
+ expect(state.next_state.ssl_context.crls.map(&:to_pem)).to eq(new_crl_bundle)
346
+ end
347
+
348
+ it 'updates the `last_update` time' do
349
+ stub_request(:get, %r{puppet-ca/v1/certificate_revocation_list/ca}).to_return(status: 200, body: new_crl_bundle.join)
350
+
351
+ expect_any_instance_of(Puppet::X509::CertProvider).to receive(:crl_last_update=).with(be_within(60).of(Time.now))
352
+
353
+ state.next_state
354
+ end
355
+ end
333
356
  end
334
357
 
335
358
  context 'when ensuring a client cert' do
@@ -362,7 +385,7 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
362
385
  }.to raise_error(Puppet::SSL::SSLError, %r{The certificate for 'CN=signed' does not match its private key})
363
386
  end
364
387
 
365
- it 'generates a new private key, saves it and passes it to the next state' do
388
+ it 'generates a new RSA private key, saves it and passes it to the next state' do
366
389
  allow(cert_provider).to receive(:load_private_key).and_return(nil)
367
390
  expect(cert_provider).to receive(:save_private_key)
368
391
 
@@ -372,6 +395,41 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
372
395
  expect(st.private_key).to be_private
373
396
  end
374
397
 
398
+ it 'generates a new EC private key, saves it and passes it to the next state' do
399
+ Puppet[:key_type] = 'ec'
400
+ allow(cert_provider).to receive(:load_private_key).and_return(nil)
401
+ expect(cert_provider).to receive(:save_private_key)
402
+
403
+ st = state.next_state
404
+ expect(st).to be_instance_of(Puppet::SSL::StateMachine::NeedSubmitCSR)
405
+ expect(st.private_key).to be_instance_of(OpenSSL::PKey::EC)
406
+ expect(st.private_key).to be_private
407
+ expect(st.private_key.group.curve_name).to eq('prime256v1')
408
+ end
409
+
410
+ it 'generates a new EC private key with curve `secp384r1`, saves it and passes it to the next state' do
411
+ Puppet[:key_type] = 'ec'
412
+ Puppet[:named_curve] = 'secp384r1'
413
+ allow(cert_provider).to receive(:load_private_key).and_return(nil)
414
+ expect(cert_provider).to receive(:save_private_key)
415
+
416
+ st = state.next_state
417
+ expect(st).to be_instance_of(Puppet::SSL::StateMachine::NeedSubmitCSR)
418
+ expect(st.private_key).to be_instance_of(OpenSSL::PKey::EC)
419
+ expect(st.private_key).to be_private
420
+ expect(st.private_key.group.curve_name).to eq('secp384r1')
421
+ end
422
+
423
+ it 'raises if the named curve is unsupported' do
424
+ Puppet[:key_type] = 'ec'
425
+ Puppet[:named_curve] = 'infiniteloop'
426
+ allow(cert_provider).to receive(:load_private_key).and_return(nil)
427
+
428
+ expect {
429
+ state.next_state
430
+ }.to raise_error(OpenSSL::PKey::ECError, /(invalid|unknown) curve name/)
431
+ end
432
+
375
433
  it 'raises an error if it fails to load the key' do
376
434
  allow(cert_provider).to receive(:load_private_key).and_raise(OpenSSL::PKey::RSAError)
377
435
 
@@ -386,9 +444,7 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
386
444
  let(:state) { Puppet::SSL::StateMachine::NeedSubmitCSR.new(machine, ssl_context, private_key) }
387
445
 
388
446
  def write_csr_attributes(data)
389
- csr_yaml = tmpfile('state_machine_csr')
390
- File.write(csr_yaml, YAML.dump(data))
391
- csr_yaml
447
+ file_containing('state_machine_csr', YAML.dump(data))
392
448
  end
393
449
 
394
450
  before :each do
@@ -487,9 +543,9 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
487
543
  it 'raises if the server errors' do
488
544
  stub_request(:put, %r{puppet-ca/v1/certificate_request/#{Puppet[:certname]}}).to_return(status: 500)
489
545
 
490
- st = state.next_state
491
- expect(st).to be_an_instance_of(Puppet::SSL::StateMachine::Error)
492
- expect(st.message).to eq("Failed to submit the CSR, HTTP response was 500")
546
+ expect {
547
+ state.next_state
548
+ }.to raise_error(Puppet::SSL::SSLError, /Failed to submit the CSR, HTTP response was 500/)
493
549
  end
494
550
 
495
551
  it "verifies the server's certificate when submitting the CSR" do
@@ -516,27 +572,16 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
516
572
  expect(state.next_state).to be_an_instance_of(Puppet::SSL::StateMachine::Done)
517
573
  end
518
574
 
519
- it "prints a message if the cert isn't signed yet" do
520
- stub_request(:get, %r{puppet-ca/v1/certificate/#{Puppet[:certname]}}).to_return(status: 404)
521
-
522
- expect {
523
- state.next_state
524
- }.to output(/Couldn't fetch certificate from CA server; you might still need to sign this agent's certificate \(#{Puppet[:certname]}\)/).to_stdout
525
- end
526
-
527
- it 'transitions to Error if the cert does not match our private key' do
575
+ it 'transitions to Wait if the cert does not match our private key' do
528
576
  wrong_cert = cert_fixture('127.0.0.1.pem')
529
577
  stub_request(:get, %r{puppet-ca/v1/certificate/#{Puppet[:certname]}}).to_return(status: 200, body: wrong_cert.to_pem)
530
578
 
531
- st = state.next_state
532
- expect(st).to be_an_instance_of(Puppet::SSL::StateMachine::Error)
533
- expect(st.message).to eq("The certificate for 'CN=127.0.0.1' does not match its private key")
579
+ expect(state.next_state).to be_an_instance_of(Puppet::SSL::StateMachine::Wait)
534
580
  end
535
581
 
536
582
  it 'transitions to Wait if the server returns non-200' do
537
583
  stub_request(:get, %r{puppet-ca/v1/certificate/#{Puppet[:certname]}}).to_return(status: 404)
538
584
 
539
- allow($stdout).to receive(:puts).with(/Couldn't fetch certificate from CA server; you might still need to sign this agent's certificate/)
540
585
  expect(state.next_state).to be_an_instance_of(Puppet::SSL::StateMachine::Wait)
541
586
  end
542
587
 
@@ -556,9 +601,9 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
556
601
  MIIBpDCCAQ2gAwIBAgIBAjANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRUZXN0
557
602
  END
558
603
 
559
- st = state.next_state
560
- expect(st).to be_an_instance_of(Puppet::SSL::StateMachine::Error)
561
- expect(st.message).to match(/Failed to parse certificate:/)
604
+ state.next_state
605
+
606
+ expect(@logs).to include(an_object_having_attributes(message: /Failed to parse certificate: /))
562
607
  expect(File).to_not exist(Puppet[:hostcert])
563
608
  end
564
609
 
@@ -566,9 +611,9 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
566
611
  wrong_cert = cert_fixture('127.0.0.1.pem').to_pem
567
612
  stub_request(:get, %r{puppet-ca/v1/certificate/#{Puppet[:certname]}}).to_return(status: 200, body: wrong_cert)
568
613
 
569
- st = state.next_state
570
- expect(st).to be_an_instance_of(Puppet::SSL::StateMachine::Error)
571
- expect(st.message).to eq("The certificate for 'CN=127.0.0.1' does not match its private key")
614
+ state.next_state
615
+
616
+ expect(@logs).to include(an_object_having_attributes(message: %r{The certificate for 'CN=127.0.0.1' does not match its private key}))
572
617
  expect(File).to_not exist(Puppet[:hostcert])
573
618
  end
574
619
 
@@ -576,9 +621,9 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
576
621
  revoked_cert = cert_fixture('revoked.pem').to_pem
577
622
  stub_request(:get, %r{puppet-ca/v1/certificate/#{Puppet[:certname]}}).to_return(status: 200, body: revoked_cert)
578
623
 
579
- st = state.next_state
580
- expect(st).to be_an_instance_of(Puppet::SSL::StateMachine::Error)
581
- expect(st.message).to eq("Certificate 'CN=revoked' is revoked")
624
+ state.next_state
625
+
626
+ expect(@logs).to include(an_object_having_attributes(message: %r{Certificate 'CN=revoked' is revoked}))
582
627
  expect(File).to_not exist(Puppet[:hostcert])
583
628
  end
584
629
  end
@@ -591,21 +636,51 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
591
636
 
592
637
  expect {
593
638
  expect {
594
- Puppet::SSL::StateMachine::Wait.new(machine).next_state
639
+ Puppet::SSL::StateMachine::Wait.new(machine, ssl_context).next_state
595
640
  }.to exit_with(1)
596
- }.to output(/Exiting now because the waitforcert setting is set to 0./).to_stdout
641
+ }.to output(/Couldn't fetch certificate from CA server; you might still need to sign this agent's certificate \(.*\). Exiting now because the waitforcert setting is set to 0./).to_stdout
597
642
  end
598
643
 
599
644
  it 'sleeps and transitions to NeedCACerts' do
600
645
  machine = described_class.new(waitforcert: 15)
601
646
 
602
- state = Puppet::SSL::StateMachine::Wait.new(machine)
603
- expect(Kernel).to receive(:sleep).with(15)
647
+ state = Puppet::SSL::StateMachine::Wait.new(machine, ssl_context)
648
+ expect(state).to receive(:sleep).with(15)
649
+
650
+ expect(Puppet).to receive(:info).with(/Couldn't fetch certificate from CA server; you might still need to sign this agent's certificate \(.*\). Will try again in 15 seconds./)
651
+
652
+ expect(state.next_state).to be_an_instance_of(Puppet::SSL::StateMachine::NeedCACerts)
653
+ end
654
+
655
+ it 'sleeps and transitions to NeedCACerts when maxwaitforcert is set' do
656
+ machine = described_class.new(waitforcert: 15, maxwaitforcert: 30)
657
+
658
+ state = Puppet::SSL::StateMachine::Wait.new(machine, ssl_context)
659
+ expect(state).to receive(:sleep).with(15)
604
660
 
605
- expect(Puppet).to receive(:info).with(/Will try again in 15 seconds./)
661
+ expect(Puppet).to receive(:info).with(/Couldn't fetch certificate from CA server; you might still need to sign this agent's certificate \(.*\). Will try again in 15 seconds./)
606
662
 
607
663
  expect(state.next_state).to be_an_instance_of(Puppet::SSL::StateMachine::NeedCACerts)
608
664
  end
665
+
666
+ it 'waits indefinitely by default' do
667
+ machine = described_class.new
668
+ expect(machine.wait_deadline).to eq(Float::INFINITY)
669
+ end
670
+
671
+ it 'exits with 1 if maxwaitforcert is exceeded' do
672
+ machine = described_class.new(maxwaitforcert: 1)
673
+
674
+ # 5 minutes in the future
675
+ future = Time.now + (5 * 60)
676
+ allow(Time).to receive(:now).and_return(future)
677
+
678
+ expect {
679
+ expect {
680
+ Puppet::SSL::StateMachine::Wait.new(machine, ssl_context).next_state
681
+ }.to exit_with(1)
682
+ }.to output(/Couldn't fetch certificate from CA server; you might still need to sign this agent's certificate \(.*\). Exiting now because the maxwaitforcert timeout has been exceeded./).to_stdout
683
+ end
609
684
  end
610
685
  end
611
686
  end