chef 17.4.38 → 17.7.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -0
  3. data/chef.gemspec +3 -0
  4. data/lib/chef/application/base.rb +11 -1
  5. data/lib/chef/chef_fs/file_pattern.rb +1 -1
  6. data/lib/chef/chef_fs/path_utils.rb +1 -1
  7. data/lib/chef/client.rb +1 -2
  8. data/lib/chef/compliance/input.rb +115 -0
  9. data/lib/chef/compliance/input_collection.rb +139 -0
  10. data/lib/chef/compliance/profile.rb +122 -0
  11. data/lib/chef/compliance/profile_collection.rb +109 -0
  12. data/lib/chef/compliance/runner.rb +47 -5
  13. data/lib/chef/compliance/waiver.rb +115 -0
  14. data/lib/chef/compliance/waiver_collection.rb +143 -0
  15. data/lib/chef/data_collector/run_end_message.rb +1 -1
  16. data/lib/chef/dsl/compliance.rb +38 -0
  17. data/lib/chef/dsl/reader_helpers.rb +51 -0
  18. data/lib/chef/dsl/reboot_pending.rb +1 -1
  19. data/lib/chef/dsl/recipe.rb +4 -2
  20. data/lib/chef/dsl/secret.rb +2 -4
  21. data/lib/chef/dsl/universal.rb +2 -0
  22. data/lib/chef/event_dispatch/base.rb +44 -2
  23. data/lib/chef/exceptions.rb +10 -0
  24. data/lib/chef/formatters/doc.rb +46 -0
  25. data/lib/chef/http/basic_client.rb +15 -7
  26. data/lib/chef/http.rb +7 -3
  27. data/lib/chef/provider/cron.rb +4 -1
  28. data/lib/chef/provider/file.rb +2 -0
  29. data/lib/chef/provider/git.rb +1 -1
  30. data/lib/chef/provider/ifconfig/debian.rb +1 -1
  31. data/lib/chef/provider/link.rb +2 -2
  32. data/lib/chef/provider/registry_key.rb +3 -2
  33. data/lib/chef/provider/remote_file/http.rb +1 -1
  34. data/lib/chef/provider/subversion.rb +5 -5
  35. data/lib/chef/provider/template.rb +1 -1
  36. data/lib/chef/resource/archive_file.rb +17 -14
  37. data/lib/chef/resource/chef_client_scheduled_task.rb +45 -2
  38. data/lib/chef/resource/chocolatey_config.rb +14 -14
  39. data/lib/chef/resource/chocolatey_feature.rb +1 -1
  40. data/lib/chef/resource/chocolatey_source.rb +24 -2
  41. data/lib/chef/resource/directory.rb +1 -1
  42. data/lib/chef/resource/file/verification/json.rb +50 -0
  43. data/lib/chef/resource/file/verification/yaml.rb +52 -0
  44. data/lib/chef/resource/habitat_install.rb +3 -3
  45. data/lib/chef/resource/inspec_input.rb +127 -0
  46. data/lib/chef/resource/inspec_waiver.rb +184 -0
  47. data/lib/chef/resource/inspec_waiver_file_entry.rb +1 -1
  48. data/lib/chef/resource/kernel_module.rb +27 -2
  49. data/lib/chef/resource/macos_userdefaults.rb +43 -128
  50. data/lib/chef/resource/mount.rb +1 -1
  51. data/lib/chef/resource/openssl_x509_certificate.rb +1 -1
  52. data/lib/chef/resource/powershell_package_source.rb +234 -70
  53. data/lib/chef/resource/registry_key.rb +36 -48
  54. data/lib/chef/resource/remote_file.rb +98 -2
  55. data/lib/chef/resource/timezone.rb +2 -2
  56. data/lib/chef/resource/user_ulimit.rb +1 -0
  57. data/lib/chef/resource/windows_auto_run.rb +1 -1
  58. data/lib/chef/resource/windows_dfs_namespace.rb +2 -2
  59. data/lib/chef/resource/windows_printer.rb +1 -1
  60. data/lib/chef/resource/windows_uac.rb +3 -1
  61. data/lib/chef/resource/windows_update_settings.rb +3 -3
  62. data/lib/chef/resource/windows_user_privilege.rb +1 -1
  63. data/lib/chef/resource.rb +1 -1
  64. data/lib/chef/resource_reporter.rb +1 -1
  65. data/lib/chef/resources.rb +2 -0
  66. data/lib/chef/run_context/cookbook_compiler.rb +112 -28
  67. data/lib/chef/run_context.rb +31 -1
  68. data/lib/chef/secret_fetcher/akeyless_vault.rb +57 -0
  69. data/lib/chef/secret_fetcher/aws_secrets_manager.rb +1 -1
  70. data/lib/chef/secret_fetcher/azure_key_vault.rb +63 -9
  71. data/lib/chef/secret_fetcher/base.rb +1 -1
  72. data/lib/chef/secret_fetcher/hashi_vault.rb +100 -0
  73. data/lib/chef/secret_fetcher.rb +8 -3
  74. data/lib/chef/version.rb +1 -1
  75. data/lib/chef/win32/version.rb +2 -1
  76. data/spec/data/archive_file/test_archive.tar.gz +0 -0
  77. data/spec/functional/dsl/reboot_pending_spec.rb +3 -3
  78. data/spec/functional/dsl/registry_helper_spec.rb +1 -1
  79. data/spec/functional/resource/archive_file_spec.rb +87 -0
  80. data/spec/functional/resource/dsc_script_spec.rb +2 -2
  81. data/spec/functional/resource/group_spec.rb +5 -1
  82. data/spec/functional/resource/link_spec.rb +8 -0
  83. data/spec/functional/resource/macos_userdefaults_spec.rb +119 -0
  84. data/spec/functional/resource/powershell_package_source_spec.rb +5 -6
  85. data/spec/functional/resource/registry_spec.rb +81 -81
  86. data/spec/functional/win32/registry_spec.rb +8 -8
  87. data/spec/integration/compliance/compliance_spec.rb +60 -0
  88. data/spec/spec_helper.rb +3 -0
  89. data/spec/support/platform_helpers.rb +4 -0
  90. data/spec/support/ruby_installer.rb +51 -0
  91. data/spec/unit/compliance/input_spec.rb +104 -0
  92. data/spec/unit/compliance/profile_spec.rb +120 -0
  93. data/spec/unit/compliance/waiver_spec.rb +104 -0
  94. data/spec/unit/data_collector_spec.rb +24 -1
  95. data/spec/unit/dsl/reboot_pending_spec.rb +1 -1
  96. data/spec/unit/http/basic_client_spec.rb +30 -0
  97. data/spec/unit/http_spec.rb +8 -2
  98. data/spec/unit/mixin/default_paths_spec.rb +1 -1
  99. data/spec/unit/mixin/securable_spec.rb +3 -3
  100. data/spec/unit/provider/cron_spec.rb +45 -0
  101. data/spec/unit/provider/link_spec.rb +13 -7
  102. data/spec/unit/provider/package/rubygems_spec.rb +5 -5
  103. data/spec/unit/provider/package/windows_spec.rb +1 -1
  104. data/spec/unit/provider/registry_key_spec.rb +4 -4
  105. data/spec/unit/provider/remote_file/http_spec.rb +10 -0
  106. data/spec/unit/provider/service/windows_spec.rb +5 -5
  107. data/spec/unit/provider/subversion_spec.rb +4 -4
  108. data/spec/unit/provider/template_spec.rb +2 -2
  109. data/spec/unit/provider/windows_env_spec.rb +1 -1
  110. data/spec/unit/provider/zypper_repository_spec.rb +1 -1
  111. data/spec/unit/resource/archive_file_spec.rb +414 -3
  112. data/spec/unit/resource/chef_client_scheduled_task_spec.rb +69 -0
  113. data/spec/unit/resource/chocolatey_config_spec.rb +1 -1
  114. data/spec/unit/resource/chocolatey_feature_spec.rb +1 -1
  115. data/spec/unit/resource/chocolatey_source_spec.rb +1 -1
  116. data/spec/unit/resource/file/verification/json_spec.rb +72 -0
  117. data/spec/unit/resource/file/verification/yaml_spec.rb +67 -0
  118. data/spec/unit/resource/inspec_input_spec.rb +300 -0
  119. data/spec/unit/resource/inspec_waiver_spec.rb +312 -0
  120. data/spec/unit/resource/kernel_module_spec.rb +2 -1
  121. data/spec/unit/resource/macos_user_defaults_spec.rb +36 -96
  122. data/spec/unit/resource/mount_spec.rb +10 -0
  123. data/spec/unit/resource/powershell_package_source_spec.rb +63 -62
  124. data/spec/unit/resource/registry_key_spec.rb +10 -10
  125. data/spec/unit/resource/user_ulimit_spec.rb +14 -1
  126. data/spec/unit/resource/windows_auto_run_spec.rb +1 -1
  127. data/spec/unit/resource/windows_feature_powershell_spec.rb +1 -1
  128. data/spec/unit/resource/windows_firewall_rule_spec.rb +2 -2
  129. data/spec/unit/resource/windows_task_spec.rb +3 -3
  130. data/spec/unit/resource_reporter_spec.rb +2 -2
  131. data/spec/unit/resource_spec.rb +5 -0
  132. data/spec/unit/secret_fetcher/akeyless_vault_spec.rb +37 -0
  133. data/spec/unit/secret_fetcher/azure_key_vault_spec.rb +99 -20
  134. data/spec/unit/secret_fetcher/hashi_vault_spec.rb +80 -0
  135. data/spec/unit/util/backup_spec.rb +1 -1
  136. data/spec/unit/win32/registry_spec.rb +3 -3
  137. data/tasks/rspec.rb +2 -1
  138. metadata +75 -6
