puppet 6.3.0-x86-mingw32 → 6.4.0-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 (147) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +30 -0
  3. data/Gemfile.lock +9 -9
  4. data/lib/puppet.rb +13 -0
  5. data/lib/puppet/application/agent.rb +8 -12
  6. data/lib/puppet/application/device.rb +2 -3
  7. data/lib/puppet/application/filebucket.rb +6 -1
  8. data/lib/puppet/application/ssl.rb +102 -55
  9. data/lib/puppet/configurer.rb +8 -7
  10. data/lib/puppet/defaults.rb +3 -1
  11. data/lib/puppet/file_system.rb +24 -4
  12. data/lib/puppet/file_system/file_impl.rb +25 -0
  13. data/lib/puppet/file_system/jruby.rb +23 -0
  14. data/lib/puppet/file_system/windows.rb +84 -0
  15. data/lib/puppet/indirector/rest.rb +4 -2
  16. data/lib/puppet/loaders.rb +1 -0
  17. data/lib/puppet/network/http.rb +1 -0
  18. data/lib/puppet/network/http/base_pool.rb +18 -0
  19. data/lib/puppet/network/http/connection.rb +49 -17
  20. data/lib/puppet/network/http/nocache_pool.rb +9 -4
  21. data/lib/puppet/network/http/pool.rb +10 -11
  22. data/lib/puppet/network/http/session.rb +3 -2
  23. data/lib/puppet/network/http_pool.rb +32 -0
  24. data/lib/puppet/pops/loader/generic_plan_instantiator.rb +28 -0
  25. data/lib/puppet/pops/loader/loader_paths.rb +46 -10
  26. data/lib/puppet/pops/loader/module_loaders.rb +10 -3
  27. data/lib/puppet/provider/file/windows.rb +49 -1
  28. data/lib/puppet/provider/package/windows.rb +5 -1
  29. data/lib/puppet/reports/http.rb +2 -1
  30. data/lib/puppet/rest/client.rb +7 -3
  31. data/lib/puppet/rest/routes.rb +9 -44
  32. data/lib/puppet/ssl.rb +6 -0
  33. data/lib/puppet/ssl/error.rb +26 -0
  34. data/lib/puppet/ssl/host.rb +9 -92
  35. data/lib/puppet/ssl/ssl_context.rb +30 -0
  36. data/lib/puppet/ssl/ssl_provider.rb +232 -0
  37. data/lib/puppet/ssl/state_machine.rb +261 -0
  38. data/lib/puppet/ssl/validator.rb +1 -0
  39. data/lib/puppet/ssl/validator/default_validator.rb +1 -0
  40. data/lib/puppet/ssl/validator/no_validator.rb +2 -0
  41. data/lib/puppet/ssl/verifier.rb +134 -0
  42. data/lib/puppet/ssl/verifier_adapter.rb +48 -0
  43. data/lib/puppet/test/test_helper.rb +2 -1
  44. data/lib/puppet/type/exec.rb +30 -6
  45. data/lib/puppet/type/file/mode.rb +6 -1
  46. data/lib/puppet/type/file/source.rb +2 -2
  47. data/lib/puppet/type/filebucket.rb +12 -8
  48. data/lib/puppet/type/user.rb +14 -1
  49. data/lib/puppet/util/connection.rb +10 -5
  50. data/lib/puppet/util/feature.rb +11 -2
  51. data/lib/puppet/util/http_proxy.rb +3 -2
  52. data/lib/puppet/util/pidlock.rb +1 -1
  53. data/lib/puppet/util/ssl.rb +1 -10
  54. data/lib/puppet/util/windows/security.rb +29 -8
  55. data/lib/puppet/version.rb +1 -1
  56. data/lib/puppet/x509.rb +7 -0
  57. data/lib/puppet/x509/cert_provider.rb +286 -0
  58. data/lib/puppet/x509/pem_store.rb +55 -0
  59. data/locales/ja/puppet.po +740 -590
  60. data/locales/puppet.pot +433 -208
  61. data/man/man5/puppet.conf.5 +6 -3
  62. data/man/man8/puppet-agent.8 +1 -1
  63. data/man/man8/puppet-apply.8 +1 -1
  64. data/man/man8/puppet-catalog.8 +1 -1
  65. data/man/man8/puppet-config.8 +1 -1
  66. data/man/man8/puppet-describe.8 +1 -1
  67. data/man/man8/puppet-device.8 +1 -1
  68. data/man/man8/puppet-doc.8 +1 -1
  69. data/man/man8/puppet-epp.8 +1 -1
  70. data/man/man8/puppet-facts.8 +1 -1
  71. data/man/man8/puppet-filebucket.8 +6 -2
  72. data/man/man8/puppet-generate.8 +1 -1
  73. data/man/man8/puppet-help.8 +1 -1
  74. data/man/man8/puppet-key.8 +1 -1
  75. data/man/man8/puppet-lookup.8 +1 -1
  76. data/man/man8/puppet-man.8 +1 -1
  77. data/man/man8/puppet-module.8 +1 -1
  78. data/man/man8/puppet-node.8 +1 -1
  79. data/man/man8/puppet-parser.8 +1 -1
  80. data/man/man8/puppet-plugin.8 +1 -1
  81. data/man/man8/puppet-report.8 +1 -1
  82. data/man/man8/puppet-resource.8 +1 -1
  83. data/man/man8/puppet-script.8 +1 -1
  84. data/man/man8/puppet-ssl.8 +5 -1
  85. data/man/man8/puppet-status.8 +1 -1
  86. data/man/man8/puppet.8 +2 -2
  87. data/spec/fixtures/ssl/127.0.0.1-key.pem +67 -0
  88. data/spec/fixtures/ssl/127.0.0.1.pem +48 -0
  89. data/spec/fixtures/ssl/bad-basic-constraints.pem +59 -0
  90. data/spec/fixtures/ssl/bad-int-basic-constraints.pem +59 -0
  91. data/spec/fixtures/ssl/ca.pem +59 -0
  92. data/spec/fixtures/ssl/crl.pem +30 -0
  93. data/spec/fixtures/ssl/encrypted-key.pem +70 -0
  94. data/spec/fixtures/ssl/intermediate-agent-crl.pem +31 -0
  95. data/spec/fixtures/ssl/intermediate-agent.pem +60 -0
  96. data/spec/fixtures/ssl/intermediate-crl.pem +36 -0
  97. data/spec/fixtures/ssl/intermediate.pem +60 -0
  98. data/spec/fixtures/ssl/netlock-arany-utf8.pem +23 -0
  99. data/spec/fixtures/ssl/pluto-key.pem +67 -0
  100. data/spec/fixtures/ssl/pluto.pem +44 -0
  101. data/spec/fixtures/ssl/request-key.pem +67 -0
  102. data/spec/fixtures/ssl/request.pem +39 -0
  103. data/spec/fixtures/ssl/revoked-key.pem +67 -0
  104. data/spec/fixtures/ssl/revoked.pem +44 -0
  105. data/spec/fixtures/ssl/signed-key.pem +67 -0
  106. data/spec/fixtures/ssl/signed.pem +44 -0
  107. data/spec/fixtures/ssl/tampered-cert.pem +44 -0
  108. data/spec/fixtures/ssl/tampered-csr.pem +39 -0
  109. data/spec/integration/network/http_pool_spec.rb +222 -0
  110. data/spec/integration/provider/file/windows_spec.rb +162 -0
  111. data/spec/integration/rest/client_spec.rb +73 -0
  112. data/spec/integration/type/file_spec.rb +0 -19
  113. data/spec/lib/puppet/test_ca.rb +87 -50
  114. data/spec/lib/puppet_spec/fixtures.rb +20 -0
  115. data/spec/lib/puppet_spec/https.rb +84 -0
  116. data/spec/unit/application/agent_spec.rb +29 -30
  117. data/spec/unit/application/device_spec.rb +12 -49
  118. data/spec/unit/application/ssl_spec.rb +24 -38
  119. data/spec/unit/configurer_spec.rb +11 -11
  120. data/spec/unit/file_system/uniquefile_spec.rb +6 -0
  121. data/spec/unit/file_system_spec.rb +214 -0
  122. data/spec/unit/indirector/rest_spec.rb +3 -3
  123. data/spec/unit/network/http/connection_spec.rb +30 -90
  124. data/spec/unit/network/http/factory_spec.rb +1 -0
  125. data/spec/unit/network/http/nocache_pool_spec.rb +8 -8
  126. data/spec/unit/network/http/pool_spec.rb +63 -33
  127. data/spec/unit/network/http/session_spec.rb +8 -1
  128. data/spec/unit/network/http_pool_spec.rb +36 -0
  129. data/spec/unit/pops/loaders/loader_spec.rb +26 -1
  130. data/spec/unit/provider/package/windows_spec.rb +12 -1
  131. data/spec/unit/reports/http_spec.rb +7 -7
  132. data/spec/unit/rest/client_spec.rb +4 -6
  133. data/spec/unit/ssl/host_spec.rb +39 -33
  134. data/spec/unit/ssl/ssl_provider_spec.rb +428 -0
  135. data/spec/unit/ssl/state_machine_spec.rb +502 -0
  136. data/spec/unit/ssl/verifier_spec.rb +123 -0
  137. data/spec/unit/type/exec_spec.rb +63 -0
  138. data/spec/unit/type/file/source_spec.rb +5 -5
  139. data/spec/unit/type/filebucket_spec.rb +8 -6
  140. data/spec/unit/util/feature_spec.rb +2 -2
  141. data/spec/unit/util/storage_spec.rb +19 -19
  142. data/spec/unit/x509/cert_provider_spec.rb +527 -0
  143. data/spec/unit/x509/pem_store_spec.rb +160 -0
  144. data/tasks/generate_cert_fixtures.rake +158 -0
  145. metadata +78 -4
  146. data/MAINTAINERS +0 -47
  147. data/lib/puppet/rest/ssl_context.rb +0 -13
