puppet 6.27.0 → 6.28.0

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +71 -11
  3. data/lib/puppet/agent.rb +47 -11
  4. data/lib/puppet/application/agent.rb +2 -12
  5. data/lib/puppet/http/client.rb +22 -2
  6. data/lib/puppet/provider/package/puppetserver_gem.rb +7 -16
  7. data/lib/puppet/provider/package/windows/exe_package.rb +30 -1
  8. data/lib/puppet/provider/package/windows/package.rb +2 -1
  9. data/lib/puppet/provider/package/windows.rb +14 -1
  10. data/lib/puppet/provider/user/directoryservice.rb +5 -0
  11. data/lib/puppet/ssl/ssl_provider.rb +65 -12
  12. data/lib/puppet/ssl/state_machine.rb +13 -17
  13. data/lib/puppet/type/user.rb +3 -0
  14. data/lib/puppet/version.rb +1 -1
  15. data/lib/puppet.rb +1 -14
  16. data/man/man5/puppet.conf.5 +2 -2
  17. data/man/man8/puppet-agent.8 +1 -1
  18. data/man/man8/puppet-apply.8 +1 -1
  19. data/man/man8/puppet-catalog.8 +1 -1
  20. data/man/man8/puppet-config.8 +1 -1
  21. data/man/man8/puppet-describe.8 +1 -1
  22. data/man/man8/puppet-device.8 +1 -1
  23. data/man/man8/puppet-doc.8 +1 -1
  24. data/man/man8/puppet-epp.8 +1 -1
  25. data/man/man8/puppet-facts.8 +1 -1
  26. data/man/man8/puppet-filebucket.8 +1 -1
  27. data/man/man8/puppet-generate.8 +1 -1
  28. data/man/man8/puppet-help.8 +1 -1
  29. data/man/man8/puppet-key.8 +1 -1
  30. data/man/man8/puppet-lookup.8 +1 -1
  31. data/man/man8/puppet-man.8 +1 -1
  32. data/man/man8/puppet-module.8 +1 -1
  33. data/man/man8/puppet-node.8 +1 -1
  34. data/man/man8/puppet-parser.8 +1 -1
  35. data/man/man8/puppet-plugin.8 +1 -1
  36. data/man/man8/puppet-report.8 +1 -1
  37. data/man/man8/puppet-resource.8 +1 -1
  38. data/man/man8/puppet-script.8 +1 -1
  39. data/man/man8/puppet-ssl.8 +1 -1
  40. data/man/man8/puppet-status.8 +1 -1
  41. data/man/man8/puppet.8 +2 -2
  42. data/spec/integration/application/agent_spec.rb +108 -0
  43. data/spec/integration/http/client_spec.rb +27 -10
  44. data/spec/lib/puppet_spec/https.rb +1 -1
  45. data/spec/lib/puppet_spec/puppetserver.rb +39 -2
  46. data/spec/unit/agent_spec.rb +28 -2
  47. data/spec/unit/application/agent_spec.rb +26 -16
  48. data/spec/unit/daemon_spec.rb +2 -11
  49. data/spec/unit/http/client_spec.rb +18 -0
  50. data/spec/unit/provider/package/puppetserver_gem_spec.rb +2 -2
  51. data/spec/unit/provider/package/windows/exe_package_spec.rb +17 -0
  52. data/spec/unit/ssl/ssl_provider_spec.rb +75 -1
  53. data/spec/unit/ssl/state_machine_spec.rb +1 -0
  54. data/tasks/generate_cert_fixtures.rake +5 -4
  55. metadata +2 -2
@@ -38,6 +38,10 @@ describe Puppet::Agent do
38
38
  end
39
39
  end
40
40
  end
41
+
42
+ ssl_context = Puppet::SSL::SSLContext.new
43
+ machine = instance_double("Puppet::SSL::StateMachine", ensure_client_certificate: ssl_context)
44
+ allow(Puppet::SSL::StateMachine).to receive(:new).and_return(machine)
41
45
  end
42
46
 
