puppet 7.16.0 → 7.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +66 -5
- data/ext/systemd/puppet.service +1 -1
- data/lib/puppet/agent.rb +20 -2
- data/lib/puppet/application/agent.rb +3 -13
- data/lib/puppet/application/apply.rb +2 -2
- data/lib/puppet/configurer.rb +1 -1
- data/lib/puppet/defaults.rb +11 -1
- data/lib/puppet/http/client.rb +22 -2
- data/lib/puppet/parameter.rb +19 -4
- data/lib/puppet/pops/evaluator/deferred_resolver.rb +46 -6
- data/lib/puppet/pops/functions/dispatcher.rb +10 -6
- data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +7 -6
- data/lib/puppet/pops/types/type_mismatch_describer.rb +22 -1
- data/lib/puppet/provider/package/puppetserver_gem.rb +7 -16
- data/lib/puppet/provider/package/yum.rb +8 -3
- data/lib/puppet/provider/user/directoryservice.rb +15 -8
- data/lib/puppet/ssl/ssl_provider.rb +65 -12
- data/lib/puppet/ssl/state_machine.rb +13 -17
- data/lib/puppet/transaction.rb +22 -0
- data/lib/puppet/type/user.rb +3 -0
- data/lib/puppet/type.rb +20 -3
- data/lib/puppet/version.rb +1 -1
- data/lib/puppet.rb +1 -14
- data/man/man5/puppet.conf.5 +11 -3
- data/man/man8/puppet-agent.8 +2 -2
- 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 +1 -1
- data/man/man8/puppet-generate.8 +1 -1
- data/man/man8/puppet-help.8 +1 -1
- data/man/man8/puppet-lookup.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 +1 -1
- data/man/man8/puppet.8 +2 -2
- data/spec/integration/application/agent_spec.rb +157 -0
- data/spec/integration/application/apply_spec.rb +74 -0
- data/spec/integration/http/client_spec.rb +27 -10
- data/spec/lib/puppet_spec/https.rb +1 -1
- data/spec/lib/puppet_spec/puppetserver.rb +39 -2
- data/spec/unit/agent_spec.rb +6 -2
- data/spec/unit/application/agent_spec.rb +26 -16
- data/spec/unit/daemon_spec.rb +2 -11
- data/spec/unit/http/client_spec.rb +18 -0
- data/spec/unit/pops/evaluator/deferred_resolver_spec.rb +26 -0
- data/spec/unit/pops/loaders/loaders_spec.rb +1 -1
- data/spec/unit/pops/types/type_mismatch_describer_spec.rb +167 -1
- data/spec/unit/provider/package/puppetserver_gem_spec.rb +2 -2
- data/spec/unit/provider/user/directoryservice_spec.rb +1 -1
- data/spec/unit/ssl/ssl_provider_spec.rb +75 -1
- data/spec/unit/ssl/state_machine_spec.rb +1 -0
- data/tasks/generate_cert_fixtures.rake +5 -4
- metadata +2 -2
@@ -17,4 +17,30 @@ describe Puppet::Pops::Evaluator::DeferredResolver do
|
|
17
17
|
|
18
18
|
expect(catalog.resource(:notify, 'deferred')[:message]).to eq('1:2:3')
|
19
19
|
end
|
20
|
+
|
21
|
+
it 'lazily resolves deferred values in a catalog' do
|
22
|
+
catalog = compile_to_catalog(<<~END)
|
23
|
+
notify { "deferred":
|
24
|
+
message => Deferred("join", [[1,2,3], ":"])
|
25
|
+
}
|
26
|
+
END
|
27
|
+
described_class.resolve_and_replace(facts, catalog, environment, false)
|
28
|
+
|
29
|
+
deferred = catalog.resource(:notify, 'deferred')[:message]
|
30
|
+
expect(deferred.resolve).to eq('1:2:3')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'lazily resolves nested deferred values in a catalog' do
|
34
|
+
catalog = compile_to_catalog(<<~END)
|
35
|
+
$args = Deferred("inline_epp", ["<%= 'a,b,c' %>"])
|
36
|
+
notify { "deferred":
|
37
|
+
message => Deferred("split", [$args, ","])
|
38
|
+
}
|
39
|
+
END
|
40
|
+
described_class.resolve_and_replace(facts, catalog, environment, false)
|
41
|
+
|
42
|
+
deferred = catalog.resource(:notify, 'deferred')[:message]
|
43
|
+
expect(deferred.resolve).to eq(["a", "b", "c"])
|
44
|
+
end
|
45
|
+
|
20
46
|
end
|
@@ -606,7 +606,7 @@ describe 'loaders' do
|
|
606
606
|
it "an illegal function is loaded" do
|
607
607
|
expect {
|
608
608
|
loader.load_typed(typed_name(:function, 'bad_func_load3')).value
|
609
|
-
}.to raise_error(SecurityError, /Illegal method definition of method 'bad_func_load3_illegal_method' on line 8 in legacy function/)
|
609
|
+
}.to raise_error(SecurityError, /Illegal method definition of method 'bad_func_load3_illegal_method' in source .*bad_func_load3.rb on line 8 in legacy function/)
|
610
610
|
end
|
611
611
|
end
|
612
612
|
|
@@ -1,12 +1,178 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'puppet/pops'
|
3
3
|
require 'puppet_spec/compiler'
|
4
|
+
require 'puppet_spec/files'
|
5
|
+
require 'puppet/loaders'
|
4
6
|
|
5
7
|
module Puppet::Pops
|
6
8
|
module Types
|
7
9
|
|
8
10
|
describe 'the type mismatch describer' do
|
9
|
-
include PuppetSpec::Compiler
|
11
|
+
include PuppetSpec::Compiler, PuppetSpec::Files
|
12
|
+
|
13
|
+
context 'with deferred functions' do
|
14
|
+
let(:env_name) { 'spec' }
|
15
|
+
let(:code_dir) { Puppet[:environmentpath] }
|
16
|
+
let(:env_dir) { File.join(code_dir, env_name) }
|
17
|
+
let(:env) { Puppet::Node::Environment.create(env_name.to_sym, [File.join(populated_code_dir, env_name, 'modules')]) }
|
18
|
+
let(:node) { Puppet::Node.new('fooname', environment: env) }
|
19
|
+
let(:populated_code_dir) do
|
20
|
+
dir_contained_in(code_dir, env_name => env_content)
|
21
|
+
PuppetSpec::Files.record_tmp(env_dir)
|
22
|
+
code_dir
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:env_content) {
|
26
|
+
{
|
27
|
+
'lib' => {
|
28
|
+
'puppet' => {
|
29
|
+
'functions' => {
|
30
|
+
'string_return.rb' => <<-RUBY.unindent,
|
31
|
+
Puppet::Functions.create_function(:string_return) do
|
32
|
+
dispatch :string_return do
|
33
|
+
param 'String', :arg1
|
34
|
+
return_type 'String'
|
35
|
+
end
|
36
|
+
def string_return(arg1)
|
37
|
+
arg1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
RUBY
|
41
|
+
'variant_return.rb' => <<-RUBY.unindent,
|
42
|
+
Puppet::Functions.create_function(:variant_return) do
|
43
|
+
dispatch :variant_return do
|
44
|
+
param 'String', :arg1
|
45
|
+
return_type 'Variant[Integer,Float]'
|
46
|
+
end
|
47
|
+
def variant_return(arg1)
|
48
|
+
arg1
|
49
|
+
end
|
50
|
+
end
|
51
|
+
RUBY
|
52
|
+
'no_return.rb' => <<-RUBY.unindent,
|
53
|
+
Puppet::Functions.create_function(:no_return) do
|
54
|
+
dispatch :no_return do
|
55
|
+
param 'String', :arg1
|
56
|
+
end
|
57
|
+
def variant_return(arg1)
|
58
|
+
arg1
|
59
|
+
end
|
60
|
+
end
|
61
|
+
RUBY
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
before(:each) do
|
69
|
+
Puppet.push_context(:loaders => Puppet::Pops::Loaders.new(env))
|
70
|
+
end
|
71
|
+
|
72
|
+
after(:each) do
|
73
|
+
Puppet.pop_context
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'will compile when the parameter type matches the function return_type' do
|
77
|
+
code = <<-CODE
|
78
|
+
$d = Deferred("string_return", ['/a/non/existing/path'])
|
79
|
+
class testclass(String $classparam) {
|
80
|
+
}
|
81
|
+
class { 'testclass':
|
82
|
+
classparam => $d
|
83
|
+
}
|
84
|
+
CODE
|
85
|
+
expect { eval_and_collect_notices(code, node) }.to_not raise_error
|
86
|
+
end
|
87
|
+
|
88
|
+
it "will compile when a Variant parameter's types matches the return type" do
|
89
|
+
code = <<-CODE
|
90
|
+
$d = Deferred("string_return", ['/a/non/existing/path'])
|
91
|
+
class testclass(Variant[String, Float] $classparam) {
|
92
|
+
}
|
93
|
+
class { 'testclass':
|
94
|
+
classparam => $d
|
95
|
+
}
|
96
|
+
CODE
|
97
|
+
expect { eval_and_collect_notices(code, node) }.to_not raise_error
|
98
|
+
end
|
99
|
+
|
100
|
+
it "will compile with a union of a Variant parameters' types and Variant return types" do
|
101
|
+
code = <<-CODE
|
102
|
+
$d = Deferred("variant_return", ['/a/non/existing/path'])
|
103
|
+
class testclass(Variant[Any,Float] $classparam) {
|
104
|
+
}
|
105
|
+
class { 'testclass':
|
106
|
+
classparam => $d
|
107
|
+
}
|
108
|
+
CODE
|
109
|
+
expect { eval_and_collect_notices(code, node) }.to_not raise_error
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'will warn when there is no defined return_type for the function definition' do
|
113
|
+
code = <<-CODE
|
114
|
+
$d = Deferred("no_return", ['/a/non/existing/path'])
|
115
|
+
class testclass(Variant[String,Boolean] $classparam) {
|
116
|
+
}
|
117
|
+
class { 'testclass':
|
118
|
+
classparam => $d
|
119
|
+
}
|
120
|
+
CODE
|
121
|
+
expect(Puppet).to receive(:warn_once).with(anything, anything, /.+function no_return has no return_type/).at_least(:once)
|
122
|
+
expect { eval_and_collect_notices(code, node) }.to_not raise_error
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'will report a mismatch between a deferred function return type and class parameter value' do
|
126
|
+
code = <<-CODE
|
127
|
+
$d = Deferred("string_return", ['/a/non/existing/path'])
|
128
|
+
class testclass(Integer $classparam) {
|
129
|
+
}
|
130
|
+
class { 'testclass':
|
131
|
+
classparam => $d
|
132
|
+
}
|
133
|
+
CODE
|
134
|
+
expect { eval_and_collect_notices(code, node) }.to raise_error(Puppet::Error, /.+'classparam' expects an Integer value, got String/)
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'will report an argument error when no matching arity is found' do
|
138
|
+
code = <<-CODE
|
139
|
+
$d = Deferred("string_return", ['/a/non/existing/path', 'second-invalid-arg'])
|
140
|
+
class testclass(Integer $classparam) {
|
141
|
+
}
|
142
|
+
class { 'testclass':
|
143
|
+
classparam => $d
|
144
|
+
}
|
145
|
+
CODE
|
146
|
+
expect { eval_and_collect_notices(code,node) }.to raise_error(Puppet::Error, /.+ No matching arity found for string_return/)
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'will error with no matching Variant class parameters and return_type' do
|
150
|
+
code = <<-CODE
|
151
|
+
$d = Deferred("string_return", ['/a/non/existing/path'])
|
152
|
+
class testclass(Variant[Integer,Float] $classparam) {
|
153
|
+
}
|
154
|
+
class { 'testclass':
|
155
|
+
classparam => $d
|
156
|
+
}
|
157
|
+
CODE
|
158
|
+
expect { eval_and_collect_notices(code,node) }.to raise_error(Puppet::Error, /.+'classparam' expects a value of type Integer or Float, got String/)
|
159
|
+
end
|
160
|
+
|
161
|
+
# This test exposes a shortcoming in the #message function for Puppet::Pops::Type::TypeMismatch
|
162
|
+
# where the `actual` is not introspected for the list of Variant types, so the error message
|
163
|
+
# shows that the list of expected types does not match Variant, instead of a list of actual types.
|
164
|
+
it 'will error with no matching Variant class parameters and Variant return_type' do
|
165
|
+
code = <<-CODE
|
166
|
+
$d = Deferred("variant_return", ['/a/non/existing/path'])
|
167
|
+
class testclass(Variant[String,Boolean] $classparam) {
|
168
|
+
}
|
169
|
+
class { 'testclass':
|
170
|
+
classparam => $d
|
171
|
+
}
|
172
|
+
CODE
|
173
|
+
expect { eval_and_collect_notices(code, node) }.to raise_error(Puppet::Error, /.+'classparam' expects a value of type String or Boolean, got Variant/)
|
174
|
+
end
|
175
|
+
end
|
10
176
|
|
11
177
|
it 'will report a mismatch between a hash and a struct with details' do
|
12
178
|
code = <<-CODE
|
@@ -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
|
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(
|
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
|
@@ -840,7 +840,7 @@ end
|
|
840
840
|
expect(provider.class.get_salted_sha512_pbkdf2('iterations', pbkdf2_embedded_bplist_hash)).to be_a(Integer)
|
841
841
|
end
|
842
842
|
it "should raise an error if a field other than 'entropy', 'salt', or 'iterations' is passed" do
|
843
|
-
expect { provider.class.get_salted_sha512_pbkdf2('othervalue', pbkdf2_embedded_bplist_hash) }.to raise_error(Puppet::Error, /Puppet has tried to read an incorrect value from the SALTED-SHA512-PBKDF2 hash. Acceptable fields are 'salt', 'entropy', or 'iterations'/)
|
843
|
+
expect { provider.class.get_salted_sha512_pbkdf2('othervalue', pbkdf2_embedded_bplist_hash, 'test_user') }.to raise_error(Puppet::Error, /Puppet has tried to read an incorrect value from the user test_user in the SALTED-SHA512-PBKDF2 hash. Acceptable fields are 'salt', 'entropy', or 'iterations'/)
|
844
844
|
end
|
845
845
|
end
|
846
846
|
|
@@ -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
|
@@ -530,6 +592,18 @@ describe Puppet::SSL::SSLProvider do
|
|
530
592
|
}.to raise_error(Puppet::SSL::SSLError, /Failed to load private key for host 'signed': Could not parse PKey/)
|
531
593
|
end
|
532
594
|
end
|
595
|
+
|
596
|
+
it 'does not trust the system ca store by default' do
|
597
|
+
expect_any_instance_of(OpenSSL::X509::Store).to receive(:set_default_paths).never
|
598
|
+
|
599
|
+
subject.load_context
|
600
|
+
end
|
601
|
+
|
602
|
+
it 'trusts the system ca store' do
|
603
|
+
expect_any_instance_of(OpenSSL::X509::Store).to receive(:set_default_paths)
|
604
|
+
|
605
|
+
subject.load_context(include_system_store: true)
|
606
|
+
end
|
533
607
|
end
|
534
608
|
|
535
609
|
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
|
-
#
|
46
|
-
# |
|
47
|
-
#
|
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: 7.
|
4
|
+
version: 7.17.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-
|
11
|
+
date: 2022-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: facter
|