chef 17.4.25-universal-mingw32 → 17.6.18-universal-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/chef.gemspec +2 -0
  4. data/lib/chef/application/base.rb +11 -1
  5. data/lib/chef/client.rb +1 -2
  6. data/lib/chef/compliance/input.rb +115 -0
  7. data/lib/chef/compliance/input_collection.rb +139 -0
  8. data/lib/chef/compliance/profile.rb +122 -0
  9. data/lib/chef/compliance/profile_collection.rb +109 -0
  10. data/lib/chef/compliance/reporter/automate.rb +1 -1
  11. data/lib/chef/compliance/runner.rb +48 -6
  12. data/lib/chef/compliance/waiver.rb +115 -0
  13. data/lib/chef/compliance/waiver_collection.rb +143 -0
  14. data/lib/chef/dsl/compliance.rb +38 -0
  15. data/lib/chef/dsl/reader_helpers.rb +51 -0
  16. data/lib/chef/dsl/recipe.rb +4 -2
  17. data/lib/chef/dsl/secret.rb +2 -4
  18. data/lib/chef/dsl/universal.rb +2 -0
  19. data/lib/chef/event_dispatch/base.rb +44 -2
  20. data/lib/chef/formatters/doc.rb +60 -13
  21. data/lib/chef/formatters/minimal.rb +6 -5
  22. data/lib/chef/http/basic_client.rb +15 -7
  23. data/lib/chef/http.rb +12 -8
  24. data/lib/chef/provider/file.rb +2 -0
  25. data/lib/chef/provider/link.rb +2 -2
  26. data/lib/chef/provider/registry_key.rb +3 -2
  27. data/lib/chef/provider/remote_file/http.rb +1 -1
  28. data/lib/chef/provider/template.rb +1 -1
  29. data/lib/chef/resource/archive_file.rb +17 -14
  30. data/lib/chef/resource/chef_client_scheduled_task.rb +45 -2
  31. data/lib/chef/resource/chocolatey_config.rb +13 -13
  32. data/lib/chef/resource/execute.rb +2 -2
  33. data/lib/chef/resource/file/verification/json.rb +50 -0
  34. data/lib/chef/resource/file/verification/yaml.rb +52 -0
  35. data/lib/chef/resource/inspec_input.rb +127 -0
  36. data/lib/chef/resource/inspec_waiver.rb +184 -0
  37. data/lib/chef/resource/mount.rb +1 -1
  38. data/lib/chef/resource/openssl_x509_certificate.rb +1 -1
  39. data/lib/chef/resource/powershell_package_source.rb +234 -70
  40. data/lib/chef/resource/registry_key.rb +36 -48
  41. data/lib/chef/resource/remote_file.rb +98 -2
  42. data/lib/chef/resource/timezone.rb +2 -2
  43. data/lib/chef/resource/user_ulimit.rb +1 -0
  44. data/lib/chef/resource/windows_printer.rb +1 -1
  45. data/lib/chef/resource/windows_uac.rb +3 -1
  46. data/lib/chef/resource/windows_user_privilege.rb +1 -1
  47. data/lib/chef/resource.rb +1 -1
  48. data/lib/chef/resources.rb +2 -0
  49. data/lib/chef/run_context/cookbook_compiler.rb +112 -28
  50. data/lib/chef/run_context.rb +31 -1
  51. data/lib/chef/secret_fetcher/akeyless_vault.rb +57 -0
  52. data/lib/chef/secret_fetcher/aws_secrets_manager.rb +1 -1
  53. data/lib/chef/secret_fetcher/azure_key_vault.rb +1 -1
  54. data/lib/chef/secret_fetcher/base.rb +1 -1
  55. data/lib/chef/secret_fetcher/hashi_vault.rb +100 -0
  56. data/lib/chef/secret_fetcher.rb +8 -2
  57. data/lib/chef/version.rb +1 -1
  58. data/lib/chef/win32/version.rb +2 -1
  59. data/spec/data/archive_file/test_archive.tar.gz +0 -0
  60. data/spec/functional/resource/archive_file_spec.rb +87 -0
  61. data/spec/functional/resource/group_spec.rb +5 -1
  62. data/spec/functional/resource/link_spec.rb +8 -0
  63. data/spec/functional/resource/powershell_package_source_spec.rb +5 -6
  64. data/spec/integration/compliance/compliance_spec.rb +60 -0
  65. data/spec/spec_helper.rb +3 -0
  66. data/spec/support/platform_helpers.rb +4 -0
  67. data/spec/support/ruby_installer.rb +51 -0
  68. data/spec/unit/compliance/input_spec.rb +104 -0
  69. data/spec/unit/compliance/profile_spec.rb +120 -0
  70. data/spec/unit/compliance/waiver_spec.rb +104 -0
  71. data/spec/unit/formatters/doc_spec.rb +1 -1
  72. data/spec/unit/http/basic_client_spec.rb +30 -0
  73. data/spec/unit/http_spec.rb +8 -2
  74. data/spec/unit/provider/link_spec.rb +13 -7
  75. data/spec/unit/provider/remote_file/http_spec.rb +10 -0
  76. data/spec/unit/provider/template_spec.rb +2 -2
  77. data/spec/unit/resource/archive_file_spec.rb +414 -3
  78. data/spec/unit/resource/chef_client_scheduled_task_spec.rb +69 -0
  79. data/spec/unit/resource/file/verification/json_spec.rb +72 -0
  80. data/spec/unit/resource/file/verification/yaml_spec.rb +67 -0
  81. data/spec/unit/resource/inspec_input_spec.rb +300 -0
  82. data/spec/unit/resource/inspec_waiver_spec.rb +312 -0
  83. data/spec/unit/resource/mount_spec.rb +10 -0
  84. data/spec/unit/resource/powershell_package_source_spec.rb +63 -62
  85. data/spec/unit/resource/user_ulimit_spec.rb +14 -1
  86. data/spec/unit/secret_fetcher/akeyless_vault_spec.rb +37 -0
  87. data/spec/unit/secret_fetcher/hashi_vault_spec.rb +80 -0
  88. data/tasks/rspec.rb +2 -1
  89. metadata +60 -6