@@ -1,4 +1,5 @@
1
1
  # Author:: Tor Magnus Rakvåg (tm@intility.no)
2
+ # Author:: John McCrae (john.mccrae@progress.com)
2
3
  # Copyright:: 2018, Intility AS
3
4
  # License:: Apache License, Version 2.0
4
5
  #
@@ -24,29 +25,110 @@ class Chef
24
25
 
25
26
  provides :powershell_package_source
26
27
 
27
- description "Use the **powershell_package_source** resource to register a PowerShell package repository."
28
+ description "Use the **powershell_package_source** resource to register a PowerShell package source and a Powershell package provider. There are 2 distinct objects we care about here. The first is a Package Source like a PowerShell Repository or a Nuget Source. The second object is a provider that PowerShell uses to get to that source with, like PowerShellGet, Nuget, Chocolatey, etc. "
28
29
  introduced "14.3"
30
+ examples <<~DOC
31
+ **Add a new PSRepository that is not trusted and which requires credentials to connect to**:
32
+
33
+ ```ruby
34
+ powershell_package_source 'PowerShellModules' do
35
+ source_name "PowerShellModules"
36
+ source_location "https://pkgs.dev.azure.com/some-org/some-project/_packaging/some_feed/nuget/v2"
37
+ publish_location "https://pkgs.dev.azure.com/some-org/some-project/_packaging/some_feed/nuget/v2"
38
+ trusted false
39
+ user "someuser@somelocation.io"
40
+ password "my_password"
41
+ provider_name "PSRepository"
42
+ action :register
43
+ end
44
+ ```
45
+
46
+ **Add a new Package Source that uses Chocolatey as the Package Provider**:
47
+
48
+ ```ruby
49
+ powershell_package_source 'PowerShellModules' do
50
+ source_name "PowerShellModules"
51
+ source_location "https://pkgs.dev.azure.com/some-org/some-project/_packaging/some_feed/nuget/v2"
52
+ publish_location "https://pkgs.dev.azure.com/some-org/some-project/_packaging/some_feed/nuget/v2"
53
+ trusted true
54
+ provider_name "chocolatey"
55
+ action :register
56
+ end
57
+ ```
58
+
59
+ **Add a new PowerShell Script source that is trusted**:
60
+
61
+ ```ruby
62
+ powershell_package_source 'MyDodgyScript' do
63
+ source_name "MyDodgyScript"
64
+ script_source_location "https://pkgs.dev.azure.com/some-org/some-project/_packaging/some_feed/nuget/v2"
65
+ script_publish_location "https://pkgs.dev.azure.com/some-org/some-project/_packaging/some_feed/nuget/v2"
66
+ trusted true
67
+ action :register
68
+ end
69
+ ```
70
+
71
+ **Update my existing PSRepository to make it Trusted after all**:
72
+
73
+ ```ruby
74
+ powershell_package_source 'MyPSModule' do
75
+ source_name "MyPSModule"
76
+ trusted true
77
+ action :set
78
+ end
79
+ ```
80
+
81
+ **Update a Nuget package source with a new name and make it trusted**:
82
+
83
+ ```ruby
84
+ powershell_package_source 'PowerShellModules -> GoldFishBowl' do
85
+ source_name "PowerShellModules"
86
+ new_name "GoldFishBowl"
87
+ provider_name "Nuget"
88
+ trusted true
89
+ action :set
90
+ end
91
+ ```
92
+
93
+ **Update a Nuget package source with a new name when the source is secured with a username and password**:
94
+
95
+ ```ruby
96
+ powershell_package_source 'PowerShellModules -> GoldFishBowl' do
97
+ source_name "PowerShellModules"
98
+ new_name "GoldFishBowl"
99
+ trusted true
100
+ user "user@domain.io"
101
+ password "some_secret_password"
102
+ action :set
103
+ end
104
+ ```
105
+
106
+ **Unregister a package source**:
107
+
108
+ ```ruby
109
+ powershell_package_source 'PowerShellModules' do
110
+ source_name "PowerShellModules"
111
+ action :unregister
112
+ end
113
+ ```
114
+ DOC
29
115
 
