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
@@ -311,14 +311,17 @@ describe Chef::Client do
311
311
  describe "eol release warning" do
312
312
  it "warns when running an EOL release" do
313
313
  stub_const("Chef::VERSION", 15)
314
- allow(Time).to receive(:now).and_return(Time.new(2021, 5, 1, 5))
315
- expect(logger).to receive(:warn).with(/This release of.*became end of life \(EOL\) on May 1st 2021/)
314
+ # added a call to client because Time.now gets invoked multiple times during instantiation. Don't mock Time until after client initialized
315
+ client
316
+ expect(Time).to receive(:now).and_return(Time.new(2024, 12, 1, 5))
317
+ allow(client).to receive(:eol_override).and_return(false)
318
+ expect(logger).to receive(:warn).with("This release of Chef Infra Client became end of life (EOL) on Nov 30, 2024. Please update to a supported release to receive new features, bug fixes, and security updates.")
316
319
  client.warn_if_eol
317
320
  end
318
321
 
319
322
  it "does not warn when running an non-EOL release" do
320
323
  stub_const("Chef::VERSION", 15)
321
- allow(Time).to receive(:now).and_return(Time.new(2021, 4, 31))
324
+ allow(Time).to receive(:now).and_return(Time.new(2021, 4, 30))
322
325
  expect(logger).to_not receive(:warn).with(/became end of life/)
323
326
  client.warn_if_eol
324
327
  end
@@ -170,7 +170,7 @@ describe Chef::Compliance::Reporter::ChefServerAutomate do
170
170
  "X-Ops-Userid" => "spec-node",
171
171
  "X-Remote-Request-Id" => /.+/,
172
172
  }
173
- ).to_return(status: 200)
173
+ ).to_return(status: 200, body: "OK")
174
174
 
175
175
  expect(reporter.send_report(inspec_report)).to eq(true)
176
176
 
@@ -170,11 +170,7 @@ describe Chef::Daemon do
170
170
 
171
171
  it "should log an appropriate error message and fail miserably" do
172
172
  allow(Process).to receive(:initgroups).and_raise(Errno::EPERM)
173
- error = "Operation not permitted"
174
- if RUBY_PLATFORM.match("solaris2") || RUBY_PLATFORM.match("aix")
175
- error = "Not owner"
176
- end
177
- expect(Chef::Application).to receive(:fatal!).with("Permission denied when trying to change 999:999 to 501:20. #{error}")
173
+ expect(Chef::Application).to receive(:fatal!).with(/Permission denied when trying to change 999:999 to 501:20/)
178
174
  Chef::Daemon._change_privilege(testuser)
179
175
  end
180
176
  end
@@ -17,11 +17,14 @@
17
17
  #
18
18
 
19
19
  require "spec_helper"
20
+ require "chef/exceptions"
20
21
  require "chef/dsl/secret"
21
22
  require "chef/secret_fetcher/base"
23
+
22
24
  class SecretDSLTester
23
25
  include Chef::DSL::Secret
24
- # Because DSL is invoked in the context of a recipe,
26
+
27
+ # Because DSL is invoked in the context of a recipe or attribute file
25
28
  # we expect run_context to always be available when SecretFetcher::Base
26
29
  # requests it - making it safe to mock here
27
30
  def run_context
@@ -37,35 +40,136 @@ end
37
40
 
38
41
  describe Chef::DSL::Secret do
39
42
  let(:dsl) { SecretDSLTester.new }
40
- it "responds to 'secret'" do
41
- expect(dsl.respond_to?(:secret)).to eq true
43
+ let(:run_context) { Chef::RunContext.new(Chef::Node.new, {}, Chef::EventDispatch::Dispatcher.new) }
44
+
45
+ before do
46
+ allow(dsl).to receive(:run_context).and_return(run_context)
42
47
  end
43
48
 
