puppet 6.16.0-x64-mingw32 → 6.17.0-x64-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 (138) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -2
  3. data/Gemfile.lock +10 -10
  4. data/README.md +2 -2
  5. data/lib/puppet/agent.rb +2 -2
  6. data/lib/puppet/application/agent.rb +14 -3
  7. data/lib/puppet/configurer.rb +20 -12
  8. data/lib/puppet/confine.rb +1 -1
  9. data/lib/puppet/defaults.rb +25 -8
  10. data/lib/puppet/file_serving/http_metadata.rb +13 -1
  11. data/lib/puppet/file_serving/metadata.rb +4 -1
  12. data/lib/puppet/file_serving/terminus_selector.rb +7 -8
  13. data/lib/puppet/file_system/file_impl.rb +1 -1
  14. data/lib/puppet/file_system/uniquefile.rb +8 -16
  15. data/lib/puppet/forge.rb +1 -1
  16. data/lib/puppet/forge/cache.rb +1 -1
  17. data/lib/puppet/forge/repository.rb +3 -7
  18. data/lib/puppet/http/client.rb +5 -0
  19. data/lib/puppet/http/redirector.rb +9 -7
  20. data/lib/puppet/http/response.rb +19 -0
  21. data/lib/puppet/indirector.rb +1 -1
  22. data/lib/puppet/indirector/file_content/rest.rb +1 -1
  23. data/lib/puppet/indirector/file_metadata/http.rb +24 -5
  24. data/lib/puppet/indirector/file_metadata/rest.rb +2 -2
  25. data/lib/puppet/indirector/request.rb +1 -1
  26. data/lib/puppet/network/http/api/indirected_routes.rb +1 -1
  27. data/lib/puppet/network/http/api/master/v3/environment.rb +3 -0
  28. data/lib/puppet/network/http/connection_adapter.rb +6 -4
  29. data/lib/puppet/parser/ast/leaf.rb +5 -5
  30. data/lib/puppet/parser/ast/pops_bridge.rb +0 -4
  31. data/lib/puppet/parser/compiler.rb +1 -1
  32. data/lib/puppet/parser/compiler/catalog_validator/env_relationship_validator.rb +2 -0
  33. data/lib/puppet/parser/compiler/catalog_validator/site_validator.rb +2 -0
  34. data/lib/puppet/parser/environment_compiler.rb +4 -1
  35. data/lib/puppet/parser/resource.rb +3 -2
  36. data/lib/puppet/parser/resource/param.rb +6 -0
  37. data/lib/puppet/pops/evaluator/evaluator_impl.rb +5 -5
  38. data/lib/puppet/pops/issues.rb +5 -0
  39. data/lib/puppet/pops/resource/resource_type_impl.rb +2 -0
  40. data/lib/puppet/pops/validation/checker4_0.rb +10 -0
  41. data/lib/puppet/pops/validation/validator_factory_4_0.rb +1 -0
  42. data/lib/puppet/provider/package/aptitude.rb +1 -1
  43. data/lib/puppet/provider/package/yum.rb +1 -1
  44. data/lib/puppet/provider/service/windows.rb +23 -7
  45. data/lib/puppet/provider/user/useradd.rb +11 -4
  46. data/lib/puppet/reports/http.rb +2 -0
  47. data/lib/puppet/resource.rb +2 -1
  48. data/lib/puppet/resource/type.rb +8 -0
  49. data/lib/puppet/ssl/ssl_context.rb +2 -2
  50. data/lib/puppet/ssl/ssl_provider.rb +20 -1
  51. data/lib/puppet/test/test_helper.rb +8 -10
  52. data/lib/puppet/trusted_external.rb +29 -1
  53. data/lib/puppet/type.rb +12 -5
  54. data/lib/puppet/type/file.rb +38 -13
  55. data/lib/puppet/type/file/checksum.rb +4 -4
  56. data/lib/puppet/type/file/source.rb +4 -4
  57. data/lib/puppet/type/service.rb +49 -0
  58. data/lib/puppet/util.rb +39 -15
  59. data/lib/puppet/util/checksums.rb +19 -4
  60. data/lib/puppet/util/fileparsing.rb +2 -2
  61. data/lib/puppet/util/provider_features.rb +1 -1
  62. data/lib/puppet/util/reference.rb +1 -1
  63. data/lib/puppet/util/windows/api_types.rb +45 -32
  64. data/lib/puppet/util/windows/eventlog.rb +1 -6
  65. data/lib/puppet/util/windows/principal.rb +8 -6
  66. data/lib/puppet/util/windows/registry.rb +11 -11
  67. data/lib/puppet/util/windows/service.rb +43 -26
  68. data/lib/puppet/util/windows/user.rb +23 -8
  69. data/lib/puppet/version.rb +1 -1
  70. data/locales/puppet.pot +249 -221
  71. data/man/man5/puppet.conf.5 +19 -8
  72. data/man/man8/puppet-agent.8 +2 -2
  73. data/man/man8/puppet-apply.8 +1 -1
  74. data/man/man8/puppet-catalog.8 +1 -1
  75. data/man/man8/puppet-config.8 +1 -1
  76. data/man/man8/puppet-describe.8 +1 -1
  77. data/man/man8/puppet-device.8 +1 -1
  78. data/man/man8/puppet-doc.8 +1 -1
  79. data/man/man8/puppet-epp.8 +1 -1
  80. data/man/man8/puppet-facts.8 +1 -1
  81. data/man/man8/puppet-filebucket.8 +1 -1
  82. data/man/man8/puppet-generate.8 +1 -1
  83. data/man/man8/puppet-help.8 +1 -1
  84. data/man/man8/puppet-key.8 +1 -1
  85. data/man/man8/puppet-lookup.8 +1 -1
  86. data/man/man8/puppet-man.8 +1 -1
  87. data/man/man8/puppet-module.8 +1 -1
  88. data/man/man8/puppet-node.8 +1 -1
  89. data/man/man8/puppet-parser.8 +1 -1
  90. data/man/man8/puppet-plugin.8 +1 -1
  91. data/man/man8/puppet-report.8 +1 -1
  92. data/man/man8/puppet-resource.8 +1 -1
  93. data/man/man8/puppet-script.8 +1 -1
  94. data/man/man8/puppet-ssl.8 +1 -1
  95. data/man/man8/puppet-status.8 +1 -1
  96. data/man/man8/puppet.8 +2 -2
  97. data/spec/integration/application/agent_spec.rb +89 -0
  98. data/spec/integration/defaults_spec.rb +1 -2
  99. data/spec/integration/network/http_pool_spec.rb +26 -9
  100. data/spec/integration/parser/compiler_spec.rb +11 -0
  101. data/spec/integration/type/file_spec.rb +1 -1
  102. data/spec/integration/util/windows/registry_spec.rb +7 -7
  103. data/spec/integration/util/windows/user_spec.rb +40 -5
  104. data/spec/unit/configurer/fact_handler_spec.rb +4 -4
  105. data/spec/unit/context/trusted_information_spec.rb +10 -4
  106. data/spec/unit/file_serving/http_metadata_spec.rb +37 -14
  107. data/spec/unit/file_serving/terminus_selector_spec.rb +45 -26
  108. data/spec/unit/http/client_spec.rb +64 -8
  109. data/spec/unit/http/response_spec.rb +6 -0
  110. data/spec/unit/indirector/file_metadata/http_spec.rb +27 -0
  111. data/spec/unit/indirector/request_spec.rb +1 -1
  112. data/spec/unit/interface_spec.rb +3 -3
  113. data/spec/unit/network/http/api/indirected_routes_spec.rb +2 -1
  114. data/spec/unit/network/http/connection_spec.rb +42 -32
  115. data/spec/unit/parser/ast/block_expression_spec.rb +1 -1
  116. data/spec/unit/parser/environment_compiler_spec.rb +7 -0
  117. data/spec/unit/parser/scope_spec.rb +1 -1
  118. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +15 -1
  119. data/spec/unit/pops/loaders/loaders_spec.rb +1 -1
  120. data/spec/unit/pops/types/type_calculator_spec.rb +1 -11
  121. data/spec/unit/provider/service/windows_spec.rb +22 -14
  122. data/spec/unit/provider/user/openbsd_spec.rb +1 -0
  123. data/spec/unit/provider/user/useradd_spec.rb +22 -16
  124. data/spec/unit/resource_spec.rb +3 -3
  125. data/spec/unit/ssl/ssl_provider_spec.rb +69 -43
  126. data/spec/unit/test/test_helper_spec.rb +17 -0
  127. data/spec/unit/transaction/report_spec.rb +1 -1
  128. data/spec/unit/type/file/source_spec.rb +3 -3
  129. data/spec/unit/type/file_spec.rb +122 -96
  130. data/spec/unit/type/service_spec.rb +176 -0
  131. data/spec/unit/type_spec.rb +50 -0
  132. data/spec/unit/util/checksums_spec.rb +16 -0
  133. data/spec/unit/util/windows/api_types_spec.rb +104 -40
  134. data/spec/unit/util/windows/service_spec.rb +4 -4
  135. data/spec/unit/util_spec.rb +3 -3
  136. data/spec/unit/x509/cert_provider_spec.rb +1 -1
  137. metadata +5 -5
  138. data/spec/integration/test/test_helper_spec.rb +0 -31
