chef 17.10.0 → 17.10.114

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +6 -5
  3. data/Rakefile +2 -2
  4. data/chef-universal-mingw32.gemspec +2 -2
  5. data/chef.gemspec +6 -6
  6. data/lib/chef/client.rb +20 -4
  7. data/lib/chef/compliance/input_collection.rb +1 -1
  8. data/lib/chef/compliance/profile_collection.rb +1 -1
  9. data/lib/chef/compliance/waiver_collection.rb +1 -1
  10. data/lib/chef/dsl/secret.rb +113 -5
  11. data/lib/chef/mixin/checksum.rb +6 -0
  12. data/lib/chef/mixin/homebrew_user.rb +15 -5
  13. data/lib/chef/mixin/properties.rb +6 -0
  14. data/lib/chef/node/attribute.rb +20 -3
  15. data/lib/chef/node/mixin/deep_merge_cache.rb +4 -4
  16. data/lib/chef/provider/file.rb +2 -2
  17. data/lib/chef/provider/package/chocolatey.rb +18 -1
  18. data/lib/chef/provider/package/powershell.rb +1 -1
  19. data/lib/chef/provider/package/windows.rb +1 -1
  20. data/lib/chef/provider/package/zypper.rb +5 -0
  21. data/lib/chef/provider/service/windows.rb +1 -0
  22. data/lib/chef/provider/user.rb +5 -1
  23. data/lib/chef/resource/chef_client_config.rb +5 -0
  24. data/lib/chef/resource/chef_client_systemd_timer.rb +1 -1
  25. data/lib/chef/resource/homebrew_cask.rb +7 -8
  26. data/lib/chef/resource/homebrew_package.rb +1 -1
  27. data/lib/chef/resource/homebrew_tap.rb +5 -5
  28. data/lib/chef/resource/locale.rb +5 -2
  29. data/lib/chef/resource/macos_userdefaults.rb +9 -5
  30. data/lib/chef/resource/rhsm_register.rb +19 -0
  31. data/lib/chef/resource/support/client.erb +1 -2
  32. data/lib/chef/resource/windows_certificate.rb +54 -43
  33. data/lib/chef/resource/windows_pagefile.rb +28 -21
  34. data/lib/chef/resource/windows_user_privilege.rb +36 -26
  35. data/lib/chef/resource.rb +2 -1
  36. data/lib/chef/run_context.rb +16 -0
  37. data/lib/chef/secret_fetcher/hashi_vault.rb +1 -1
  38. data/lib/chef/version.rb +1 -1
  39. data/lib/chef/win32/version.rb +2 -1
  40. data/spec/data/trusted_certs/example.crt +29 -20
  41. data/spec/data/trusted_certs/example_no_cn.crt +30 -34
  42. data/spec/data/trusted_certs/opscode.pem +33 -54
  43. data/spec/functional/resource/chocolatey_package_spec.rb +32 -20
  44. data/spec/functional/resource/macos_userdefaults_spec.rb +4 -4
  45. data/spec/functional/resource/windows_certificate_spec.rb +41 -13
  46. data/spec/functional/resource/windows_font_spec.rb +1 -1
  47. data/spec/functional/resource/windows_pagefile_spec.rb +31 -4
  48. data/spec/functional/resource/yum_package_spec.rb +1 -1
  49. data/spec/functional/resource/zypper_package_spec.rb +10 -0
  50. data/spec/functional/shell_spec.rb +6 -0
  51. data/spec/unit/client_spec.rb +6 -3
  52. data/spec/unit/compliance/reporter/chef_server_automate_spec.rb +1 -1
  53. data/spec/unit/daemon_spec.rb +1 -5
  54. data/spec/unit/dsl/secret_spec.rb +127 -23
  55. data/spec/unit/mixin/checksum_spec.rb +28 -0
  56. data/spec/unit/mixin/homebrew_user_spec.rb +30 -7
  57. data/spec/unit/provider/package/chocolatey_spec.rb +19 -3
  58. data/spec/unit/provider/package/rubygems_spec.rb +1 -1
  59. data/spec/unit/provider/user/linux_spec.rb +55 -0
  60. data/spec/unit/resource/chef_client_config_spec.rb +8 -0
  61. data/spec/unit/resource/chef_client_systemd_timer_spec.rb +1 -1
  62. data/spec/unit/resource/macos_user_defaults_spec.rb +4 -4
  63. data/spec/unit/resource_spec.rb +22 -1
  64. data/spec/unit/run_context_spec.rb +16 -0
  65. metadata +35 -35
  66. /data/spec/functional/assets/chocolatey_feed/{test-A.1.0.nupkg → test-A.1.0.0.nupkg} +0 -0
  67. /data/spec/functional/assets/chocolatey_feed/{test-A.1.5.nupkg → test-A.1.5.0.nupkg} +0 -0
  68. /data/spec/functional/assets/chocolatey_feed/{test-A.2.0.nupkg → test-A.2.0.0.nupkg} +0 -0
  69. /data/spec/functional/assets/chocolatey_feed/{test-B.1.0.nupkg → test-B.1.0.0.nupkg} +0 -0
  70. /data/spec/functional/assets/yumrepo/repodata/{4632d67cb92636e7575d911c24f0e04d3505a944e97c483abe0c3e73a7c62d33-filelists.sqlite.bz2 → 01a3b-filelists.sqlite.bz2} +0 -0
  71. /data/spec/functional/assets/yumrepo/repodata/{bdb4f5f1492a3b9532f22c43110a81500dd744f23da0aec5c33b2a41317c737d-filelists.xml.gz → 401dc-filelists.xml.gz} +0 -0
  72. /data/spec/functional/assets/yumrepo/repodata/{a845d418f919d2115ab95a56b2c76f6825ad0d0bede49181a55c04f58995d057-primary.sqlite.bz2 → 5dc1e-primary.sqlite.bz2} +0 -0
  73. /data/spec/functional/assets/yumrepo/repodata/{74599b793e54d877323837d2d81a1c3c594c44e4335f9528234bb490f7b9b439-other.xml.gz → 6bf96-other.xml.gz} +0 -0
  74. /data/spec/functional/assets/yumrepo/repodata/{af9b7cf9ef23bd7b43068d74a460f3b5d06753d638e58e4a0c9edc35bfb9cdc4-other.sqlite.bz2 → 7c365-other.sqlite.bz2} +0 -0
  75. /data/spec/functional/assets/yumrepo/repodata/{c10d1d34ce99e02f12ec96ef68360543ab1bb7c3cb81a4a2bf78df7d8597e9df-primary.xml.gz → dabe2-primary.xml.gz} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6ac04518e7a36c9f65ca1a131832704645b078bf0290708683d6dd5cfeb8975c
