chef 18.1.29-x64-mingw-ucrt → 18.3.0-x64-mingw-ucrt

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/chef-universal-mingw-ucrt.gemspec +2 -2
  3. data/chef.gemspec +1 -2
  4. data/distro/powershell/chef/chef.psm1 +459 -0
  5. data/lib/chef/application/base.rb +2 -0
  6. data/lib/chef/client.rb +2 -2
  7. data/lib/chef/cookbook/synchronizer.rb +20 -2
  8. data/lib/chef/cookbook_version.rb +1 -1
  9. data/lib/chef/http/authenticator.rb +2 -2
  10. data/lib/chef/http/ssl_policies.rb +2 -2
  11. data/lib/chef/mixin/homebrew_user.rb +12 -5
  12. data/lib/chef/mixin/proxified_socket.rb +1 -1
  13. data/lib/chef/monkey_patches/net-http.rb +127 -0
  14. data/lib/chef/node/attribute_collections.rb +8 -0
  15. data/lib/chef/node/immutable_collections.rb +5 -2
  16. data/lib/chef/node/mixin/state_tracking.rb +1 -1
  17. data/lib/chef/platform/query_helpers.rb +4 -2
  18. data/lib/chef/provider/launchd.rb +1 -1
  19. data/lib/chef/provider/mount/linux.rb +1 -1
  20. data/lib/chef/provider/mount/mount.rb +5 -5
  21. data/lib/chef/provider/package/chocolatey.rb +18 -1
  22. data/lib/chef/provider/package/zypper.rb +1 -0
  23. data/lib/chef/provider/remote_file/http.rb +1 -1
  24. data/lib/chef/provider/yum_repository.rb +1 -1
  25. data/lib/chef/resource/apt_repository.rb +25 -6
  26. data/lib/chef/resource/homebrew_cask.rb +6 -7
  27. data/lib/chef/resource/homebrew_package.rb +1 -1
  28. data/lib/chef/resource/homebrew_tap.rb +5 -5
  29. data/lib/chef/resource/launchd.rb +5 -1
  30. data/lib/chef/resource/macos_userdefaults.rb +9 -5
  31. data/lib/chef/resource/selinux_login.rb +129 -0
  32. data/lib/chef/resource/selinux_user.rb +137 -0
  33. data/lib/chef/resource/windows_certificate.rb +1 -1
  34. data/lib/chef/resource/windows_security_policy.rb +2 -2
  35. data/lib/chef/resource.rb +11 -1
  36. data/lib/chef/resources.rb +2 -0
  37. data/lib/chef/version.rb +1 -1
  38. data/lib/chef/win32/security.rb +7 -1
  39. data/spec/data/trusted_certs/intermediate.pem +38 -27
  40. data/spec/data/trusted_certs/opscode.pem +33 -54
  41. data/spec/functional/resource/chocolatey_package_spec.rb +32 -20
  42. data/spec/functional/resource/execute_spec.rb +1 -1
  43. data/spec/functional/resource/macos_userdefaults_spec.rb +4 -4
  44. data/spec/functional/resource/windows_certificate_spec.rb +25 -0
  45. data/spec/unit/client_spec.rb +2 -2
  46. data/spec/unit/mixin/homebrew_user_spec.rb +30 -7
  47. data/spec/unit/node/vivid_mash_spec.rb +42 -0
  48. data/spec/unit/provider/apt_repository_spec.rb +17 -7
  49. data/spec/unit/provider/launchd_spec.rb +2 -2
  50. data/spec/unit/provider/mount/aix_spec.rb +2 -2
  51. data/spec/unit/provider/mount/linux_spec.rb +6 -5
  52. data/spec/unit/provider/mount/mount_spec.rb +8 -8
  53. data/spec/unit/provider/package/chocolatey_spec.rb +19 -3
  54. data/spec/unit/provider/package/rpm_spec.rb +2 -2
  55. data/spec/unit/provider/package/zypper_spec.rb +10 -0
  56. data/spec/unit/provider/remote_file/http_spec.rb +4 -4
  57. data/spec/unit/resource/apt_repository_spec.rb +5 -0
  58. data/spec/unit/resource/macos_user_defaults_spec.rb +4 -4
  59. data/spec/unit/resource/selinux_login_spec.rb +73 -0
  60. data/spec/unit/resource/selinux_user_spec.rb +92 -0
  61. data/spec/unit/resource_spec.rb +86 -0
  62. metadata +22 -17
  63. data/lib/chef/powershell.rb +0 -81
  64. /data/spec/functional/assets/chocolatey_feed/{test-A.1.0.nupkg → test-A.1.0.0.nupkg} +0 -0
  65. /data/spec/functional/assets/chocolatey_feed/{test-A.1.5.nupkg → test-A.1.5.0.nupkg} +0 -0
  66. /data/spec/functional/assets/chocolatey_feed/{test-A.2.0.nupkg → test-A.2.0.0.nupkg} +0 -0
  67. /data/spec/functional/assets/chocolatey_feed/{test-B.1.0.nupkg → test-B.1.0.0.nupkg} +0 -0