44
- it "uses SecretFetcher.for_service to find the fetcher" do
45
- substitute_fetcher = SecretFetcherImpl.new({}, nil)
46
- expect(Chef::SecretFetcher).to receive(:for_service).with(:example, {}, nil).and_return(substitute_fetcher)
47
- expect(substitute_fetcher).to receive(:fetch).with("key1", nil)
48
- dsl.secret(name: "key1", service: :example, config: {})
49
+ %w{
50
+ secret
51
+ default_secret_service
52
+ default_secret_config
53
+ with_secret_service
54
+ with_secret_config
55
+ }.each do |m|
56
+ it "responds to ##{m}" do
57
+ expect(dsl.respond_to?(m)).to eq true
58
+ end
59
+ end
60
+
61
+ describe "#default_secret_service" do
62
+ let(:service) { :hashi_vault }
63
+
64
+ it "persists the service passed in as an argument" do
65
+ expect(dsl.default_secret_service).to eq(nil)
66
+ dsl.default_secret_service(service)
67
+ expect(dsl.default_secret_service).to eq(service)
68
+ end
69
+
70
+ it "returns run_context.default_secret_service value when no argument is given" do
71
+ run_context.default_secret_service = :my_thing
72
+ expect(dsl.default_secret_service).to eq(:my_thing)
73
+ end
74
+
75
+ it "raises exception when service given is not valid" do
76
+ stub_const("Chef::SecretFetcher::SECRET_FETCHERS", %i{service_a service_b})
77
+ expect { dsl.default_secret_service(:unknown_service) }.to raise_error(Chef::Exceptions::Secret::InvalidFetcherService)
78
+ end
49
79
  end
50
80
 
51
- it "resolves a secret when using the example fetcher" do
52
- secret_value = dsl.secret(name: "test1", service: :example, config: { "test1" => "secret value" })
53
- expect(secret_value).to eq "secret value"
81
+ describe "#with_secret_config" do
82
+ let(:service) { :hashi_vault }
83
+
84
+ it "sets the service for the scope of the block only" do
85
+ expect(dsl.default_secret_service).to eq(nil)
86
+ dsl.with_secret_service(service) do
87
+ expect(dsl.default_secret_service).to eq(service)
88
+ end
89
+ expect(dsl.default_secret_service).to eq(nil)
90
+ end
91
+
92
+ it "raises exception when block is not given" do
93
+ expect { dsl.with_secret_service(service) }.to raise_error(ArgumentError)
94
+ end
54
95
  end
55
96
 
56
- context "when used within a resource" do
57
- let(:run_context) {
58
- Chef::RunContext.new(Chef::Node.new,
59
- Chef::CookbookCollection.new(Chef::CookbookLoader.new(File.join(CHEF_SPEC_DATA, "cookbooks"))),
60
- Chef::EventDispatch::Dispatcher.new)
61
- }
62
-
63
- it "marks that resource as 'sensitive'" do
64
- recipe = Chef::Recipe.new("secrets", "test", run_context)
65
- recipe.zen_master "secret_test" do
66
- peace secret(name: "test1", service: :example, config: { "test1" => true })
97
+ describe "#default_secret_config" do
98
+ let(:config) { { my_key: "value" } }
99
+
100
+ it "persists the config passed in as argument" do
101
+ expect(dsl.default_secret_config).to eq({})
102
+ dsl.default_secret_config(**config)
103
+ expect(dsl.default_secret_config).to eq(config)
104
+ end
105
+
106
+ it "returns run_context.default_secret_config value when no argument is given" do
107
+ run_context.default_secret_config = { my_thing: "that" }
108
+ expect(dsl.default_secret_config).to eq({ my_thing: "that" })
109
+ end
110
+ end
111
+
112
+ describe "#with_secret_config" do
113
+ let(:config) { { my_key: "value" } }
114
+
115
+ it "sets the config for the scope of the block only" do
116
+ expect(dsl.default_secret_config).to eq({})
117
+ dsl.with_secret_config(**config) do
118
+ expect(dsl.default_secret_config).to eq(config)
67
119
  end