43
47
  after do
@@ -99,6 +103,8 @@ describe Puppet::Agent do
99
103
  end
100
104
 
101
105
  it "should splay" do
106
+ Puppet[:splay] = true
107
+
102
108
  expect(@agent).to receive(:splay)
103
109
 
104
110
  @agent.run
@@ -181,6 +187,26 @@ describe Puppet::Agent do
181
187
  expect(@agent.run).to eq(:result)
182
188
  end
183
189
 
190
+ it "should check if it's disabled after splaying and log a message" do
191
+ Puppet[:splay] = true
192
+ Puppet[:splaylimit] = '5s'
193
+ Puppet[:onetime] = true
194
+
195
+ expect(@agent).to receive(:disabled?).and_return(false, true)
196
+
197
+ allow(Puppet).to receive(:notice).and_call_original
198
+ expect(Puppet).to receive(:notice).with(/Skipping run of .*; administratively disabled.*/)
199
+ @agent.run
200
+ end
201
+
202
+ it "should check if it's disabled after acquiring the lock and log a message" do
203
+ expect(@agent).to receive(:disabled?).and_return(false, true)
204
+
205
+ allow(Puppet).to receive(:notice).and_call_original
206
+ expect(Puppet).to receive(:notice).with(/Skipping run of .*; administratively disabled.*/)
207
+ @agent.run
208
+ end
209
+
184
210
  describe "and a puppet agent is already running" do
185
211
  before(:each) do
186
212
  allow_any_instance_of(Object).to receive(:sleep)
@@ -197,7 +223,7 @@ describe Puppet::Agent do
197
223
  @agent.run
198
224
  end
199
225
 
200
- it "should inform that a run is already in progres and try to run every X seconds if waitforlock is used" do
226
+ it "should inform that a run is already in progress and try to run every X seconds if waitforlock is used" do
201
227
  # so the locked file exists
202
228
  allow(File).to receive(:file?).and_return(true)
203
229
  # so we don't have to wait again for the run to exit (default maxwaitforcert is 60)
@@ -226,7 +252,7 @@ describe Puppet::Agent do
226
252
  @agent.run
227
253
  end
228
254
  end
229
-
255
+
230
256
  describe "when should_fork is true", :if => Puppet.features.posix? && RUBY_PLATFORM != 'java' do
231
257
  before do
232
258
  @agent = Puppet::Agent.new(AgentTestClient, true)
@@ -4,6 +4,11 @@ require 'puppet/agent'
4
4
  require 'puppet/application/agent'
5
5
  require 'puppet/daemon'
6
6
 
7
+ class TestAgentClientClass
8
+ def initialize(transaction_uuid = nil, job_id = nil); end
9
+ def run(options = {}); end
10
+ end
11
+
7
12
  describe Puppet::Application::Agent do
8
13
  include PuppetSpec::Files
9
14
 
@@ -12,13 +17,20 @@ describe Puppet::Application::Agent do
12
17
  before :each do
13
18
  @puppetd = Puppet::Application[:agent]
14
19
 
15
- @agent = double('agent')
20
+ @client = TestAgentClientClass.new
21
+ allow(TestAgentClientClass).to receive(:new).and_return(@client)
22
+
23
+ @agent = Puppet::Agent.new(TestAgentClientClass, false)
16
24
  allow(Puppet::Agent).to receive(:new).and_return(@agent)
17
25
 
18
- @daemon = Puppet::Daemon.new(@agent, nil)
26
+ Puppet[:pidfile] = tmpfile('pidfile')
27
+ @daemon = Puppet::Daemon.new(@agent, Puppet::Util::Pidlock.new(Puppet[:pidfile]))
19
28
  allow(@daemon).to receive(:daemonize)
20
- allow(@daemon).to receive(:start)
21
29
  allow(@daemon).to receive(:stop)
30
+ # simulate one run so we don't infinite looptwo runs of the agent, then return so we don't infinite loop
31
+ allow(@daemon).to receive(:run_event_loop) do
32
+ @agent.run(splay: false)
33
+ end
22
34
  allow(Puppet::Daemon).to receive(:new).and_return(@daemon)