30
116
  property :source_name, String,
31
- description: "The name of the package source.",
117
+ description: "A label that names your package source.",
32
118
  name_property: true
33
119
 
34
- property :url, String,
35
- description: "The URL to the package source.",
36
- required: [:register]
120
+ property :new_name, String,
121
+ introduced: "17.6",
122
+ description: "Used to change the name of a standard package source."
37
123
 
38
- property :trusted, [TrueClass, FalseClass],
39
- description: "Whether or not to trust packages from this source.",
40
- default: false
124
+ property :source_location, String,
125
+ introduced: "17.6",
126
+ description: "The URL to the location to retrieve modules from."
41
127
 
42
- property :provider_name, String,
43
- equal_to: %w{ Programs msi NuGet msu PowerShellGet psl chocolatey },
44
- validation_message: "The following providers are supported: 'Programs', 'msi', 'NuGet', 'msu', 'PowerShellGet', 'psl' or 'chocolatey'",
45
- description: "The package management provider for the source.",
46
- default: "NuGet"
128
+ alias :url :source_location
47
129
 
48
130
  property :publish_location, String,
49
- description: "The URL where modules will be published to for this source. Only valid if the provider is `PowerShellGet`."
131
+ description: "The URL where modules will be published to. Only valid if the provider is `PowerShellGet`."
50
132
 
51
133
  property :script_source_location, String,
52
134
  description: "The URL where scripts are located for this source. Only valid if the provider is `PowerShellGet`."
@@ -54,6 +136,24 @@ class Chef
54
136
  property :script_publish_location, String,
55
137
  description: "The location where scripts will be published to for this source. Only valid if the provider is `PowerShellGet`."
56
138
 
