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.
- checksums.yaml +4 -4
- data/CODEOWNERS +30 -0
- data/Gemfile.lock +9 -9
- data/lib/puppet.rb +13 -0
- data/lib/puppet/application/agent.rb +8 -12
- data/lib/puppet/application/device.rb +2 -3
- data/lib/puppet/application/filebucket.rb +6 -1
- data/lib/puppet/application/ssl.rb +102 -55
- data/lib/puppet/configurer.rb +8 -7
- data/lib/puppet/defaults.rb +3 -1
- data/lib/puppet/file_system.rb +24 -4
- data/lib/puppet/file_system/file_impl.rb +25 -0
- data/lib/puppet/file_system/jruby.rb +23 -0
- data/lib/puppet/file_system/windows.rb +84 -0
- data/lib/puppet/indirector/rest.rb +4 -2
- data/lib/puppet/loaders.rb +1 -0
- data/lib/puppet/network/http.rb +1 -0
- data/lib/puppet/network/http/base_pool.rb +18 -0
- data/lib/puppet/network/http/connection.rb +49 -17
- data/lib/puppet/network/http/nocache_pool.rb +9 -4
- data/lib/puppet/network/http/pool.rb +10 -11
- data/lib/puppet/network/http/session.rb +3 -2
- data/lib/puppet/network/http_pool.rb +32 -0
- data/lib/puppet/pops/loader/generic_plan_instantiator.rb +28 -0
- data/lib/puppet/pops/loader/loader_paths.rb +46 -10
- data/lib/puppet/pops/loader/module_loaders.rb +10 -3
- data/lib/puppet/provider/file/windows.rb +49 -1
- data/lib/puppet/provider/package/windows.rb +5 -1
- data/lib/puppet/reports/http.rb +2 -1
- data/lib/puppet/rest/client.rb +7 -3
- data/lib/puppet/rest/routes.rb +9 -44
- data/lib/puppet/ssl.rb +6 -0
- data/lib/puppet/ssl/error.rb +26 -0
- data/lib/puppet/ssl/host.rb +9 -92
- data/lib/puppet/ssl/ssl_context.rb +30 -0
- data/lib/puppet/ssl/ssl_provider.rb +232 -0
- data/lib/puppet/ssl/state_machine.rb +261 -0
- data/lib/puppet/ssl/validator.rb +1 -0
- data/lib/puppet/ssl/validator/default_validator.rb +1 -0
- data/lib/puppet/ssl/validator/no_validator.rb +2 -0
- data/lib/puppet/ssl/verifier.rb +134 -0
- data/lib/puppet/ssl/verifier_adapter.rb +48 -0
- data/lib/puppet/test/test_helper.rb +2 -1
- data/lib/puppet/type/exec.rb +30 -6
- data/lib/puppet/type/file/mode.rb +6 -1
- data/lib/puppet/type/file/source.rb +2 -2
- data/lib/puppet/type/filebucket.rb +12 -8
- data/lib/puppet/type/user.rb +14 -1
- data/lib/puppet/util/connection.rb +10 -5
- data/lib/puppet/util/feature.rb +11 -2
- data/lib/puppet/util/http_proxy.rb +3 -2
- data/lib/puppet/util/pidlock.rb +1 -1
- data/lib/puppet/util/ssl.rb +1 -10
- data/lib/puppet/util/windows/security.rb +29 -8
- data/lib/puppet/version.rb +1 -1
- data/lib/puppet/x509.rb +7 -0
- data/lib/puppet/x509/cert_provider.rb +286 -0
- data/lib/puppet/x509/pem_store.rb +55 -0
- data/locales/ja/puppet.po +740 -590
- data/locales/puppet.pot +433 -208
- data/man/man5/puppet.conf.5 +6 -3
- data/man/man8/puppet-agent.8 +1 -1
- data/man/man8/puppet-apply.8 +1 -1
- data/man/man8/puppet-catalog.8 +1 -1
- data/man/man8/puppet-config.8 +1 -1
- data/man/man8/puppet-describe.8 +1 -1
- data/man/man8/puppet-device.8 +1 -1
- data/man/man8/puppet-doc.8 +1 -1
- data/man/man8/puppet-epp.8 +1 -1
- data/man/man8/puppet-facts.8 +1 -1
- data/man/man8/puppet-filebucket.8 +6 -2
- data/man/man8/puppet-generate.8 +1 -1
- data/man/man8/puppet-help.8 +1 -1
- data/man/man8/puppet-key.8 +1 -1
- data/man/man8/puppet-lookup.8 +1 -1
- data/man/man8/puppet-man.8 +1 -1
- data/man/man8/puppet-module.8 +1 -1
- data/man/man8/puppet-node.8 +1 -1
- data/man/man8/puppet-parser.8 +1 -1
- data/man/man8/puppet-plugin.8 +1 -1
- data/man/man8/puppet-report.8 +1 -1
- data/man/man8/puppet-resource.8 +1 -1
- data/man/man8/puppet-script.8 +1 -1
- data/man/man8/puppet-ssl.8 +5 -1
- data/man/man8/puppet-status.8 +1 -1
- data/man/man8/puppet.8 +2 -2
- data/spec/fixtures/ssl/127.0.0.1-key.pem +67 -0
- data/spec/fixtures/ssl/127.0.0.1.pem +48 -0
- data/spec/fixtures/ssl/bad-basic-constraints.pem +59 -0
- data/spec/fixtures/ssl/bad-int-basic-constraints.pem +59 -0
- data/spec/fixtures/ssl/ca.pem +59 -0
- data/spec/fixtures/ssl/crl.pem +30 -0
- data/spec/fixtures/ssl/encrypted-key.pem +70 -0
- data/spec/fixtures/ssl/intermediate-agent-crl.pem +31 -0
- data/spec/fixtures/ssl/intermediate-agent.pem +60 -0
- data/spec/fixtures/ssl/intermediate-crl.pem +36 -0
- data/spec/fixtures/ssl/intermediate.pem +60 -0
- data/spec/fixtures/ssl/netlock-arany-utf8.pem +23 -0
- data/spec/fixtures/ssl/pluto-key.pem +67 -0
- data/spec/fixtures/ssl/pluto.pem +44 -0
- data/spec/fixtures/ssl/request-key.pem +67 -0
- data/spec/fixtures/ssl/request.pem +39 -0
- data/spec/fixtures/ssl/revoked-key.pem +67 -0
- data/spec/fixtures/ssl/revoked.pem +44 -0
- data/spec/fixtures/ssl/signed-key.pem +67 -0
- data/spec/fixtures/ssl/signed.pem +44 -0
- data/spec/fixtures/ssl/tampered-cert.pem +44 -0
- data/spec/fixtures/ssl/tampered-csr.pem +39 -0
- data/spec/integration/network/http_pool_spec.rb +222 -0
- data/spec/integration/provider/file/windows_spec.rb +162 -0
- data/spec/integration/rest/client_spec.rb +73 -0
- data/spec/integration/type/file_spec.rb +0 -19
- data/spec/lib/puppet/test_ca.rb +87 -50
- data/spec/lib/puppet_spec/fixtures.rb +20 -0
- data/spec/lib/puppet_spec/https.rb +84 -0
- data/spec/unit/application/agent_spec.rb +29 -30
- data/spec/unit/application/device_spec.rb +12 -49
- data/spec/unit/application/ssl_spec.rb +24 -38
- data/spec/unit/configurer_spec.rb +11 -11
- data/spec/unit/file_system/uniquefile_spec.rb +6 -0
- data/spec/unit/file_system_spec.rb +214 -0
- data/spec/unit/indirector/rest_spec.rb +3 -3
- data/spec/unit/network/http/connection_spec.rb +30 -90
- data/spec/unit/network/http/factory_spec.rb +1 -0
- data/spec/unit/network/http/nocache_pool_spec.rb +8 -8
- data/spec/unit/network/http/pool_spec.rb +63 -33
- data/spec/unit/network/http/session_spec.rb +8 -1
- data/spec/unit/network/http_pool_spec.rb +36 -0
- data/spec/unit/pops/loaders/loader_spec.rb +26 -1
- data/spec/unit/provider/package/windows_spec.rb +12 -1
- data/spec/unit/reports/http_spec.rb +7 -7
- data/spec/unit/rest/client_spec.rb +4 -6
- data/spec/unit/ssl/host_spec.rb +39 -33
- data/spec/unit/ssl/ssl_provider_spec.rb +428 -0
- data/spec/unit/ssl/state_machine_spec.rb +502 -0
- data/spec/unit/ssl/verifier_spec.rb +123 -0
- data/spec/unit/type/exec_spec.rb +63 -0
- data/spec/unit/type/file/source_spec.rb +5 -5
- data/spec/unit/type/filebucket_spec.rb +8 -6
- data/spec/unit/util/feature_spec.rb +2 -2
- data/spec/unit/util/storage_spec.rb +19 -19
- data/spec/unit/x509/cert_provider_spec.rb +527 -0
- data/spec/unit/x509/pem_store_spec.rb +160 -0
- data/tasks/generate_cert_fixtures.rake +158 -0
- metadata +78 -4
- data/MAINTAINERS +0 -47
- 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::
|
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::
|
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::
|
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::
|
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::
|
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
|
-
|
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
|
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
|
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
|
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(
|
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(
|
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(:
|
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(:
|
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(:
|
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
|
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(:
|
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
|
1052
|
+
it "should not make multiple node requests when the server is found" do
|
1055
1053
|
Puppet.settings[:server_list] = ["myserver:123"]
|
1056
|
-
|
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
|