23
35
  Puppet[:daemonize] = false
24
36
 
@@ -92,10 +104,6 @@ describe Puppet::Application::Agent do
92
104
  end
93
105
 
94
106
  describe "when handling options" do
95
- before do
96
- allow(@puppetd.command_line).to receive(:args).and_return([])
97
- end
98
-
99
107
  [:enable, :debug, :fqdn, :test, :verbose, :digest].each do |option|
100
108
  it "should declare handle_#{option} method" do
101
109
  expect(@puppetd).to respond_to("handle_#{option}".to_sym)
@@ -127,32 +135,34 @@ describe Puppet::Application::Agent do
127
135
  end
128
136
 
129
137
  it "should set waitforcert to 0 with --onetime and if --waitforcert wasn't given" do
130
- allow(@agent).to receive(:run).and_return(2)
138
+ allow(@client).to receive(:run).and_return(2)
131
139
  Puppet[:onetime] = true
132
140
 
133
- expect(Puppet::SSL::StateMachine).to receive(:new).with(waitforcert: 0).and_return(machine)
141
+ expect(Puppet::SSL::StateMachine).to receive(:new).with(hash_including(waitforcert: 0)).and_return(machine)
134
142
 
135
143
  expect { execute_agent }.to exit_with 0
136
144
  end
137
145
 
138
146
  it "should use supplied waitforcert when --onetime is specified" do
139
- allow(@agent).to receive(:run).and_return(2)
147
+ allow(@client).to receive(:run).and_return(2)
140
148
  Puppet[:onetime] = true
141
149
  @puppetd.handle_waitforcert(60)
142
150
 
143
- expect(Puppet::SSL::StateMachine).to receive(:new).with(waitforcert: 60).and_return(machine)
151
+ expect(Puppet::SSL::StateMachine).to receive(:new).with(hash_including(waitforcert: 60)).and_return(machine)
144
152
 
145
153
  expect { execute_agent }.to exit_with 0
146
154
  end
147
155
 
148
156
  it "should use a default value for waitforcert when --onetime and --waitforcert are not specified" do
149
- expect(Puppet::SSL::StateMachine).to receive(:new).with(waitforcert: 120).and_return(machine)
157
+ allow(@client).to receive(:run).and_return(2)
158
+
159
+ expect(Puppet::SSL::StateMachine).to receive(:new).with(hash_including(waitforcert: 120)).and_return(machine)
150
160
 
151
161
  execute_agent
152
162
  end
153
163
 
154
164
  it "should register ssl OIDs" do
155
- expect(Puppet::SSL::StateMachine).to receive(:new).with(waitforcert: 120).and_return(double(ensure_client_certificate: nil))
165
+ expect(Puppet::SSL::StateMachine).to receive(:new).with(hash_including(waitforcert: 120)).and_return(machine)
156
166
  expect(Puppet::SSL::Oids).to receive(:register_puppet_oids)
157
167
 
158
168
  execute_agent
@@ -161,7 +171,7 @@ describe Puppet::Application::Agent do
161
171
  it "should use the waitforcert setting when checking for a signed certificate" do
162
172
  Puppet[:waitforcert] = 10
163
173
 
164
- expect(Puppet::SSL::StateMachine).to receive(:new).with(waitforcert: 10).and_return(machine)
174
+ expect(Puppet::SSL::StateMachine).to receive(:new).with(hash_including(waitforcert: 10)).and_return(machine)
165
175
 
166
176
  execute_agent
167
177
  end
@@ -413,9 +423,9 @@ describe Puppet::Application::Agent do
413
423
  end
414
424
 
415
425
  it "should wait for a certificate" do
416
- @puppetd.options[:waitforcert] = 123
426
+ Puppet[:waitforcert] = 123
417
427
 
