chef 17.10.68-universal-mingw32 → 17.10.95-universal-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/chef-universal-mingw32.gemspec +2 -2
- data/chef.gemspec +1 -1
- data/lib/chef/mixin/properties.rb +6 -0
- data/lib/chef/provider/package/chocolatey.rb +18 -1
- data/lib/chef/provider/user.rb +5 -1
- data/lib/chef/resource/locale.rb +5 -2
- data/lib/chef/resource/macos_userdefaults.rb +9 -5
- data/lib/chef/resource.rb +2 -1
- data/lib/chef/version.rb +1 -1
- data/spec/data/trusted_certs/example.crt +29 -20
- data/spec/data/trusted_certs/example_no_cn.crt +30 -34
- data/spec/functional/resource/chocolatey_package_spec.rb +32 -20
- data/spec/functional/resource/macos_userdefaults_spec.rb +4 -4
- data/spec/functional/resource/yum_package_spec.rb +1 -1
- data/spec/unit/compliance/reporter/chef_server_automate_spec.rb +1 -1
- data/spec/unit/provider/package/chocolatey_spec.rb +19 -3
- data/spec/unit/provider/user/linux_spec.rb +55 -0
- data/spec/unit/resource/macos_user_defaults_spec.rb +4 -4
- data/spec/unit/resource_spec.rb +22 -1
- metadata +35 -35
- /data/spec/functional/assets/chocolatey_feed/{test-A.1.0.nupkg → test-A.1.0.0.nupkg} +0 -0
- /data/spec/functional/assets/chocolatey_feed/{test-A.1.5.nupkg → test-A.1.5.0.nupkg} +0 -0
- /data/spec/functional/assets/chocolatey_feed/{test-A.2.0.nupkg → test-A.2.0.0.nupkg} +0 -0
- /data/spec/functional/assets/chocolatey_feed/{test-B.1.0.nupkg → test-B.1.0.0.nupkg} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2cef379375db57951a202d81e9ea1292682d53dc37a798c7bb1d3112a4da5f24
|
4
|
+
data.tar.gz: 3f8b9c412863cf00b7c1c570b577580c5bd2533de6e0d5a3ad0c85e5888907db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fca6c017424272808c6aa5742be4dc51a908880579323cd00f8969b74698110d8761415ba7f0fa2c939d8f3ee06181d0c1432b0fd9e8abbcc02b273f7ecc3df6
|
7
|
+
data.tar.gz: d5f4dca147e35a6440f5ea461e910caab7be6680e5d3de52031a5fb785679361ce2a7971ff14126478425f7b1d5848c3aac187605a11f15e7a19a8aa9a3ca55c
|
@@ -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.14"
|
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
@@ -38,7 +38,7 @@ Gem::Specification.new do |s|
|
|
38
38
|
s.add_dependency "ohai", "~> 17.0"
|
39
39
|
s.add_dependency "inspec-core", ">= 4.23"
|
40
40
|
|
41
|
-
s.add_dependency "ffi", "
|
41
|
+
s.add_dependency "ffi", "~> 1.15.0"
|
42
42
|
s.add_dependency "ffi-yajl", "~> 2.2"
|
43
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
|
@@ -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
|
@@ -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 = [
|
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]
|
data/lib/chef/provider/user.rb
CHANGED
@@ -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
|
-
|
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
|
|
data/lib/chef/resource/locale.rb
CHANGED
@@ -113,8 +113,11 @@ class Chef
|
|
113
113
|
end
|
114
114
|
|
115
115
|
requirements.assert(:all_actions) do |a|
|
116
|
-
|
117
|
-
|
116
|
+
a.assertion do
|
117
|
+
# RHEL/CentOS type platforms don't have locale-gen
|
118
|
+
# Windows has locale-gen as part of the install, but not in the path
|
119
|
+
which("locale-gen") || windows?
|
120
|
+
end
|
118
121
|
a.failure_message(Chef::Exceptions::ProviderNotFound, "The locale resource requires the locale-gen tool")
|
119
122
|
end
|
120
123
|
end
|
@@ -51,15 +51,17 @@ class Chef
|
|
51
51
|
end
|
52
52
|
```
|
53
53
|
|
54
|
-
**
|
54
|
+
**Setting a value for specific user and hosts**
|
55
55
|
|
56
56
|
```ruby
|
57
|
-
macos_userdefaults '
|
58
|
-
key '
|
59
|
-
value
|
60
|
-
|
57
|
+
macos_userdefaults 'Enable macOS firewall' do
|
58
|
+
key 'globalstate'
|
59
|
+
value 1
|
60
|
+
user 'jane'
|
61
|
+
host :current
|
61
62
|
end
|
62
63
|
```
|
64
|
+
|
63
65
|
DOC
|
64
66
|
|
65
67
|
property :domain, String,
|
@@ -80,6 +82,7 @@ class Chef
|
|
80
82
|
|
81
83
|
property :host, [String, Symbol],
|
82
84
|
description: "Set either :current, :all or a hostname to set the user default at the host level.",
|
85
|
+
default: :all,
|
83
86
|
desired_state: false,
|
84
87
|
introduced: "16.3"
|
85
88
|
|
@@ -95,6 +98,7 @@ class Chef
|
|
95
98
|
|
96
99
|
property :user, [String, Symbol],
|
97
100
|
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",
|
101
|
+
default: :current,
|
98
102
|
desired_state: false
|
99
103
|
|
100
104
|
property :sudo, [TrueClass, FalseClass],
|
data/lib/chef/resource.rb
CHANGED
@@ -660,7 +660,8 @@ class Chef
|
|
660
660
|
text << "#{resource_name}(\"#{name}\") do\n"
|
661
661
|
|
662
662
|
all_props = {}
|
663
|
-
|
663
|
+
|
664
|
+
self.class.sensitive_properties.map do |p|
|
664
665
|
|
665
666
|
all_props[p.name.to_s] = p.sensitive? ? '"*sensitive value suppressed*"' : value_to_text(p.get(self))
|
666
667
|
rescue Chef::Exceptions::ValidationFailed
|
data/lib/chef/version.rb
CHANGED
@@ -1,22 +1,31 @@
|
|
1
1
|
-----BEGIN CERTIFICATE-----
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
/
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
2
|
+
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
|
30
|
+
qA==
|
22
31
|
-----END CERTIFICATE-----
|
@@ -1,36 +1,32 @@
|
|
1
1
|
-----BEGIN CERTIFICATE-----
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
wRSvwk/VHifYPxJ54RRB51ebYjmD1j41tRseHdFq21qpXSvr9DFLUJBvdN9zA/6t
|
33
|
-
xCBlXAdYxD0n0/bruUYNoXBeMhLp+WKSAQvTlVIyqoNQCo1OBBzBVNg9otl3jw5d
|
34
|
-
1QOhodRqmS5UQAJptuXtk8WN8OZqMCCeogIfdpa5tJG+/fxFML9EvqedS4c05Wf/
|
35
|
-
oYdVLVWSjyoA2l4Xb4LdexAgCg==
|
2
|
+
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
|
36
32
|
-----END CERTIFICATE-----
|
@@ -22,8 +22,16 @@ describe Chef::Resource::ChocolateyPackage, :windows_only, :choco_installed do
|
|
22
22
|
include Chef::Mixin::ShellOut
|
23
23
|
|
24
24
|
let(:package_name) { "test-A" }
|
25
|
-
let(:package_list) { proc { shell_out!("choco list -lo -r #{Array(package_name).join(" ")}").stdout.chomp } }
|
26
25
|
let(:package_source) { File.join(CHEF_SPEC_ASSETS, "chocolatey_feed") }
|
26
|
+
let(:package_list) do
|
27
|
+
if Chef::Provider::Package::Chocolatey.query_command == "list"
|
28
|
+
# using result of query_command because that indicates which "search" command to use
|
29
|
+
# which coincides with the package list output
|
30
|
+
proc { shell_out!("choco search -lo #{Array(package_name).join(" ")}").stdout.chomp }
|
31
|
+
else
|
32
|
+
proc { shell_out!("choco list #{Array(package_name).join(" ")}").stdout.chomp }
|
33
|
+
end
|
34
|
+
end
|
27
35
|
|
28
36
|
let(:run_context) do
|
29
37
|
Chef::RunContext.new(Chef::Node.new, {}, Chef::EventDispatch::Dispatcher.new)
|
@@ -54,12 +62,16 @@ describe Chef::Resource::ChocolateyPackage, :windows_only, :choco_installed do
|
|
54
62
|
ENV["Path"] = ENV.delete("Path")
|
55
63
|
end
|
56
64
|
|
65
|
+
after(:each) do
|
66
|
+
described_class.instance_variable_set(:@get_choco_version, nil)
|
67
|
+
end
|
68
|
+
|
57
69
|
context "installing a package" do
|
58
70
|
after { remove_package }
|
59
71
|
|
60
72
|
it "installs the latest version" do
|
61
73
|
subject.run_action(:install)
|
62
|
-
expect(package_list.call).to
|
74
|
+
expect(package_list.call).to match(/^#{package_name}|2.0.0$/)
|
63
75
|
end
|
64
76
|
|
65
77
|
it "does not install if already installed" do
|
@@ -69,19 +81,19 @@ describe Chef::Resource::ChocolateyPackage, :windows_only, :choco_installed do
|
|
69
81
|
end
|
70
82
|
|
71
83
|
it "installs version given" do
|
72
|
-
subject.version "1.0"
|
84
|
+
subject.version "1.0.0"
|
73
85
|
subject.run_action(:install)
|
74
|
-
expect(package_list.call).to
|
86
|
+
expect(package_list.call).to match(/^#{package_name}|1.0.0$/)
|
75
87
|
end
|
76
88
|
|
77
89
|
it "installs new version if one is already installed" do
|
78
|
-
subject.version "1.0"
|
90
|
+
subject.version "1.0.0"
|
79
91
|
subject.run_action(:install)
|
80
|
-
expect(package_list.call).to
|
92
|
+
expect(package_list.call).to match(/^#{package_name}|1.0.0$/)
|
81
93
|
|
82
|
-
subject.version "2.0"
|
94
|
+
subject.version "2.0.0"
|
83
95
|
subject.run_action(:install)
|
84
|
-
expect(package_list.call).to
|
96
|
+
expect(package_list.call).to match(/^#{package_name}|2.0.0$/)
|
85
97
|
end
|
86
98
|
|
87
99
|
context "installing multiple packages" do
|
@@ -89,7 +101,7 @@ describe Chef::Resource::ChocolateyPackage, :windows_only, :choco_installed do
|
|
89
101
|
|
90
102
|
it "installs both packages" do
|
91
103
|
subject.run_action(:install)
|
92
|
-
expect(package_list.call).to
|
104
|
+
expect(package_list.call).to match(/^test-A|2.0.0\r\ntest-B|1.0.0$/)
|
93
105
|
end
|
94
106
|
end
|
95
107
|
|
@@ -101,13 +113,13 @@ describe Chef::Resource::ChocolateyPackage, :windows_only, :choco_installed do
|
|
101
113
|
it "installs with an option as a string" do
|
102
114
|
subject.options "--force --confirm"
|
103
115
|
subject.run_action(:install)
|
104
|
-
expect(package_list.call).to
|
116
|
+
expect(package_list.call).to match(/^#{package_name}|2.0.0$/)
|
105
117
|
end
|
106
118
|
|
107
119
|
it "installs with multiple options as a string" do
|
108
120
|
subject.options "--force --confirm"
|
109
121
|
subject.run_action(:install)
|
110
|
-
expect(package_list.call).to
|
122
|
+
expect(package_list.call).to match(/^#{package_name}|2.0.0$/)
|
111
123
|
end
|
112
124
|
|
113
125
|
context "when multiple options passed as string" do
|
@@ -137,7 +149,7 @@ describe Chef::Resource::ChocolateyPackage, :windows_only, :choco_installed do
|
|
137
149
|
it "installs with multiple options as an array" do
|
138
150
|
subject.options [ "--force", "--confirm" ]
|
139
151
|
subject.run_action(:install)
|
140
|
-
expect(package_list.call).to
|
152
|
+
expect(package_list.call).to match(/^#{package_name}|2.0.0$/)
|
141
153
|
end
|
142
154
|
end
|
143
155
|
|
@@ -145,24 +157,24 @@ describe Chef::Resource::ChocolateyPackage, :windows_only, :choco_installed do
|
|
145
157
|
after { remove_package }
|
146
158
|
|
147
159
|
it "upgrades to a specific version" do
|
148
|
-
subject.version "1.0"
|
160
|
+
subject.version "1.0.0"
|
149
161
|
subject.run_action(:install)
|
150
|
-
expect(package_list.call).to
|
162
|
+
expect(package_list.call).to match(/^#{package_name}|1.0.0$/)
|
151
163
|
|
152
|
-
subject.version "1.5"
|
164
|
+
subject.version "1.5.0"
|
153
165
|
subject.run_action(:upgrade)
|
154
|
-
expect(package_list.call).to
|
166
|
+
expect(package_list.call).to match(/^#{package_name}|1.5.0$/)
|
155
167
|
end
|
156
168
|
|
157
169
|
it "upgrades to the latest version if no version given" do
|
158
|
-
subject.version "1.0"
|
170
|
+
subject.version "1.0.0"
|
159
171
|
subject.run_action(:install)
|
160
|
-
expect(package_list.call).to
|
172
|
+
expect(package_list.call).to match(/^#{package_name}|1.0.0$/)
|
161
173
|
|
162
174
|
subject2 = Chef::Resource::ChocolateyPackage.new("test-A", run_context)
|
163
175
|
subject2.source package_source
|
164
176
|
subject2.run_action(:upgrade)
|
165
|
-
expect(package_list.call).to
|
177
|
+
expect(package_list.call).to match(/^#{package_name}|2.0.0$/)
|
166
178
|
end
|
167
179
|
end
|
168
180
|
|
@@ -170,7 +182,7 @@ describe Chef::Resource::ChocolateyPackage, :windows_only, :choco_installed do
|
|
170
182
|
it "removes an installed package" do
|
171
183
|
subject.run_action(:install)
|
172
184
|
remove_package
|
173
|
-
expect(package_list.call).to
|
185
|
+
expect(package_list.call).to match(/0 packages installed/)
|
174
186
|
end
|
175
187
|
end
|
176
188
|
|
@@ -38,12 +38,12 @@ describe Chef::Resource::MacosUserDefaults, :macos_only do
|
|
38
38
|
expect(resource.domain).to eq("NSGlobalDomain")
|
39
39
|
end
|
40
40
|
|
41
|
-
it "
|
42
|
-
expect(resource.host).to
|
41
|
+
it ":all for the host property" do
|
42
|
+
expect(resource.host).to eq(:all)
|
43
43
|
end
|
44
44
|
|
45
|
-
it "
|
46
|
-
expect(resource.user).to
|
45
|
+
it ":current for the user property" do
|
46
|
+
expect(resource.user).to eq(:current)
|
47
47
|
end
|
48
48
|
|
49
49
|
it ":write for resource action" do
|
@@ -20,7 +20,7 @@ require "chef/mixin/shell_out"
|
|
20
20
|
|
21
21
|
# run this test only for following platforms.
|
22
22
|
exclude_test = !(%w{rhel fedora amazon}.include?(OHAI_SYSTEM[:platform_family]) && !File.exist?("/usr/bin/dnf"))
|
23
|
-
describe Chef::Resource::YumPackage, :requires_root, external: exclude_test do
|
23
|
+
describe Chef::Resource::YumPackage, :requires_root, external: exclude_test, not_rhel6: true do
|
24
24
|
include RecipeDSLHelper
|
25
25
|
include Chef::Mixin::ShellOut
|
26
26
|
|
@@ -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
|
|
@@ -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,
|
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,
|
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,
|
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
|
@@ -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
|
@@ -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 "
|
43
|
-
expect(resource.host).to
|
42
|
+
it ":all for the host property" do
|
43
|
+
expect(resource.host).to eq(:all)
|
44
44
|
end
|
45
45
|
|
46
|
-
it "
|
47
|
-
expect(resource.user).to
|
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
|
data/spec/unit/resource_spec.rb
CHANGED
@@ -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 "\*
|
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
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chef
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 17.10.
|
4
|
+
version: 17.10.95
|
5
5
|
platform: universal-mingw32
|
6
6
|
authors:
|
7
7
|
- Adam Jacob
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef-config
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 17.10.
|
19
|
+
version: 17.10.95
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 17.10.
|
26
|
+
version: 17.10.95
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: chef-utils
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 17.10.
|
33
|
+
version: 17.10.95
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 17.10.
|
40
|
+
version: 17.10.95
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: train-core
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -218,16 +218,16 @@ dependencies:
|
|
218
218
|
name: ffi
|
219
219
|
requirement: !ruby/object:Gem::Requirement
|
220
220
|
requirements:
|
221
|
-
- - "
|
221
|
+
- - "~>"
|
222
222
|
- !ruby/object:Gem::Version
|
223
|
-
version: 1.
|
223
|
+
version: 1.15.0
|
224
224
|
type: :runtime
|
225
225
|
prerelease: false
|
226
226
|
version_requirements: !ruby/object:Gem::Requirement
|
227
227
|
requirements:
|
228
|
-
- - "
|
228
|
+
- - "~>"
|
229
229
|
- !ruby/object:Gem::Version
|
230
|
-
version: 1.
|
230
|
+
version: 1.15.0
|
231
231
|
- !ruby/object:Gem::Dependency
|
232
232
|
name: ffi-yajl
|
233
233
|
requirement: !ruby/object:Gem::Requirement
|
@@ -601,33 +601,47 @@ dependencies:
|
|
601
601
|
- !ruby/object:Gem::Version
|
602
602
|
version: '3.0'
|
603
603
|
- !ruby/object:Gem::Dependency
|
604
|
-
name:
|
604
|
+
name: win32-taskscheduler
|
605
605
|
requirement: !ruby/object:Gem::Requirement
|
606
606
|
requirements:
|
607
607
|
- - "~>"
|
608
608
|
- !ruby/object:Gem::Version
|
609
|
-
version: '
|
609
|
+
version: '2.0'
|
610
610
|
type: :runtime
|
611
611
|
prerelease: false
|
612
612
|
version_requirements: !ruby/object:Gem::Requirement
|
613
613
|
requirements:
|
614
614
|
- - "~>"
|
615
615
|
- !ruby/object:Gem::Version
|
616
|
-
version: '
|
616
|
+
version: '2.0'
|
617
617
|
- !ruby/object:Gem::Dependency
|
618
|
-
name: win32-
|
618
|
+
name: win32-certstore
|
619
619
|
requirement: !ruby/object:Gem::Requirement
|
620
620
|
requirements:
|
621
621
|
- - "~>"
|
622
622
|
- !ruby/object:Gem::Version
|
623
|
-
version:
|
623
|
+
version: 0.6.15
|
624
624
|
type: :runtime
|
625
625
|
prerelease: false
|
626
626
|
version_requirements: !ruby/object:Gem::Requirement
|
627
627
|
requirements:
|
628
628
|
- - "~>"
|
629
629
|
- !ruby/object:Gem::Version
|
630
|
-
version:
|
630
|
+
version: 0.6.15
|
631
|
+
- !ruby/object:Gem::Dependency
|
632
|
+
name: wmi-lite
|
633
|
+
requirement: !ruby/object:Gem::Requirement
|
634
|
+
requirements:
|
635
|
+
- - "~>"
|
636
|
+
- !ruby/object:Gem::Version
|
637
|
+
version: '1.0'
|
638
|
+
type: :runtime
|
639
|
+
prerelease: false
|
640
|
+
version_requirements: !ruby/object:Gem::Requirement
|
641
|
+
requirements:
|
642
|
+
- - "~>"
|
643
|
+
- !ruby/object:Gem::Version
|
644
|
+
version: '1.0'
|
631
645
|
- !ruby/object:Gem::Dependency
|
632
646
|
name: iso8601
|
633
647
|
requirement: !ruby/object:Gem::Requirement
|
@@ -648,20 +662,6 @@ dependencies:
|
|
648
662
|
- - "<"
|
649
663
|
- !ruby/object:Gem::Version
|
650
664
|
version: '0.14'
|
651
|
-
- !ruby/object:Gem::Dependency
|
652
|
-
name: win32-certstore
|
653
|
-
requirement: !ruby/object:Gem::Requirement
|
654
|
-
requirements:
|
655
|
-
- - "~>"
|
656
|
-
- !ruby/object:Gem::Version
|
657
|
-
version: 0.6.14
|
658
|
-
type: :runtime
|
659
|
-
prerelease: false
|
660
|
-
version_requirements: !ruby/object:Gem::Requirement
|
661
|
-
requirements:
|
662
|
-
- - "~>"
|
663
|
-
- !ruby/object:Gem::Version
|
664
|
-
version: 0.6.14
|
665
665
|
- !ruby/object:Gem::Dependency
|
666
666
|
name: chef-powershell
|
667
667
|
requirement: !ruby/object:Gem::Requirement
|
@@ -2450,10 +2450,10 @@ files:
|
|
2450
2450
|
- spec/functional/assets/PkgA.1.0.0.0.bff
|
2451
2451
|
- spec/functional/assets/PkgA.2.0.0.0.bff
|
2452
2452
|
- spec/functional/assets/chefinittest
|
2453
|
-
- spec/functional/assets/chocolatey_feed/test-A.1.0.nupkg
|
2454
|
-
- spec/functional/assets/chocolatey_feed/test-A.1.5.nupkg
|
2455
|
-
- spec/functional/assets/chocolatey_feed/test-A.2.0.nupkg
|
2456
|
-
- spec/functional/assets/chocolatey_feed/test-B.1.0.nupkg
|
2453
|
+
- spec/functional/assets/chocolatey_feed/test-A.1.0.0.nupkg
|
2454
|
+
- spec/functional/assets/chocolatey_feed/test-A.1.5.0.nupkg
|
2455
|
+
- spec/functional/assets/chocolatey_feed/test-A.2.0.0.nupkg
|
2456
|
+
- spec/functional/assets/chocolatey_feed/test-B.1.0.0.nupkg
|
2457
2457
|
- spec/functional/assets/dummy-1-0.aix6.1.noarch.rpm
|
2458
2458
|
- spec/functional/assets/dummy-2-0.aix6.1.noarch.rpm
|
2459
2459
|
- spec/functional/assets/inittest
|
@@ -3181,7 +3181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
3181
3181
|
- !ruby/object:Gem::Version
|
3182
3182
|
version: '0'
|
3183
3183
|
requirements: []
|
3184
|
-
rubygems_version: 3.2.
|
3184
|
+
rubygems_version: 3.2.33
|
3185
3185
|
signing_key:
|
3186
3186
|
specification_version: 4
|
3187
3187
|
summary: A systems integration framework, built to bring the benefits of configuration
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|