puppet 7.15.0-x86-mingw32 → 7.18.0-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +75 -14
  3. data/ext/systemd/puppet.service +1 -1
  4. data/lib/puppet/agent.rb +47 -11
  5. data/lib/puppet/application/agent.rb +3 -13
  6. data/lib/puppet/application/apply.rb +2 -2
  7. data/lib/puppet/configurer.rb +1 -1
  8. data/lib/puppet/defaults.rb +11 -1
  9. data/lib/puppet/http/client.rb +22 -2
  10. data/lib/puppet/info_service/task_information_service.rb +1 -1
  11. data/lib/puppet/module/task.rb +5 -1
  12. data/lib/puppet/parameter.rb +19 -4
  13. data/lib/puppet/pops/evaluator/deferred_resolver.rb +46 -6
  14. data/lib/puppet/pops/functions/dispatcher.rb +10 -6
  15. data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +7 -6
  16. data/lib/puppet/pops/types/type_mismatch_describer.rb +22 -1
  17. data/lib/puppet/provider/package/puppetserver_gem.rb +7 -16
  18. data/lib/puppet/provider/package/yum.rb +8 -3
  19. data/lib/puppet/provider/user/directoryservice.rb +15 -8
  20. data/lib/puppet/ssl/ssl_provider.rb +75 -19
  21. data/lib/puppet/ssl/state_machine.rb +13 -17
  22. data/lib/puppet/transaction.rb +22 -0
  23. data/lib/puppet/type/user.rb +3 -0
  24. data/lib/puppet/type.rb +20 -3
  25. data/lib/puppet/version.rb +1 -1
  26. data/lib/puppet.rb +1 -14
  27. data/man/man5/puppet.conf.5 +11 -3
  28. data/man/man8/puppet-agent.8 +2 -2
  29. data/man/man8/puppet-apply.8 +1 -1
  30. data/man/man8/puppet-catalog.8 +1 -1
  31. data/man/man8/puppet-config.8 +1 -1
  32. data/man/man8/puppet-describe.8 +1 -1
  33. data/man/man8/puppet-device.8 +1 -1
  34. data/man/man8/puppet-doc.8 +1 -1
  35. data/man/man8/puppet-epp.8 +1 -1
  36. data/man/man8/puppet-facts.8 +1 -1
  37. data/man/man8/puppet-filebucket.8 +1 -1
  38. data/man/man8/puppet-generate.8 +1 -1
  39. data/man/man8/puppet-help.8 +1 -1
  40. data/man/man8/puppet-lookup.8 +1 -1
  41. data/man/man8/puppet-module.8 +1 -1
  42. data/man/man8/puppet-node.8 +1 -1
  43. data/man/man8/puppet-parser.8 +1 -1
  44. data/man/man8/puppet-plugin.8 +1 -1
  45. data/man/man8/puppet-report.8 +1 -1
  46. data/man/man8/puppet-resource.8 +1 -1
  47. data/man/man8/puppet-script.8 +1 -1
  48. data/man/man8/puppet-ssl.8 +1 -1
  49. data/man/man8/puppet.8 +2 -2
  50. data/spec/integration/application/agent_spec.rb +157 -0
  51. data/spec/integration/application/apply_spec.rb +74 -0
  52. data/spec/integration/http/client_spec.rb +51 -4
  53. data/spec/lib/puppet_spec/https.rb +1 -1
  54. data/spec/lib/puppet_spec/puppetserver.rb +39 -2
  55. data/spec/unit/agent_spec.rb +28 -2
  56. data/spec/unit/application/agent_spec.rb +26 -16
  57. data/spec/unit/daemon_spec.rb +2 -11
  58. data/spec/unit/http/client_spec.rb +18 -0
  59. data/spec/unit/info_service_spec.rb +11 -3
  60. data/spec/unit/pops/evaluator/deferred_resolver_spec.rb +26 -0
  61. data/spec/unit/pops/loaders/loaders_spec.rb +1 -1
  62. data/spec/unit/pops/types/type_mismatch_describer_spec.rb +167 -1
  63. data/spec/unit/provider/package/puppetserver_gem_spec.rb +2 -2
  64. data/spec/unit/provider/user/directoryservice_spec.rb +1 -1
  65. data/spec/unit/ssl/ssl_provider_spec.rb +75 -1
  66. data/spec/unit/ssl/state_machine_spec.rb +1 -0
  67. data/spec/unit/task_spec.rb +56 -13
  68. data/tasks/generate_cert_fixtures.rake +5 -4
  69. metadata +2 -2
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-DESCRIBE" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-DESCRIBE" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-describe\fR \- Display help about resource types
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-DEVICE" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-DEVICE" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-device\fR \- Manage remote network devices
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-DOC" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-DOC" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-doc\fR \- Generate Puppet references
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-EPP" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-EPP" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-epp\fR \- Interact directly with the EPP template parser/renderer\.
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-FACTS" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-FACTS" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-facts\fR \- Retrieve and store facts\.
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-FILEBUCKET" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-FILEBUCKET" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-filebucket\fR \- Store and retrieve files in a filebucket
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-GENERATE" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-GENERATE" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-generate\fR \- Generates Puppet code from Ruby definitions\.
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-HELP" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-HELP" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-help\fR \- Display Puppet help\.
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-LOOKUP" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-LOOKUP" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-lookup\fR \- Interactive Hiera lookup
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-MODULE" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-MODULE" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-module\fR \- Creates, installs and searches for modules on the Puppet Forge\.
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-NODE" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-NODE" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-node\fR \- View and manage node definitions\.
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-PARSER" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-PARSER" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-parser\fR \- Interact directly with the parser\.
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-PLUGIN" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-PLUGIN" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-plugin\fR \- Interact with the Puppet plugin system\.
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-REPORT" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-REPORT" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-report\fR \- Create, display, and submit reports\.
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-RESOURCE" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-RESOURCE" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-resource\fR \- The resource abstraction layer shell
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-SCRIPT" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-SCRIPT" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-script\fR \- Run a puppet manifests as a script without compiling a catalog
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET\-SSL" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET\-SSL" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\-ssl\fR \- Manage SSL keys and certificates for puppet SSL clients
data/man/man8/puppet.8 CHANGED
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "PUPPET" "8" "March 2022" "Puppet, Inc." "Puppet manual"
4
+ .TH "PUPPET" "8" "July 2022" "Puppet, Inc." "Puppet manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBpuppet\fR
@@ -25,4 +25,4 @@ Specialized:
25
25
  catalog Compile, save, view, and convert catalogs\. describe Display help about resource types device Manage remote network devices doc Generate Puppet references epp Interact directly with the EPP template parser/renderer\. facts Retrieve and store facts\. filebucket Store and retrieve files in a filebucket generate Generates Puppet code from Ruby definitions\. node View and manage node definitions\. parser Interact directly with the parser\. plugin Interact with the Puppet plugin system\. script Run a puppet manifests as a script without compiling a catalog ssl Manage SSL keys and certificates for puppet SSL clients