418
- expect(Puppet::SSL::StateMachine).to receive(:new).with(waitforcert: 123).and_return(machine)
428
+ expect(Puppet::SSL::StateMachine).to receive(:new).with(hash_including(waitforcert: 123)).and_return(machine)
419
429
 
420
430
  execute_agent
421
431
  end
@@ -1,6 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'puppet/daemon'
3
3
  require 'puppet/agent'
4
+ require 'puppet/configurer'
4
5
 
5
6
  def without_warnings
6
7
  flag = $VERBOSE
@@ -9,12 +10,6 @@ def without_warnings
9
10
  $VERBOSE = flag
10
11
  end
11
12
 
12
- class TestClient
13
- def lockfile_path
14
- "/dev/null"
15
- end
16
- end
17
-
18
13
  describe Puppet::Daemon, :unless => Puppet::Util::Platform.windows? do
19
14
  include PuppetSpec::Files
20
15
 
@@ -26,7 +21,7 @@ describe Puppet::Daemon, :unless => Puppet::Util::Platform.windows? do
26
21
  end
27
22
  end
28
23
 
29
- let(:agent) { Puppet::Agent.new(TestClient.new, false) }
24
+ let(:agent) { Puppet::Agent.new(Puppet::Configurer, false) }
30
25
  let(:server) { double("Server", :start => nil, :wait_for_shutdown => nil) }
31
26
 
32
27
  let(:pidfile) { double("PidFile", :lock => true, :unlock => true, :file_path => 'fake.pid') }
@@ -131,10 +126,6 @@ describe Puppet::Daemon, :unless => Puppet::Util::Platform.windows? do
131
126
  end
132
127
 
133
128
  describe "when reloading" do
134
- it "should do nothing if no agent is configured" do
135
- daemon.reload
136
- end
137
-
138
129
  it "should do nothing if the agent is running" do
139
130
  expect(agent).to receive(:run).with({:splay => false}).and_raise(Puppet::LockError, 'Failed to aquire lock')
140
131
  expect(Puppet).to receive(:notice).with('Not triggering already-running agent')
@@ -120,6 +120,24 @@ describe Puppet::HTTP::Client do
120
120
 
121
121
  client.close
122
122
  end
123
+
124
+ it 'reloads the default ssl context' do
125
+ expect(client.pool).to receive(:with_connection) do |_, verifier|
126
+ expect(verifier.ssl_context).to_not equal(puppet_context)
127
+ end
128
+
129
+ client.close
130
+ client.connect(uri)
131
+ end
132
+
133
+ it 'reloads the default system ssl context' do
134
+ expect(client.pool).to receive(:with_connection) do |_, verifier|
135
+ expect(verifier.ssl_context).to_not equal(system_context)
136
+ end
137
+
138
+ client.close
139
+ client.connect(uri, options: {include_system_store: true})
140
+ end
123
141
  end
124
142
 
125
143
  context "for GET requests" do
@@ -105,9 +105,9 @@ describe Puppet::Type.type(:package).provider(:puppetserver_gem) do
105
105
 
106
106
  describe ".gemlist" do
107
107
  context "listing installed packages" do
108
- it "uses the puppet rubygems library to list local gems" do
108
+ it "uses the puppet_gem provider_command to list local gems" do
109
109
  expected = { name: 'world_airports', provider: :puppetserver_gem, ensure: ['1.1.3'] }
110
- expect(described_class).to receive(:execute_rubygems_list_command).with(nil).and_return(File.read(my_fixture('gem-list-local-packages')))
110
+ expect(described_class).to receive(:execute_rubygems_list_command).with(['gem', 'list', '--local']).and_return(File.read(my_fixture('gem-list-local-packages')))
111
111
  expect(described_class.gemlist({ local: true })).to include(expected)
112
112
  end
113
113
  end
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'puppet/provider/package/windows/exe_package'
3
+ require 'puppet/provider/package/windows'
3
4
 
4
5
  describe Puppet::Provider::Package::Windows::ExePackage do
5
6
  let (:name) { 'Git version 1.7.11' }
@@ -71,10 +72,26 @@ describe Puppet::Provider::Package::Windows::ExePackage do
71
72
 