@@ -0,0 +1,127 @@
1
+ if RUBY_VERSION.split(".")[0..1].join(".") == "3.1"
2
+ require "net/http" unless defined?(Net::HTTP)
3
+ # This is monkey-patch for ruby 3.1.x
4
+ # Due to change https://github.com/ruby/net-http/pull/10, when making net/http requests to a url which supports only IPv6 and not IPv4,
5
+ # ruby waits for IPv4 request to timeout first, then makes IPv6 request. This increased response time.
6
+ # NOTE 1: This is already reverted https://github.com/ruby/ruby/commit/f88bff770578583a708093f4a0d8b1483a1d2039 but under ruby 3.2.2
7
+ # NOTE 2: We are patching action `connect` from here https://github.com/ruby/ruby/blob/f88bff770578583a708093f4a0d8b1483a1d2039/lib/net/http.rb#L1000
8
+
9
+ module Net
10
+ class HTTP
11
+ def connect
12
+ if use_ssl?
13
+ # reference early to load OpenSSL before connecting,
14
+ # as OpenSSL may take time to load.
15
+ @ssl_context = OpenSSL::SSL::SSLContext.new
16
+ end
17
+
18
+ if proxy?
19
+ conn_addr = proxy_address
20
+ conn_port = proxy_port
21
+ else
22
+ conn_addr = conn_address
23
+ conn_port = port
24
+ end
25
+
26
+ puts "opening connection to #{conn_addr}:#{conn_port}..."
27
+ s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {
28
+ begin
29
+ TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
30
+ rescue => e
31
+ raise e, "Failed to open TCP connection to " +
32
+ "#{conn_addr}:#{conn_port} (#{e.message})"
33
+ end
34
+ }
35
+ s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
36
+ puts "opened"
37
+ if use_ssl?
38
+ if proxy?
39
+ plain_sock = BufferedIO.new(s, read_timeout: @read_timeout,
40
+ write_timeout: @write_timeout,
41
+ continue_timeout: @continue_timeout,
42
+ debug_output: @debug_output)
43
+ buf = "CONNECT #{conn_address}:#{@port} HTTP/#{HTTPVersion}\r\n"
44
+ buf << "Host: #{@address}:#{@port}\r\n"
45
+ if proxy_user
46
+ credential = ["#{proxy_user}:#{proxy_pass}"].pack("m0")
47
+ buf << "Proxy-Authorization: Basic #{credential}\r\n"
48
+ end
49
+ buf << "\r\n"
50
+ plain_sock.write(buf)
51
+ HTTPResponse.read_new(plain_sock).value
52
+ # assuming nothing left in buffers after successful CONNECT response
53
+ end
54
+
55
+ ssl_parameters = {}
56
+ iv_list = instance_variables
57
+ SSL_IVNAMES.each_with_index do |ivname, i|
58
+ if iv_list.include?(ivname)
59
+ value = instance_variable_get(ivname)
60
+ unless value.nil?
61
+ ssl_parameters[SSL_ATTRIBUTES[i]] = value
62
+ end
63
+ end
64
+ end
65
+ @ssl_context.set_params(ssl_parameters)
66
+ unless @ssl_context.session_cache_mode.nil? # a dummy method on JRuby
67
+ @ssl_context.session_cache_mode =
68
+ OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
69
+ OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
70
+ end
71
+ if @ssl_context.respond_to?(:session_new_cb) # not implemented under JRuby
72
+ @ssl_context.session_new_cb = proc { |sock, sess| @ssl_session = sess }
73
+ end
74
+
75
+ # Still do the post_connection_check below even if connecting
76
+ # to IP address
77
+ verify_hostname = @ssl_context.verify_hostname
78
+
79
+ # requiring 'resolv' near the top of the file causes registry.rb monkey patch to fail
80
+ # Windows 2012 R2 somehow fails to have Resolv defined unless we require it manually
81
+ require "resolv" unless defined?(Resolv)
82
+
83
+ # Server Name Indication (SNI) RFC 3546/6066
84
+ case @address
85
+ when ::Resolv::IPv4::Regex, ::Resolv::IPv6::Regex
86
+ # don't set SNI, as IP addresses in SNI is not valid
87
+ # per RFC 6066, section 3.
88
+
89
+ # Avoid openssl warning
90
+ @ssl_context.verify_hostname = false
91
+ else
92
+ ssl_host_address = @address
93
+ end
94
+
95
+ puts "starting SSL for #{conn_addr}:#{conn_port}..."
96
+ s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
97
+ s.sync_close = true
98
+ s.hostname = ssl_host_address if s.respond_to?(:hostname=) && ssl_host_address
99
+
100
+ if @ssl_session &&
101
+ (Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout)
102
+ s.session = @ssl_session
103
+ end
104
+ ssl_socket_connect(s, @open_timeout)
105
+ if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname
106
+ s.post_connection_check(@address)
107
+ end
108
+ puts "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}"
109
+ end
110
+ @socket = BufferedIO.new(s, read_timeout: @read_timeout,
111
+ write_timeout: @write_timeout,
112
+ continue_timeout: @continue_timeout,
113
+ debug_output: @debug_output)
114
+ @last_communicated = nil
115
+ on_connect
116
+ rescue => exception
117
+ if s
118
+ puts "Conn close because of connect error #{exception}"
119
+ s.close
120
+ end
121
+ raise
122
+ end
123
+ end
124
+ end
125
+ else
126
+ warn "Not applying net/http monkey patch needed for ruby 3.1"
127
+ end
@@ -39,11 +39,19 @@ class Chef
39
39
  MUTATOR_METHODS.each do |mutator|