26
26
  .
27
27
  .P
28
- See \'puppet help \fIsubcommand\fR \fIaction\fR\' for help on a specific subcommand action\. See \'puppet help \fIsubcommand\fR\' for help on a specific subcommand\. Puppet v7\.15\.0
28
+ See \'puppet help \fIsubcommand\fR \fIaction\fR\' for help on a specific subcommand action\. See \'puppet help \fIsubcommand\fR\' for help on a specific subcommand\. Puppet v7\.18\.0
@@ -3,6 +3,7 @@ require 'puppet_spec/files'
3
3
  require 'puppet_spec/puppetserver'
4
4
  require 'puppet_spec/compiler'
5
5
  require 'puppet_spec/https'
6
+ require 'puppet/application/agent'
6
7
 
7
8
  describe "puppet agent", unless: Puppet::Util::Platform.jruby? do
8
9
  include PuppetSpec::Files
@@ -97,6 +98,18 @@ describe "puppet agent", unless: Puppet::Util::Platform.jruby? do
97
98
  end
98
99
 
99
100
  context 'rich data' do
101
+ let(:deferred_file) { tmpfile('deferred') }
102
+ let(:deferred_manifest) do <<~END
103
+ file { '#{deferred_file}':
104
+ ensure => file,
105
+ content => '123',
106
+ } ->
107
+ notify { 'deferred':
108
+ message => Deferred('binary_file', ['#{deferred_file}'])
109
+ }
110
+ END
111
+ end
112
+
100
113
  it "calls a deferred 4x function" do