@@ -122,7 +122,7 @@ describe Puppet::Network::HttpPool, unless: Puppet::Util::Platform.jruby? do
122
122
  Puppet::Network::HttpPool.http_client_class = klass
123
123
  end
124
124
 
125
- it "connects using the scheme, host and port from the http instance" do
125
+ it "connects using the scheme, host and port from the http instance preserving the URL path and query" do
126
126
  request_line = nil
127
127
 
128
128
  response_proc = -> (req, res) {
@@ -131,20 +131,20 @@ describe Puppet::Network::HttpPool, unless: Puppet::Util::Platform.jruby? do
131
131
 
132
132
  server.start_server(response_proc: response_proc) do |port|
133
133
  http = Puppet::Network::HttpPool.http_instance(hostname, port, true)
134
- path = "http://bogus.example.com:443/foo"
134
+ path = "http://bogus.example.com:443/foo?q=a"
135
135
  http.get(path)
136
136
 
137
137
  if legacy_api
138
- # The old API passed the bogus hostname which didn't match
139
- # the host we connected to.
140
- expect(request_line).to eq("GET http://bogus.example.com:443/foo HTTP/1.1\r\n")
138
+ # The old API uses 'absolute-form' and passes the bogus hostname
139
+ # which isn't the host we connected to.
140
+ expect(request_line).to eq("GET http://bogus.example.com:443/foo?q=a HTTP/1.1\r\n")
141
141
  else
142
- expect(request_line).to eq("GET /foo HTTP/1.1\r\n")
142
+ expect(request_line).to eq("GET /foo?q=a HTTP/1.1\r\n")
143
143
  end
144
144
  end
145
145
  end
146
146
 
147
- it "requires the caller to URL encode the path" do
147
+ it "requires the caller to URL encode the path and query when using absolute form" do
148
148
  request_line = nil
149
149
 
150
150
  response_proc = -> (req, res) {
@@ -153,16 +153,33 @@ describe Puppet::Network::HttpPool, unless: Puppet::Util::Platform.jruby? do
153
153
 
154
154
  server.start_server(response_proc: response_proc) do |port|
155
155
  http = Puppet::Network::HttpPool.http_instance(hostname, port, true)
156
- encoded_url = "https://#{hostname}:#{port}/foo%20bar"
156
+ params = { 'key' => 'a value' }
157
+ encoded_url = "https://#{hostname}:#{port}/foo%20bar?q=#{Puppet::Util.uri_query_encode(params.to_json)}"
157
158
  http.get(encoded_url)
158
159
 
159
160
  if legacy_api
160
161
  expect(request_line).to eq("GET #{encoded_url} HTTP/1.1\r\n")
161
162
  else
162
- expect(request_line).to eq("GET /foo%20bar HTTP/1.1\r\n")
163
+ expect(request_line).to eq("GET /foo%20bar?q=%7B%22key%22%3A%22a%20value%22%7D HTTP/1.1\r\n")
163
164
  end
164
165
  end
165
166
  end
167
+
168
+ it "requires the caller to URL encode the path and query when using a path" do
169
+ request_line = nil
170
+
171
+ response_proc = -> (req, res) {
172
+ request_line = req.request_line
173
+ }
174
+
175
+ server.start_server(response_proc: response_proc) do |port|
176
+ http = Puppet::Network::HttpPool.http_instance(hostname, port, true)
177
+ params = { 'key' => 'a value' }
178
+ http.get("/foo%20bar?q=#{Puppet::Util.uri_query_encode(params.to_json)}")
179
+
180
+ expect(request_line).to eq("GET /foo%20bar?q=%7B%22key%22%3A%22a%20value%22%7D HTTP/1.1\r\n")
181
+ end
182
+ end
166
183
  end
167
184
 
168
185
  describe Puppet::Network::HTTP::Connection do
@@ -834,6 +834,17 @@ describe Puppet::Parser::Compiler do
834
834
  MANIFEST
835
835
  end.to raise_error(/Foo\[bar\]:\s+parameter 'a' expects a value for key 'd'\s+parameter 'a' unrecognized key 'c'/m)
836
836
  end
837
+
838
+ it 'handles Sensitive type in resource array' do
839
+ catalog = compile_to_catalog(<<-MANIFEST)
840
+ define foo(Sensitive[String] $password) {
841
+ notify{ "${title}": message => "${password}" }
842
+ }
843
+ foo { ['testA', 'testB']: password =>Sensitive('some password') }
844
+ MANIFEST
845
+ expect(catalog).to have_resource("Notify[testA]").with_parameter(:message, 'Sensitive [value redacted]')
846
+ expect(catalog).to have_resource("Notify[testB]").with_parameter(:message, 'Sensitive [value redacted]')
847
+ end
837
848
  end
838
849
 
839
850
  context 'when using typed parameters in class' do
@@ -1160,7 +1160,7 @@ describe Puppet::Type.type(:file), :uses_checksums => true do
1160
1160
  source_prefix = Puppet::Util::Platform.windows? ? '/' : ''
1161
1161
 
1162
1162
  # the URI can be round-tripped through unescape
1163
- expect(URI.unescape(uri_path)).to eq(source_prefix + source)
1163
+ expect(Puppet::Util.uri_unescape(uri_path)).to eq(source_prefix + source)
1164
1164
  # and is properly UTF-8
1165
1165
  expect(uri_path.encoding).to eq (Encoding::UTF_8)
1166
1166
 
@@ -259,23 +259,23 @@ describe Puppet::Util::Windows::Registry do
259
259
  {
260
260
  name: 'REG_SZ',
261
261
  type: Win32::Registry::REG_SZ,
262
- value: "reg sz\u0000 string",
263
- expected_value: "reg sz string"
262
+ value: "reg sz\u0000\u0000 string",
263
+ expected_value: "reg sz"
264
264
  },
265
265
  {
266
266
  name: 'REG_SZ_2',
267
267
  type: Win32::Registry::REG_SZ,
268
- value: "reg sz\x00 string",
269
- expected_value: "reg sz string"
268
+ value: "reg sz 2\x00\x00 string",
269
+ expected_value: "reg sz 2"
270
270
  },
271
271
  {
272
272
  name: 'REG_EXPAND_SZ',
273
273
  type: Win32::Registry::REG_EXPAND_SZ,
274
- value: "\0reg expand string",
275
- expected_value: " reg expand string"
274
+ value: "\0\0\0reg expand string",
275
+ expected_value: ""
276
276
  }
277
277
  ].each do |pair|
278
- it 'replaces null bytes with spaces' do
278
+ it 'reads up to the first wide null' do
279
279
  hklm.create("#{puppet_key}\\#{subkey_name}", Win32::Registry::KEY_ALL_ACCESS) do |reg|
280
280
  reg.write(value_name, pair[:type], pair[:value])
281
281
  end
@@ -125,19 +125,16 @@ describe "Puppet::Util::Windows::User", :if => Puppet::Util::Platform.windows? d
125
125
  end
126
126
 
127
127
  it 'should raise error given that logon returns false' do
128
-
129
128
  allow(Puppet::Util::Windows::User).to receive(:logon_user_by_logon_type).with(
130
- user, passwd, fLOGON32_LOGON_NETWORK, fLOGON32_PROVIDER_DEFAULT, anything).and_return (0)
129
+ user, '.', passwd, fLOGON32_LOGON_NETWORK, fLOGON32_PROVIDER_DEFAULT, anything).and_return (0)
131
130
  allow(Puppet::Util::Windows::User).to receive(:logon_user_by_logon_type).with(
132
- user, passwd, fLOGON32_LOGON_INTERACTIVE, fLOGON32_PROVIDER_DEFAULT, anything).and_return(0)
131
+ user, '.', passwd, fLOGON32_LOGON_INTERACTIVE, fLOGON32_PROVIDER_DEFAULT, anything).and_return(0)
133
132
 