@@ -20,6 +20,8 @@ describe Puppet::Application::Device do
20
20
  Puppet::Node::Facts.indirection.stubs(:terminus_class=)
21
21
  end
22
22
 
23
+ let(:state_machine) { stub(ensure_client_certificate: nil) }
24
+
23
25
  it "should operate in agent run_mode" do
24
26
  expect(@device.class.run_mode.name).to eq(:agent)
25
27
  end
@@ -74,25 +76,28 @@ describe Puppet::Application::Device do
74
76
 
75
77
  it "should set waitforcert to 0 with --onetime and if --waitforcert wasn't given" do
76
78
  Puppet[:onetime] = true
77
- Puppet::SSL::Host.any_instance.expects(:wait_for_cert).with(0)
79
+ Puppet::SSL::StateMachine.expects(:new).with(has_entry(waitforcert: 0)).returns(state_machine)
80
+
78
81
  @device.setup_host('device.example.com')
79
82
  end
80
83
 
81
84
  it "should use supplied waitforcert when --onetime is specified" do
82
85
  Puppet[:onetime] = true
83
86
  @device.handle_waitforcert(60)
84
- Puppet::SSL::Host.any_instance.expects(:wait_for_cert).with(60)
87
+ Puppet::SSL::StateMachine.expects(:new).with(has_entry(waitforcert: 60)).returns(state_machine)
88
+
85
89
  @device.setup_host('device.example.com')