40
40
  define_method(mutator) do |*args, &block|
41
41
  ret = super(*args, &block)
42
+ # TODO: use `send_reset_cache(__path__)` for all mutator methods?
42
43
  send_reset_cache
43
44
  ret
44
45
  end
45
46
  end
46
47
 
48
+ def <<(obj)
49
+ ret = super(obj)
50
+ # NOTE: Expecting __path__ to be top-level attribute only
51
+ send_reset_cache(__path__)
52
+ ret
53
+ end
54
+
47
55
  def delete(key, &block)
48
56
  send_reset_cache(__path__, key)
49
57
  super
@@ -32,13 +32,16 @@ class Chef
32
32
  end
33
33
 
34
34
  def convert_value(value)
35
+ # The order in this case statement is *important*.
36
+ # ImmutableMash and ImmutableArray should be tested first,
37
+ # as this saves unnecessary creation of intermediate objects
35
38
  case value
39
+ when ImmutableMash, ImmutableArray
40
+ value
36
41
  when Hash
37
42
  ImmutableMash.new(value, __root__, __node__, __precedence__)
38
43
  when Array
39
44
  ImmutableArray.new(value, __root__, __node__, __precedence__)
40
- when ImmutableMash, ImmutableArray
41
- value
42
45
  else
43
46
  safe_dup(value).freeze
44
47
  end
@@ -78,7 +78,7 @@ class Chef
78
78
 
79
79
  def send_reset_cache(path = nil, key = nil)
80
80
  next_path = [ path, key ].flatten.compact