72
73
  context '#install_command' do
73
74
  it 'should install using the source' do
75
+ allow(Puppet::FileSystem).to receive(:exist?).with(source).and_return(true)
74
76
  cmd = described_class.install_command({:source => source})
75
77
 
76
78
  expect(cmd).to eq(source)
77
79
  end
80
+
81
+ it 'should raise error when URI is invalid' do
82
+ web_source = 'https://www.t e s t.test/test.exe'
83
+
84
+ expect do
85
+ described_class.install_command({:source => web_source, :name => name})
86
+ end.to raise_error(Puppet::Error, /Error when installing #{name}:/)
87
+ end
88
+
89
+ it 'should download package from source file before installing', if: Puppet::Util::Platform.windows? do
90
+ web_source = 'https://www.test.test/test.exe'
91
+ stub_request(:get, web_source).to_return(status: 200, body: 'package binaries')
92
+ cmd = described_class.install_command({:source => web_source})
93
+ expect(File.read(cmd)).to eq('package binaries')
94
+ end
78
95
  end
79
96
 
80
97
  context '#uninstall_command' do
@@ -113,12 +113,21 @@ describe Puppet::SSL::SSLProvider do
113
113
  }.to raise_error(/can't modify frozen/)
114
114
  end
115
115
 
116
- it 'trusts system ca store' do
116
+ it 'trusts system ca store by default' do
117
117
  expect_any_instance_of(OpenSSL::X509::Store).to receive(:set_default_paths)
118
118
 
119
119
  subject.create_system_context(cacerts: [])
120
120
  end
121
121
 
122
+ it 'trusts an external ca store' do
123
+ path = tmpfile('system_cacerts')
124
+ File.write(path, cert_fixture('ca.pem').to_pem)
125
+
126
+ expect_any_instance_of(OpenSSL::X509::Store).to receive(:add_file).with(path)
127
+
128
+ subject.create_system_context(cacerts: [], path: path)
129
+ end
130
+
122
131
  it 'verifies peer' do
123
132
  sslctx = subject.create_system_context(cacerts: [])
124
133
  expect(sslctx.verify_peer).to eq(true)
@@ -135,6 +144,47 @@ describe Puppet::SSL::SSLProvider do
135
144
  expect(sslctx.private_key).to be_nil
136
145
  end
137
146
 
147
+ it 'includes the client cert and private key when requested' do
148
+ Puppet[:hostcert] = fixtures('ssl/signed.pem')
149
+ Puppet[:hostprivkey] = fixtures('ssl/signed-key.pem')
150
+ sslctx = subject.create_system_context(cacerts: [], include_client_cert: true)
151
+ expect(sslctx.client_cert).to be_an(OpenSSL::X509::Certificate)
152
+ expect(sslctx.private_key).to be_an(OpenSSL::PKey::RSA)
153
+ end
154
+
155
+ it 'ignores non-existent client cert and private key when requested' do
156
+ Puppet[:certname] = 'doesnotexist'
157
+ sslctx = subject.create_system_context(cacerts: [], include_client_cert: true)
158
+ expect(sslctx.client_cert).to be_nil
159
+ expect(sslctx.private_key).to be_nil
160
+ end
161
+
162
+ it 'warns if the client cert does not exist' do
163
+ Puppet[:certname] = 'missingcert'
164
+ Puppet[:hostprivkey] = fixtures('ssl/signed-key.pem')
165
+
166
+ expect(Puppet).to receive(:warning).with("Client certificate for 'missingcert' does not exist")
167
+ subject.create_system_context(cacerts: [], include_client_cert: true)
168
+ end
169
+
170
+ it 'warns if the private key does not exist' do
171
+ Puppet[:certname] = 'missingkey'
172
+ Puppet[:hostcert] = fixtures('ssl/signed.pem')
173
+
174
+ expect(Puppet).to receive(:warning).with("Private key for 'missingkey' does not exist")
175
+ subject.create_system_context(cacerts: [], include_client_cert: true)
176
+ end
177
+
178
+ it 'raises if client cert and private key are mismatched' do
179
+ Puppet[:hostcert] = fixtures('ssl/signed.pem')
180
+ Puppet[:hostprivkey] = fixtures('ssl/127.0.0.1-key.pem')
181
+
182
+ expect {
183
+ subject.create_system_context(cacerts: [], include_client_cert: true)
184
+ }.to raise_error(Puppet::SSL::SSLError,
185
+ "The certificate for 'CN=signed' does not match its private key")
186
+ end
187
+
138
188
  it 'trusts additional system certs' do
139
189
  path = tmpfile('system_cacerts')
140
190
  File.write(path, cert_fixture('ca.pem').to_pem)
@@ -448,6 +498,18 @@ describe Puppet::SSL::SSLProvider do
448
498
  sslctx = subject.create_context(**config)
449
499
  expect(sslctx.verify_peer).to eq(true)
450
500
  end
501
+
502
+ it 'does not trust the system ca store by default' do
503
+ expect_any_instance_of(OpenSSL::X509::Store).to receive(:set_default_paths).never
504
+
505
+ subject.create_context(**config)
506
+ end
507
+
508
+ it 'trusts the system ca store' do
509
+ expect_any_instance_of(OpenSSL::X509::Store).to receive(:set_default_paths)
510
+
511
+ subject.create_context(**config.merge(include_system_store: true))
512
+ end
451
513
  end
452
514
 
453
515
  context 'when loading an ssl context' do
@@ -528,6 +590,18 @@ describe Puppet::SSL::SSLProvider do
528
590
  subject.load_context(password: 'wrongpassword')
529
591
  }.to raise_error(Puppet::SSL::SSLError, /Failed to load private key for host 'signed': Could not parse PKey/)