68
- expect(run_context.resource_collection.lookup("zen_master[secret_test]").sensitive).to eql(true)
120
+ expect(dsl.default_secret_config).to eq({})
121
+ end
122
+
123
+ it "raises exception when block is not given" do
124
+ expect { dsl.with_secret_config(**config) }.to raise_error(ArgumentError)
125
+ end
126
+ end
127
+
128
+ describe "#secret" do
129
+ it "uses SecretFetcher.for_service to find the fetcher" do
130
+ substitute_fetcher = SecretFetcherImpl.new({}, nil)
131
+ expect(Chef::SecretFetcher).to receive(:for_service).with(:example, {}, run_context).and_return(substitute_fetcher)
132
+ expect(substitute_fetcher).to receive(:fetch).with("key1", nil)
133
+ dsl.secret(name: "key1", service: :example, config: {})
134
+ end
135
+
136
+ it "resolves a secret when using the example fetcher" do
137
+ secret_value = dsl.secret(name: "test1", service: :example, config: { "test1" => "secret value" })
138
+ expect(secret_value).to eq "secret value"
139
+ end
140
+
141
+ context "when used within a resource" do
142
+ let(:run_context) {
143
+ Chef::RunContext.new(Chef::Node.new,
144
+ Chef::CookbookCollection.new(Chef::CookbookLoader.new(File.join(CHEF_SPEC_DATA, "cookbooks"))),
145
+ Chef::EventDispatch::Dispatcher.new)
146
+ }
147
+
148
+ it "marks that resource as 'sensitive'" do
149
+ recipe = Chef::Recipe.new("secrets", "test", run_context)
150
+ recipe.zen_master "secret_test" do
151
+ peace secret(name: "test1", service: :example, config: { "test1" => true })
152
+ end
153
+ expect(run_context.resource_collection.lookup("zen_master[secret_test]").sensitive).to eql(true)
154
+ end
155
+ end
156
+
157
+ it "passes default service to SecretFetcher.for_service" do
158
+ service = :example
159
+ dsl.default_secret_service(service)
160
+ substitute_fetcher = SecretFetcherImpl.new({}, nil)
161
+ expect(Chef::SecretFetcher).to receive(:for_service).with(service, {}, run_context).and_return(substitute_fetcher)
162
+ allow(substitute_fetcher).to receive(:fetch).with("key1", nil)
163
+ dsl.secret(name: "key1")
164
+ end
165
+
166
+ it "passes default config to SecretFetcher.for_service" do
167
+ config = { my_config: "value" }
168
+ dsl.default_secret_config(**config)
169
+ substitute_fetcher = SecretFetcherImpl.new({}, nil)
170
+ expect(Chef::SecretFetcher).to receive(:for_service).with(:example, config, run_context).and_return(substitute_fetcher)
171
+ allow(substitute_fetcher).to receive(:fetch).with("key1", nil)
172
+ dsl.secret(name: "key1", service: :example)
69
173
  end
70
174
  end
71
175
  end
@@ -51,4 +51,32 @@ describe Chef::Mixin::Checksum do
51
51
  end
52
52
  end
53
53
 
54
+ describe "checksum_match?" do
55
+ context "when checksum cases match" do
56
+ it "returns true" do
57
+ expect(@checksum_user.checksum_match?("u7ghbxikk3i9blsimmy2y2ionmxx", "u7ghbxikk3i9blsimmy2y2ionmxx")).to be true
58
+ end
59
+ end
60
+
61
+ context "when one checksum is uppercase and other is lowercase" do
62
+ it "returns true" do
63
+ expect(@checksum_user.checksum_match?("U7GHBXIKK3I9BLSIMMY2Y2IONMXX", "u7ghbxikk3i9blsimmy2y2ionmxx")).to be true
64
+ end
65
+ end
66
+
67
+ context "when checksums do not match" do
68
+ it "returns false" do
69
+ expect(@checksum_user.checksum_match?("u7ghbxikk3i9blsimmy2y2ionmxx", "09ee9c8cc70501763563bcf9c218")).to be false
70
+ end
71
+ end
72
+
73
+ context "when checksum is nil" do
74
+ it "returns false" do
75
+ expect(@checksum_user.checksum_match?("u7ghbxikk3i9blsimmy2y2ionmxx", nil)).to be false
76
+ expect(@checksum_user.checksum_match?(nil, "09ee9c8cc70501763563bcf9c218")).to be false
77
+ expect(@checksum_user.checksum_match?(nil, nil)).to be false
78
+ end
79
+ end
80
+ end
81
+
54
82
  end