4
- data.tar.gz: 339602296915ea1c25bd3581db776b7478f109a1a6b0e6b1b887113357ebf0c9
3
+ metadata.gz: b9a67538138af0d5f0ffb36bab93c72df9698f2d6e01da4eebb2a1892b445329
4
+ data.tar.gz: 10055191565a3bbfa6eab934cd2a3a55094a5e7f5736c382de854b6d67478124
5
5
  SHA512:
6
- metadata.gz: 1abbcfb133838d1b902a033589f24529331dea60e4da3c6678c1e1e666c29601175671ca837e23ea7e0a02ed327a1b7a8be0ee9bf73a62cf9a994634bf909ff0
7
- data.tar.gz: 4bae17edf6da41be96f21055a3d9d456b57c75e04f4faeb9155af8ee23d5d43a6f3c6952c06131473a3818e461c941ddeb482f92cf46c7e18553bbef1f4ebc9f
6
+ metadata.gz: 7685875558fbdbdac49f1e4f10c5c5522b0bbe2ae08568493f677d3ce0286299b847f3ae64a6b79e4cfdcae5b1548966314ac09ad68e44289b831137db72740c
7
+ data.tar.gz: 3859034bb19e28b6dee0eb1814213c7027057b567aba33eb728b77b4a1611853bbfb5bf312828f54049236b462d35f5d10a5ba175ad7cda4c54045639a85b6a8
data/Gemfile CHANGED
@@ -15,19 +15,20 @@ else
15
15
  gem "chef-bin" # rubocop:disable Bundler/DuplicatedGem
16
16
  end
17
17
 
18
- gem "cheffish", "~> 17.0"
18
+ gem "cheffish", "~> 17.0.0"
19
+
20
+ gem "ast", "~> 2.4.2"
21
+ gem "rubocop-ast", ">= 1.30.0"
19
22
 
20
23
  group(:omnibus_package) do
21
24
  gem "appbundler"
22
25
  gem "rb-readline"
23
- gem "inspec-core-bin", "~> 4.24" # need to provide the binaries for inspec
26
+ gem "inspec-core-bin", "~> 5.22.36" # need to provide the binaries for inspec
24
27
  gem "chef-vault"
25
28
  end
26
29
 
27
30
  group(:omnibus_package, :pry) do
28
- # Locked because pry-byebug is broken with 13+.
29
- # some work is ongoing? https://github.com/deivid-rodriguez/pry-byebug/issues/343
30
- gem "pry", "= 0.13.0"
31
+ gem "pry", ">= 0.14.1"
31
32
  # byebug does not install on freebsd on ruby 3.0
32
33
  gem "pry-byebug" unless RUBY_PLATFORM.match?(/freebsd/i)
33
34
  gem "pry-stack_explorer"
data/Rakefile CHANGED
@@ -70,7 +70,7 @@ Bundler::GemHelper.install_tasks name: gemspec
70
70
  task :install do
71
71
  chef_bin_path = ::File.join(::File.dirname(__FILE__), "chef-bin")
72
72
  Dir.chdir(chef_bin_path) do
73
- sh("rake install:force")
73
+ system "rake install:force"
74
74
  end
75
75
  end
76
76
 
@@ -80,7 +80,7 @@ namespace :install do
80
80
  task :local do
81
81
  chef_bin_path = ::File.join(::File.dirname(__FILE__), "chef-bin")
