chef 18.4.12 → 18.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +9 -2
  3. data/chef-universal-mingw-ucrt.gemspec +1 -1
  4. data/chef.gemspec +8 -8
  5. data/lib/chef/client.rb +0 -15
  6. data/lib/chef/cookbook/chefignore.rb +4 -1
  7. data/lib/chef/cookbook/cookbook_version_loader.rb +1 -1
  8. data/lib/chef/cookbook/remote_file_vendor.rb +3 -2
  9. data/lib/chef/cookbook/synchronizer.rb +2 -1
  10. data/lib/chef/cookbook_manifest.rb +2 -2
  11. data/lib/chef/exceptions.rb +1 -1
  12. data/lib/chef/file_cache.rb +17 -2
  13. data/lib/chef/formatters/doc.rb +1 -1
  14. data/lib/chef/mixin/{homebrew_user.rb → homebrew.rb} +13 -16
  15. data/lib/chef/mixin/openssl_helper.rb +2 -13
  16. data/lib/chef/node/attribute.rb +3 -11
  17. data/lib/chef/node/immutable_collections.rb +15 -8
  18. data/lib/chef/node/mixin/state_tracking.rb +6 -3
  19. data/lib/chef/policy_builder/policyfile.rb +8 -0
  20. data/lib/chef/provider/package/chocolatey.rb +56 -26
  21. data/lib/chef/provider/package/homebrew.rb +6 -9
  22. data/lib/chef/provider/package/powershell.rb +1 -0
  23. data/lib/chef/provider/package/rubygems.rb +4 -0
  24. data/lib/chef/provider/package/snap.rb +1 -0
  25. data/lib/chef/provider/package/zypper.rb +0 -1
  26. data/lib/chef/provider/service/windows.rb +0 -1
  27. data/lib/chef/provider/user/windows.rb +5 -0
  28. data/lib/chef/resource/chef_client_config.rb +4 -2
  29. data/lib/chef/resource/chef_client_systemd_timer.rb +5 -0
  30. data/lib/chef/resource/chef_gem.rb +1 -1
  31. data/lib/chef/resource/execute.rb +8 -6
  32. data/lib/chef/resource/habitat_install.rb +2 -1
  33. data/lib/chef/resource/homebrew_cask.rb +19 -30
  34. data/lib/chef/resource/homebrew_tap.rb +32 -17
  35. data/lib/chef/resource/homebrew_update.rb +4 -4
  36. data/lib/chef/resource/powershell_package.rb +4 -0
  37. data/lib/chef/resource/snap_package.rb +23 -0
  38. data/lib/chef/resource/support/client.erb +4 -3
  39. data/lib/chef/resource/sysctl.rb +1 -0
  40. data/lib/chef/resource_inspector.rb +25 -7
  41. data/lib/chef/version.rb +1 -1
  42. data/lib/chef/win32/registry.rb +5 -0
  43. data/lib/chef/win32/security.rb +9 -0
  44. data/spec/functional/resource/cookbook_file_spec.rb +1 -1
  45. data/spec/functional/resource/remote_file_spec.rb +1 -1
  46. data/spec/integration/client/fips_spec.rb +11 -2
  47. data/spec/integration/client/open_ssl_spec.rb +20 -0
  48. data/spec/spec_helper.rb +4 -1
  49. data/spec/support/chef_helpers.rb +2 -2
  50. data/spec/support/platform_helpers.rb +28 -7
  51. data/spec/support/shared/functional/file_resource.rb +3 -3
  52. data/spec/unit/client_spec.rb +0 -16
  53. data/spec/unit/file_cache_spec.rb +64 -0
  54. data/spec/unit/mixin/homebrew_spec.rb +118 -0
  55. data/spec/unit/mixin/openssl_helper_spec.rb +6 -1
  56. data/spec/unit/provider/package/chocolatey_spec.rb +17 -12
  57. data/spec/unit/provider/package/homebrew_spec.rb +4 -1
  58. data/spec/unit/provider/package/windows_spec.rb +5 -5
  59. data/spec/unit/provider/package/zypper_spec.rb +0 -10
  60. data/spec/unit/provider/user/windows_spec.rb +1 -0
  61. data/spec/unit/resource_inspector_spec.rb +36 -0
  62. metadata +23 -10
  63. data/spec/unit/mixin/homebrew_user_spec.rb +0 -119
data/spec/spec_helper.rb CHANGED
@@ -138,12 +138,14 @@ RSpec.configure do |config|
138
138
 
139
139
  config.filter_run_excluding skip_buildkite: true if ENV["BUILDKITE"]
140
140
 
141
- config.filter_run_excluding fips_mode: !fips_mode_build?
141
+ config.filter_run_excluding fips_mode_test: true unless fips_mode_build?
142
+ config.filter_run_excluding fips_mode_negative_test: true # disable all fips_mode negative tests
142
143
  # Skip fips on windows
143
144
  # config.filter_run_excluding :fips_mode if windows?
144
145
 
145
146
  config.filter_run_excluding windows_only: true unless windows?