81
- __root__.reset_cache(next_path.first) if !__root__.nil? && __root__.respond_to?(:reset_cache) && !next_path.nil?
81
+ __root__.reset_cache(next_path.first) if !__root__.nil? && __root__.respond_to?(:reset_cache)
82
82
  end
83
83
 
84
84
  def copy_state_to(ret, next_path)
@@ -17,11 +17,14 @@
17
17
  #
18
18
 
19
19
  require "chef-utils" unless defined?(ChefUtils::CANARY)
20
+ require_relative "../mixin/powershell_exec"
20
21
 
21
22
  class Chef
22
23
  class Platform
23
24
 
24
25
  class << self
26
+ include Chef::Mixin::PowershellExec
27
+
25
28
  def windows?
26
29
  ChefUtils.windows?
27
30
  end
@@ -58,8 +61,7 @@ class Chef
58
61
  end
59
62
 
60
63
  def dsc_refresh_mode_disabled?(node)
61
- require_relative "../powershell"
62
- exec = Chef::PowerShell.new("Get-DscLocalConfigurationManager")
64
+ exec = powershell_exec!("Get-DscLocalConfigurationManager")
63
65
  exec.error!
64
66
  exec.result["RefreshMode"] == "Disabled"
65
67
  end
@@ -52,7 +52,7 @@ class Chef
52
52
  end
53
53
 
54
54
  action :delete, description: "Delete a launchd property list. This will unload a daemon or agent, if loaded." do
55
- if ::File.exists?(path)
55
+ if ::File.exist?(path)
56
56
  manage_service(:disable)
57
57
  end
58
58
  manage_plist(:delete)
@@ -39,7 +39,7 @@ class Chef
39
39
 
40
40
  def mounted?
41
41
  mounted = false
42
- real_mount_point = if ::File.exists? @new_resource.mount_point
42
+ real_mount_point = if ::File.exist? @new_resource.mount_point
43
43
  ::File.realpath(@new_resource.mount_point)
44
44
  else
45
45
  @new_resource.mount_point
@@ -42,9 +42,9 @@ class Chef
42
42
 
43
43
  def mountable?
44
44
  # only check for existence of non-remote devices
45
- if device_should_exist? && !::File.exists?(device_real)
45
+ if device_should_exist? && !::File.exist?(device_real)
46
46
  raise Chef::Exceptions::Mount, "Device #{@new_resource.device} does not exist"
47
- elsif @new_resource.mount_point != "none" && !::File.exists?(@new_resource.mount_point)
47
+ elsif @new_resource.mount_point != "none" && !::File.exist?(@new_resource.mount_point)
48
48
  raise Chef::Exceptions::Mount, "Mount point #{@new_resource.mount_point} does not exist"
49
49
  end
50
50
 
@@ -81,7 +81,7 @@ class Chef
81
81
  # "mount" outputs the mount points as real paths. Convert
82
82
  # the mount_point of the resource to a real path in case it
83
83
  # contains symlinks in its parents dirs.
84
- real_mount_point = if ::File.exists? @new_resource.mount_point
84
+ real_mount_point = if ::File.exist? @new_resource.mount_point
85
85
  ::File.realpath(@new_resource.mount_point)
86
86
  else
87
87
  @new_resource.mount_point
@@ -186,7 +186,7 @@ class Chef
186
186
  def device_should_exist?
187
187
  ( @new_resource.device != "none" ) &&
188
188
  ( not network_device? ) &&
189
- ( not %w{ cgroup tmpfs fuse vboxsf zfs }.include? @new_resource.fstype )
189
+ ( not %w{ cgroup tmpfs fuse vboxsf zfs efivarfs }.include? @new_resource.fstype )
190
190
  end
191
191
 
192
192
  private
@@ -287,4 +287,4 @@ class Chef
287
287
  end
288
288
  end
289
289
  end
290
- end
290
+ end
@@ -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]
@@ -141,6 +141,7 @@ class Chef
141
141
  if md = line.match(/^(\S*)\s+\|\s+(\S+)\s+\|\s+(\S+)\s+\|\s+(\S+)\s+\|\s+(\S+)\s+\|\s+(.*)$/)