139
+ property :trusted, [TrueClass, FalseClass],
140
+ description: "Whether or not to trust packages from this source. Used when creating a NON-PSRepository Package Source",
141
+ default: false
142
+
143
+ property :user, String,
144
+ introduced: "17.6",
145
+ description: "A username that, as part of a credential object, is used to register a repository or other package source with."
146
+
147
+ property :password, String,
148
+ introduced: "17.6",
149
+ description: "A password that, as part of a credential object, is used to register a repository or other package source with."
150
+
151
+ property :provider_name, String,
152
+ equal_to: %w{ Programs msi NuGet msu PowerShellGet psl chocolatey winget },
153
+ validation_message: "The following providers are supported: 'Programs', 'msi', 'NuGet', 'msu', 'PowerShellGet', 'psl', 'chocolatey' or 'winget'",
154
+ description: "The package management provider for the package source. The default is PowerShellGet and this option need only be set otherwise in specific use cases.",
155
+ default: "NuGet"
156
+
57
157
  load_current_value do
58
158
  cmd = load_resource_state_script(source_name)
59
159
  repo = powershell_exec!(cmd)
@@ -62,7 +162,9 @@ class Chef
62
162
  else
63
163
  status = repo.result
64
164
  end
65
- url status["url"]
165
+ source_name status["source_name"]
166
+ new_name status["new_name"]
167
+ source_location status["source_location"]
66
168
  trusted status["trusted"]
67
169
  provider_name status["provider_name"]
68
170
  publish_location status["publish_location"]
@@ -70,97 +172,159 @@ class Chef
70
172
  script_publish_location status["script_publish_location"]
71
173
  end
72
174
 
73
- action :register, description: "Registers and updates the PowerShell package source." do
74
- # TODO: Ensure package provider is installed?
75
- if psrepository_cmdlet_appropriate?
76
- if package_source_exists?
77
- converge_if_changed :url, :trusted, :publish_location, :script_source_location, :script_publish_location do
78
- update_cmd = build_ps_repository_command("Set", new_resource)
79
- res = powershell_exec(update_cmd)
80
- raise "Failed to update #{new_resource.source_name}: #{res.errors}" if res.error?
81
- end
82
- else
83
- converge_by("register source: #{new_resource.source_name}") do
84
- register_cmd = build_ps_repository_command("Register", new_resource)
85
- res = powershell_exec(register_cmd)
86
- raise "Failed to register #{new_resource.source_name}: #{res.errors}" if res.error?
87
- end
175
+ # Notes:
176
+ # There are 2 objects we care about with this code. 1) The Package Provider which can be Nuget, PowerShellGet, Chocolatey, et al. 2) The PackageSource where the files we want access to live. The Package Provider gets us access to the Package Source.
177
+ # Per the Microsoft docs you can only have one provider for one source. Enter the PSRepository. It is a sub-type of Package Source.
178
+ # If you register a new PSRepository you get both a PSRepository object AND a Package Source object which are distinct. If you call "Get-PSRepository -Name 'PSGallery'" from powershell, notice that the Packageprovider is Nuget
179
+ # now go execute "Get-PackageSource -Name 'PSGallery'" and notice that the PackageProvider is PowerShellGet. If you set a new PSRepository without specifying a PackageProvider ("Register-PSRepository -Name 'foo' -source...") the command will create both
180
+ # a PackageSource and a PSRepository with different providers.
181
+
182
+ # Unregistering a PackageSource (unregister-packagesource -name 'foo') where that source is also a PSRepository also causes that object to delete as well. This makes sense as PSRepository is a sub-type of packagesource.
183
+ # All PSRepositories are PackageSources, and all PackageSources with Provider PowerShellGet are PSRepositories. They are 2 different views of the same object.
184
+
185
+ action :register, description: "Registers a PowerShell package source." do
186
+ package_details = get_package_source_details
187
+ output = package_details.result
188
+ if output == "PSRepository" || output == "PackageSource"
189
+ action_set
190
+ elsif new_resource.provider_name.downcase.strip == "powershellget"
191
+ converge_by("register source: #{new_resource.source_name}") do
192
+ register_cmd = build_ps_repository_command("Register", new_resource)
193
+ res = powershell_exec(register_cmd)
194
+ raise "Failed to register #{new_resource.source_name}: #{res.errors}" if res.error?
88
195
  end
89
196
  else
90
- if package_source_exists?
91
- converge_if_changed :url, :trusted, :provider_name do
92
- update_cmd = build_package_source_command("Set", new_resource)
93
- res = powershell_exec(update_cmd)
94
- raise "Failed to update #{new_resource.source_name}: #{res.errors}" if res.error?
95
- end
96
- else
97
- converge_by("register source: #{new_resource.source_name}") do
98
- register_cmd = build_package_source_command("Register", new_resource)
99
- res = powershell_exec(register_cmd)
100
- raise "Failed to register #{new_resource.source_name}: #{res.errors}" if res.error?
101
- end
197
+ converge_by("register source: #{new_resource.source_name}") do
198
+ register_cmd = build_package_source_command("Register", new_resource)
199
+ res = powershell_exec(register_cmd)
200
+ raise "Failed to register #{new_resource.source_name}: #{res.errors}" if res.error?
201
+ end
202
+ end
203
+ end
204
+
205
+ action :set, description: "Updates an existing PSRepository or Package Source" do
206
+ package_details = get_package_source_details
207
+ output = package_details.result
208
+ if output == "PSRepository"
209
+ converge_if_changed :source_location, :trusted, :publish_location, :script_source_location, :script_publish_location, :source_name do
210
+ set_cmd = build_ps_repository_command("Set", new_resource)
211
+ res = powershell_exec(set_cmd)
212
+ raise "Failed to Update #{new_resource.source_name}: #{res.errors}" if res.error?
213
+ end
214
+ elsif output == "PackageSource"
215
+ converge_if_changed :source_location, :trusted, :new_name, :provider_name do
216
+ set_cmd = build_package_source_command("Set", new_resource)
217
+ res = powershell_exec(set_cmd)
218
+ raise "Failed to Update #{new_resource.source_name}: #{res.errors}" if res.error?
102
219
  end