134
133
  expect {Puppet::Util::Windows::User.logon_user(user, passwd) {}}
135
134
  .to raise_error(Puppet::Util::Windows::Error, /Failed to logon user/)
136
-
137
135
  end
138
136
  end
139
137
 
140
-
141
138
  describe "password_is?" do
142
139
  it "should return false given an incorrect username and password" do
143
140
  expect(Puppet::Util::Windows::User.password_is?(username, bad_password)).to be_falsey
@@ -180,5 +177,43 @@ describe "Puppet::Util::Windows::User", :if => Puppet::Util::Platform.windows? d
180
177
  expect { Puppet::Util::Windows::User.check_token_membership }.not_to raise_error
181
178
  end
182
179
  end
180
+
181
+ describe "default_system_account?" do
182
+ it "should succesfully identify 'SYSTEM' user as a default system account" do
183
+ allow(Puppet::Util::Windows::SID).to receive(:name_to_sid).with('SYSTEM').and_return(Puppet::Util::Windows::SID::LocalSystem)
184
+ expect(Puppet::Util::Windows::User.default_system_account?('SYSTEM')).to eq(true)
185
+ end
186
+
187
+ it "should succesfully identify 'NETWORK SERVICE' user as a default system account" do
188
+ allow(Puppet::Util::Windows::SID).to receive(:name_to_sid).with('NETWORK SERVICE').and_return(Puppet::Util::Windows::SID::NtNetwork)
189
+ expect(Puppet::Util::Windows::User.default_system_account?('NETWORK SERVICE')).to eq(true)
190
+ end
191
+
192
+ it "should succesfully identify 'LOCAL SERVICE' user as a default system account" do
193
+ allow(Puppet::Util::Windows::SID).to receive(:name_to_sid).with('LOCAL SERVICE').and_return(Puppet::Util::Windows::SID::NtLocal)
194
+ expect(Puppet::Util::Windows::User.default_system_account?('LOCAL SERVICE')).to eq(true)
195
+ end
196
+
197
+ it "should not identify user with unknown sid as a default system account" do
198
+ allow(Puppet::Util::Windows::SID).to receive(:name_to_sid).with('UnknownUser').and_return(Puppet::Util::Windows::SID::Null)
199
+ expect(Puppet::Util::Windows::User.default_system_account?('UnknownUser')).to eq(false)
200
+ end
201
+ end
202
+
203
+ describe "localsystem?" do
204
+ before do
205
+ allow(Puppet::Util::Windows::ADSI).to receive(:computer_name).and_return("myPC")
206
+ end
207
+
208
+ ['LocalSystem', '.\LocalSystem', 'myPC\LocalSystem', 'lOcALsysTem'].each do |input|
209
+ it "should succesfully identify #{input} as the 'LocalSystem' account" do
210
+ expect(Puppet::Util::Windows::User.localsystem?(input)).to eq(true)
211
+ end
212
+ end
213
+
214
+ it "should not identify any other user as the 'LocalSystem' account" do
215
+ expect(Puppet::Util::Windows::User.localsystem?('OtherUser')).to eq(false)
216
+ end
217
+ end
183
218
  end