146
147
  config.filter_run_excluding not_supported_on_windows: true if windows?
148
+ config.filter_run_excluding not_supported_on_windows_11: true if windows_11?
147
149
  config.filter_run_excluding not_supported_on_macos: true if macos?
148
150
  config.filter_run_excluding macos_only: true unless macos?
149
151
  config.filter_run_excluding not_macos_gte_11: true if macos_gte_11?
@@ -180,6 +182,7 @@ RSpec.configure do |config|
180
182
  config.filter_run_excluding aes_256_gcm_only: true unless aes_256_gcm?
181
183
  config.filter_run_excluding broken: true
182
184
  config.filter_run_excluding not_wpar: true unless wpar?
185
+ config.filter_run_excluding not_supported_on_s390x: true unless s390x?
183
186
  config.filter_run_excluding not_supported_under_fips: true if fips?
184
187
  config.filter_run_excluding rhel: true unless rhel?
185
188
  config.filter_run_excluding rhel6: true unless rhel6?
@@ -69,8 +69,8 @@ def make_canonical_temp_directory
69
69
  end
70
70
 
71
71
  # Check if a cmd exists on the PATH
72
- def which(cmd)
73
- paths = ENV["PATH"].split(File::PATH_SEPARATOR) + [ "/bin", "/usr/bin", "/sbin", "/usr/sbin" ]
72
+ def which(cmd, prepend_path: nil, extra_path: nil)
73
+ paths = Array(prepend_path) + ENV["PATH"].split(File::PATH_SEPARATOR) + [ "/bin", "/usr/bin", "/sbin", "/usr/sbin" ] + Array(extra_path)
74
74
  paths.each do |path|
75
75
  filename = File.join(path, cmd)
76
76
  return filename if File.executable?(filename)
@@ -65,12 +65,18 @@ def windows_gte_10?
65
65
  Gem::Requirement.new(">= 10").satisfied_by?(Gem::Version.new(win32_os_version))
66
66
  end
67
67
 
68
+ def windows_11?
69
+ return false unless windows?
70
+
71
+ Gem::Requirement.new(">= 10.0.22621").satisfied_by?(Gem::Version.new(win32_os_version))
72
+ end
73
+
68
74
  def win32_os_version
69
75
  @win32_os_version ||= begin
70
- wmi = WmiLite::Wmi.new
71
- host = wmi.first_of("Win32_OperatingSystem")
72
- host["version"]
73
- end
76
+ wmi = WmiLite::Wmi.new
77
+ host = wmi.first_of("Win32_OperatingSystem")
78
+ host["version"]
79
+ end
74
80
  end
75
81
 
76
82
  def windows_powershell_dsc?
@@ -80,7 +86,7 @@ def windows_powershell_dsc?
80
86
  begin
81
87
  wmi = WmiLite::Wmi.new("root/microsoft/windows/desiredstateconfiguration")
82
88
  lcm = wmi.query("SELECT * FROM meta_class WHERE __this ISA 'MSFT_DSCLocalConfigurationManager'")
83
- supports_dsc = !! lcm
89
+ supports_dsc = !!lcm
84
90
  rescue WmiLite::WmiException
85
91
  end
86
92
  supports_dsc
@@ -95,7 +101,7 @@ end
95
101
 
96
102
  # detects if the hardware is 64-bit (evaluates to true in "WOW64" mode in a 32-bit app on a 64-bit system)
97
103
  def windows64?
98
- windows? && ( ENV["PROCESSOR_ARCHITECTURE"] == "AMD64" || ENV["PROCESSOR_ARCHITEW6432"] == "AMD64" )
104
+ windows? && (ENV["PROCESSOR_ARCHITECTURE"] == "AMD64" || ENV["PROCESSOR_ARCHITEW6432"] == "AMD64")
99
105
  end
100
106
 
101
107
  # detects if the hardware is 32-bit
@@ -175,6 +181,10 @@ def wpar?
175
181
  !((ohai[:virtualization] || {})[:wpar_no].nil?)
176
182
  end
177
183
 
184
+ def s390x?
185
+ RUBY_PLATFORM.include?("s390x")
186
+ end
187
+
178
188
  def supports_cloexec?
179
189
  Fcntl.const_defined?(:F_SETFD) && Fcntl.const_defined?(:FD_CLOEXEC)
180
190
  end
@@ -224,7 +234,17 @@ def aes_256_gcm?
224
234
  end
225
235
 
226
236
  def fips_mode_build?
227
- OpenSSL::OPENSSL_FIPS
237
+ return false if ENV.fetch("BUILDKITE_PIPELINE_SLUG", "") =~ /verify$/
238
+
239
+ if ENV.include?("BUILDKITE_LABEL") # try keying directly off Buildkite environments
240
+ # regex version of chef/chef-foundation:.expeditor/release.omnibus.yml:fips-platforms
241
+ [/el-.*-x86_64/, /el-.*-ppc64/, /el-.*aarch/, /ubuntu-/, /windows-/, /amazon-2/].any? do |os_arch|
242
+ ENV["BUILDKITE_LABEL"].match?(os_arch)
243
+ end
244
+ else
245
+ # if you're testing your local build
246
+ OpenSSL::OPENSSL_FIPS
247
+ end
228
248
  end