103
220
  end
104
221
  end
105
222
 
106
223
  action :unregister, description: "Unregisters the PowerShell package source." do
107
- if package_source_exists?
108
- unregister_cmd = "Get-PackageSource -Name '#{new_resource.source_name}' | Unregister-PackageSource"
224
+ package_details = get_package_source_details
225
+ output = package_details.result
226
+ if output == "PackageSource" || output == "PSRepository"
227
+ unregister_cmd = "Unregister-PackageSource -Name '#{new_resource.source_name}'"
109
228
  converge_by("unregister source: #{new_resource.source_name}") do
110
- res = powershell_exec(unregister_cmd)
229
+ res = powershell_exec!(unregister_cmd)
111
230
  raise "Failed to unregister #{new_resource.source_name}: #{res.errors}" if res.error?
112
231
  end
232
+ else
233
+ logger.warn("*****************************************")
234
+ logger.warn("Failed to unregister #{new_resource.source_name}: Package Source does not exist")
235
+ logger.warn("*****************************************")
113
236
  end
114
237
  end
115
238
 
116
239
  action_class do
117
- def package_source_exists?
118
- cmd = powershell_exec!("(Get-PackageSource -Name '#{new_resource.source_name}' -ErrorAction SilentlyContinue).Name")
119
- !cmd.result.empty? && cmd.result.to_s.downcase.strip == new_resource.source_name.downcase
120
- end
121
240
 
122
- def psrepository_cmdlet_appropriate?
123
- new_resource.provider_name == "PowerShellGet"
241
+ def get_package_source_details
242
+ powershell_exec! <<~EOH
243
+ $package_details = Get-PackageSource -Name '#{new_resource.source_name}' -ErrorAction SilentlyContinue
244
+ if ($package_details.ProviderName -match "PowerShellGet"){
245
+ return "PSRepository"
246
+ }
247
+ elseif ($package_details.ProviderName ) {
248
+ return "PackageSource"
249
+ }
250
+ elseif ($null -eq $package_details)
251
+ {
252
+ return "Unregistered"
253
+ }
254
+ EOH
124
255
  end
125
256
 
126
257
  def build_ps_repository_command(cmdlet_type, new_resource)
127
- cmd = "#{cmdlet_type}-PSRepository -Name '#{new_resource.source_name}'"
128
- cmd << " -SourceLocation '#{new_resource.url}'" if new_resource.url
129
- cmd << " -InstallationPolicy '#{new_resource.trusted ? "Trusted" : "Untrusted"}'"
130
- cmd << " -PublishLocation '#{new_resource.publish_location}'" if new_resource.publish_location
131
- cmd << " -ScriptSourceLocation '#{new_resource.script_source_location}'" if new_resource.script_source_location
132
- cmd << " -ScriptPublishLocation '#{new_resource.script_publish_location}'" if new_resource.script_publish_location
133
- cmd << " | Out-Null"
258
+ if new_resource.trusted == true
259
+ install_policy = "Trusted"
260
+ else
261
+ install_policy = "Untrusted"
262
+ end
263
+ if new_resource.user && new_resource.password
264
+ cmd = "$user = '#{new_resource.user}';"
265
+ cmd << "[securestring]$secure_password = Convertto-SecureString -String '#{new_resource.password}' -AsPlainText -Force;"
266
+ cmd << "$Credentials = New-Object System.Management.Automation.PSCredential -Argumentlist ($user, $secure_password);"
267
+ cmd << "#{cmdlet_type}-PSRepository -Name '#{new_resource.source_name}'"
268
+ cmd << " -SourceLocation '#{new_resource.source_location}'" if new_resource.source_location
269
+ cmd << " -InstallationPolicy '#{install_policy}'"
270
+ cmd << " -PublishLocation '#{new_resource.publish_location}'" if new_resource.publish_location
271
+ cmd << " -ScriptSourceLocation '#{new_resource.script_source_location}'" if new_resource.script_source_location
272
+ cmd << " -ScriptPublishLocation '#{new_resource.script_publish_location}'" if new_resource.script_publish_location
273
+ cmd << " -Credential $Credentials"
274
+ cmd << " | Out-Null"
275
+ else
276
+ cmd = "#{cmdlet_type}-PSRepository -Name '#{new_resource.source_name}'"
277
+ cmd << " -SourceLocation '#{new_resource.source_location}'" if new_resource.source_location
278
+ cmd << " -InstallationPolicy '#{install_policy}'"
279
+ cmd << " -PublishLocation '#{new_resource.publish_location}'" if new_resource.publish_location
280
+ cmd << " -ScriptSourceLocation '#{new_resource.script_source_location}'" if new_resource.script_source_location
281
+ cmd << " -ScriptPublishLocation '#{new_resource.script_publish_location}'" if new_resource.script_publish_location
282
+ cmd << " | Out-Null"
283
+ end
134
284
  cmd
135
285
  end
136
286
 
137
287
  def build_package_source_command(cmdlet_type, new_resource)