142
142
  (status, name, type, version, arch, repo) = [ md[1], md[2], md[3], md[4], md[5], md[6] ]
143
143
  next if version == "Version" # header
144
+ next if name != package_name
144
145
 
145
146
  # sometimes even though we request a specific version in the search string above and have match exact, we wind up
146
147
  # with other versions in the output, particularly getting the installed version when downgrading.
@@ -113,7 +113,7 @@ class Chef
113
113
  end
114
114
 
115
115
  def last_modified_time_from(response)
116
- response["last_modified"] || response["date"]
116
+ response["last-modified"] || response["date"]
117
117
  end
118
118
 
119
119
  def etag_from(response)
@@ -45,7 +45,7 @@ class Chef
45
45
  if new_resource.make_cache
46
46
  notifies :run, "execute[yum clean metadata #{new_resource.repositoryid}]", :immediately if new_resource.clean_metadata || new_resource.clean_headers
47
47
  # makecache fast only works on non-dnf systems.
48
- if !which "dnf" && new_resource.makecache_fast
48
+ if !which("dnf") && new_resource.makecache_fast
49
49
  notifies :run, "execute[yum-makecache-fast-#{new_resource.repositoryid}]", :immediately
50
50
  else
51
51
  notifies :run, "execute[yum-makecache-#{new_resource.repositoryid}]", :immediately
@@ -98,6 +98,18 @@ class Chef
98
98
  end
99
99
  ```
100
100
 
101
+ **Add repository that needs custom options**:
102
+ ```ruby
103
+ apt_repository 'corretto' do
104
+ uri 'https://apt.corretto.aws'
105
+ arch 'amd64'
106
+ distribution 'stable'
107
+ components ['main']
108
+ options ['target-=Contents-deb']
109
+ key 'https://apt.corretto.aws/corretto.key'
110
+ end
111
+ ```
112
+
101
113
  **Remove a repository from the list**:
102
114
 
103
115
  ```ruby
@@ -159,6 +171,10 @@ class Chef
159
171
  description: "Determines whether to rebuild the APT package cache.",
160
172
  default: true, desired_state: false
161
173
 
174
+ property :options, [String, Array],
175
+ description: "Additional options to set for the repository",
176
+ default: [], coerce: proc { |x| Array(x) }
177
+
162
178
  default_action :add
163
179
  allowed_actions :add, :remove
164
180
 
@@ -388,19 +404,21 @@ class Chef
388
404
  # @param [Array] components
389
405
  # @param [Boolean] trusted
390
406
  # @param [String] arch
407
+ # @param [Array] options
391
408
  # @param [Boolean] add_src
392
409
  #
393
410
  # @return [String] complete repo config text
394
- def build_repo(uri, distribution, components, trusted, arch, add_src = false)
411
+ def build_repo(uri, distribution, components, trusted, arch, options, add_src = false)
395
412
  uri = make_ppa_url(uri) if is_ppa_url?(uri)
396
413
 
397
414
  uri = Addressable::URI.parse(uri)
398
415
  components = Array(components).join(" ")
399
- options = []
400
- options << "arch=#{arch}" if arch
401
- options << "trusted=yes" if trusted
402
- optstr = unless options.empty?
403
- "[" + options.join(" ") + "]"
416
+ options_list = []
417
+ options_list << "arch=#{arch}" if arch
418
+ options_list << "trusted=yes" if trusted
419
+ options_list += options
420
+ optstr = unless options_list.empty?
421
+ "[" + options_list.join(" ") + "]"
404
422
  end
405
423
  info = [ optstr, uri.normalize.to_s, distribution, components ].compact.join(" ")
406
424
  repo = "deb #{info}\n"
@@ -461,6 +479,7 @@ class Chef
461
479
  repo_components,
462
480
  new_resource.trusted,
463
481
  new_resource.arch,
482
+ new_resource.options,
464
483
  new_resource.deb_src
465
484
  )
466
485
 
@@ -45,8 +45,7 @@ class Chef
45
45
  default: true
46
46
 