82
82
  Dir.chdir(chef_bin_path) do
83
- sh("rake install:local")
83
+ system "rake install:local"
84
84
  end
85
85
  end
86
86
  end
@@ -11,10 +11,10 @@ gemspec.add_dependency "win32-mmap", "~> 0.4.1"
11
11
  gemspec.add_dependency "win32-mutex", "~> 0.4.2"
12
12
  gemspec.add_dependency "win32-process", "~> 0.9"
13
13
  gemspec.add_dependency "win32-service", ">= 2.1.5", "< 3.0"
14
- gemspec.add_dependency "wmi-lite", "~> 1.0"
15
14
  gemspec.add_dependency "win32-taskscheduler", "~> 2.0"
15
+ gemspec.add_dependency "win32-certstore", "~> 0.6.15"
16
+ gemspec.add_dependency "wmi-lite", "~> 1.0"
16
17
  gemspec.add_dependency "iso8601", ">= 0.12.1", "< 0.14" # validate 0.14 when it comes out
17
- gemspec.add_dependency "win32-certstore", "~> 0.6.2"
18
18
  gemspec.add_dependency "chef-powershell", "~> 1.0.12" # 0.5+ required for specifying user vs. system store
19
19
  gemspec.extensions << "ext/win32-eventlog/Rakefile"
20
20
  gemspec.files += Dir.glob("{distro,ext}/**/*")
data/chef.gemspec CHANGED
@@ -22,11 +22,11 @@ Gem::Specification.new do |s|
22
22
  s.email = "adam@chef.io"
23
23
  s.homepage = "https://www.chef.io"
24
24
 
25
- s.required_ruby_version = ">= 2.6.0"
25
+ s.required_ruby_version = ">= 2.7.0"
26
26
 
27
27
  s.add_dependency "chef-config", "= #{Chef::VERSION}"
28
28
  s.add_dependency "chef-utils", "= #{Chef::VERSION}"
29
- s.add_dependency "train-core", "~> 3.2", ">= 3.2.28" # 3.2.28 fixes sudo prompts. See https://github.com/chef/chef/pull/9635
29
+ s.add_dependency "train-core", "~> 3.10" # 3.2.28 fixes sudo prompts. See https://github.com/chef/chef/pull/9635
30
30
  s.add_dependency "train-winrm", ">= 0.2.5"
31
31
 
32
32
  s.add_dependency "license-acceptance", ">= 1.0.5", "< 3"
@@ -36,11 +36,11 @@ Gem::Specification.new do |s|
36
36
  s.add_dependency "mixlib-shellout", ">= 3.1.1", "< 4.0"
37
37
  s.add_dependency "mixlib-archive", ">= 0.4", "< 2.0"
38
38
  s.add_dependency "ohai", "~> 17.0"
39
- s.add_dependency "inspec-core", "~> 4.23"
39
+ s.add_dependency "inspec-core", "~> 5.22.36"
40
40
 
41
- s.add_dependency "ffi", ">= 1.5.0"
42
- s.add_dependency "ffi-yajl", "~> 2.2"
43
- s.add_dependency "net-sftp", ">= 2.1.2", "< 4.0" # remote_file resource
41
+ s.add_dependency "ffi", "~> 1.15.5"
42
+ s.add_dependency "ffi-yajl", ">= 2.2", "< 4.0"
43
+ s.add_dependency "net-sftp", ">= 2.1.2", "< 5.0" # remote_file resource
44
44
  s.add_dependency "erubis", "~> 2.7" # template resource / cookbook syntax check
45
45
  s.add_dependency "diff-lcs", ">= 1.2.4", "!= 1.4.0", "< 1.6.0" # 1.4 breaks output. Used in lib/chef/util/diff
46
46
  s.add_dependency "ffi-libarchive", "~> 1.0", ">= 1.0.3" # archive_file resource
data/lib/chef/client.rb CHANGED
@@ -326,12 +326,28 @@ class Chef
326
326
  def warn_if_eol
327
327
  require_relative "version"
328
328
 
329
+ # New Date format is YYYY-MM-DD or false
330
+ new_date = eol_override
331
+
329
332
  # We make a release every year so take the version you're on + 2006 and you get
330
- # the year it goes EOL
331
- eol_year = 2006 + Gem::Version.new(Chef::VERSION).segments.first
333
+ # the year it goes EOL. 1/8/2024 - EOL for Chef-17 is now November 1, 2024
334
+ # eol_year = 2006 + Gem::Version.new(Chef::VERSION).segments.first
335
+ eol_year = "2024"
336
+ cut_off_date = !!new_date ? Time.parse(new_date) : Time.new(eol_year, 11, 30)
337
+
338
+ return if Time.now < cut_off_date
332
339
 