@@ -47,6 +47,8 @@ describe Chef::Mixin::HomebrewUser do
47
47
  let(:user) { nil }
48
48
  let(:brew_owner) { 2001 }
49
49
  let(:default_brew_path) { "/usr/local/bin/brew" }
50
+ let(:default_brew_path_arm) { "/opt/homebrew/bin/brew" }
51
+ let(:default_brew_path_linux) { "/home/linuxbrew/.linuxbrew/bin/brew" }
50
52
  let(:stat_double) do
51
53
  d = double
52
54
  expect(d).to receive(:uid).and_return(brew_owner)
@@ -59,16 +61,38 @@ describe Chef::Mixin::HomebrewUser do
59
61
  expect(Etc).to receive(:getpwuid).with(brew_owner).and_return(OpenStruct.new(name: "name"))
60
62
  end
61
63
 
62
- it "returns the owner of the brew executable when it is at a default location" do
63
- expect(File).to receive(:exist?).with(default_brew_path).and_return(true)
64
- expect(File).to receive(:stat).with(default_brew_path).and_return(stat_double)
64
+ def false_unless_specific_value(object, method, value)
65
+ allow(object).to receive(method).and_return(false)
66
+ allow(object).to receive(method).with(value).and_return(true)
67
+ end
68
+
69
+ it "returns the owner of the brew executable when it is at a default location for x86_64 machines" do
70
+ false_unless_specific_value(File, :exist?, default_brew_path)
71
+ false_unless_specific_value(File, :executable?, default_brew_path)
72
+ allow(File).to receive(:stat).with(default_brew_path).and_return(stat_double)
73
+ expect(homebrew_user.find_homebrew_uid(user)).to eq(brew_owner)
74
+ end
75
+
76
+ it "returns the owner of the brew executable when it is at a default location for arm machines" do
77
+ false_unless_specific_value(File, :exist?, default_brew_path_arm)
78
+ false_unless_specific_value(File, :executable?, default_brew_path_arm)
79
+ allow(File).to receive(:stat).with(default_brew_path_arm).and_return(stat_double)
80
+ expect(homebrew_user.find_homebrew_uid(user)).to eq(brew_owner)
81
+ end
82
+
83
+ it "returns the owner of the brew executable when it is at a default location for linux machines" do
84
+ false_unless_specific_value(File, :exist?, default_brew_path_linux)
85
+ false_unless_specific_value(File, :executable?, default_brew_path_linux)
86
+ allow(File).to receive(:stat).with(default_brew_path_linux).and_return(stat_double)
65
87
  expect(homebrew_user.find_homebrew_uid(user)).to eq(brew_owner)
66
88
  end
67
89
 
68
90
  it "returns the owner of the brew executable when it is not at a default location" do
69
- expect(File).to receive(:exist?).with(default_brew_path).and_return(false)
91
+ allow_any_instance_of(ExampleHomebrewUser).to receive(:which).and_return("/foo")
92
+ false_unless_specific_value(File, :exist?, "/foo")
93
+ false_unless_specific_value(File, :executable?, "/foo")
70
94
  allow(homebrew_user).to receive_message_chain(:shell_out, :stdout, :strip).and_return("/foo")