229
249
 
230
250
  def fips?
@@ -233,6 +253,7 @@ end
233
253
 
234
254
  class HttpHelper
235
255
  extend Ohai::Mixin::HttpHelper
256
+
236
257
  def self.logger
237
258
  Chef::Log
238
259
  end
@@ -245,14 +245,14 @@ shared_examples_for "a file resource" do
245
245
 
246
246
  include_context "deploying with move"
247
247
 
248
- describe "when deploying via tmpdir" do
248
+ describe "when deploying via tmpdir", :not_supported_on_windows_11 do
249
249
 
250
250
  include_context "deploying via tmpdir"
251
251
 
252
252
  it_behaves_like "a configured file resource"
253
253
  end
254
254
 
255
- describe "when deploying via destdir" do
255
+ describe "when deploying via destdir", :not_supported_on_windows_11 do
256
256
 
257
257
  include_context "deploying via destdir"
258
258
 
@@ -912,7 +912,7 @@ shared_examples_for "a configured file resource" do
912
912
  dummy_desc
913
913
  end
914
914
 
915
- it_behaves_like "a securable resource without existing target"
915
+ it_behaves_like "a securable resource without existing target", :not_supported_on_windows_11
916
916
 
917
917
  context "when the target file has the wrong content" do
918
918
  before(:each) do
@@ -384,22 +384,6 @@ describe Chef::Client do
384
384
  end
385
385
  end
386
386
 
387
- describe "eol release warning" do
388
- it "warns when running an EOL release" do
389
- stub_const("Chef::VERSION", 15)
390
- allow(Time).to receive(:now).and_return(Time.new(2021, 5, 1, 5))
391
- expect(logger).to receive(:warn).with(/This release of.*became end of life \(EOL\) on May 1st 2021/)
392
- client.warn_if_eol
393
- end
394
-
395
- it "does not warn when running an non-EOL release" do
396
- stub_const("Chef::VERSION", 15)
397
- allow(Time).to receive(:now).and_return(Time.new(2021, 4, 31))
398
- expect(logger).to_not receive(:warn).with(/became end of life/)
399
- client.warn_if_eol
400
- end
401
- end
402
-
403
387
  describe "authentication protocol selection" do
404
388
  context "when FIPS is disabled" do
405
389
  before do
@@ -94,7 +94,71 @@ describe Chef::FileCache do
94
94
  it "searches for cached files by globbing" do
95
95
  expect(Chef::FileCache.find("snappy/**/*")).to eq(%w{snappy/patter})
96
96
  end
97
+ end
98
+
99
+ describe "#find handles regex-unsafe unix paths" do
100
+ before(:each) do
101
+ # Dir.mktmpdir doesn't allow regex unsafe characters (the nerve!), so we'll have to fake file lookups
102
+ @file_cache_path = "/tmp/[foo* ^bar]"
103
+ escaped_file_cache_path = '/tmp/\[foo\* ^bar\]'
104
+ Chef::Config[:file_cache_path] = @file_cache_path
105
+ allow(Chef::Util::PathHelper).to receive(:escape_glob_dir).and_return(escaped_file_cache_path)
106
+ allow(Dir).to receive(:[]).with(File.join(escaped_file_cache_path, "snappy/**/*")).and_return([
107
+ File.join(@file_cache_path, "snappy"),
108
+ File.join(@file_cache_path, "snappy", "patter"),
109
+ ])
110
+ allow(Dir).to receive(:[]).with(escaped_file_cache_path).and_return([
111
+ @file_cache_path,
112
+ ])
113
+ [
114
+ File.join(@file_cache_path, "snappy", "patter"),
115
+ File.join(@file_cache_path, "whiz", "bang"),
116
+ ].each do |f|
117
+ allow(File).to receive(:file?).with(f).and_return(true)
118
+ end
119
+ [
120
+ File.join(@file_cache_path, "snappy"),
121
+ File.join(@file_cache_path, "whiz"),
122
+ ].each do |f|
123
+ allow(File).to receive(:file?).with(f).and_return(false)
124
+ end
125
+ end
126
+
127
+ it "searches for cached files by globbing" do
128
+ expect(Chef::FileCache.find("snappy/**/*")).to eq(%w{snappy/patter})
129
+ end
130
+ end
97
131
 