530
592
  end
593
+
594
+ it 'does not trust the system ca store by default' do
595
+ expect_any_instance_of(OpenSSL::X509::Store).to receive(:set_default_paths).never
596
+
597
+ subject.load_context
598
+ end
599
+
600
+ it 'trusts the system ca store' do
601
+ expect_any_instance_of(OpenSSL::X509::Store).to receive(:set_default_paths)
602
+
603
+ subject.load_context(include_system_store: true)
604
+ end
531
605
  end
532
606
 
533
607
  context 'when verifying requests' do
@@ -27,6 +27,7 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
27
27
  let(:refused_message) { %r{Connection refused|No connection could be made because the target machine actively refused it} }
28
28
 
29
29
  before(:each) do
30
+ Puppet[:daemonize] = false
30
31
  Puppet[:ssl_lockfile] = tmpfile('ssllock')
31
32
  allow(Kernel).to receive(:sleep)
32
33
  end
@@ -37,14 +37,15 @@ task(:gen_cert_fixtures) do
37
37
  # | |
38
38
  # signed.pem | +- /CN=signed
39
39
  # revoked.pem | +- /CN=revoked
40
- # 127.0.0.1.pem | +- /CN=127.0.0.1 (with dns alt names)
41
40
  # tampered-cert.pem | +- /CN=signed (with different public key)
42
41
  # ec.pem | +- /CN=ec (with EC private key)
43
42
  # oid.pem | +- /CN=oid (with custom oid)
44
43
  # |
45
- # + /CN=Test CA Agent Subauthority
46
- # | |
47
- # pluto.pem | +- /CN=pluto
44
+ # 127.0.0.1.pem +- /CN=127.0.0.1 (with dns alt names)
45
+ # |
46
+ # intermediate-agent.pem +- /CN=Test CA Agent Subauthority
47
+ # | |
48
+ # pluto.pem | +- /CN=pluto
48
49
  # |
49
50
  # bad-int-basic-constraints.pem +- /CN=Test CA Subauthority (bad isCA constraint)
50
51
  #
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppet
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.27.0
4
+ version: 6.28.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet Labs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-06 00:00:00.000000000 Z
11
+ date: 2022-07-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: facter