138
- cmd = "#{cmdlet_type}-PackageSource -Name '#{new_resource.source_name}'"
139
- cmd << " -Location '#{new_resource.url}'" if new_resource.url
140
- cmd << " -Trusted:#{new_resource.trusted ? "$true" : "$false"}"
141
- cmd << " -ProviderName '#{new_resource.provider_name}'" if new_resource.provider_name
142
- cmd << " | Out-Null"
143
- cmd
288
+ if new_resource.user && new_resource.password
289
+ cmd = "$user = '#{new_resource.user}';"
290
+ cmd << "[securestring]$secure_password = Convertto-SecureString -String '#{new_resource.password}' -AsPlainText -Force;"
291
+ cmd << "$Credentials = New-Object System.Management.Automation.PSCredential -Argumentlist ($user, $secure_password);"
292
+ cmd << "#{cmdlet_type}-PackageSource -Name '#{new_resource.source_name}'"
293
+ cmd << " -Location '#{new_resource.source_location}'" if new_resource.source_location
294
+ cmd << " -Trusted" if new_resource.trusted
295
+ cmd << " -ProviderName '#{new_resource.provider_name}'" if new_resource.provider_name
296
+ cmd << " -Credential $credentials"
297
+ cmd << " | Out-Null"
298
+ cmd
299
+ else
300
+ cmd = "#{cmdlet_type}-PackageSource -Name '#{new_resource.source_name}'"
301
+ cmd << " -NewName '#{new_resource.new_name}'" if new_resource.new_name
302
+ cmd << " -Location '#{new_resource.source_location}'" if new_resource.source_location
303
+ cmd << " -Trusted" if new_resource.trusted
304
+ cmd << " -ProviderName '#{new_resource.provider_name}'" if new_resource.provider_name
305
+ cmd << " | Out-Null"
306
+ cmd
307
+ end
144
308
  end
145
309
  end
146
310
  end
147
311
 
148
312
  private
149
313
 
150
- def load_resource_state_script(name)
314
+ def load_resource_state_script(source_name)
151
315
  <<-EOH
152
316
  $PSDefaultParameterValues = @{
153
317
  "*:WarningAction" = "SilentlyContinue"
154
318
  }