132
+ describe "#find handles Windows paths" do
133
+ before(:each) do
134
+ allow(ChefUtils).to receive(:windows?).and_return(true)
135
+ @file_cache_path = 'C:\tmp\fakecache'
136
+ escaped_file_cache_path = "C:\\tmp\\fakecache"
137
+ Chef::Config[:file_cache_path] = @file_cache_path
138
+ allow(Chef::Util::PathHelper).to receive(:escape_glob_dir).and_return(escaped_file_cache_path)
139
+ allow(Dir).to receive(:[]).with(File.join(escaped_file_cache_path, "snappy/**/*")).and_return([
140
+ File.join(@file_cache_path, "snappy"),
141
+ File.join(@file_cache_path, "snappy", "patter"),
142
+ ])
143
+ allow(Dir).to receive(:[]).with(escaped_file_cache_path).and_return([
144
+ @file_cache_path,
145
+ ])
146
+ [
147
+ File.join(@file_cache_path, "snappy", "patter"),
148
+ File.join(@file_cache_path, "whiz", "bang"),
149
+ ].each do |f|
150
+ allow(File).to receive(:file?).with(f).and_return(true)
151
+ end
152
+ [
153
+ File.join(@file_cache_path, "snappy"),
154
+ File.join(@file_cache_path, "whiz"),
155
+ ].each do |f|
156
+ allow(File).to receive(:file?).with(f).and_return(false)
157
+ end
158
+ end
159
+ it "searches for cached files by globbing" do
160
+ expect(Chef::FileCache.find("snappy/**/*")).to eq(%w{snappy/patter})
161
+ end
98
162
  end
99
163
 
100
164
  describe "when checking for the existence of a file" do
@@ -0,0 +1,118 @@
1
+ #
2
+ # Author:: Joshua Timberman (<joshua@chef.io>)
3
+ #
4
+ # Copyright:: Copyright (c) Chef Software Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require "spec_helper"
19
+
20
+ describe Chef::Mixin::Homebrew do
21
+ let(:homebrew) { Class.new { include Chef::Mixin::Homebrew }.new }
22
+ let(:uid) { 1001 }
23
+ let(:username) { "foobar" }
24
+ let(:alt_brew_path) { "/foo" }
25
+
26
+ describe "#find_homebrew_uid" do
27
+ it "returns the provided UID when an integer is given" do
28
+ expect(File).to receive(:exist?).exactly(0).times
29
+ expect(homebrew.find_homebrew_uid(uid)).to eq(uid)
30
+ end
31
+
32
+ it "returns the provided UID when username is given" do
33
+ expect(File).to receive(:exist?).exactly(0).times
34
+ allow(Etc).to receive(:getpwnam).with(username).and_return(OpenStruct.new(uid: uid))
35
+ expect(homebrew.find_homebrew_uid(username)).to eq(uid)
36
+ end
37
+
38
+ it "raises an error when the brew executable is not found" do
39
+ allow(homebrew).to receive(:homebrew_bin_path).and_raise(Chef::Exceptions::CannotDetermineHomebrewPath)
40
+ expect { homebrew.find_homebrew_uid }.to raise_error(Chef::Exceptions::CannotDetermineHomebrewPath)
41
+ end
42
+
43
+ it "returns the UID of the owner based on the brew executable" do
44
+ allow(homebrew).to receive(:homebrew_bin_path).and_return(alt_brew_path)
45
+ allow(File).to receive(:stat).with(alt_brew_path).and_return(OpenStruct.new(uid: uid))
46
+ allow(Etc).to receive(:getpwuid).with(uid).and_return(OpenStruct.new(name: username))
47
+ expect(homebrew.find_homebrew_uid).to eq(uid)
48
+ end
49
+ end
50
+
51
+ describe "#find_homebrew_username" do
52
+ it "returns the username for the provided UID" do
53
+ allow(homebrew).to receive(:find_homebrew_uid).and_return(uid)
54
+ allow(Etc).to receive(:getpwuid).with(uid).and_return(OpenStruct.new(name: username))
55
+ expect(homebrew.find_homebrew_username(uid)).to eq(username)
56
+ end
57
+ end
58
+
59
+ describe "#homebrew_bin_path" do
60
+ it "returns the correct path when a valid path is provided" do
61
+ allow(File).to receive(:exist?).with(alt_brew_path).and_return(true)
62
+ expect(homebrew.homebrew_bin_path(alt_brew_path)).to eq(alt_brew_path)
63
+ end
64
+
65
+ it "raises an error when the brew executable is not found" do
66
+ allow(homebrew).to receive(:which).and_return(false)
67
+ expect { homebrew.homebrew_bin_path }.to raise_error(Chef::Exceptions::CannotDetermineHomebrewPath)
68
+ end
69
+ end
70
+
71
+ shared_examples "successfully find executable" do
72
+ let(:default_brew_path) { "/usr/local/bin/brew" }
73
+ let(:default_brew_path_arm) { "/opt/homebrew/bin/brew" }
74
+ let(:default_brew_path_linux) { "/home/linuxbrew/.linuxbrew/bin/brew" }
75
+
76
+ context "debug statement prints owner name" do
77
+
78
+ before do
79
+ expect(Etc).to receive(:getpwuid).with(uid).and_return(OpenStruct.new(name: username))
80
+ end
81
+
82
+ it "returns the owner of the brew executable when it is at a default location for x86_64 machines" do
83
+ allow(homebrew).to receive(:homebrew_bin_path).and_return(default_brew_path)
84
+ allow(File).to receive(:stat).with(default_brew_path).and_return(OpenStruct.new(uid: uid))
85
+ expect(homebrew.find_homebrew_uid).to eq(uid)
86
+ end
87
+
88
+ it "returns the owner of the brew executable when it is at a default location for arm machines" do
89
+ allow(homebrew).to receive(:homebrew_bin_path).and_return(default_brew_path_arm)
90
+ allow(File).to receive(:stat).with(default_brew_path_arm).and_return(OpenStruct.new(uid: uid))
91
+ expect(homebrew.find_homebrew_uid).to eq(uid)
92
+ end
93
+
94
+ it "returns the owner of the brew executable when it is at a default location for linux machines" do
95
+ allow(homebrew).to receive(:homebrew_bin_path).and_return(default_brew_path_linux)
96
+ allow(File).to receive(:stat).with(default_brew_path_linux).and_return(OpenStruct.new(uid: uid))
97
+ expect(homebrew.find_homebrew_uid).to eq(uid)
98
+ end
99
+
100
+ it "returns the owner of the brew executable when it is not at a default location" do
101
+ allow(homebrew).to receive(:homebrew_bin_path).and_return(alt_brew_path)
102
+ allow(File).to receive(:stat).with(alt_brew_path).and_return(OpenStruct.new(uid: uid))
103
+ expect(homebrew.find_homebrew_uid).to eq(uid)
104
+ end
105
+ end
106
+ end
107
+
108
+ describe "#When the homebrew user is not provided" do
109
+
110
+ include_examples "successfully find executable"
111
+
112
+ context "the executable is owned by root" do
113
+ include_examples "successfully find executable" do
114
+ let(:uid) { 0 }
115
+ end
116
+ end
117
+ end
118
+ end
@@ -92,7 +92,12 @@ describe Chef::Mixin::OpenSSLHelper do
92
92
 