47
47
  property :homebrew_path, String,
48
- description: "The path to the homebrew binary.",
49
- default: "/usr/local/bin/brew"
48
+ description: "The path to the Homebrew binary."
50
49
 
51
50
  property :owner, [String, Integer],
52
51
  description: "The owner of the Homebrew installation.",
@@ -56,14 +55,14 @@ class Chef
56
55
  action :install, description: "Install an application that is packaged as a Homebrew cask." do
57
56
  if new_resource.install_cask
58
57
  homebrew_tap "homebrew/cask" do
59
- homebrew_path new_resource.homebrew_path
58
+ homebrew_path homebrew_bin_path(new_resource.homebrew_path)
60
59
  owner new_resource.owner
61
60
  end
62
61
  end
63
62
 
64
63
  unless casked?
65
64
  converge_by("install cask #{new_resource.cask_name} #{new_resource.options}") do
66
- shell_out!("#{new_resource.homebrew_path} install --cask #{new_resource.cask_name} #{new_resource.options}",
65
+ shell_out!("#{homebrew_bin_path(new_resource.homebrew_path)} install --cask #{new_resource.cask_name} #{new_resource.options}",
67
66
  user: new_resource.owner,
68
67
  env: { "HOME" => ::Dir.home(new_resource.owner), "USER" => new_resource.owner },
69
68
  cwd: ::Dir.home(new_resource.owner))
@@ -74,14 +73,14 @@ class Chef
74
73
  action :remove, description: "Remove an application that is packaged as a Homebrew cask." do
75
74
  if new_resource.install_cask
76
75
  homebrew_tap "homebrew/cask" do
77
- homebrew_path new_resource.homebrew_path
76
+ homebrew_path homebrew_bin_path(new_resource.homebrew_path)
78
77
  owner new_resource.owner
79
78
  end
80
79
  end
81
80
 
82
81
  if casked?
83
82
  converge_by("uninstall cask #{new_resource.cask_name}") do
84
- shell_out!("#{new_resource.homebrew_path} uninstall --cask #{new_resource.cask_name}",
83
+ shell_out!("#{homebrew_bin_path(new_resource.homebrew_path)} uninstall --cask #{new_resource.cask_name}",
85
84
  user: new_resource.owner,
86
85
  env: { "HOME" => ::Dir.home(new_resource.owner), "USER" => new_resource.owner },
87
86
  cwd: ::Dir.home(new_resource.owner))
@@ -99,7 +98,7 @@ class Chef
99
98
  # @return [Boolean]
100
99
  def casked?
101
100
  unscoped_name = new_resource.cask_name.split("/").last
102
- shell_out!("#{new_resource.homebrew_path} list --cask 2>/dev/null",
101
+ shell_out!("#{homebrew_bin_path(new_resource.homebrew_path)} list --cask 2>/dev/null",
103
102
  user: new_resource.owner,
104
103
  env: { "HOME" => ::Dir.home(new_resource.owner), "USER" => new_resource.owner },
105
104
  cwd: ::Dir.home(new_resource.owner)).stdout.split.include?(unscoped_name)
@@ -63,7 +63,7 @@ class Chef
63
63
  allowed_actions :install, :upgrade, :remove, :purge
64
64
 
65
65
  property :homebrew_user, [ String, Integer ],
66
- 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.'"
66
+ 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.'"
67
67
 
68
68
  end
69
69
  end
@@ -41,8 +41,7 @@ class Chef
41
41
  description: "The URL of the tap."
42
42
 
43
43
  property :homebrew_path, String,
44
- description: "The path to the Homebrew binary.",
45
- default: "/usr/local/bin/brew"
44
+ description: "The path to the Homebrew binary."
46
45
 
47
46
  property :owner, String,
48
47
  description: "The owner of the Homebrew installation.",
@@ -52,7 +51,7 @@ class Chef
52
51
  action :tap, description: "Add a Homebrew tap." do
53
52
  unless tapped?(new_resource.tap_name)
54
53
  converge_by("tap #{new_resource.tap_name}") do
55
- shell_out!("#{new_resource.homebrew_path} tap #{new_resource.tap_name} #{new_resource.url || ""}",
54
+ shell_out!("#{homebrew_bin_path(new_resource.homebrew_path)} tap #{new_resource.tap_name} #{new_resource.url || ""}",
56
55
  user: new_resource.owner,
57
56
  env: { "HOME" => ::Dir.home(new_resource.owner), "USER" => new_resource.owner },
58
57
  cwd: ::Dir.home(new_resource.owner))
@@ -63,7 +62,7 @@ class Chef
63
62
  action :untap, description: "Remove a Homebrew tap." do
64
63
  if tapped?(new_resource.tap_name)
65
64
  converge_by("untap #{new_resource.tap_name}") do
66
- shell_out!("#{new_resource.homebrew_path} untap #{new_resource.tap_name}",
65
+ shell_out!("#{homebrew_bin_path(new_resource.homebrew_path)} untap #{new_resource.tap_name}",
67
66
  user: new_resource.owner,
68
67
  env: { "HOME" => ::Dir.home(new_resource.owner), "USER" => new_resource.owner },
69
68
  cwd: ::Dir.home(new_resource.owner))
@@ -75,8 +74,9 @@ class Chef
75
74
  #
76
75
  # @return [Boolean]
77
76
  def tapped?(name)
77
+ base_path = ["#{::File.dirname(which("brew"))}/../homebrew", "#{::File.dirname(which("brew"))}/../Homebrew", "/opt/homebrew", "/usr/local/Homebrew", "/home/linuxbrew/.linuxbrew"].uniq.select { |x| Dir.exist?(x) }.first
78
78
  tap_dir = name.gsub("/", "/homebrew-")
79
- ::File.directory?("/usr/local/Homebrew/Library/Taps/#{tap_dir}")
79
+ ::File.directory?("#{base_path}/Library/Taps/#{tap_dir}")
80
80
  end
81
81
  end
82
82
  end
@@ -202,7 +202,11 @@ class Chef
202
202
  description: "The first argument of `execvp`, typically the file name associated with the file to be executed. This value must be specified if `program_arguments` is not specified, and vice-versa."
203
203
 
204
204
  property :program_arguments, Array,
205
- description: "The second argument of `execvp`. If program is not specified, this property must be specified and will be handled as if it were the first argument."
205
+ description: "The second argument of `execvp`. If program is not specified, this property must be specified and will be handled as if it were the first argument.",
206
+ coerce: proc { |args|
207
+ # Cast all values to a string. Launchd only supports string values
208
+ args.map(&:to_s)
209
+ }
206
210
 
207
211
  property :queue_directories, Array,
208
212
  description: "An array of non-empty directories which, if any are modified, will cause a job to be started."
@@ -50,15 +50,17 @@ class Chef
50
50
  end
51
51
  ```
52
52
 
53
- **Specifying the type of a key to skip automatic type detection**
53
+ **Setting a value for specific user and hosts**
54
54
 
55
55
  ```ruby
56
- macos_userdefaults 'Finder expanded save dialogs' do
57
- key 'NSNavPanelExpandedStateForSaveMode'
58
- value 'TRUE'
59
- type 'bool'
56
+ macos_userdefaults 'Enable macOS firewall' do
57
+ key 'globalstate'
58
+ value 1
59
+ user 'jane'
60
+ host :current
60
61
  end
61
62
  ```
63
+
62
64
  DOC
63
65
 
64
66
  property :domain, String,
@@ -79,6 +81,7 @@ class Chef
79
81
 
80
82
  property :host, [String, Symbol],
81
83
  description: "Set either :current, :all or a hostname to set the user default at the host level.",
84
+ default: :all,
82
85
  desired_state: false,
83
86
  introduced: "16.3"
84
87
 
@@ -94,6 +97,7 @@ class Chef
94
97
 
95
98
  property :user, [String, Symbol],
96
99
  description: "The system user that the default will be applied to. Set :current for current user, :all for all users or pass a valid username",
100
+ default: :current,
97
101
  desired_state: false
98
102
 
99
103
  property :sudo, [TrueClass, FalseClass],