86
90
  end
87
91
 
88
92
  it "should use a default value for waitforcert when --onetime and --waitforcert are not specified" do
89
- Puppet::SSL::Host.any_instance.expects(:wait_for_cert).with(120)
93
+ Puppet::SSL::StateMachine.expects(:new).with(has_entry(waitforcert: 120)).returns(state_machine)
94
+
90
95
  @device.setup_host('device.example.com')
91
96
  end
92
97
 
93
98
  it "should use the waitforcert setting when checking for a signed certificate" do
94
99
  Puppet[:waitforcert] = 10
95
- Puppet::SSL::Host.any_instance.expects(:wait_for_cert).with(10)
100
+ Puppet::SSL::StateMachine.expects(:new).with(has_entry(waitforcert: 10)).returns(state_machine)
96
101
  @device.setup_host('device.example.com')
97
102
  end
98
103
 
@@ -155,8 +160,6 @@ describe Puppet::Application::Device do
155
160
  Puppet::Resource::Catalog.indirection.stubs(:terminus_class=)
156
161
  Puppet::Resource::Catalog.indirection.stubs(:cache_class=)
157
162
  Puppet::Node::Facts.indirection.stubs(:terminus_class=)
158
- @host = stub_everything 'host'
159
- Puppet::SSL::Host.stubs(:new).returns(@host)
160
163
  Puppet.stubs(:settraps)
161
164
  end
162
165
 
@@ -264,19 +267,15 @@ describe Puppet::Application::Device do
264
267
  end
265
268
 
266
269
  describe "when initializing each devices SSL" do
267
- before(:each) do
268
- @host = stub_everything 'host'
269
- Puppet::SSL::Host.stubs(:new).returns(@host)
270
- end
271
-
272
270
  it "should create a new ssl host" do
273
- Puppet::SSL::Host.expects(:new).returns(@host)
271
+ Puppet::SSL::StateMachine.expects(:new).with(has_entry(certname: 'device.example.com')).returns(state_machine)
272
+
274
273
  @device.setup_host('device.example.com')
275
274
  end
276
275
 
277
276
  it "should wait for a certificate" do
278
277
  @device.options.stubs(:[]).with(:waitforcert).returns(123)
279
- @host.expects(:wait_for_cert).with(123)
278
+ Puppet::SSL::StateMachine.expects(:new).with(has_entry(waitforcert: 123)).returns(state_machine)
280
279
 
281
280
  @device.setup_host('device.example.com')
282
281
  end
@@ -585,42 +584,6 @@ describe Puppet::Application::Device do
585
584
  expect(found_devices).to eq(all_devices)
586
585
  end
587
586
  end
588
-
589
- it "should cleanup the certname setting after the run" do
590
- all_devices = Set.new(@device_hash.keys)
591
- found_devices = Set.new()
592
-
593
- # a block to use in a few places later to validate the updated settings
594
- p = Proc.new do |my_setting, my_value|
595
- if my_setting == :certname && all_devices.include?(my_value)
596
- found_devices.add(my_value)
597
- true
598
- else
599
- false
600
- end
601
- end
602
-
603
- seq = sequence("clean up certname")
604
-
605
- all_devices.size.times do
606
- ## one occurrence of set / run / set("certname") for each device
607
- Puppet.expects(:[]=).with(&p).in_sequence(seq)
608
- @configurer.expects(:run).in_sequence(seq)
609
- Puppet.expects(:[]=).with(:certname, "certname").in_sequence(seq)
610
- end
611
-
612
-
613
- expect { @device.main }.to exit_with 1
614
-
615
- # make sure that we were called with each of the defined devices
616
- expect(found_devices).to eq(all_devices)
617
- end
618
-
619
- it "should expire all cached attributes" do
620
- Puppet::SSL::Host.expects(:reset).twice
621
-
622
- expect { @device.main }.to exit_with 1
623
- end
624
587
  end
625
588
  end