184
219
  end
@@ -104,7 +104,7 @@ describe Puppet::Configurer::FactHandler do
104
104
  expect(text).to include(test_fact[:encoded])
105
105
 
106
106
  # this is not sufficient to test whether these values are sent via HTTP GET or HTTP POST in actual catalog request
107
- expect(JSON.parse(URI.unescape(to_upload[:facts]))['values']).to eq(test_fact[:hash])
107
+ expect(JSON.parse(Puppet::Util.uri_unescape(to_upload[:facts]))['values']).to eq(test_fact[:hash])
108
108
  end
109
109
  end
110
110
  end
@@ -129,7 +129,7 @@ describe Puppet::Configurer::FactHandler do
129
129
  expect(to_upload).to eq({:facts_format => 'application/json', :facts => text})
130
130
  expect(text).to include(test_fact[:encoded])
131
131
 
132
- expect(JSON.parse(URI.unescape(to_upload[:facts]))['values']).to eq(test_fact[:hash])
132
+ expect(JSON.parse(Puppet::Util.uri_unescape(to_upload[:facts]))['values']).to eq(test_fact[:hash])
133
133
  end
134
134
  end
135
135
  end
@@ -138,9 +138,9 @@ describe Puppet::Configurer::FactHandler do
138
138
  facts = Puppet::Node::Facts.new(Puppet[:node_name_value], 'my_name_fact' => 'other_node_name')