71
- expect(File).to receive(:stat).with("/foo").and_return(stat_double)
95
+ allow(File).to receive(:stat).with("/foo").and_return(stat_double)
72
96
  expect(homebrew_user.find_homebrew_uid(user)).to eq(brew_owner)
73
97
  end
74
98
 
@@ -78,8 +102,7 @@ describe Chef::Mixin::HomebrewUser do
78
102
  describe "when the homebrew user is not provided" do
79
103
 
80
104
  it "raises an error if no executable is found" do
81
- expect(File).to receive(:exist?).with(default_brew_path).and_return(false)
82
- allow(homebrew_user).to receive_message_chain(:shell_out, :stdout, :strip).and_return("")
105
+ expect(File).to receive(:exist?).and_return(nil).at_least(:once)
83
106
  expect { homebrew_user.find_homebrew_uid(user) }.to raise_error(Chef::Exceptions::CannotDetermineHomebrewOwner)
84
107
  end
85
108
 
@@ -49,6 +49,10 @@ describe Chef::Provider::Package::Chocolatey, :windows_only do
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
50
  end
51
51
 
52
+ after(:each) do
53
+ described_class.instance_variable_set(:@get_choco_version, nil)
54
+ end
55
+
52
56
  def allow_remote_list(package_names, args = nil)
53
57
  remote_list_stdout = <<~EOF
54
58
  Chocolatey v0.9.9.11
@@ -61,9 +65,9 @@ describe Chef::Provider::Package::Chocolatey, :windows_only do
61
65
  remote_list_obj = double(stdout: remote_list_stdout)
62
66
  package_names.each do |pkg|
63
67
  if args
64
- allow(provider).to receive(:shell_out_compacted!).with(choco_exe, "list", "-r", pkg, *args, { returns: [0, 2], timeout: timeout }).and_return(remote_list_obj)
68
+ allow(provider).to receive(:shell_out_compacted!).with(choco_exe, described_class.query_command, "-r", pkg, *args, { returns: [0, 2], timeout: timeout }).and_return(remote_list_obj)
65
69
  else
66
- allow(provider).to receive(:shell_out_compacted!).with(choco_exe, "list", "-r", pkg, { returns: [0, 2], timeout: timeout }).and_return(remote_list_obj)
70
+ allow(provider).to receive(:shell_out_compacted!).with(choco_exe, described_class.query_command, "-r", pkg, { returns: [0, 2], timeout: timeout }).and_return(remote_list_obj)
67
71
  end
68
72
  end
69
73
  end
@@ -78,6 +82,18 @@ describe Chef::Provider::Package::Chocolatey, :windows_only do
78
82
  end
79
83
  end
80
84
 
85
+ describe "choco searches change with the version" do
86
+ it "Choco V1 uses List" do
87
+ allow(described_class).to receive(:get_choco_version).and_return("1.4.0")
88
+ expect(provider.query_command).to eql("list")
89
+ end
90
+
91
+ it "Choco V2 uses Search" do
92
+ allow(described_class).to receive(:get_choco_version).and_return("2.1.0")
93
+ expect(provider.query_command).to eql("search")
94
+ end
95
+ end
96
+
81
97
  describe "#candidate_version" do
82
98
  it "should set the candidate_version to the latest version when not pinning" do
83
99
  allow_remote_list(["git"])
@@ -150,7 +166,7 @@ describe Chef::Provider::Package::Chocolatey, :windows_only do
150
166
  new_resource.package_name("package-does-not-exist")
151
167
  new_resource.returns([0])
152
168
  allow(provider).to receive(:shell_out_compacted!)
153
- .with(choco_exe, "list", "-r", new_resource.package_name.first, { returns: new_resource.returns, timeout: timeout })
169
+ .with(choco_exe, described_class.query_command, "-r", new_resource.package_name.first, { returns: new_resource.returns, timeout: timeout })
154
170
  .and_raise(Mixlib::ShellOut::ShellCommandFailed, "Expected process to exit with [0], but received '2'")