333
- if Time.now > Time.new(eol_year, 5, 01)
334
- logger.warn("This release of #{ChefUtils::Dist::Infra::PRODUCT} became end of life (EOL) on May 1st #{eol_year}. Please update to a supported release to receive new features, bug fixes, and security updates.")
340
+ logger.warn("This release of #{ChefUtils::Dist::Infra::PRODUCT} became end of life (EOL) on #{cut_off_date.strftime("%b %d, %Y")}. Please update to a supported release to receive new features, bug fixes, and security updates.")
341
+ end
342
+
343
+ def eol_override
344
+ # If you want to override the existing EOL date, add a file in the root of Chef
345
+ # put a date in it in the form of YYYY-DD-MM.
346
+ override_file = "EOL_override"
347
+ if File.exist?(override_file)
348
+ File.read(File.expand_path(override_file)).strip
349
+ else
350
+ false
335
351
  end
336
352
  end
337
353
 
@@ -40,7 +40,7 @@ class Chef
40
40
  def from_file(filename, cookbook_name)
41
41
  new_input = Input.from_file(events, filename, cookbook_name)
42
42
  self << new_input
43
- events.compliance_input_loaded(new_input)
43
+ events&.compliance_input_loaded(new_input)
44
44
  end
45
45
 
46
46
  # Add a input from a raw hash. This input will be enabled by default.
@@ -41,7 +41,7 @@ class Chef
41
41
  def from_file(path, cookbook_name)
42
42
  new_profile = Profile.from_file(events, path, cookbook_name)
43
43
  self << new_profile
44
- events.compliance_profile_loaded(new_profile)
44
+ events&.compliance_profile_loaded(new_profile)
45
45
  end
46
46
 
47
47
  # @return [Boolean] if any of the profiles are enabled
@@ -40,7 +40,7 @@ class Chef
40
40
  def from_file(filename, cookbook_name)
41
41
  new_waiver = Waiver.from_file(events, filename, cookbook_name)
42
42
  self << new_waiver
43
- events.compliance_waiver_loaded(new_waiver)
43
+ events&.compliance_waiver_loaded(new_waiver)
44
44
  end
45
45
 
46
46
  # Add a waiver from a raw hash. This waiver will be enabled by default.
@@ -21,6 +21,118 @@ class Chef
21
21
  module DSL
22
22
  module Secret
23
23
 
24
+ #
25
+ # This allows you to set the default secret service that is used when
26
+ # fetching secrets.
27
+ #
28
+ # @example
29
+ #
30
+ # default_secret_service :hashi_vault
31
+ # val1 = secret(name: "test1", config: { region: "us-west-1" })
32
+ #
33
+ # @example
34
+ #
35
+ # default_secret_service #=> nil
36
+ # default_secret_service :hashi_vault
37
+ # default_secret_service #=> :hashi_vault
38
+ #
39
+ # @param [Symbol] service default secret service to use when fetching secrets
40
+ # @return [Symbol, nil] default secret service to use when fetching secrets
41
+ #
42
+ def default_secret_service(service = nil)
43
+ return run_context.default_secret_service if service.nil?
44
+ raise Chef::Exceptions::Secret::InvalidFetcherService.new("Unsupported secret service: #{service.inspect}", Chef::SecretFetcher::SECRET_FETCHERS) unless Chef::SecretFetcher::SECRET_FETCHERS.include?(service)
45
+
46
+ run_context.default_secret_service = service
47
+ end
48
+
49
+ #
50
+ # This allows you to set the secret service for the scope of the block
51
+ # passed into this method.
52
+ #
53
+ # @example
54
+ #
55
+ # with_secret_service :hashi_vault do
56
+ # val1 = secret(name: "test1", config: { region: "us-west-1" })
57
+ # val2 = secret(name: "test2", config: { region: "us-west-1" })
58
+ # end
59
+ #
60
+ # @example Combine with #with_secret_config
61
+ #
62
+ # with_secret_service :hashi_vault do
63
+ # with_secret_config region: "us-west-1" do
64
+ # val1 = secret(name: "test1")
65
+ # val2 = secret(name: "test2")
66
+ # end
67
+ # end
68
+ #
69
+ # @param [Symbol] service The default secret service to use when fetching secrets
70
+ #
71
+ def with_secret_service(service)
72
+ raise ArgumentError, "You must pass a block to #with_secret_service" unless block_given?
73
+
74
+ begin
75
+ old_service = default_secret_service
76
+ # Use "public" API for input validation
77
+ default_secret_service(service)
78
+ yield
79
+ ensure
80
+ # Use "private" API so we can set back to nil
81
+ run_context.default_secret_service = old_service
82
+ end
83
+ end
84
+
85
+ #
86
+ # This allows you to set the default secret config that is used when
87
+ # fetching secrets.
88
+ #
89
+ # @example
90
+ #
91
+ # default_secret_config region: "us-west-1"
92
+ # val1 = secret(name: "test1", service: :hashi_vault)
93
+ #
94
+ # @example
95
+ #
96
+ # default_secret_config #=> {}
97
+ # default_secret_service region: "us-west-1"
98
+ # default_secret_service #=> { region: "us-west-1" }
99
+ #
100
+ # @param [Hash<Symbol,Object>] config The default configuration options to apply when fetching secrets
101
+ # @return [Hash<Symbol,Object>]
102
+ #
103
+ def default_secret_config(**config)
104
+ return run_context.default_secret_config if config.empty?
105
+
106
+ run_context.default_secret_config = config
107
+ end
108
+
109
+ #
110
+ # This allows you to set the secret config for the scope of the block
111
+ # passed into this method.
112
+ #
113
+ # @example
114
+ #
115
+ # with_secret_config region: "us-west-1" do
116
+ # val1 = secret(name: "test1", service: :hashi_vault)
117
+ # val2 = secret(name: "test2", service: :hashi_vault)
118
+ # end
119
+ #
120
+ # @param [Hash<Symbol,Object>] config The default configuration options to use when fetching secrets
121
+ #
122
+ def with_secret_config(**config)
123
+ raise ArgumentError, "You must pass a block to #with_secret_config" unless block_given?
124
+
125
+ begin
126
+ old_config = default_secret_config
127
+ # Use "public" API for input validation
128
+ default_secret_config(**config)
129
+ yield
130
+ ensure
131
+ # Use "private" API so we can set back to nil
132
+ run_context.default_secret_config = old_config
133
+ end
134
+ end
135
+
24
136
  # Helper method which looks up a secret using the given service and configuration,