101
114
  catalog_handler = -> (req, res) {
102
115
  catalog = compile_to_catalog(<<-MANIFEST, node)
@@ -141,6 +154,43 @@ describe "puppet agent", unless: Puppet::Util::Platform.jruby? do
141
154
  end
142
155
  end
143
156
 
157
+ it "fails to apply a deferred function with an unsatified prerequisite" do
158
+ catalog_handler = -> (req, res) {
159
+ catalog = compile_to_catalog(deferred_manifest, node)
160
+ res.body = formatter.render(catalog)
161
+ res['Content-Type'] = formatter.mime
162
+ }
163
+
164
+ server.start_server(mounts: {catalog: catalog_handler}) do |port|
165
+ Puppet[:serverport] = port
166
+ expect {
167
+ agent.command_line.args << '--test'
168
+ agent.run
169
+ }.to exit_with(1)
170
+ .and output(%r{Using environment}).to_stdout
171
+ .and output(%r{The given file '#{deferred_file}' does not exist}).to_stderr
172
+ end
173
+ end
174
+
175
+ it "applies a deferred function and its prerequisite in the same run" do
176
+ Puppet[:preprocess_deferred] = false
177
+
178
+ catalog_handler = -> (req, res) {
179
+ catalog = compile_to_catalog(deferred_manifest, node)
180
+ res.body = formatter.render(catalog)
181
+ res['Content-Type'] = formatter.mime
182
+ }
183
+
184
+ server.start_server(mounts: {catalog: catalog_handler}) do |port|
185
+ Puppet[:serverport] = port
186
+ expect {
187
+ agent.command_line.args << '--test'
188
+ agent.run
189
+ }.to exit_with(2)
190
+ .and output(%r{defined 'message' as Binary\("MTIz"\)}).to_stdout
191
+ end
192
+ end
193
+
144
194
  it "re-evaluates a deferred function in a cached catalog" do
145
195
  Puppet[:report] = false
146
196
  Puppet[:use_cached_catalog] = true
@@ -740,4 +790,111 @@ describe "puppet agent", unless: Puppet::Util::Platform.jruby? do
740
790
  end
741
791
  end
742
792
  end
793
+
794
+ context "ssl" do
795
+ context "bootstrapping" do
796
+ before :each do
797
+ # reconfigure ssl to non-existent dir and files to force bootstrapping
798
+ dir = tmpdir('ssl')
799
+ Puppet[:ssldir] = dir
800
+ Puppet[:localcacert] = File.join(dir, 'ca.pem')
801
+ Puppet[:hostcrl] = File.join(dir, 'crl.pem')
802
+ Puppet[:hostprivkey] = File.join(dir, 'cert.pem')
803
+ Puppet[:hostcert] = File.join(dir, 'key.pem')
804
+
805
+ Puppet[:daemonize] = false
806
+ Puppet[:logdest] = 'console'
807
+ Puppet[:log_level] = 'info'
808
+ end
809
+
810
+ it "exits if the agent is not allowed to wait" do
811
+ Puppet[:waitforcert] = 0
812
+
813
+ server.start_server do |port|
814
+ Puppet[:serverport] = port
815
+ expect {
816
+ agent.run
817
+ }.to exit_with(1)
818
+ .and output(%r{Exiting now because the waitforcert setting is set to 0}).to_stdout
819
+ .and output(%r{Failed to submit the CSR, HTTP response was 404}).to_stderr
820
+ end
821
+ end
822
+
823
+ it "exits if the maxwaitforcert time is exceeded" do
824
+ Puppet[:waitforcert] = 1
825
+ Puppet[:maxwaitforcert] = 1
826
+
827
+ server.start_server do |port|
828
+ Puppet[:serverport] = port
829
+ expect {
830
+ agent.run
831
+ }.to exit_with(1)
832
+ .and output(%r{Couldn't fetch certificate from CA server; you might still need to sign this agent's certificate \(127.0.0.1\). Exiting now because the maxwaitforcert timeout has been exceeded.}).to_stdout
833
+ .and output(%r{Failed to submit the CSR, HTTP response was 404}).to_stderr
834
+ end
835
+ end
836
+ end
837
+
838
+ def copy_fixtures(sources, dest)
839
+ ssldir = File.join(PuppetSpec::FIXTURE_DIR, 'ssl')
840
+ File.open(dest, 'w') do |f|
841
+ sources.each do |s|
842
+ f.write(File.read(File.join(ssldir, s)))
843
+ end
844
+ end
845
+ end
846
+
847
+ it "reloads the CRL between runs" do
848
+ Puppet[:localcacert] = ca = tmpfile('ca')
849
+ Puppet[:hostcrl] = crl = tmpfile('crl')
850
+ Puppet[:hostcert] = cert = tmpfile('cert')
851
+ Puppet[:hostprivkey] = key = tmpfile('key')
852
+
853
+ copy_fixtures(%w[ca.pem intermediate.pem], ca)
854
+ copy_fixtures(%w[crl.pem intermediate-crl.pem], crl)
855
+ copy_fixtures(%w[127.0.0.1.pem], cert)
856
+ copy_fixtures(%w[127.0.0.1-key.pem], key)
857
+
858
+ revoked = cert_fixture('revoked.pem')
859
+ revoked_key = key_fixture('revoked-key.pem')
860
+
861
+ mounts = {}
862
+ mounts[:catalog] = -> (req, res) {
863
+ catalog = compile_to_catalog(<<~MANIFEST, node)
864
+ file { '#{cert}':
865
+ ensure => file,
866
+ content => '#{revoked}'
867
+ }
868
+ file { '#{key}':
869
+ ensure => file,
870
+ content => '#{revoked_key}'
871
+ }
872
+ MANIFEST
873
+
874
+ res.body = formatter.render(catalog)
875
+ res['Content-Type'] = formatter.mime
876
+ }
877
+
878
+ server.start_server(mounts: mounts) do |port|
879
+ Puppet[:serverport] = port
880
+ Puppet[:daemonize] = false
881
+ Puppet[:runinterval] = 1
882
+ Puppet[:waitforcert] = 1
883
+ Puppet[:maxwaitforcert] = 1
884
+
885
+ # simulate two runs of the agent, then return so we don't infinite loop
886
+ allow_any_instance_of(Puppet::Daemon).to receive(:run_event_loop) do |instance|
887
+ instance.agent.run(splay: false)
888
+ instance.agent.run(splay: false)
889
+ end
890
+
891
+ agent.command_line.args << '--verbose'
892
+ expect {
893
+ agent.run
894
+ }.to exit_with(1)
895
+ .and output(%r{Exiting now because the maxwaitforcert timeout has been exceeded}).to_stdout
896
+ .and output(%r{Certificate 'CN=revoked' is revoked}).to_stderr
897
+ end
898
+ end
899
+ end
743
900
  end
@@ -665,6 +665,18 @@ class amod::bad_type {
665
665
  end
666
666
 
667
667
  context 'rich data' do
668
+ let(:deferred_file) { tmpfile('deferred') }
669
+ let(:deferred_manifest) do <<~END
670
+ file { '#{deferred_file}':
671
+ ensure => file,
672
+ content => '123',
673
+ } ->
674
+ notify { 'deferred':
675
+ message => Deferred('binary_file', ['#{deferred_file}'])
676
+ }
677
+ END
678
+ end
679
+
668
680
  it "calls a deferred 4x function" do
669
681
  apply.command_line.args = ['-e', 'notify { "deferred3x": message => Deferred("join", [[1,2,3], ":"]) }']
670
682
 
@@ -681,5 +693,67 @@ class amod::bad_type {
681
693
  }.to exit_with(0) # for some reason apply returns 0 instead of 2
682
694
  .and output(%r{Notice: /Stage\[main\]/Main/Notify\[deferred4x\]/message: defined 'message' as 'I am deferred'}).to_stdout
683
695
  end
696
+
697
+ it "fails to apply a deferred function with an unsatified prerequisite" do
698
+ apply.command_line.args = ['-e', deferred_manifest]
699
+ expect {
700
+ apply.run
701
+ }.to exit_with(1) # for some reason apply returns 0 instead of 2
702
+ .and output(/Compiled catalog/).to_stdout
703
+ .and output(%r{The given file '#{deferred_file}' does not exist}).to_stderr
704
+ end
705
+
706
+ it "applies a deferred function and its prerequisite in the same run" do
707
+ Puppet[:preprocess_deferred] = false
708
+
709
+ apply.command_line.args = ['-e', deferred_manifest]
710
+ expect {
711
+ apply.run
712
+ }.to exit_with(0) # for some reason apply returns 0 instead of 2
713
+ .and output(%r{defined 'message' as Binary\("MTIz"\)}).to_stdout
714
+ end
715
+
716
+ it "validates the deferred resource before applying any resources" do
717
+ undeferred_file = tmpfile('undeferred')
718
+
719
+ manifest = <<~END
720
+ file { '#{undeferred_file}':
721
+ ensure => file,
722
+ }
723
+ file { '#{deferred_file}':
724
+ ensure => file,
725
+ content => Deferred('inline_epp', ['<%= 42 %>']),
726
+ source => 'http://example.com/content',
727
+ }
728
+ END
729
+ apply.command_line.args = ['-e', manifest]
730
+ expect {
731
+ apply.run
732
+ }.to exit_with(1)
733
+ .and output(/Compiled catalog/).to_stdout
734
+ .and output(/Validation of File.* failed: You cannot specify more than one of content, source, target/).to_stderr
735
+
736
+ # validation happens before all resources are applied, so this shouldn't exist
737
+ expect(File).to_not be_exist(undeferred_file)
738
+ end
739
+
740
+ it "evaluates resources before validating the deferred resource" do
741
+ Puppet[:preprocess_deferred] = false
742
+
743
+ manifest = <<~END
744
+ notify { 'runs before file': } ->
745
+ file { '#{deferred_file}':
746
+ ensure => file,
747
+ content => Deferred('inline_epp', ['<%= 42 %>']),
748
+ source => 'http://example.com/content',
749
+ }
750
+ END
751
+ apply.command_line.args = ['-e', manifest]
752
+ expect {
753
+ apply.run
754
+ }.to exit_with(1)
755
+ .and output(/Notify\[runs before file\]/).to_stdout
756
+ .and output(/Validation of File.* failed: You cannot specify more than one of content, source, target/).to_stderr
757
+ end
684
758
  end
685
759
  end
@@ -77,7 +77,13 @@ describe Puppet::HTTP::Client, unless: Puppet::Util::Platform.jruby? do
77
77
  }
78
78
  }