@@ -0,0 +1,184 @@
1
+ #
2
+ # Copyright:: Copyright (c) Chef Software Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require_relative "../resource"
18
+
19
+ class Chef
20
+ class Resource
21
+ class InspecWaiver < Chef::Resource
22
+ provides :inspec_waiver
23
+ unified_mode true
24
+
25
+ description "Use the **inspec_waiver** resource to add a waiver to the Compliance Phase."
26
+ introduced "17.5"
27
+ examples <<~DOC
28
+ **Activate the default waiver in the openssh cookbook's compliance segment**:
29
+
30
+ ```ruby
31
+ inspec_waiver 'openssh' do
32
+ action :add
33
+ end
34
+ ```
35
+
36
+ **Activate all waivers in the openssh cookbook's compliance segment**:
37
+
38
+ ```ruby
39
+ inspec_waiver 'openssh::.*' do
40
+ action :add
41
+ end
42
+ ```
43
+
44
+ **Add an InSpec waiver to the Compliance Phase**:
45
+
46
+ ```ruby
47
+ inspec_waiver 'Add waiver entry for control' do
48
+ control 'my_inspec_control_01'
49
+ run_test false
50
+ justification "The subject of this control is not managed by #{ChefUtils::Dist::Infra::PRODUCT} on the systems in policy group \#{node['policy_group']}"
51
+ expiration '2022-01-01'
52
+ action :add
53
+ end
54
+ ```
55
+
56
+ **Add an InSpec waiver to the Compliance Phase using the 'name' property to identify the control**:
57
+
58
+ ```ruby
59
+ inspec_waiver 'my_inspec_control_01' do
60
+ justification "The subject of this control is not managed by #{ChefUtils::Dist::Infra::PRODUCT} on the systems in policy group \#{node['policy_group']}"
61
+ action :add
62
+ end
63
+ ```
64
+
65
+ **Add an InSpec waiver to the Compliance Phase using an arbitrary YAML, JSON, or TOML file**:
66
+
67
+ ```ruby
68
+ # files ending in .yml or .yaml that exist are parsed as YAML
69
+ inspec_waiver "/path/to/my/waiver.yml"
70
+
71
+ inspec_waiver "my-waiver-name" do
72
+ source "/path/to/my/waiver.yml"
73
+ end
74
+
75
+ # files ending in .json that exist are parsed as JSON
76
+ inspec_waiver "/path/to/my/waiver.json"
77
+
78
+ inspec_waiver "my-waiver-name" do
79
+ source "/path/to/my/waiver.json"
80
+ end
81
+
82
+ # files ending in .toml that exist are parsed as TOML
83
+ inspec_waiver "/path/to/my/waiver.toml"
84
+
85
+ inspec_waiver "my-waiver-name" do
86
+ source "/path/to/my/waiver.toml"
87
+ end
88
+ ```
89
+
90
+ **Add an InSpec waiver to the Compliance Phase using a hash**:
91
+
92
+ ```ruby
93
+ my_hash = { "ssh-01" => {
94
+ "expiration_date" => "2033-07-31",
95
+ "run" => false,
96
+ "justification" => "because"
97
+ } }
98
+
99
+ inspec_waiver "my-waiver-name" do
100
+ source my_hash
101
+ end
102
+ ```
103
+
104
+ Note that the **inspec_waiver** resource does not update and will not fire notifications (similar to the log resource). This is done to preserve the ability to use
105
+ the resource while not causing the updated resource count to be larger than zero. Since the resource does not update the state of the managed node, this behavior
106
+ is still consistent with the configuration management model. Instead, you should use events to observe configuration changes for the compliance phase. It is
107
+ possible to use the `notify_group` resource to chain notifications of the two resources, but notifications are the wrong model to use, and you should use pure ruby
108
+ conditionals instead. Compliance configuration should be independent of other resources and should only be conditional based on state/attributes, not other resources.
109
+ DOC
110
+
111
+ property :control, String,
112
+ name_property: true,
113
+ description: "The name of the control being waived"
114
+
115
+ property :expiration, String,
116
+ description: "The expiration date of the waiver - provided in YYYY-MM-DD format",
117
+ callbacks: {
118
+ "Expiration date should be a valid calendar date and match the following format: YYYY-MM-DD" => proc { |e|
119
+ re = Regexp.new('\d{4}-\d{2}-\d{2}$').freeze
120
+ if re.match?(e)
121
+ Date.valid_date?(*e.split("-").map(&:to_i))
122
+ else
123
+ e.nil?
124
+ end
125
+ },
126
+ }
127
+
128
+ property :run_test, [true, false],
129
+ description: "If present and true, the control will run and be reported, but failures in it won’t make the overall run fail. If absent or false, the control will not be run."
130
+
131
+ property :justification, String,
132
+ description: "Can be any text you want and might include a reason for the waiver as well as who signed off on the waiver."
133
+
134
+ property :source, [ Hash, String ]
135
+
136
+ action :add, description: "Add a waiver to the compliance phase" do
137
+ if run_context.waiver_collection.valid?(new_resource.control)
138
+ include_waiver(new_resource.control)
139
+ else
140
+ include_waiver(waiver_hash)
141
+ end
142
+ end
143
+
144
+ action_class do
145
+ # If the source is nil and the control / name_property contains a file separator and is a string of a
146
+ # file that exists, then use that as the file (similar to the package provider automatic source property). Otherwise
147
+ # just return the source.
148
+ #
149
+ # @api private
150
+ def source
151
+ @source ||= build_source
152
+ end
153
+
154
+ def build_source
155
+ return new_resource.source unless new_resource.source.nil?
156
+ return nil unless new_resource.control.count(::File::SEPARATOR) > 0 || (::File::ALT_SEPARATOR && new_resource.control.count(::File::ALT_SEPARATOR) > 0 )
157
+ return nil unless ::File.exist?(new_resource.control)
158
+
159
+ new_resource.control
160
+ end
161
+
162
+ def waiver_hash
163
+ case source
164
+ when Hash
165
+ source
166
+ when String
167
+ parse_file(source)
168
+ when nil
169
+ if new_resource.justification.nil? || new_resource.justification == ""
170
+ raise Chef::Exceptions::ValidationFailed, "Entries for an InSpec waiver must have a justification given, this parameter must have a value."
171
+ end
172
+
173
+ control_hash = {}
174
+ control_hash["expiration_date"] = new_resource.expiration.to_s unless new_resource.expiration.nil?
175
+ control_hash["run"] = new_resource.run_test unless new_resource.run_test.nil?
176
+ control_hash["justification"] = new_resource.justification.to_s
177
+
178
+ { new_resource.control => control_hash }
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
@@ -42,7 +42,7 @@ class Chef
42
42
  sensitive: true
43
43
 
44
44
  property :mount_point, String, name_property: true,
45
- coerce: proc { |arg| arg.chomp("/") }, # Removed "/" from the end of str, because it was causing idempotency issue.
45
+ coerce: proc { |arg| (arg == "/" || arg.match?(":/$")) ? arg : arg.chomp("/") }, # Removed "/" from the end of str, because it was causing idempotency issue.
46
46
  description: "The directory (or path) in which the device is to be mounted. Defaults to the name of the resource block if not provided."
47
47
 
48
48
  property :device, String, identity: true,
@@ -226,7 +226,7 @@ class Chef
226
226
  end
227
227
 
228
228
  def ca_private_key
229
- if new_resource.csr_file.nil?
229
+ if new_resource.ca_key_file.nil?
230
230
  key
231
231
  else
232
232
  OpenSSL::PKey.read ::File.read(new_resource.ca_key_file), new_resource.ca_key_pass
@@ -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