25
137
  # and returns the retrieved secret value.
26
138
  # This DSL providers a wrapper around [Chef::SecretFetcher]
@@ -49,11 +161,7 @@ class Chef
49
161
  #
50
162
  # value = secret(name: "test1", service: :aws_secrets_manager, version: "v1", config: { region: "us-west-1" })
51
163
  # log "My secret is #{value}"
52
- def secret(name: nil, version: nil, service: nil, config: {})
53
- Chef::Log.warn <<~EOM.gsub("\n", " ")
54
- The secrets Chef Infra language helper is currently in beta. If you have feedback or you would
55
- like to be part of the future design of this helper e-mail us at secrets_management_beta@progress.com"
56
- EOM
164
+ def secret(name: nil, version: nil, service: default_secret_service, config: default_secret_config)
57
165
  sensitive(true) if is_a?(Chef::Resource)
58
166
  Chef::SecretFetcher.for_service(service, config, run_context).fetch(name, version)
59
167
  end
@@ -31,6 +31,12 @@ class Chef
31
31
 
32
32
  checksum.slice(0, 6)
33
33
  end
34
+
35
+ def checksum_match?(ref_checksum, diff_checksum)
36
+ return false if ref_checksum.nil? || diff_checksum.nil?
37
+
38
+ ref_checksum.casecmp?(diff_checksum)
39
+ end
34
40
  end
35
41
  end
36
42
  end
@@ -57,18 +57,28 @@ class Chef
57
57
  @homebrew_owner_username
58
58
  end
59
59
 
60
+ def homebrew_bin_path(brew_bin_path = nil)
61
+ if brew_bin_path && ::File.exist?(brew_bin_path)
62
+ brew_bin_path
63
+ else
64
+ [which("brew"), "/opt/homebrew/bin/brew", "/usr/local/bin/brew", "/home/linuxbrew/.linuxbrew/bin/brew"].uniq.select do |x|
65
+ next if x == false
66
+
67
+ ::File.exist?(x) && ::File.executable?(x)
68
+ end.first || nil
69
+ end
70
+ end
71
+
60
72
  private
61
73
 
62
74
  def calculate_owner
63
- default_brew_path = "/usr/local/bin/brew"
64
- if ::File.exist?(default_brew_path)
75
+ brew_path = homebrew_bin_path
76
+ if brew_path
65
77
  # By default, this follows symlinks which is what we want
66
- owner = ::File.stat(default_brew_path).uid
67
- elsif (brew_path = shell_out("which brew").stdout.strip) && !brew_path.empty?
68
78
  owner = ::File.stat(brew_path).uid
69
79
  else
70
80
  raise Chef::Exceptions::CannotDetermineHomebrewOwner,
71
- 'Could not find the "brew" executable in /usr/local/bin or anywhere on the path.'
81
+ 'Could not find the "brew" executable anywhere on the path.'
72
82
  end
73
83
 
74
84
  Chef::Log.debug "Found Homebrew owner #{Etc.getpwuid(owner).name}; executing `brew` commands as them"
@@ -274,6 +274,12 @@ class Chef
274
274
  result
275
275
  end
276
276
 
277
+ # This method returns list of sensitive properties
278
+ # @return [Array<Property>] All sensitive properties.
279
+ def sensitive_properties
280
+ properties.values.empty? ? [] : properties.values.select(&:sensitive?)
281
+ end
282
+
277
283
  # Returns the name of the name property. Returns nil if there is no name property.
278
284
  #
279
285
  # @return [Symbol] the name property for this resource
@@ -452,17 +452,34 @@ class Chef
452
452
  # method-style access to attributes (has to come after the prepended ImmutablizeHash)
453
453
 
454
454
  def read(*path)