139
139
  Puppet::Node::Facts.indirection.save(facts)
140
140
 
141
- # prefer URI.unescape but validate CGI also works
141
+ # prefer Puppet::Util.uri_unescape but validate CGI also works
142
142
  encoded_facts = facthandler.facts_for_uploading[:facts]
143
- expect(URI.unescape(encoded_facts)).to validate_against('api/schemas/facts.json')
143
+ expect(Puppet::Util.uri_unescape(encoded_facts)).to validate_against('api/schemas/facts.json')
144
144
  expect(CGI.unescape(encoded_facts)).to validate_against('api/schemas/facts.json')
145
145
  end
146
146
  end
@@ -41,8 +41,12 @@ describe Puppet::Context::TrustedInformation, :unless => RUBY_PLATFORM == 'java'
41
41
  }
42
42
 
43
43
  def allow_external_trusted_data(certname, data)
44
- Puppet[:trusted_external_command] = '/usr/bin/generate_data.sh'
45
- allow(Puppet::Util::Execution).to receive(:execute).with(['/usr/bin/generate_data.sh', certname], anything).and_return(JSON.dump(data))
44
+ command = 'generate_data.sh'
45
+ Puppet[:trusted_external_command] = command
46
+ # The expand_path bit is necessary b/c :trusted_external_command is a
47
+ # file_or_directory setting, and file_or_directory settings automatically
48
+ # expand the given path.
49
+ allow(Puppet::Util::Execution).to receive(:execute).with([File.expand_path(command), certname], anything).and_return(JSON.dump(data))
46
50
  end
47
51
 
48
52
  it "defaults external to an empty hash" do
@@ -99,9 +103,11 @@ describe Puppet::Context::TrustedInformation, :unless => RUBY_PLATFORM == 'java'
99
103
  end
100
104
 
101
105
  it 'only runs the trusted external command the first time it is invoked' do