626
589
  end
@@ -25,6 +25,9 @@ describe Puppet::Application::Ssl, unless: Puppet::Util::Platform.jruby? do
25
25
  before do
26
26
  WebMock.disable_net_connect!
27
27
 
28
+ Net::HTTP.any_instance.stubs(:start)
29
+ Net::HTTP.any_instance.stubs(:finish)
30
+
28
31
  Puppet.settings.use(:main)
29
32
  Puppet[:certname] = name
30
33
  Puppet[:vardir] = tmpdir("ssl_testing")
@@ -56,7 +59,6 @@ describe Puppet::Application::Ssl, unless: Puppet::Util::Platform.jruby? do
56
59
  it 'downloads the CA bundle first when missing' do
57
60
  File.delete(Puppet[:localcacert])
58
61
  stub_request(:get, %r{puppet-ca/v1/certificate/ca}).to_return(status: 200, body: @ca.ca_cert.to_pem)
59
- stub_request(:get, %r{puppet-ca/v1/certificate_request/#{name}}).to_return(status: 404)
60
62
  stub_request(:put, %r{puppet-ca/v1/certificate_request/#{name}}).to_return(status: 200)
61
63
  stub_request(:get, %r{puppet-ca/v1/certificate/#{name}}).to_return(status: 200, body: @host[:cert].to_pem)
62
64
 
@@ -68,7 +70,6 @@ describe Puppet::Application::Ssl, unless: Puppet::Util::Platform.jruby? do
68
70
  it 'downloads the CRL bundle first when missing' do
69
71
  File.delete(Puppet[:hostcrl])
70
72
  stub_request(:get, %r{puppet-ca/v1/certificate_revocation_list/ca}).to_return(status: 200, body: @crl.to_pem)
71
- stub_request(:get, %r{puppet-ca/v1/certificate_request/#{name}}).to_return(status: 404)
72
73
  stub_request(:put, %r{puppet-ca/v1/certificate_request/#{name}}).to_return(status: 200)
73
74
  stub_request(:get, %r{puppet-ca/v1/certificate/#{name}}).to_return(status: 200, body: @host[:cert].to_pem)
74
75
 
@@ -106,7 +107,6 @@ describe Puppet::Application::Ssl, unless: Puppet::Util::Platform.jruby? do
106
107
  it_behaves_like 'an ssl action'
107
108
 
108
109
  it 'submits the CSR and saves it locally' do
109
- stub_request(:get, %r{puppet-ca/v1/certificate_request/#{name}}).to_return(status: 404)
110
110
  stub_request(:put, %r{puppet-ca/v1/certificate_request/#{name}}).to_return(status: 200)
111
111
  stub_request(:get, %r{puppet-ca/v1/certificate/#{name}}).to_return(status: 404)
112
112
 
@@ -116,55 +116,29 @@ describe Puppet::Application::Ssl, unless: Puppet::Util::Platform.jruby? do
116
116
  end
117
117
 
118
118
  it 'detects when a CSR with the same public key has already been submitted' do
119
- stub_request(:get, %r{puppet-ca/v1/certificate_request/#{name}}).to_return(status: 404)
120
119
  stub_request(:put, %r{puppet-ca/v1/certificate_request/#{name}}).to_return(status: 200)
121
120
  stub_request(:get, %r{puppet-ca/v1/certificate/#{name}}).to_return(status: 404)
122
121
 
123
122
  expects_command_to_pass(%r{Submitted certificate request for '#{name}' to https://.*})
124
123
 
125
- stub_request(:get, %r{puppet-ca/v1/certificate_request/#{name}}).to_return(status: 200, body: @host[:csr].to_pem)
126
- # we skip :put
127
124
  stub_request(:get, %r{puppet-ca/v1/certificate/#{name}}).to_return(status: 404)
128
125
 
129
126
  expects_command_to_pass
130
127
  end
131
128
 
132
- it "warns if the local CSR doesn't match the local public key, and submits a new CSR" do
133
- # write out the local CSR
134
- File.open(csr_path, 'w') { |f| f.write(@host[:csr].to_pem) }
135
-
136
- # generate a new host key, whose public key doesn't match
137
- private_key = OpenSSL::PKey::RSA.new(512)
138
- public_key = private_key.public_key
139
- File.open(Puppet[:hostprivkey], 'w') { |f| f.write(private_key.to_pem) }
140
- File.open(Puppet[:hostpubkey], 'w') { |f| f.write(public_key.to_pem) }
141
-
142
- # expect CSR to contain the new pub key
143
- stub_request(:put, %r{puppet-ca/v1/certificate_request/#{name}}).with do |request|
144
- sent_pem = OpenSSL::X509::Request.new(request.body).public_key.to_pem
145
- expect(sent_pem).to eq(public_key.to_pem)
146
- end.to_return(status: 200)
147
- stub_request(:get, %r{puppet-ca/v1/certificate/#{name}}).to_return(status: 404)
148
-
149
- Puppet.stubs(:warning) # ignore unrelated warnings
150
- Puppet.expects(:warning).with("The local CSR does not match the agent's public key. Generating a new CSR.")
151
- expects_command_to_pass(%r{Submitted certificate request for '#{name}' to https://.*})
152
- end
153
-
154
129
  it 'downloads the certificate when autosigning is enabled' do
155
- stub_request(:get, %r{puppet-ca/v1/certificate_request/#{name}}).to_return(status: 404)
156
130
  stub_request(:put, %r{puppet-ca/v1/certificate_request/#{name}}).to_return(status: 200)
157
131
  stub_request(:get, %r{puppet-ca/v1/certificate/#{name}}).to_return(status: 200, body: @host[:cert].to_pem)
158
132
 
159
133
  expects_command_to_pass(%r{Submitted certificate request for '#{name}' to https://.*})
160
134
 
161
135
  expect(Puppet::FileSystem).to be_exist(Puppet[:hostcert])
136
+ expect(Puppet::FileSystem).to_not be_exist(csr_path)
162
137
  end
163
138
 
164
139
  it 'accepts dns alt names' do
165
140
  Puppet[:dns_alt_names] = 'majortom'
166
141
 
167
- stub_request(:get, %r{puppet-ca/v1/certificate_request/#{name}}).to_return(status: 404)
168
142
  stub_request(:put, %r{puppet-ca/v1/certificate_request/#{name}}).to_return(status: 200)
169
143
  stub_request(:get, %r{puppet-ca/v1/certificate/#{name}}).to_return(status: 404)
170
144
 
@@ -212,7 +186,7 @@ describe Puppet::Application::Ssl, unless: Puppet::Util::Platform.jruby? do
212
186
  stub_request(:get, %r{puppet-ca/v1/certificate/#{name}}).to_return(status: 200, body: @host[:cert].to_pem)
213
187
 
214
188
  expects_command_to_fail(
215
- %r{^Failed to download certificate: The certificate retrieved from the master does not match the agent's private key. Did you forget to run as root?}
189
+ %r{^Failed to download certificate: The certificate for '/CN=ssl-client' does not match its private key}
216
190
  )
217
191
  end
218
192
 
@@ -233,13 +207,13 @@ describe Puppet::Application::Ssl, unless: Puppet::Util::Platform.jruby? do
233
207
  it 'reports if the key is missing' do
234
208
  File.delete(Puppet[:hostprivkey])
235
209
 
236
- expects_command_to_fail(/The host's private key is missing/)
210
+ expects_command_to_fail(/The private key is missing from/)
237
211
  end
238
212
 
239
213
  it 'reports if the cert is missing' do
240
214
  File.delete(Puppet[:hostcert])
241
215
 
242
- expects_command_to_fail(/The host's certificate is missing/)
216
+ expects_command_to_fail(/The client certificate is missing from/)
243
217
  end
244
218
 
245
219
  it 'reports if the key and cert are mismatched' do
@@ -249,7 +223,7 @@ describe Puppet::Application::Ssl, unless: Puppet::Util::Platform.jruby? do
249
223
  File.open(Puppet[:hostprivkey], 'w') { |f| f.write(private_key.to_pem) }
250
224
  File.open(Puppet[:hostpubkey], 'w') { |f| f.write(public_key.to_pem) }
251
225
 
252
- expects_command_to_fail(/The host's key does not match the certificate/)
226
+ expects_command_to_fail(%r{The certificate for '/CN=ssl-client' does not match its private key})
253
227
  end
254
228
 
255
229
  it 'reports if the cert verification fails' do
@@ -260,15 +234,13 @@ describe Puppet::Application::Ssl, unless: Puppet::Util::Platform.jruby? do
260
234
  # and CRL for that CA
261
235
  File.open(Puppet[:hostcrl], 'w') { |f| f.write(new_ca.ca_crl.to_pem) }
262
236
 
263
- expects_command_to_fail(
264
- /Failed to verify certificate '#{name}': certificate signature failure \(7\)/
265
- )
237
+ expects_command_to_fail(%r{Invalid signature for certificate '/CN=ssl-client'})
266
238
  end
267
239
 
268
240
  it 'reports when verification succeeds' do
269
241
  OpenSSL::X509::Store.any_instance.stubs(:verify).returns(true)
270
242
 
271
- expects_command_to_pass(/Verified certificate '#{name}'/)
243
+ expects_command_to_pass(%r{Verified client certificate '/CN=ssl-client' fingerprint})
272
244
  end
273
245
  end
274
246
 
@@ -386,6 +358,20 @@ describe Puppet::Application::Ssl, unless: Puppet::Util::Platform.jruby? do
386
358
  File.open(device_cert_file, 'w') { |f| f.write('device.example.com') }
387
359
  expects_command_to_pass(%r{Removed certificate #{device_cert_file}})
388
360
  end
361
+ end
389
362
  end
363
+
364
+ context 'when bootstrapping' do
365
+ before do
366
+ ssl.command_line.args << 'bootstrap'
367
+ end
368
+
369
+ it 'returns an SSLContext with the loaded CA certs, CRLs, private key and client cert' do
370
+ Puppet::SSL::StateMachine.any_instance.expects(:ensure_client_certificate).returns(
371
+ stub('ssl_context')
372
+ )
373
+
374
+ expects_command_to_pass
375
+ end
390
376
  end
391
377
  end
@@ -1011,7 +1011,7 @@ describe Puppet::Configurer do
1011
1011
  it "should select a server when provided" do
1012
1012
  Puppet.settings[:server_list] = ["myserver:123"]
1013
1013
  response = Net::HTTPOK.new(nil, 200, 'OK')
1014
- Puppet::Network::HttpPool.stubs(:http_ssl_instance).with('myserver', '123').returns(mock('request', get: response))
1014
+ Puppet::Network::HttpPool.stubs(:connection).with('myserver', 123, anything).returns(mock('request', get: response))
1015
1015
  @agent.stubs(:run_internal)
1016
1016
 
1017
1017
  options = {}
@@ -1024,7 +1024,7 @@ describe Puppet::Configurer do
1024
1024
  response = Net::HTTPOK.new(nil, 200, 'OK')
1025
1025
  http = mock('request')
1026
1026
  http.expects(:get).with('/status/v1/simple/master').returns(response)
1027
- Puppet::Network::HttpPool.stubs(:http_ssl_instance).with('myserver', '123').returns(http)
1027
+ Puppet::Network::HttpPool.stubs(:connection).with('myserver', 123, anything).returns(http)
1028
1028
  @agent.stubs(:run_internal)
1029
1029
 
1030
1030
  @agent.run
@@ -1033,27 +1033,27 @@ describe Puppet::Configurer do
1033
1033
  it "should report when a server is unavailable" do
1034
1034
  Puppet.settings[:server_list] = ["myserver:123"]
1035
1035
  response = Net::HTTPInternalServerError.new(nil, 500, 'Internal Server Error')
1036
- Puppet::Network::HttpPool.stubs(:http_ssl_instance).with('myserver', '123').returns(mock('request', get: response))
1037
- @agent.stubs(:run_internal)
1036
+ Puppet::Network::HttpPool.stubs(:connection).with('myserver', 123, anything).returns(mock('request', get: response))
1038
1037
 
1039
1038
  Puppet.expects(:debug).with("Puppet server myserver:123 is unavailable: 500 Internal Server Error")
1040
- @agent.run
1039
+ expect{ @agent.run }.to raise_error(Puppet::Error, /Could not select a functional puppet master from server_list/)
1041
1040
  end
1042
1041
 
1043
- it "should fallback to an empty server when failover fails" do
1042
+ it "should error when no servers in 'server_list' are reachable" do
1044
1043
  Puppet.settings[:server_list] = ["myserver:123"]
1045
1044
  error = Net::HTTPError.new(400, 'dummy server communication error')
1046
- Puppet::Network::HttpPool.stubs(:http_ssl_instance).with('myserver', '123').returns(error)
1047
- @agent.stubs(:run_internal)
1045
+ Puppet::Network::HttpPool.stubs(:connection).with('myserver', 123, anything).returns(mock('request', get: error))
1048
1046
 
1049
1047
  options = {}
1050
- @agent.run(options)
1048
+ expect{ @agent.run(options) }.to raise_error(Puppet::Error, /Could not select a functional puppet master from server_list/)
1051
1049
  expect(options[:report].master_used).to be_nil
1052
1050
  end
1053
1051
 
1054
- it "should not make multiple node requets when the server is found" do
1052
+ it "should not make multiple node requests when the server is found" do
1055
1053
  Puppet.settings[:server_list] = ["myserver:123"]
1056
- Puppet::Network::HttpPool.expects(:http_ssl_instance).once
1054
+ response = Net::HTTPOK.new(nil, 200, 'OK')
1055
+
1056
+ Puppet::Network::HttpPool.expects(:connection).with('myserver', 123, anything).returns(mock('request', get: response))
1057
1057
  @agent.stubs(:run_internal)
1058
1058
 
1059
1059
  @agent.run
@@ -7,6 +7,12 @@ describe Puppet::FileSystem::Uniquefile do
7
7
  end
8
8
  end
9
9
 
10
+ it "ensures the file has permissions 0600", unless: Puppet::Util::Platform.windows? do
11
+ Puppet::FileSystem::Uniquefile.open_tmp('foo') do |file|
12
+ expect(Puppet::FileSystem.stat(file.path).mode & 07777).to eq(0600)
13
+ end
14
+ end
15
+
10
16
  it "provides a writeable file" do
11
17
  Puppet::FileSystem::Uniquefile.open_tmp('foo') do |file|
12
18
  file.write("stuff")
@@ -30,6 +30,35 @@ describe "Puppet::FileSystem" do
30
30
  SYSTEM_SID_BYTES == Puppet::Util::Windows::ADSI::User.current_user_sid.sid_bytes
31
31
  end
32
32
 
33
+ def expects_public_file(path)
34
+ if Puppet::Util::Platform.windows?
35
+ current_sid = Puppet::Util::Windows::SID.name_to_sid(Puppet::Util::Windows::ADSI::User.current_user_name)
36
+ sd = Puppet::Util::Windows::Security.get_security_descriptor(path)
37
+ expect(sd.dacl).to contain_exactly(
38
+ an_object_having_attributes(sid: Puppet::Util::Windows::SID::LocalSystem, mask: 0x1f01ff),
39
+ an_object_having_attributes(sid: Puppet::Util::Windows::SID::BuiltinAdministrators, mask: 0x1f01ff),
40
+ an_object_having_attributes(sid: current_sid, mask: 0x1f01ff),
41
+ an_object_having_attributes(sid: Puppet::Util::Windows::SID::BuiltinUsers, mask: 0x120089)
42
+ )
43
+ else
44
+ expect(File.stat(path).mode & 07777).to eq(0644)
45
+ end
46
+ end
47
+
48
+ def expects_private_file(path)
49
+ if Puppet::Util::Platform.windows?
50
+ current_sid = Puppet::Util::Windows::SID.name_to_sid(Puppet::Util::Windows::ADSI::User.current_user_name)
51
+ sd = Puppet::Util::Windows::Security.get_security_descriptor(path)
52
+ expect(sd.dacl).to contain_exactly(
53
+ an_object_having_attributes(sid: Puppet::Util::Windows::SID::LocalSystem, mask: 0x1f01ff),
54
+ an_object_having_attributes(sid: Puppet::Util::Windows::SID::BuiltinAdministrators, mask: 0x1f01ff),
55
+ an_object_having_attributes(sid: current_sid, mask: 0x1f01ff)
56
+ )
57
+ else
58
+ expect(File.stat(path).mode & 07777).to eq(0640)
59
+ end
60
+ end
61
+
33
62
  context "#open" do
34
63
  it "uses the same default mode as File.open, when specifying a nil mode (umask used on non-Windows)" do
35
64
  file = tmpfile('file_to_update')
@@ -770,6 +799,20 @@ describe "Puppet::FileSystem" do
770
799
 
771
800
  expect(Puppet::FileSystem.exist?(dir)).to be_truthy
772
801
  end
802
+
803
+ it "should raise Errno::EACCESS when trying to delete a file whose parent directory does not allow execute/traverse", unless: Puppet::Util::Platform.windows? do
804
+ dir = tmpdir('file_system_unlink')
805
+ path = File.join(dir, 'deleteme')
806
+ mode = Puppet::FileSystem.stat(dir).mode
807
+ Puppet::FileSystem.chmod(0, dir)
808
+ begin
809
+ expect {
810
+ Puppet::FileSystem.unlink(path)
811
+ }.to raise_error(Errno::EACCES, /^Permission denied .* #{path}/)
812
+ ensure
813
+ Puppet::FileSystem.chmod(mode, dir)
814
+ end
815
+ end
773
816
  end
774
817
 
775
818
  describe "exclusive_create" do
@@ -875,4 +918,175 @@ describe "Puppet::FileSystem" do
875
918
  end
876
919
  end
877
920
  end
921
+
922
+ describe '#replace_file' do
923
+ let(:dest) { tmpfile('replace_file') }
924
+ let(:content) { "some data" }
925
+
926
+ context 'when creating' do
927
+ it 'writes the data' do
928
+ Puppet::FileSystem.replace_file(dest) { |f| f.write(content) }
929
+
930
+ expect(Puppet::FileSystem.binread(dest)).to eq(content)
931
+ end
932
+
933
+ it 'writes in binary mode' do
934
+ Puppet::FileSystem.replace_file(dest) { |f| f.write("\x00\x01\x02") }
935
+
936
+ expect(Puppet::FileSystem.binread(dest)).to eq("\x00\x01\x02")
937
+ end
938
+
939
+ context 'on posix', unless: Puppet::Util::Platform.windows? do
940
+ it 'applies the default mode 0640' do
941
+ Puppet::FileSystem.replace_file(dest) { |f| f.write(content) }
942
+
943
+ mode = Puppet::FileSystem.stat(dest).mode
944
+ expect(mode & 07777).to eq(0640)
945
+ end
946
+
947
+ it 'applies the specified mode' do
948
+ Puppet::FileSystem.replace_file(dest, 0777) { |f| f.write(content) }
949
+
950
+ mode = Puppet::FileSystem.stat(dest).mode
951
+ expect(mode & 07777).to eq(0777)
952
+ end
953
+
954
+ it 'raises EACCES if we do not have permission' do
955
+ dir = tmpdir('file_system')
956
+ dest = File.join(dir, 'unwritable')
957
+
958
+ Puppet::FileSystem.chmod(0600, dir)
959
+
960
+ expect {
961
+ Puppet::FileSystem.replace_file(dest) { |_| }
962
+ }.to raise_error(Errno::EACCES, /Permission denied/)
963
+ end
964
+
965
+ it 'creates a read-only file' do
966
+ Puppet::FileSystem.replace_file(dest, 0400) { |f| f.write(content) }
967
+
968
+ expect(Puppet::FileSystem.binread(dest)).to eq(content)
969
+
970
+ mode = Puppet::FileSystem.stat(dest).mode
971
+ expect(mode & 07777).to eq(0400)
972
+ end
973
+ end
974
+
975
+ context 'on windows', if: Puppet::Util::Platform.windows? do
976
+ it 'does not grant users access by default' do
977
+ Puppet::FileSystem.replace_file(dest) { |f| f.write(content) }
978
+
979
+ expects_private_file(dest)
980
+ end
981
+
982
+ it 'applies the specified mode' do
983
+ Puppet::FileSystem.replace_file(dest, 0644) { |f| f.write(content) }
984
+
985
+ expects_public_file(dest)
986
+ end
987
+
988
+ it 'rejects unsupported modes' do
989
+ expect {
990
+ Puppet::FileSystem.replace_file(dest, 0755) { |_| }
991
+ }.to raise_error(ArgumentError, /Only modes 0644, 0640 and 0600 are allowed/)
992
+ end
993
+ end
994
+ end
995
+
996
+ context "when overwriting" do
997
+ before :each do
998
+ FileUtils.touch(dest)
999
+ end
1000
+
1001
+ it 'overwrites the content' do
1002
+ Puppet::FileSystem.replace_file(dest) { |f| f.write(content) }
1003
+
1004
+ expect(Puppet::FileSystem.binread(dest)).to eq(content)
1005
+ end
1006
+
1007
+ it 'raises ISDIR if the destination is a directory' do
1008
+ dir = tmpdir('file_system')
1009
+
1010
+ expect {
1011
+ Puppet::FileSystem.replace_file(dir) { |f| f.write(content) }
1012
+ }.to raise_error(Errno::EISDIR, /Is a directory/)
1013
+ end
1014
+
1015
+ it 'preserves the existing content if an error is raised' do
1016
+ File.write(dest, 'existing content')
1017
+
1018
+ Puppet::FileSystem.replace_file(dest) { |f| raise 'whoops' } rescue nil
1019
+
1020
+ expect(Puppet::FileSystem.binread(dest)).to eq('existing content')
1021
+ end
1022
+
1023
+ context 'on posix', unless: Puppet::Util::Platform.windows? do
1024
+ it 'preserves the existing mode' do
1025
+ Puppet::FileSystem.chmod(0600, dest)
1026
+
1027
+ Puppet::FileSystem.replace_file(dest) { |f| f.write(content) }
1028
+
1029
+ mode = Puppet::FileSystem.stat(dest).mode
1030
+ expect(mode & 07777).to eq(0600)
1031
+ end
1032
+
1033
+ it 'applies the specified mode' do
1034
+ Puppet::FileSystem.chmod(0600, dest)
1035
+
1036
+ Puppet::FileSystem.replace_file(dest, 0777) { |f| f.write(content) }
1037
+
1038
+ mode = Puppet::FileSystem.stat(dest).mode
1039
+ expect(mode & 07777).to eq(0777)
1040
+ end
1041
+
1042
+ it 'updates a read-only file' do
1043
+ Puppet::FileSystem.chmod(0400, dest)
1044
+
1045
+ Puppet::FileSystem.replace_file(dest) { |f| f.write(content) }
1046
+
1047
+ expect(Puppet::FileSystem.binread(dest)).to eq(content)
1048
+
1049
+ mode = Puppet::FileSystem.stat(dest).mode
1050
+ expect(mode & 07777).to eq(0400)
1051
+ end
1052
+ end
1053
+
1054
+ context 'on windows', if: Puppet::Util::Platform.windows? do
1055
+ it 'preserves the existing mode' do
1056
+ old_sd = Puppet::Util::Windows::Security.get_security_descriptor(dest)
1057
+
1058
+ Puppet::FileSystem.replace_file(dest) { |f| f.write(content) }
1059
+
1060
+ new_sd = Puppet::Util::Windows::Security.get_security_descriptor(dest)
1061
+ expect(old_sd.owner).to eq(new_sd.owner)
1062
+ expect(old_sd.group).to eq(new_sd.group)
1063
+ old_sd.dacl.each do |ace|
1064
+ expect(new_sd.dacl).to include(an_object_having_attributes(sid: ace.sid, mask: ace.mask))
1065
+ end
1066
+ end
1067
+
1068
+ it 'applies the specified mode' do
1069
+ Puppet::FileSystem.replace_file(dest, 0644) { |f| f.write(content) }
1070
+
1071
+ expects_public_file(dest)
1072
+ end
1073
+
1074
+ it 'raises Errno::EACCES if access is denied' do
1075
+ Puppet::Util::Windows::Security.stubs(:get_security_descriptor).raises(Puppet::Util::Windows::Error.new('access denied', 5))
1076
+
1077
+ expect {
1078
+ Puppet::FileSystem.replace_file(dest) { |f| f.write(content) }
1079
+ }.to raise_error(Errno::EACCES, /Access is denied/)
1080
+ end
1081
+
1082
+ it 'raises SystemCallError otherwise' do
1083
+ Puppet::Util::Windows::Security.stubs(:get_security_descriptor).raises(Puppet::Util::Windows::Error.new('arena is trashed', 7))
1084
+
1085
+ expect {
1086
+ Puppet::FileSystem.replace_file(dest) { |f| f.write(content) }
1087
+ }.to raise_error(SystemCallError, /The storage control blocks were destroyed/)
1088
+ end
1089
+ end
1090
+ end
1091
+ end
878
1092
  end