455
- merged_attributes.read(*path)
455
+ if path[0].nil?
456
+ Chef::Log.warn "Calling node.read() without any path argument is very slow, probably a bug, and should be avoided"
457
+ merged_attributes.read(*path) # re-merges everything, slow edge case
458
+ else
459
+ self[path[0]] unless path[0].nil? # force deep_merge_cache key construction if necessary
460
+ deep_merge_cache.read(*path)
461
+ end
456
462
  end
457
463
 
458
464
  alias :dig :read
459
465
 
460
466
  def read!(*path)
461
- merged_attributes.read!(*path)
467
+ if path[0].nil?
468
+ Chef::Log.warn "Calling node.read!() without any path argument is very slow, probably a bug, and should be avoided"
469
+ merged_attributes.read!(*path) # re-merges everything, slow edge case
470
+ else
471
+ self[path[0]] unless path[0].nil? # force deep_merge_cache key construction if necessary
472
+ deep_merge_cache.read!(*path)
473
+ end
462
474
  end
463
475
 
464
476
  def exist?(*path)
465
- merged_attributes.exist?(*path)
477
+ if path[0].nil?
478
+ true
479
+ else
480
+ self[path[0]] unless path[0].nil? # force deep_merge_cache key construction if necessary
481
+ deep_merge_cache.exist?(*path)
482
+ end
466
483
  end
467
484
 
468
485
  def write(level, *args, &block)
@@ -30,7 +30,7 @@ class Chef
30
30
  @merged_attributes = nil
31
31
  @combined_override = nil
32
32
  @combined_default = nil
33
- @deep_merge_cache = {}
33
+ @deep_merge_cache = Chef::Node::ImmutableMash.new
34
34
  end
35
35
 
36
36
  # Invalidate a key in the deep_merge_cache. If called with nil, or no arg, this will invalidate
@@ -39,9 +39,9 @@ class Chef
39
39
  # must invalidate the entire cache and re-deep-merge the entire node object.
40
40
  def reset_cache(path = nil)
41
41
  if path.nil?
42
- deep_merge_cache.clear
42
+ deep_merge_cache.regular_clear
43
43
  else
44
- deep_merge_cache.delete(path.to_s)
44
+ deep_merge_cache.regular_delete(path.to_s)
45
45
  end
46
46
  end
47
47
 
@@ -53,7 +53,7 @@ class Chef
53
53
  deep_merge_cache[key.to_s]
54
54
  else
55
55
  # save all the work of computing node[key]
56
- deep_merge_cache[key.to_s] = merged_attributes(key)
56
+ deep_merge_cache.internal_set(key.to_s, merged_attributes(key))
57
57
  end
58
58
  ret = ret.call while ret.is_a?(::Chef::DelayedEvaluator)
59
59
  ret
@@ -336,7 +336,7 @@ class Chef
336
336
  end
337
337
 
338
338
  def do_validate_content
339
- if new_resource.checksum && tempfile && ( new_resource.checksum != tempfile_checksum )
339
+ if new_resource.checksum && tempfile && !checksum_match?(new_resource.checksum, tempfile_checksum)
340
340
  raise Chef::Exceptions::ChecksumMismatch.new(short_cksum(new_resource.checksum), short_cksum(tempfile_checksum))
341
341
  end
342
342
 
@@ -450,7 +450,7 @@ class Chef
450
450
 
451
451
  def contents_changed?
452
452
  logger.trace "calculating checksum of #{tempfile.path} to compare with #{current_resource.checksum}"
453
- tempfile_checksum != current_resource.checksum
453
+ !checksum_match?(tempfile_checksum, current_resource.checksum)
454
454
  end
455
455
 
456
456
  def tempfile
@@ -130,6 +130,21 @@ class Chef
130
130
  # install from, but like the rubygem provider's sources which are more like repos.
131
131
  def check_resource_semantics!; end
132
132
 
133
+ def self.get_choco_version
134
+ @get_choco_version ||= powershell_exec!("choco --version").result
135
+ end
136
+
137
+ # Choco V2 uses 'Search' for remote repositories and 'List' for local packages
138
+ def self.query_command
139
+ return "list" if get_choco_version.match?(/^1/)
140
+
141
+ "search"
142
+ end
143
+
144
+ def query_command
145
+ self.class.query_command
146
+ end
147
+
133
148
  private
134
149
 
135
150
  def version_compare(v1, v2)
@@ -225,7 +240,7 @@ class Chef
225
240
  package_name_array.each do |pkg|
226
241
  available_versions =
227
242
  begin
228
- cmd = [ "list", "-r", pkg ]
243
+ cmd = [ query_command, "-r", pkg ]
229
244
  cmd += common_options
230
245
  cmd.push( new_resource.list_options ) if new_resource.list_options
231
246
 
@@ -242,6 +257,8 @@ class Chef
242
257
  # Installed packages in chocolatey as a Hash of names mapped to versions
243
258
  # (names are downcased for case-insensitive matching)
244
259
  #
260
+ # Beginning with Choco 2.0, "list" returns local packages only while "search" returns packages from external package sources
261
+ #
245
262
  # @return [Hash] name-to-version mapping of installed packages
246
263
  def installed_packages