155
171
  expect { provider.send(:available_packages) }.to raise_error(Mixlib::ShellOut::ShellCommandFailed, "Expected process to exit with [0], but received '2'")
156
172
  end
@@ -143,7 +143,7 @@ describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do
143
143
  .to_return(status: 200, body: File.binread(File.join(CHEF_SPEC_DATA, "rubygems.org", "sexp_processor-4.15.1.gemspec.rz")))
144
144
 
145
145
  dep = Gem::Dependency.new("sexp_processor", ">= 0")
146
- expect(@gem_env.candidate_version_from_remote(dep, "https://rubygems2.org")).to be_kind_of(Gem::Version)
146
+ expect(@gem_env.candidate_version_from_remote(dep, "https://rubygems2.org")).to be_nil
147
147
  end
148
148
  end
149
149
 
@@ -70,4 +70,59 @@ describe Chef::Provider::User::Linux do
70
70
  expect( provider.useradd_options ).to eql(["-m"])
71
71
  end
72
72
  end
73
+
74
+ describe "compare_user_linux" do
75
+ before(:each) do
76
+ @new_resource = Chef::Resource::User::LinuxUser.new("notarealuser")
77
+ @current_resource = Chef::Resource::User::LinuxUser.new("notarealuser")
78
+ end
79
+
80
+ let(:mapping) do
81
+ {
82
+ "username" => %w{notarealuser notarealuser},
83
+ "comment" => ["Nota Realuser", "Not a Realuser"],
84
+ "uid" => [1000, 1001],
85
+ "gid" => [1000, 1001],
86
+ "home" => ["/home/notarealuser", "/Users/notarealuser"],
87
+ "shell" => ["/usr/bin/zsh", "/bin/bash"],
88
+ "password" => %w{abcd 12345},
89
+ "sensitive" => [true],
90
+ }
91
+ end
92
+
93
+ %w{uid gid comment home shell password}.each do |property|
94
+ it "should return true if #{property} doesn't match" do
95
+ @new_resource.send(property, mapping[property][0])
96
+ @current_resource.send(property, mapping[property][1])
97
+ expect(provider.compare_user).to eql(true)
98
+ end
99
+ end
100
+
101
+ it "should show a blank for password if sensitive set to true" do
102
+ @new_resource.password mapping["password"][0]
103
+ @current_resource.password mapping["password"][1]
104
+ @new_resource.sensitive true
105
+ @current_resource.sensitive true
106
+ provider.compare_user
107
+ expect(provider.change_desc).to eql(["change password from ******** to ********"])
108
+ end
109
+
110
+ %w{uid gid}.each do |property|
111
+ it "should return false if string #{property} matches fixnum" do
112
+ @new_resource.send(property, "100")
113
+ @current_resource.send(property, 100)
114
+ expect(provider.compare_user).to eql(false)
115
+ end
116
+ end
117
+
118
+ it "should return false if the objects are identical" do
119
+ expect(provider.compare_user).to eql(false)
120
+ end
121
+
122
+ it "should ignore differences in trailing slash in home paths" do
123
+ @new_resource.home "/home/notarealuser"
124
+ @current_resource.home "/home/notarealuser/"
125
+ expect(provider.compare_user).to eql(false)
126
+ end
127
+ end
73
128
  end
@@ -134,4 +134,12 @@ describe Chef::Resource::ChefClientConfig do
134
134
  expect(provider.format_handler([{ "class" => "Foo", "arguments" => ["'one'", "two", "three"] }])).to eql(["Foo.new('one',two,three)"])
135
135
  end
136
136
  end
137
+
138
+ describe "rubygems_url property" do
139
+ it "accepts nil, a single URL, or an array of URLs" do
140
+ expect { resource.rubygems_url(nil) }.not_to raise_error
141
+ expect { resource.rubygems_url("https://rubygems.internal.example.com") }.not_to raise_error
142
+ expect { resource.rubygems_url(["https://rubygems.east.example.com", "https://rubygems.west.example.com"]) }.not_to raise_error
143
+ end
144
+ end
137
145
  end