93
93
  context "When the dhparam.pem file does exist, and does contain a vaild dhparam key" do
94
94
  it "returns true" do
95
- @dhparam_file.puts(::OpenSSL::PKey::DH.new(256).to_pem) # this is 256 to speed up specs
95
+ # bumped this from 256 to 1024 because OpenSSL 3.x will enforce
96
+ # size
97
+ # OpenSSL::PKey::PKeyError:
98
+ # EVP_PKEY_paramgen: modulus too small
99
+ # need to double check that the mixin itself doesn't allow smaller
100
+ @dhparam_file.puts(::OpenSSL::PKey::DH.new(1024).to_pem)
96
101
  @dhparam_file.close
97
102
  expect(instance.dhparam_pem_valid?(@dhparam_file.path)).to be_truthy
98
103
  end
@@ -36,9 +36,9 @@ describe Chef::Provider::Package::Chocolatey, :windows_only do
36
36
  # installed packages (ConEmu is upgradable)
37
37
  let(:local_list_stdout) do
38
38
  <<~EOF
39
- Chocolatey v0.9.9.11
40
- chocolatey|0.9.9.11
41
- ConEmu|15.10.25.0
39
+ Chocolatey v0.9.9.10
40
+ chocolatey|0.9.9.12
41
+ ConEmu|15.10.25.2
42
42
  EOF
43
43
  end
44
44
 
@@ -47,10 +47,10 @@ describe Chef::Provider::Package::Chocolatey, :windows_only do
47
47
  allow(provider).to receive(:choco_exe).and_return(choco_exe)
48
48
  local_list_obj = double(stdout: local_list_stdout)
49
49
  allow(provider).to receive(:shell_out_compacted!).with(choco_exe, "list", "-l", "-r", { returns: [0, 2], timeout: timeout }).and_return(local_list_obj)
50
- allow(provider).to receive(:powershell_exec!).with("#{choco_exe} --version").and_return(double(result: "2.1.0"))
50
+ allow(provider).to receive(:powershell_exec!).with("Get-ItemProperty #{choco_exe} | select-object -expandproperty versioninfo | select-object -expandproperty productversion").and_return(double(result: "2.1.0"))
51
51
  # Mock the local file system choco queries
52
52
  allow(provider).to receive(:get_local_pkg_dirs).and_return(%w{chocolatey ConEmu})
53
- allow(provider).to receive(:fetch_package_versions_local).and_return({ "chocolatey" => "0.9.9.11", "conemu" => "15.10.25.0" })
53
+ allow(provider).to receive(:fetch_package_versions).and_return({ "chocolatey" => "0.9.9.11", "conemu" => "15.10.25.0" })
54
54
  end
55
55
 
56
56
  after(:each) do
@@ -70,10 +70,13 @@ describe Chef::Provider::Package::Chocolatey, :windows_only do
70
70
  munin-node|1.6.1.20130823
71
71
  EOF
72
72
  remote_list_obj = double(stdout: remote_list_stdout)