247
264
  @installed_packages ||= Hash[*parse_list_output("list", "-l", "-r").flatten]
@@ -56,7 +56,7 @@ class Chef
56
56
  names.each_with_index do |name, index|
57
57
  cmd = powershell_exec(build_powershell_package_command("Install-Package '#{name}'", versions[index]), timeout: new_resource.timeout)
58
58
  next if cmd.nil?
59
- raise Chef::Exceptions::PowershellCmdletException, "Failed to install package due to catalog signing error, use skip_publisher_check to force install" if /SkipPublisherCheck/.match?(cmd.error)
59
+ raise Chef::Exceptions::PowershellCmdletException, "Failed to install package due to catalog signing error, use skip_publisher_check to force install" if /SkipPublisherCheck/.match?(cmd.error!)
60
60
  end
61
61
  end
62
62
 
@@ -38,7 +38,7 @@ class Chef
38
38
  def define_resource_requirements
39
39
  if new_resource.checksum
40
40
  requirements.assert(:install) do |a|
41
- a.assertion { new_resource.checksum == checksum(source_location) }
41
+ a.assertion { checksum_match?(new_resource.checksum, checksum(source_location)) }
42
42
  a.failure_message Chef::Exceptions::Package, "Checksum on resource (#{short_cksum(new_resource.checksum)}) does not match checksum on content (#{short_cksum(source_location)})"
43
43
  end
44
44
  end
@@ -93,6 +93,11 @@ class Chef
93
93
  end
94
94
  current_version ||= latest_version if is_installed
95
95
  current_version
96
+ rescue Mixlib::ShellOut::ShellCommandFailed => e
97
+ # zypper returns a '104' code if info is called for a non-existent package
98
+ return nil if e.message =~ /'104'/
99
+
100
+ raise
96
101
  end
97
102
 
98
103
  def resolve_available_version(package_name, new_version)
@@ -74,6 +74,7 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
74
74
  current_resource.run_as_user(config_info.service_start_name) if config_info.service_start_name
75
75
  current_resource.display_name(config_info.display_name) if config_info.display_name
76
76
  current_resource.delayed_start(current_delayed_start) if current_delayed_start
77
+ current_resource.description(config_info.description) if new_resource.description
77
78
  end
78
79
 
79
80
  current_resource
@@ -117,7 +117,11 @@ class Chef
117
117
  new_val = new_resource.send(user_attrib)
118
118
  cur_val = current_resource.send(user_attrib)
119
119
  if !new_val.nil? && new_val.to_s != cur_val.to_s
120
- @change_desc << "change #{user_attrib} from #{cur_val} to #{new_val}"
120
+ if user_attrib.to_s == "password" && new_resource.sensitive
121
+ @change_desc << "change #{user_attrib} from ******** to ********"
122
+ else
123
+ @change_desc << "change #{user_attrib} from #{cur_val} to #{new_val}"
124
+ end
121
125
  end
122
126
  end
123
127
 
@@ -209,6 +209,10 @@ class Chef
209
209
  description: %q(An array of hashes that contain a report handler class and the arguments to pass to that class on initialization. The hash should include `class` and `argument` keys where `class` is a String and `argument` is an array of quoted String values. For example: `[{'class' => 'MyHandler', %w('"argument1"', '"argument2"')}]`),
210
210
  default: []
211
211
 
212
+ property :rubygems_url, [String, Array],
213
+ description: "The location to source rubygems. It can be set to a string or array of strings for URIs to set as rubygems sources. This allows individuals to setup an internal mirror of rubygems for “airgapped” environments.",
214
+ introduced: "17.11"
215
+
212
216
  property :exception_handlers, Array,
213
217
  description: %q(An array of hashes that contain a exception handler class and the arguments to pass to that class on initialization. The hash should include `class` and `argument` keys where `class` is a String and `argument` is an array of quoted String values. For example: `[{'class' => 'MyHandler', %w('"argument1"', '"argument2"')}]`),
214
218
  default: []
@@ -297,6 +301,7 @@ class Chef
297
301
  policy_group: new_resource.policy_group,
298
302
  policy_name: new_resource.policy_name,
299
303
  report_handlers: format_handler(new_resource.report_handlers),
304
+ rubygems_url: new_resource.rubygems_url,
300
305
  ssl_verify_mode: new_resource.ssl_verify_mode,
301
306
  start_handlers: format_handler(new_resource.start_handlers),
302
307
  additional_config: new_resource.additional_config,
@@ -177,7 +177,7 @@ class Chef
177
177
  }
178
178
 
179
179
  unit["Service"]["ConditionACPower"] = "true" unless new_resource.run_on_battery
180
- unit["Service"]["CPUQuota"] = new_resource.cpu_quota if new_resource.cpu_quota
180
+ unit["Service"]["CPUQuota"] = "#{new_resource.cpu_quota}%" if new_resource.cpu_quota
181
181
  unit["Service"]["Environment"] = new_resource.environment.collect { |k, v| "\"#{k}=#{v}\"" } unless new_resource.environment.empty?
182
182
  unit
183
183
  end