102
- Puppet[:trusted_external_command] = '/usr/bin/generate_data.sh'
106
+ command = 'generate_data.sh'
107
+ Puppet[:trusted_external_command] = command
103
108
 
104
- expect(Puppet::Util::Execution).to receive(:execute).with(['/usr/bin/generate_data.sh', 'cert name'], anything).and_return(JSON.dump(external_data)).once
109
+ # See allow_external_trusted_data to understand why expand_path is necessary
110
+ expect(Puppet::Util::Execution).to receive(:execute).with([File.expand_path(command), 'cert name'], anything).and_return(JSON.dump(external_data)).once
105
111
 
106
112
  trusted = Puppet::Context::TrustedInformation.remote(true, 'cert name', cert)
107
113
  trusted.external
@@ -30,11 +30,6 @@ describe Puppet::FileServing::HttpMetadata do
30
30
  end
31
31
 
32
32
  context "with no Last-Modified or Content-MD5 header from the server" do
33
- before do
34
- allow(http_response).to receive(:[]).with('last-modified').and_return(nil)
35
- allow(http_response).to receive(:[]).with('content-md5').and_return(nil)
36
- end
37
-
38
33
  it "should use :mtime as the checksum type, based on current time" do
39
34
  # Stringifying Time.now does some rounding; do so here so we don't end up with a time
40
35
  # that's greater than the stringified version returned by collect.
@@ -51,13 +46,9 @@ describe Puppet::FileServing::HttpMetadata do
51
46
  context "with a Last-Modified header from the server" do
52
47
  let(:time) { Time.now.utc }
53
48
 
54
- before do
55
- allow(http_response).to receive(:[]).with('content-md5').and_return(nil)
56
- end
57
-
58
49
  it "should use :mtime as the checksum type, based on Last-Modified" do
59
50
  # HTTP uses "GMT" not "UTC"
60
- allow(http_response).to receive(:[]).with('last-modified').and_return(time.strftime("%a, %d %b %Y %T GMT"))
51
+ http_response.add_field('last-modified', time.strftime("%a, %d %b %Y %T GMT"))
61
52
  metadata = described_class.new(http_response)
62
53
  metadata.collect
63
54
  expect( metadata.checksum_type ).to eq :mtime
@@ -70,16 +61,48 @@ describe Puppet::FileServing::HttpMetadata do
70
61
  let(:base64) { Digest::MD5.new.base64digest input }
71
62
  let(:hex) { Digest::MD5.new.hexdigest input }
72
63
 
73
- before do
74
- allow(http_response).to receive(:[]).with('last-modified').and_return(nil)
75
- allow(http_response).to receive(:[]).with('content-md5').and_return(base64)
64
+ it "should use the md5 checksum" do
65
+ http_response.add_field('content-md5', base64)
66
+ metadata = described_class.new(http_response)
67
+ metadata.collect
68
+ expect( metadata.checksum_type ).to eq :md5
69
+ expect( metadata.checksum ).to eq "{md5}#{hex}"
76
70
  end
71
+ end
72
+
73
+ context "with X-Checksum-Md5" do
74
+ let(:md5) { "c58989e9740a748de4f5054286faf99b" }
77
75
 
78
76
  it "should use the md5 checksum" do
77
+ http_response.add_field('X-Checksum-Md5', md5)
79
78
  metadata = described_class.new(http_response)
80
79
  metadata.collect
81
80
  expect( metadata.checksum_type ).to eq :md5
82
- expect( metadata.checksum ).to eq "{md5}#{hex}"
81
+ expect( metadata.checksum ).to eq "{md5}#{md5}"
82
+ end
83
+ end
84
+
85
+ context "with X-Checksum-Sha1" do
86
+ let(:sha1) { "01e4d15746f4274b84d740a93e04b9fd2882e3ea" }
87
+
88
+ it "should use the SHA1 checksum" do
89
+ http_response.add_field('X-Checksum-Sha1', sha1)
90
+ metadata = described_class.new(http_response)
91
+ metadata.collect
92
+ expect( metadata.checksum_type ).to eq :sha1
93
+ expect( metadata.checksum ).to eq "{sha1}#{sha1}"
94
+ end
95
+ end
96
+
97
+ context "with X-Checksum-Sha256" do
98
+ let(:sha256) { "a3eda98259c30e1e75039c2123670c18105e1c46efb672e42ca0e4cbe77b002a" }
99
+
100
+ it "should use the SHA256 checksum" do
101
+ http_response.add_field('X-Checksum-Sha256', sha256)
102
+ metadata = described_class.new(http_response)
103
+ metadata.collect
104
+ expect( metadata.checksum_type ).to eq :sha256
105
+ expect( metadata.checksum ).to eq "{sha256}#{sha256}"
83
106
  end
84
107
  end
85
108
  end