73
- if args
74
- allow(provider).to receive(:shell_out_compacted!).with(choco_exe, provider.query_command, "-r", *(package_names.sort + args), { returns: [0, 2], timeout: timeout }).and_return(remote_list_obj)
75
- else
76
- allow(provider).to receive(:shell_out_compacted!).with(choco_exe, provider.query_command, "-r", *(package_names.sort), { returns: [0, 2], timeout: timeout }).and_return(remote_list_obj)
73
+
74
+ package_names.each do |pkg|
75
+ if args
76
+ allow(provider).to receive(:shell_out_compacted!).with(choco_exe, provider.query_command, "-r", *([pkg] + args), { returns: [0, 2], timeout: timeout }).and_return(remote_list_obj)
77
+ else
78
+ allow(provider).to receive(:shell_out_compacted!).with(choco_exe, provider.query_command, "-r", pkg, { returns: [0, 2], timeout: timeout }).and_return(remote_list_obj)
79
+ end
77
80
  end
78
81
  end
79
82
 
@@ -89,12 +92,12 @@ describe Chef::Provider::Package::Chocolatey, :windows_only do
89
92
 
90
93
  describe "choco searches change with the version" do
91
94
  it "Choco V1 uses List" do
92
- allow(provider).to receive(:powershell_exec!).with("#{choco_exe} --version").and_return(double(result: "1.4.0"))
95
+ allow(provider).to receive(:powershell_exec!).with("Get-ItemProperty #{choco_exe} | select-object -expandproperty versioninfo | select-object -expandproperty productversion").and_return(double(result: "1.3.0"))
93
96
  expect(provider.query_command).to eql("list")
94
97
  end
95
98
 
96
99
  it "Choco V2 uses Search" do
97
- allow(provider).to receive(:powershell_exec!).with("#{choco_exe} --version").and_return(double(result: "2.1.0"))
100
+ allow(provider).to receive(:powershell_exec!).with("Get-ItemProperty #{choco_exe} | select-object -expandproperty versioninfo | select-object -expandproperty productversion").and_return(double(result: "2.1.0"))
98
101
  expect(provider.query_command).to eql("search")
99
102
  end
100
103
  end
@@ -168,6 +171,7 @@ describe Chef::Provider::Package::Chocolatey, :windows_only do
168
171
 
169
172
  it "should load and downcase names in the installed_packages hash (with disk provider)" do
170
173
  new_resource.use_choco_list(false)
174
+ provider.invalidate_cache
171
175
  provider.load_current_resource