79
79
 
80
- it "mutually authenticates the connection" do
80
+ let(:cert_file) do
81
+ res = tmpfile('cert_file')
82
+ File.write(res, https_server.ca_cert)
83
+ res
84
+ end
85
+
86
+ it "mutually authenticates the connection using an explicit context" do
81
87
  client_context = ssl_provider.create_context(
82
88
  cacerts: [https_server.ca_cert], crls: [https_server.ca_crl],
83
89
  client_cert: https_server.server_cert, private_key: https_server.server_key
@@ -88,6 +94,47 @@ describe Puppet::HTTP::Client, unless: Puppet::Util::Platform.jruby? do
88
94
  expect(res).to be_success
89
95
  end
90
96
  end
97
+
98
+ it "mutually authenticates the connection when the client and server certs are issued from different CAs" do
99
+ # this is the client cert's CA, key and cert
100
+ Puppet[:localcacert] = fixtures('ssl/unknown-ca.pem')
101
+ Puppet[:hostprivkey] = fixtures('ssl/unknown-127.0.0.1-key.pem')
102
+ Puppet[:hostcert] = fixtures('ssl/unknown-127.0.0.1.pem')
103
+
104
+ # this is the server cert's CA that the client needs in order to authenticate the server
105
+ Puppet[:ssl_trust_store] = fixtures('ssl/ca.pem')
106
+
107
+ # need to pass both the client and server CAs. The former is needed so the server can authenticate our client cert
108
+ https_server = PuppetSpec::HTTPSServer.new(ca_cert: [cert_fixture('ca.pem'), cert_fixture('unknown-ca.pem')])
109
+ https_server.start_server(ctx_proc: ctx_proc) do |port|
110
+ res = client.get(URI("https://127.0.0.1:#{port}"), options: {include_system_store: true})
111
+ expect(res).to be_success
112
+ end
113
+ end
114
+
115
+ it "connects when the server's CA is in the system store and the connection is mutually authenticated using create_context" do
116
+ Puppet::Util.withenv("SSL_CERT_FILE" => cert_file) do
117
+ client_context = ssl_provider.create_context(
118
+ cacerts: [], crls: [],
119
+ client_cert: https_server.server_cert, private_key: https_server.server_key,
120
+ revocation: false, include_system_store: true
121
+ )
122
+ https_server.start_server(ctx_proc: ctx_proc) do |port|
123
+ res = client.get(URI("https://127.0.0.1:#{port}"), options: {ssl_context: client_context})
124
+ expect(res).to be_success
125
+ end
126
+ end
127
+ end
128
+
129
+ it "connects when the server's CA is in the system store and the connection is mutually authenticated using load_context" do
130
+ Puppet::Util.withenv("SSL_CERT_FILE" => cert_file) do
131
+ client_context = ssl_provider.load_context(revocation: false, include_system_store: true)
132
+ https_server.start_server(ctx_proc: ctx_proc) do |port|
133
+ res = client.get(URI("https://127.0.0.1:#{port}"), options: {ssl_context: client_context})
134
+ expect(res).to be_success
135
+ end
136
+ end
137
+ end
91
138
  end
92
139
 
93
140
  context "with a system trust store" do
@@ -102,12 +149,12 @@ describe Puppet::HTTP::Client, unless: Puppet::Util::Platform.jruby? do
102
149
 
103
150
  it "connects when the server's CA is in the system store" do
104
151
  # create a temp cacert bundle
105
- ssl_file = tmpfile('systemstore')
106
- File.write(ssl_file, https_server.ca_cert)
152
+ cert_file = tmpfile('cert_file')
153
+ File.write(cert_file, https_server.ca_cert)
107
154
 
108
155
  # override path to system cacert bundle, this must be done before
109
156
  # the SSLContext is created and the call to X509::Store.set_default_paths
110
- Puppet::Util.withenv("SSL_CERT_FILE" => ssl_file) do
157
+ Puppet::Util.withenv("SSL_CERT_FILE" => cert_file) do
111
158
  system_context = ssl_provider.create_system_context(cacerts: [])
112
159
  https_server.start_server do |port|
113
160
  res = client.get(URI("https://127.0.0.1:#{port}"), options: {ssl_context: system_context})
@@ -40,7 +40,7 @@ class PuppetSpec::HTTPSServer
40
40
 
41
41
  IO.pipe {|stop_pipe_r, stop_pipe_w|
42
42
  store = OpenSSL::X509::Store.new
43
- store.add_cert(@ca_cert)
43
+ Array(@ca_cert).each { |c| store.add_cert(c) }
44
44
  store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
45
45
  ctx = OpenSSL::SSL::SSLContext.new
46
46
  ctx.cert_store = store
@@ -72,6 +72,40 @@ class PuppetSpec::Puppetserver
72
72
  end
73
73
  end
74
74
 
75
+ class CertificateServlet < WEBrick::HTTPServlet::AbstractServlet
76
+ def initialize(server, ca_cert)
77
+ super(server)
78
+ @ca_cert = ca_cert
79
+ end
80
+
81
+ def do_GET request, response
82
+ if request.path =~ %r{/puppet-ca/v1/certificate/ca$}
83
+ response['Content-Type'] = 'text/plain'
84
+ response.body = @ca_cert.to_pem
85
+ else
86
+ response.status = 404
87
+ end
88
+ end
89
+ end
90
+
91
+ class CertificateRevocationListServlet < WEBrick::HTTPServlet::AbstractServlet
92
+ def initialize(server, crl)
93
+ super(server)
94
+ @crl = crl
95
+ end
96
+
97
+ def do_GET request, response
98
+ response['Content-Type'] = 'text/plain'
99
+ response.body = @crl.to_pem
100
+ end
101
+ end
102
+
103
+ class CertificateRequestServlet < WEBrick::HTTPServlet::AbstractServlet
104
+ def do_PUT request, response
105
+ response.status = 404
106
+ end
107
+ end
108
+
75
109
  def initialize
76
110
  @ca_cert = cert_fixture('ca.pem')
77
111
  @ca_crl = crl_fixture('crl.pem')
@@ -125,15 +159,18 @@ class PuppetSpec::Puppetserver
125
159
  register_mount('/puppet/v3/static_file_content', mounts[:static_file_content], StaticFileContentServlet)
126
160
  register_mount('/puppet/v3/report', mounts[:report], ReportServlet)
127
161
  register_mount('/puppet/v3/file_bucket_file', mounts[:filebucket], FilebucketServlet)
162
+ register_mount('/puppet-ca/v1/certificate', mounts[:certificate], CertificateServlet, @ca_cert)
163
+ register_mount('/puppet-ca/v1/certificate_revocation_list', mounts[:certificate_revocation_list], CertificateRevocationListServlet, @ca_crl)
164
+ register_mount('/puppet-ca/v1/certificate_request', mounts[:certificate_request], CertificateRequestServlet)
128
165
  end
129
166
 
130
- def register_mount(path, user_proc, default_servlet)
167
+ def register_mount(path, user_proc, default_servlet, *args)
131
168
  handler = if user_proc
132
169
  WEBrick::HTTPServlet::ProcHandler.new(user_proc)
133
170
  else
134
171
  default_servlet
135
172
  end
136
- @https.mount(path, handler)
173
+ @https.mount(path, handler, *args)
137
174
  end
138
175
 
139
176
  def upload_directory