@@ -46,25 +46,24 @@ class Chef
46
46
  default: true
47
47
 
48
48
  property :homebrew_path, String,
49
- description: "The path to the homebrew binary.",
50
- default: "/usr/local/bin/brew"
49
+ description: "The path to the homebrew binary."
51
50
 
52
51
  property :owner, [String, Integer],
53
52
  description: "The owner of the Homebrew installation.",
54
53
  default: lazy { find_homebrew_username },
55
- default_description: "Calculated default username"\
54
+ default_description: "Calculated default username"
56
55
 
57
56
  action :install, description: "Install an application that is packaged as a Homebrew cask." do
58
57
  if new_resource.install_cask
59
58
  homebrew_tap "homebrew/cask" do
60
- homebrew_path new_resource.homebrew_path
59
+ homebrew_path homebrew_bin_path(new_resource.homebrew_path)
61
60
  owner new_resource.owner
62
61
  end
63
62
  end
64
63
 
65
64
  unless casked?
66
65
  converge_by("install cask #{new_resource.cask_name} #{new_resource.options}") do
67
- shell_out!("#{new_resource.homebrew_path} install --cask #{new_resource.cask_name} #{new_resource.options}",
66
+ shell_out!("#{homebrew_bin_path(new_resource.homebrew_path)} install --cask #{new_resource.cask_name} #{new_resource.options}",
68
67
  user: new_resource.owner,
69
68
  env: { "HOME" => ::Dir.home(new_resource.owner), "USER" => new_resource.owner },
70
69
  cwd: ::Dir.home(new_resource.owner))
@@ -75,14 +74,14 @@ class Chef
75
74
  action :remove, description: "Remove an application that is packaged as a Homebrew cask." do
76
75
  if new_resource.install_cask
77
76
  homebrew_tap "homebrew/cask" do
78
- homebrew_path new_resource.homebrew_path
77
+ homebrew_path homebrew_bin_path(new_resource.homebrew_path)
79
78
  owner new_resource.owner
80
79
  end
81
80
  end
82
81
 
83
82
  if casked?
84
83
  converge_by("uninstall cask #{new_resource.cask_name}") do
85
- shell_out!("#{new_resource.homebrew_path} uninstall --cask #{new_resource.cask_name}",
84
+ shell_out!("#{homebrew_bin_path(new_resource.homebrew_path)} uninstall --cask #{new_resource.cask_name}",
86
85
  user: new_resource.owner,
87
86
  env: { "HOME" => ::Dir.home(new_resource.owner), "USER" => new_resource.owner },
88
87
  cwd: ::Dir.home(new_resource.owner))
@@ -100,7 +99,7 @@ class Chef
100
99
  # @return [Boolean]
101
100
  def casked?
102
101
  unscoped_name = new_resource.cask_name.split("/").last
103
- shell_out!("#{new_resource.homebrew_path} list --cask 2>/dev/null",
102
+ shell_out!("#{homebrew_bin_path(new_resource.homebrew_path)} list --cask 2>/dev/null",
104
103
  user: new_resource.owner,
105
104
  env: { "HOME" => ::Dir.home(new_resource.owner), "USER" => new_resource.owner },
106
105
  cwd: ::Dir.home(new_resource.owner)).stdout.split.include?(unscoped_name)
@@ -62,7 +62,7 @@ class Chef
62
62
  DOC
63
63
 
64
64
  property :homebrew_user, [ String, Integer ],
65
- description: "The name or uid of the Homebrew owner to be used by #{ChefUtils::Dist::Infra::PRODUCT} when executing a command.\n\n#{ChefUtils::Dist::Infra::PRODUCT}, by default, will attempt to execute a Homebrew command as the owner of the `/usr/local/bin/brew` executable. If that executable does not exist, #{ChefUtils::Dist::Infra::PRODUCT} will attempt to find the user by executing `which brew`. If that executable cannot be found, #{ChefUtils::Dist::Infra::PRODUCT} will print an error message: `Could not find the 'brew' executable in /usr/local/bin or anywhere on the path.`.\n\nSet this property to specify the Homebrew owner for situations where Chef Infra Client cannot automatically detect the correct owner.'"
65
+ description: "The name or uid of the Homebrew owner to be used by #{ChefUtils::Dist::Infra::PRODUCT} when executing a command.\n\n#{ChefUtils::Dist::Infra::PRODUCT}, by default, will attempt to execute a Homebrew command as the owner of the `/usr/local/bin/brew` executable on x86_64 machines or `/opt/homebrew/bin/brew` executable on arm64 machines. If that executable does not exist, #{ChefUtils::Dist::Infra::PRODUCT} will attempt to find the user by executing `which brew`. If that executable cannot be found, #{ChefUtils::Dist::Infra::PRODUCT} will print an error message: `Could not find the 'brew' executable in /usr/local/bin, /opt/homebrew/bin, or anywhere on the path.`.\n\nSet this property to specify the Homebrew owner for situations where Chef Infra Client cannot automatically detect the correct owner.'"
66
66
 
67
67
  end
68
68
  end