172
176
  expect(provider.send(:installed_packages)).to eql(
173
177
  { "chocolatey" => "0.9.9.11", "conemu" => "15.10.25.0" }
@@ -176,9 +180,10 @@ describe Chef::Provider::Package::Chocolatey, :windows_only do
176
180
 
177
181
  it "should load and downcase names in the installed_packages hash (with choco list provider)" do
178
182
  new_resource.use_choco_list(true)
183
+ provider.invalidate_cache
179
184
  provider.load_current_resource
180
185
  expect(provider.send(:installed_packages)).to eql(
181
- { "chocolatey" => "0.9.9.11", "conemu" => "15.10.25.0" }
186
+ { "chocolatey" => "0.9.9.12", "conemu" => "15.10.25.2" }
182
187
  )
183
188
  end
184
189
 
@@ -19,6 +19,7 @@
19
19
  require "spec_helper"
20
20
 
21
21
  describe Chef::Provider::Package::Homebrew do
22
+ let(:default_brew_path) { "/usr/local/bin/brew" }
22
23
  let(:node) { Chef::Node.new }
23
24
  let(:new_resource) { Chef::Resource::HomebrewPackage.new(%w{emacs vim}) }
24
25
  let(:current_resource) { Chef::Resource::HomebrewPackage.new("emacs, vim") }
@@ -30,7 +31,6 @@ describe Chef::Provider::Package::Homebrew do
30
31
  end
31
32
 
32
33
  let(:homebrew_uid) { 1001 }
33
-
34
34
  let(:brew_cmd_output_data) { '[{"name":"emacs","full_name":"emacs","oldname":null,"aliases":[],"versioned_formulae":[],"desc":"GNU Emacs text editor","homepage":"https://www.gnu.org/software/emacs/","versions":{"stable":"26.3","devel":null,"head":"HEAD","bottle":true},"urls":{"stable":{"url":"https://ftp.gnu.org/gnu/emacs/emacs-26.3.tar.xz","tag":null,"revision":null}},"revision":0,"version_scheme":0,"bottle":{"stable":{"rebuild":0,"cellar":"/usr/local/Cellar","prefix":"/usr/local","root_url":"https://homebrew.bintray.com/bottles","files":{"catalina":{"url":"https://homebrew.bintray.com/bottles/emacs-26.3.catalina.bottle.tar.gz","sha256":"9ab33f4386ca5f7326a8c28da1324556ec990f682a7ca88641203da0b42dbdae"},"mojave":{"url":"https://homebrew.bintray.com/bottles/emacs-26.3.mojave.bottle.tar.gz","sha256":"8162a26246de7db44c53ea0d0ef0a806140318d19c69e8e5e33aa88ce7e823a8"},"high_sierra":{"url":"https://homebrew.bintray.com/bottles/emacs-26.3.high_sierra.bottle.tar.gz","sha256":"6a2629b6deddf99f81abb1990ecd6c87f0242a0eecbb6b6c2e4c3540e421d4c4"},"sierra":{"url":"https://homebrew.bintray.com/bottles/emacs-26.3.sierra.bottle.tar.gz","sha256":"2a47477e71766d7dd6b16c29ad5ba71817ed80d06212e3261ef3c776e7e9f5a2"}}}},"keg_only":false,"bottle_disabled":false,"options":[],"build_dependencies":["pkg-config"],"dependencies":["gnutls"],"recommended_dependencies":[],"optional_dependencies":[],"uses_from_macos":["libxml2","ncurses"],"requirements":[],"conflicts_with":[],"caveats":null,"installed":[],"linked_keg":null,"pinned":false,"outdated":false},{"name":"vim","full_name":"vim","oldname":null,"aliases":[],"versioned_formulae":[],"desc":"Vi \'workalike\' with many additional features","homepage":"https://www.vim.org/","versions":{"stable":"8.2.0550","devel":null,"head":"HEAD","bottle":true},"urls":{"stable":{"url":"https://github.com/vim/vim/archive/v8.2.0550.tar.gz","tag":null,"revision":null}},"revision":0,"version_scheme":0,"bottle":{"stable":{"rebuild":0,"cellar":"/usr/local/Cellar","prefix":"/usr/local","root_url":"https://homebrew.bintray.com/bottles","files":{"catalina":{"url":"https://homebrew.bintray.com/bottles/vim-8.2.0550.catalina.bottle.tar.gz","sha256":"8f9252500775aa85d8f826af30ca9e1118a56145fc2f961c37abed48bf78cf6b"},"mojave":{"url":"https://homebrew.bintray.com/bottles/vim-8.2.0550.mojave.bottle.tar.gz","sha256":"7566c83b770f3e8c4d4b462a39e5eb26609b37a8f8db6690a2560a3e22ded6b6"},"high_sierra":{"url":"https://homebrew.bintray.com/bottles/vim-8.2.0550.high_sierra.bottle.tar.gz","sha256":"a76e517fc69bf67b6903cb82295bc085c5eb4b46b4659f034c694dd97d2ee2d9"}}}},"keg_only":false,"bottle_disabled":false,"options":[],"build_dependencies":[],"dependencies":["gettext","lua","perl","python","ruby"],"recommended_dependencies":[],"optional_dependencies":[],"uses_from_macos":["ncurses"],"requirements":[],"conflicts_with":["ex-vi","macvim"],"caveats":null,"installed":[{"version":"8.2.0550","used_options":[],"built_as_bottle":true,"poured_from_bottle":true,"runtime_dependencies":[{"full_name":"gettext","version":"0.20.1"},{"full_name":"lua","version":"5.3.5"},{"full_name":"perl","version":"5.30.2"},{"full_name":"gdbm","version":"1.18.1"},{"full_name":"openssl@1.1","version":"1.1.1f"},{"full_name":"readline","version":"8.0.4"},{"full_name":"sqlite","version":"3.31.1"},{"full_name":"xz","version":"5.2.5"},{"full_name":"python","version":"3.7.7"},{"full_name":"libyaml","version":"0.2.2"},{"full_name":"ruby","version":"2.7.1"}],"installed_as_dependency":false,"installed_on_request":true}],"linked_keg":"8.2.0550","pinned":false,"outdated":false}]' }
35
35
 
36
36
  let(:brew_info_data) do
@@ -297,11 +297,13 @@ describe Chef::Provider::Package::Homebrew do
297
297
 
298
298
  it "passes a single pkg to the brew command and return stdout" do
299
299
  allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(stdout: "zombo"))
300
+ allow(provider).to receive(:homebrew_bin_path).and_return(default_brew_path)
300
301
  expect(provider.brew_cmd_output).to eql("zombo")
301
302
  end
302
303
 
303
304
  it "takes multiple arguments as an array" do
304
305
  allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(stdout: "homestarrunner"))
306
+ allow(provider).to receive(:homebrew_bin_path).and_return(default_brew_path)
305
307
  expect(provider.brew_cmd_output("info", "opts", "bananas")).to eql("homestarrunner")
306
308
  end
307
309
 
@@ -310,6 +312,7 @@ describe Chef::Provider::Package::Homebrew do
310
312
 
311
313
  it "does not try to read homebrew_user from Package, which does not have it" do
312
314
  allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(stdout: "zombo"))
315
+ allow(provider).to receive(:homebrew_bin_path).and_return(default_brew_path)
313
316
  expect(provider.brew_cmd_output).to eql("zombo")
314
317
  end
315
318
  end
@@ -106,27 +106,27 @@ describe Chef::Provider::Package::Windows, :windows_only do
106
106
  provider.package_provider
107
107
  end
108
108
 
109
- it "sets the package provider to MSI if the the installer type is :msi" do
109
+ it "sets the package provider to MSI if the installer type is :msi" do
110
110
  allow(provider).to receive(:installer_type).and_return(:msi)
111
111
  expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::MSI)
112
112
  end
113
113
 
114
- it "sets the package provider to Exe if the the installer type is :inno" do
114
+ it "sets the package provider to Exe if the installer type is :inno" do
115
115
  allow(provider).to receive(:installer_type).and_return(:inno)