@@ -102,7 +102,7 @@ describe Chef::Resource::ChefClientSystemdTimer do
102
102
 
103
103
  it "sets CPUQuota if cpu_quota property is set" do
104
104
  resource.cpu_quota 50
105
- expect(provider.service_content["Service"]["CPUQuota"]).to eq(50)
105
+ expect(provider.service_content["Service"]["CPUQuota"]).to eq("50%")
106
106
  end
107
107
  end
108
108
  end
@@ -39,12 +39,12 @@ describe Chef::Resource::MacosUserDefaults, :macos_only do
39
39
  expect(resource.domain).to eq("NSGlobalDomain")
40
40
  end
41
41
 
42
- it "nil for the host property" do
43
- expect(resource.host).to be_nil
42
+ it ":all for the host property" do
43
+ expect(resource.host).to eq(:all)
44
44
  end
45
45
 
46
- it "nil for the user property" do
47
- expect(resource.user).to be_nil
46
+ it ":current for the user property" do
47
+ expect(resource.user).to eq(:current)
48
48
  end
49
49
 
50
50
  it ":write for resource action" do
@@ -371,6 +371,9 @@ describe Chef::Resource do
371
371
  end
372
372
 
373
373
  describe "to_text" do
374
+
375
+ let(:sensitive_property_masked_value) { "sensitive value suppressed" }
376
+
374
377
  it "prints nice message" do
375
378
  resource_class = Class.new(Chef::Resource) { property :foo, String }
376
379
  resource = resource_class.new("sensitive_property_tests")
@@ -383,7 +386,25 @@ describe Chef::Resource do
383
386
  resource_class = Class.new(Chef::Resource) { property :foo, String, sensitive: true }
384
387
  resource = resource_class.new("sensitive_property_tests")
385
388
  resource.foo = "some value"
386
- expect(resource.to_text).to match(/foo "\*sensitive value suppressed\*"/)
389
+ expect(resource.to_text).to match(/foo "\*#{sensitive_property_masked_value}\*"/)
390
+ end
391
+
392
+ it "suppresses that properties value irrespective of desired state (false) " do
393
+ resource_class = Class.new(Chef::Resource) {
394
+ property :suppressed_content, String, sensitive: true, desired_state: false
395
+ }
396
+ resource = resource_class.new("desired_state_property_tests")
397
+ resource.suppressed_content = "some value"
398
+ expect(resource.to_text).to match(/suppressed_content "\*#{sensitive_property_masked_value}\*"/)
399
+ end
400
+
401
+ it "suppresses that properties value irrespective of desired state (true) " do
402
+ resource_class = Class.new(Chef::Resource) {
403
+ property :desired_state_content, String, sensitive: true, desired_state: true
404
+ }
405
+ resource = resource_class.new("desired_state_property_tests")
406
+ resource.desired_state_content = "some value"
407
+ expect(resource.to_text).to match(/desired_state_content "\*#{sensitive_property_masked_value}\*"/)
387
408
  end
388
409
  end
389
410
 
@@ -53,6 +53,22 @@ describe Chef::RunContext do
53
53
  expect(run_context.node).to eq(node)
54
54
  end
55
55
 
56
+ it "responds to #default_secret_service" do
57
+ expect(run_context).to respond_to(:default_secret_service)
58
+ end
59
+
60
+ it "responds to #default_secret_config" do
61
+ expect(run_context).to respond_to(:default_secret_config)
62
+ end
63
+
64
+ it "#default_secret_service defaults to nil" do
65
+ expect(run_context.default_secret_service).to eq(nil)
66
+ end
67
+
68
+ it "#default_secret_config defaults to {}" do
69
+ expect(run_context.default_secret_config).to eq({})
70
+ end
71
+
56
72
  it "loads up node[:cookbooks]" do
57
73
  expect(run_context.node[:cookbooks]).to eql(
58
74
  {