@@ -3,62 +3,81 @@ require 'spec_helper'
3
3
  require 'puppet/file_serving/terminus_selector'
4
4
 
5
5
  describe Puppet::FileServing::TerminusSelector do
6
- before do
7
- @object = Object.new
8
- @object.extend(Puppet::FileServing::TerminusSelector)
6
+ class TestSelector
7
+ include Puppet::FileServing::TerminusSelector
8
+ end
9
9
 
10
- @request = double('request', :key => "mymod/myfile", :options => {:node => "whatever"}, :server => nil, :protocol => nil)
10
+ def create_request(key)
11
+ Puppet::Indirector::Request.new(:indirection_name, :find, key, nil, {node: 'whatever'})
11
12
  end
12
13
 
14
+ subject { TestSelector.new }
15
+
13
16
  describe "when being used to select termini" do
14
17
  it "should return :file if the request key is fully qualified" do
15
- expect(@request).to receive(:key).and_return(File.expand_path('/foo'))
16
- expect(@object.select(@request)).to eq(:file)
18
+ request = create_request(File.expand_path('/foo'))
19
+
20
+ expect(subject.select(request)).to eq(:file)
21
+ end
22
+
23
+ it "should return :file_server if the request key is relative" do
24
+ request = create_request('modules/my_module/path/to_file')
25
+
26
+ expect(subject.select(request)).to eq(:file_server)
17
27
  end
18
28
 
19
29
  it "should return :file if the URI protocol is set to 'file'" do
20
- expect(@request).to receive(:protocol).and_return("file")
21
- expect(@object.select(@request)).to eq(:file)
30
+ request = create_request(Puppet::Util.path_to_uri(File.expand_path("/foo")).to_s)
31
+
32
+ expect(subject.select(request)).to eq(:file)
22
33
  end
23
34
 
24
35
  it "should return :http if the URI protocol is set to 'http'" do
25
- expect(@request).to receive(:protocol).and_return("http")
26
- expect(@object.select(@request)).to eq :http
36
+ request = create_request("http://www.example.com")
37
+
38
+ expect(subject.select(request)).to eq(:http)
27
39
  end
28
40
 
29
41
  it "should return :http if the URI protocol is set to 'https'" do
30
- expect(@request).to receive(:protocol).and_return("https")
31
- expect(@object.select(@request)).to eq :http
42
+ request = create_request("https://www.example.com")
43
+
44
+ expect(subject.select(request)).to eq(:http)
45
+ end
46
+
47
+ it "should return :http if the path starts with a double slash" do
48
+ request = create_request("https://www.example.com//index.html")
49
+
50
+ expect(subject.select(request)).to eq(:http)
32
51
  end
33
52
 
34
53
  it "should fail when a protocol other than :puppet, :http(s) or :file is used" do
35
- allow(@request).to receive(:protocol).and_return("ftp")
36
- expect { @object.select(@request) }.to raise_error(ArgumentError)
54
+ request = create_request("ftp://ftp.example.com")
55
+
56
+ expect {
57
+ subject.select(request)
58
+ }.to raise_error(ArgumentError, /URI protocol 'ftp' is not currently supported for file serving/)
37
59
  end
38
60
 
39
61
  describe "and the protocol is 'puppet'" do
40
- before do
41
- allow(@request).to receive(:protocol).and_return("puppet")
42
- end
43
-
44
62
  it "should choose :rest when a server is specified" do
45
- allow(@request).to receive(:protocol).and_return("puppet")
46
- expect(@request).to receive(:server).and_return("foo")
47
- expect(@object.select(@request)).to eq(:rest)
63
+ request = create_request("puppet://puppetserver.example.com")
64
+
65
+ expect(subject.select(request)).to eq(:rest)
48
66
  end
49
67
 
50
68
  # This is so a given file location works when bootstrapping with no server.
51
69
  it "should choose :rest when default_file_terminus is rest" do
52
- allow(@request).to receive(:protocol).and_return("puppet")
53
70
  Puppet[:server] = 'localhost'
54
- expect(@object.select(@request)).to eq(:rest)
71
+ request = create_request("puppet:///plugins")
72
+
73
+ expect(subject.select(request)).to eq(:rest)
55
74
  end
56
75
 
57
76
  it "should choose :file_server when default_file_terminus is file_server and no server is specified on the request" do
58
- expect(@request).to receive(:protocol).and_return("puppet")
59
- expect(@request).to receive(:server).and_return(nil)
60
77
  Puppet[:default_file_terminus] = 'file_server'
61
- expect(@object.select(@request)).to eq(:file_server)
78
+ request = create_request("puppet:///plugins")
79
+
80
+ expect(subject.select(request)).to eq(:file_server)
62
81
  end
63
82
  end
64
83
  end
@@ -507,6 +507,20 @@ describe Puppet::HTTP::Client do
507
507
 