155
- if(Get-PackageSource -Name '#{name}' -ErrorAction SilentlyContinue) {
156
- if ((Get-PackageSource -Name '#{name}').ProviderName -eq 'PowerShellGet') {
157
- (Get-PSRepository -Name '#{name}') | Select @{n='source_name';e={$_.Name}}, @{n='url';e={$_.SourceLocation}},
319
+ if(Get-PackageSource -Name '#{source_name}' -ErrorAction SilentlyContinue) {
320
+ if ((Get-PackageSource -Name '#{source_name}').ProviderName -eq 'PowerShellGet') {
321
+ (Get-PSRepository -Name '#{source_name}') | Select @{n='source_name';e={$_.Name}}, @{n='source_location';e={$_.SourceLocation}},
158
322
  @{n='trusted';e={$_.Trusted}}, @{n='provider_name';e={$_.PackageManagementProvider}}, @{n='publish_location';e={$_.PublishLocation}},
159
323
  @{n='script_source_location';e={$_.ScriptSourceLocation}}, @{n='script_publish_location';e={$_.ScriptPublishLocation}}
160
324
  }
161
325
  else {
162
- (Get-PackageSource -Name '#{name}') | Select @{n='source_name';e={$_.Name}}, @{n='url';e={$_.Location}},
163
- @{n='provider_name';e={$_.ProviderName}}, @{n='trusted';e={$_.IsTrusted}}
326
+ (Get-PackageSource -Name '#{source_name}') | Select @{n='source_name';e={$_.Name}}, @{n='new_name';e={$_.Name}}, @{n='source_location';e={$_.Location}},
327
+ @{n='provider_name';e={$_.ProviderName}}, @{n='trusted';e={$_.IsTrusted}}, @{n='publish_location';e={$_.PublishLocation}}
164
328
  }
165
329
  }
166
330
  EOH
@@ -18,6 +18,7 @@
18
18
 
19
19
  require_relative "../resource"
20
20
  require_relative "../digester"
21
+ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
21
22
 
22
23
  class Chef
23
24
  class Resource
@@ -26,7 +27,7 @@ class Chef
26
27
 
27
28
  provides(:registry_key) { true }
28
29
 
29
- description "Use the **registry_key** resource to create and delete registry keys in Microsoft Windows."
30
+ description "Use the **registry_key** resource to create and delete registry keys in Microsoft Windows. Note: 64-bit versions of Microsoft Windows have a 32-bit compatibility layer in the registry that reflects and redirects certain keys (and their values) into specific locations (or logical views) of the registry hive.\n\n#{ChefUtils::Dist::Infra::PRODUCT} can access any reflected or redirected registry key. The machine architecture of the system on which #{ChefUtils::Dist::Infra::PRODUCT} is running is used as the default (non-redirected) location. Access to the SysWow64 location is redirected must be specified. Typically, this is only necessary to ensure compatibility with 32-bit applications that are running on a 64-bit operating system.\n\nFor more information, see: [Registry Reflection](https://docs.microsoft.com/en-us/windows/win32/winprog64/registry-reflection)."
30
31
  examples <<~'DOC'
31
32
  **Create a registry key**
32
33
 
@@ -66,7 +67,7 @@ class Chef
66
67
  end
67
68
  ```
68
69
 
69
- **Set proxy settings to be the same as those used by Chef Infra Client**
70
+ **Set proxy settings to be the same as those used by #{ChefUtils::Dist::Infra::PRODUCT}**
70
71
 
71
72
  ```ruby
72
73
  proxy = URI.parse(Chef::Config[:http_proxy])
@@ -115,14 +116,42 @@ class Chef
115
116
  end
116
117
  ```
117
118
 
118
- Note: Be careful when using the :delete_key action with the recursive attribute. This will delete the registry key, all of its values and all of the names, types, and data associated with them. This cannot be undone by Chef Infra Client.
119
+ Note: Be careful when using the :delete_key action with the recursive attribute. This will delete the registry key, all of its values and all of the names, types, and data associated with them. This cannot be undone by #{ChefUtils::Dist::Infra::PRODUCT}.
119
120
  DOC
120
121
 
121
- state_attrs :values
122
-
123
122
  default_action :create
124
123
  allowed_actions :create, :create_if_missing, :delete, :delete_key
125
124
 
125
+ VALID_VALUE_HASH_KEYS = %i{name type data}.freeze
126
+
127
+ property :key, String, name_property: true
128
+ property :values, [Hash, Array],
129
+ default: [],
130
+ coerce: proc { |v|
131
+ @unscrubbed_values =
132
+ case v
133
+ when Hash
134
+ [ Mash.new(v).symbolize_keys ]
135
+ when Array
136
+ v.map { |value| Mash.new(value).symbolize_keys }
137
+ else
138
+ raise ArgumentError, "Bad type for RegistryKey resource, use Hash or Array"
139
+ end
140
+ scrub_values(@unscrubbed_values)
141
+ },
142
+ callbacks: {
143
+ "Missing name key in RegistryKey values hash" => lambda { |v| v.all? { |value| value.key?(:name) } },
144
+ "Bad key in RegistryKey values hash. Should be one of: #{VALID_VALUE_HASH_KEYS}" => lambda do |v|
145
+ v.all? do |value|
146
+ value.keys.all? { |key| VALID_VALUE_HASH_KEYS.include?(key) }
147
+ end
148
+ end,
149
+ "Type of name should be a string" => lambda { |v| v.all? { |value| value[:name].is_a?(String) } },
150
+ "Type of type should be a symbol" => lambda { |v| v.all? { |value| value[:type] ? value[:type].is_a?(Symbol) : true } },
151
+ }
152
+ property :recursive, [TrueClass, FalseClass], default: false
153
+ property :architecture, Symbol, default: :machine, equal_to: %i{machine x86_64 i386}
154
+
126
155
  # Some registry key data types may not be safely reported as json.
127
156
  # Example (CHEF-5323):
128
157
  #
@@ -152,51 +181,10 @@ class Chef
152
181
  # may want to extend the state_attrs API with the ability to rename POST'd attrs.
153
182
  #
154
183
  # See lib/chef/resource_reporter.rb for more information.
155
- attr_reader :unscrubbed_values
156
-
157
- def initialize(name, run_context = nil)
158
- super
159
- @values, @unscrubbed_values = [], []
160
- end
161
-
162
- property :key, String, name_property: true
163
-
164
- VALID_VALUE_HASH_KEYS = %i{name type data}.freeze
165
-
166
- def values(arg = nil)
167
- if not arg.nil?
168
- if arg.is_a?(Hash)
169
- @values = [ Mash.new(arg).symbolize_keys ]
170
- elsif arg.is_a?(Array)
171
- @values = []
172
- arg.each do |value|
173
- @values << Mash.new(value).symbolize_keys
174
- end
175
- else
176
- raise ArgumentError, "Bad type for RegistryKey resource, use Hash or Array"
177
- end
178
-
179
- @values.each do |v|
180
- raise ArgumentError, "Missing name key in RegistryKey values hash" unless v.key?(:name)
181
-
182
- v.each_key do |key|
183
- raise ArgumentError, "Bad key #{key} in RegistryKey values hash" unless VALID_VALUE_HASH_KEYS.include?(key)
184
- end
185
- raise ArgumentError, "Type of name => #{v[:name]} should be string" unless v[:name].is_a?(String)
186
-
187
- if v[:type]
188
- raise ArgumentError, "Type of type => #{v[:type]} should be symbol" unless v[:type].is_a?(Symbol)
189
- end
190
- end
191
- @unscrubbed_values = @values
192
- elsif instance_variable_defined?(:@values)
193
- scrub_values(@values)
194
- end
184
+ def unscrubbed_values
185
+ @unscrubbed_values ||= []
195
186
  end
196
187
 
197
- property :recursive, [TrueClass, FalseClass], default: false
198
- property :architecture, Symbol, default: :machine, equal_to: %i{machine x86_64 i386}
199
-
200
188
  private
201
189
 
202
190
  def scrub_values(values)
@@ -34,6 +34,78 @@ class Chef
34
34
 
35
35
  description "Use the **remote_file** resource to transfer a file from a remote location using file specificity. This resource is similar to the **file** resource. Note: Fetching files from the `files/` directory in a cookbook should be done with the **cookbook_file** resource."
36
36
 
37
+ examples <<~'DOC'
38
+ **Download a file without checking the checksum**:
39
+
40
+ ```ruby
41
+ remote_file '/tmp/remote.txt' do
42
+ source 'https://example.org/remote.txt'
43
+ end
44
+ ```
45
+
46
+ **Download a file with a checksum to validate**:
47
+
48
+ ```ruby
49
+ remote_file '/tmp/test_file' do
50
+ source 'http://www.example.com/tempfiles/test_file'
51
+ mode '0755'
52
+ checksum '3a7dac00b1' # A SHA256 (or portion thereof) of the file.
53
+ end
54
+ ```
55
+
56
+ **Download a file only if it's not already present**:
57
+
58
+ ```ruby
59
+ remote_file '/tmp/remote.txt' do
60
+ source 'https://example.org/remote.txt'
61
+ checksum '3a7dac00b1' # A SHA256 (or portion thereof) of the file.
62
+ action :create_if_missing
63
+ end
64
+ ```
65
+
66
+ **Using HTTP Basic Authentication in Headers**:
67
+
68
+ ```ruby
69
+ remote_file '/tmp/remote.txt' do
70
+ source 'https://example.org/remote.txt'
71
+ headers('Authorization' => "Basic #{Base64.encode64("USERNAME_VALUE:PASSWORD_VALUE").delete("\n")}")
72
+ checksum '3a7dac00b1' # A SHA256 (or portion thereof) of the file.
73
+ action :create_if_missing
74
+ end
75
+ ```
76
+
77
+ **Downloading a file to the Chef file cache dir for execution**:
78
+
79
+ ```ruby
80
+ remote_file '#{Chef::Config['file_cache_path']}/install.sh' do
81
+ source 'https://example.org/install.sh'
82
+ action :create_if_missing
83
+ end
84
+
85
+ execute '#{Chef::Config['file_cache_path']}/install.sh'
86
+ ```
87
+
88
+ **Specify advanced HTTP connection options including Net::HTTP (nethttp) options:**
89
+
90
+ ```ruby
91
+ remote_file '/tmp/remote.txt' do
92
+ source 'https://example.org/remote.txt'
93
+ http_options({
94
+ http_retry_delay: 0,
95
+ http_retry_count: 0,
96
+ keepalives: false,
97
+ nethttp: {
98
+ continue_timeout: 5,
99
+ max_retries: 5,
100
+ read_timeout: 5,
101
+ write_timeout: 5,
102
+ ssl_timeout: 5,
103
+ },
104
+ })
105
+ end
106
+ ```
107
+ DOC
108
+
37
109
  def initialize(name, run_context = nil)
38
110
  super
39
111
  @source = []
@@ -96,9 +168,29 @@ class Chef
96
168
  description: "Whether #{ChefUtils::Dist::Infra::PRODUCT} uses active or passive FTP. Set to `true` to use active FTP."
97
169
 
98
170
  property :headers, Hash, default: {},
99
- description: "A Hash of custom HTTP headers."
171
+ description: <<~'DOCS'
172
+ A Hash of custom headers. For example:
173
+
174
+ ```ruby
175
+ headers({ "Cookie" => "user=some_user; pass=p@ssw0rd!" })
176
+ ```
100
177
 
101
- property :show_progress, [ TrueClass, FalseClass ], default: false
178
+ or:
179
+
180
+ ```ruby
181
+ headers({ "Referer" => "#{header}" })
182
+ ```
183
+
184
+ or:
185
+
186
+ ```ruby
187
+ headers( "Authorization"=>"Basic #{ Base64.encode64("#{username}:#{password}").gsub("\n", "") }" )
188
+ ```
189
+ DOCS
190
+
191
+ property :show_progress, [ TrueClass, FalseClass ],
192
+ description: "Displays the progress of the file download.",
193
+ default: false
102
194
 
103
195
  property :ssl_verify_mode, Symbol, equal_to: %i{verify_none verify_peer},
104
196
  introduced: "16.2",
@@ -118,6 +210,10 @@ class Chef
118
210
 
119
211
  property :authentication, Symbol, equal_to: %i{remote local}, default: :remote
120
212
 
213
+ property :http_options, Hash, default: {},
214
+ introduced: "17.5",
215
+ description: "A Hash of custom HTTP options. For example: `http_options({ http_retry_count: 0, http_retry_delay: 2 })`"
216
+
121
217
  def after_created
122
218
  validate_identity_platform(remote_user, remote_password, remote_domain)
123
219
  identity = qualify_user(remote_user, remote_password, remote_domain)
@@ -38,7 +38,7 @@ class Chef
38
38
  **Set the timezone to America/Los_Angeles with a friendly resource name on Linux/macOS**
39
39
 
40
40
  ```ruby
41
- timezone 'Set the host's timezone to America/Los_Angeles' do
41
+ timezone "Set the host's timezone to America/Los_Angeles" do
42
42
  timezone 'America/Los_Angeles'
43
43
  end
44
44
  ```
@@ -46,7 +46,7 @@ class Chef
46
46
  **Set the timezone to PST with a friendly resource name on Windows**
47
47
 
48
48
  ```ruby
49
- timezone 'Set the host's timezone to PST' do
49
+ timezone "Set the host's timezone to PST" do
50
50
  timezone 'Pacific Standard time'
51
51
  end
52
52
  ```
@@ -83,6 +83,7 @@ class Chef
83
83
  source ::File.expand_path("support/ulimit.erb", __dir__)
84
84
  local true
85
85
  mode "0644"
86
+ sensitive new_resource.sensitive
86
87
  variables(
87
88
  ulimit_user: new_resource.username,
88
89
  filehandle_limit: new_resource.filehandle_limit,