116
116
  expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
117
117
  end
118
118
 
119
- it "sets the package provider to Exe if the the installer type is :nsis" do
119
+ it "sets the package provider to Exe if the installer type is :nsis" do
120
120
  allow(provider).to receive(:installer_type).and_return(:nsis)
121
121
  expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
122
122
  end
123
123
 
124
- it "sets the package provider to Exe if the the installer type is :wise" do
124
+ it "sets the package provider to Exe if the installer type is :wise" do
125
125
  allow(provider).to receive(:installer_type).and_return(:wise)
126
126
  expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
127
127
  end
128
128
 
129
- it "sets the package provider to Exe if the the installer type is :installshield" do
129
+ it "sets the package provider to Exe if the installer type is :installshield" do
130
130
  allow(provider).to receive(:installer_type).and_return(:installshield)
131
131
  expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
132
132
  end
@@ -491,14 +491,4 @@ describe Chef::Provider::Package::Zypper do
491
491
  provider.remove_package(%w{emacs vim}, ["1.0", "2.0"])
492
492
  end
493
493
  end
494
-
495
- describe "resolve_available_version" do
496
- it "should return correct version if multiple packages are shown" do
497
- status = double(stdout: "S | Name | Type | Version | Arch | Repository\n---+--------------------------+---------+---------------------+--------+-------------------------------------------------------------\n | apache2-mod_wsgi | package | 4.7.1-150400.3.3.1 | x86_64 | Update repository with updates from SUSE Linux Enterprise 15\n | apache2-mod_wsgi | package | 4.7.1-150400.1.52 | x86_64 | Main Repository\ni+ | apache2-mod_wsgi-python3 | package | 4.5.18-150000.4.6.1 | x86_64 | Update repository with updates from SUSE Linux Enterprise 15\nv | apache2-mod_wsgi-python3 | package | 4.5.18-4.3.1 | x86_64 | Main Repository\n", exitstatus: 0)
498
-
499
- allow(provider).to receive(:shell_out_compacted!).and_return(status)
500
- result = provider.send(:resolve_available_version, "apache2-mod_wsgi-python3", nil)
501
- expect(result).to eq("4.5.18-150000.4.6.1")
502
- end
503
- end
504
494
  end
@@ -158,6 +158,7 @@ describe Chef::Provider::User::Windows do
158
158
 
159
159
  describe "when removing the user" do
160
160
  it "should call @net_user.delete" do
161
+ allow(Chef::ReservedNames::Win32::Security).to receive(:clear_account_rights)
161
162
  expect(@net_user).to receive(:delete)
162
163
  @provider.remove_user
163
164
  end
@@ -17,6 +17,20 @@
17
17
  require "spec_helper"
18
18
  require "chef/resource_inspector"
19
19
 
20
+ COMBINED_RESOURCE_TEXT = <<~EOF.freeze
21
+ class Dummy1 < Chef::Resource::LWRPBase
22
+ resource_name :dummy1
23
+ description "A dummy resource"
24
+ property :first, String, description: "My First Property", introduced: "14.0"
25
+ end
26
+
27
+ class Dummy2 < Chef::Resource::LWRPBase
28
+ resource_name :dummy2
29
+ description "Another dummy resource"
30
+ property :second, String, description: "My Second Property", introduced: "14.0"
31
+ end
32
+ EOF
33
+
20
34
  class DummyResource < Chef::Resource
21
35
  resource_name :dummy
22
36
  description "A dummy resource"
@@ -62,4 +76,26 @@ describe Chef::ResourceInspector do
62
76
  end
63
77
  end
64
78
  end
79
+
80
+ describe "inspecting a multi-resource file" do
81
+ # Call the inspector with a fake file containing two resources, and ensure that we get
82
+ # both of them back!
83
+ subject {
84
+ Chef::ResourceInspector.load_from_resources([
85
+ { "full_path" => "/cookbooks/fake_cookbook/resources/big_resource.rb" },
86
+ ], false)
87
+ }
88
+ it "has elephants" do
89
+ allow(File).to receive(:file?).with("/cookbooks/fake_cookbook/resources/big_resource.rb").and_return(true)
90
+ allow(File).to receive(:readable?).with("/cookbooks/fake_cookbook/resources/big_resource.rb").and_return(true)
91
+ allow(IO).to receive(:read).with("/cookbooks/fake_cookbook/resources/big_resource.rb").and_return(COMBINED_RESOURCE_TEXT)
92
+ expect(subject.keys.count).to be 2
93
+ expect(subject.keys.sort).to eq(%i{dummy1 dummy2})
94
+ # This is correct - because they're not fully realised resources at this point, sensitive and friends are not added yet.
95
+ expect(subject[:dummy1][:properties].count).to be 1
96
+ expect(subject[:dummy2][:properties].count).to be 1
97
+ expect(subject[:dummy1][:properties][0][:description]).to eq "My First Property"
98
+ expect(subject[:dummy2][:properties][0][:description]).to eq "My Second Property"
99
+ end
100
+ end
65
101
  end