508
508
  client.get(uri, options: {basic_auth: {user: 'user', password: nil}})
509
509
  end
510
+
511
+ it 'observes userinfo in the URL' do
512
+ stub_request(:get, uri).with(basic_auth: credentials)
513
+
514
+ client.get(URI("https://user:pass@www.example.com"))
515
+ end
516
+
517
+ it 'prefers explicit basic_auth credentials' do
518
+ uri = URI("https://ignored_user:ignored_pass@www.example.com")
519
+
520
+ stub_request(:get, "https://www.example.com").with(basic_auth: credentials)
521
+
522
+ client.get(uri, options: {basic_auth: {user: 'user', password: 'pass'}})
523
+ end
510
524
  end
511
525
 
512
526
  context "when redirecting" do
@@ -535,10 +549,41 @@ describe Puppet::HTTP::Client do
535
549
  expect(response).to be_success
536
550
  end
537
551
 
538
- it "preserves query parameters" do
539
- query = { 'debug' => true }
540
- stub_request(:get, start_url).with(query: query).to_return(redirect_to(url: bar_url))
541
- stub_request(:get, bar_url).with(query: query).to_return(status: 200)
552
+ it "updates the Host header from the Location host and port" do
553
+ stub_request(:get, start_url).with(headers: { 'Host' => 'www.example.com:8140' })
554
+ .to_return(redirect_to(url: other_host))
555
+ stub_request(:get, other_host).with(headers: { 'Host' => 'other.example.com:8140' })
556
+ .to_return(status: 200)
557
+
558
+ response = client.get(start_url)
559
+ expect(response).to be_success
560
+ end
561
+
562
+ it "omits the default HTTPS port from the Host header" do
563
+ stub_request(:get, start_url).with(headers: { 'Host' => 'www.example.com:8140' })
564
+ .to_return(redirect_to(url: "https://other.example.com/qux"))
565
+ stub_request(:get, "https://other.example.com/qux").with(headers: { 'Host' => 'other.example.com' })
566
+ .to_return(status: 200)
567
+
568
+ response = client.get(start_url)
569
+ expect(response).to be_success
570
+ end
571
+
572
+ it "omits the default HTTP port from the Host header" do
573
+ stub_request(:get, start_url).with(headers: { 'Host' => 'www.example.com:8140' })
574
+ .to_return(redirect_to(url: "http://other.example.com/qux"))
575
+ stub_request(:get, "http://other.example.com/qux").with(headers: { 'Host' => 'other.example.com' })
576
+ .to_return(status: 200)
577
+
578
+ response = client.get(start_url)
579
+ expect(response).to be_success
580
+ end
581
+
582
+ it "applies query parameters from the location header" do
583
+ query = { 'redirected' => false }
584
+
585
+ stub_request(:get, start_url).with(query: query).to_return(redirect_to(url: "#{bar_url}?redirected=true"))
586
+ stub_request(:get, bar_url).with(query: {'redirected' => 'true'}).to_return(status: 200)
542
587
 
543
588
  response = client.get(start_url, params: query)
544
589
  expect(response).to be_success
@@ -569,16 +614,27 @@ describe Puppet::HTTP::Client do
569
614
  expect(response).to be_success
570
615
  end
571
616
 
572
- it "preserves query parameters given a relative location" do
617
+ it "applies query parameters from the location header" do
573
618
  relative_url = "/people.html"
574
- query = { 'debug' => true }
575
- stub_request(:get, start_url).with(query: query).to_return(redirect_to(url: relative_url))
576
- stub_request(:get, "https://www.example.com:8140/people.html").with(query: query).to_return(status: 200)
619
+ query = { 'redirected' => false }
620
+ stub_request(:get, start_url).with(query: query).to_return(redirect_to(url: "#{relative_url}?redirected=true"))
621
+ stub_request(:get, "https://www.example.com:8140/people.html").with(query: {'redirected' => 'true'}).to_return(status: 200)
577
622
 
578
623
  response = client.get(start_url, params: query)
579
624
  expect(response).to be_success
580
625
  end
581
626
 
627
+ it "removes dot segments from a relative location" do
628
+ # from https://tools.ietf.org/html/rfc3986#section-5.4.2
629
+ base_url = URI("http://a/b/c/d;p?q")
630
+ relative_url = "../../../../g"
631
+ stub_request(:get, base_url).to_return(redirect_to(url: relative_url))
632
+ stub_request(:get, "http://a/g").to_return(status: 200)
633
+
634
+ response = client.get(base_url)
635
+ expect(response).to be_success
636
+ end
637
+
582
638
  it "preserves request body for each request" do
583
639
  data = 'some data'
584
640
  stub_request(:put, start_url).with(body: data).to_return(redirect_to(url: bar_url))