chef 17.4.38-universal-mingw32 → 17.5.22-universal-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/chef.gemspec +2 -0
  3. data/lib/chef/application/base.rb +11 -1
  4. data/lib/chef/client.rb +1 -2
  5. data/lib/chef/compliance/input.rb +115 -0
  6. data/lib/chef/compliance/input_collection.rb +139 -0
  7. data/lib/chef/compliance/profile.rb +122 -0
  8. data/lib/chef/compliance/profile_collection.rb +109 -0
  9. data/lib/chef/compliance/runner.rb +47 -5
  10. data/lib/chef/compliance/waiver.rb +115 -0
  11. data/lib/chef/compliance/waiver_collection.rb +143 -0
  12. data/lib/chef/dsl/compliance.rb +38 -0
  13. data/lib/chef/dsl/reader_helpers.rb +51 -0
  14. data/lib/chef/dsl/recipe.rb +4 -2
  15. data/lib/chef/dsl/secret.rb +2 -4
  16. data/lib/chef/dsl/universal.rb +2 -0
  17. data/lib/chef/event_dispatch/base.rb +44 -2
  18. data/lib/chef/formatters/doc.rb +46 -0
  19. data/lib/chef/http/basic_client.rb +15 -7
  20. data/lib/chef/http.rb +7 -3
  21. data/lib/chef/provider/file.rb +2 -0
  22. data/lib/chef/provider/link.rb +2 -2
  23. data/lib/chef/provider/registry_key.rb +3 -2
  24. data/lib/chef/provider/remote_file/http.rb +1 -1
  25. data/lib/chef/provider/template.rb +1 -1
  26. data/lib/chef/resource/archive_file.rb +17 -14
  27. data/lib/chef/resource/chef_client_scheduled_task.rb +45 -2
  28. data/lib/chef/resource/chocolatey_config.rb +13 -13
  29. data/lib/chef/resource/file/verification/json.rb +50 -0
  30. data/lib/chef/resource/file/verification/yaml.rb +52 -0
  31. data/lib/chef/resource/inspec_input.rb +128 -0
  32. data/lib/chef/resource/inspec_waiver.rb +185 -0
  33. data/lib/chef/resource/mount.rb +1 -1
  34. data/lib/chef/resource/registry_key.rb +36 -48
  35. data/lib/chef/resource/remote_file.rb +98 -2
  36. data/lib/chef/resource/timezone.rb +2 -2
  37. data/lib/chef/resource/user_ulimit.rb +1 -0
  38. data/lib/chef/resource/windows_printer.rb +1 -1
  39. data/lib/chef/resource/windows_uac.rb +3 -1
  40. data/lib/chef/resource/windows_user_privilege.rb +1 -1
  41. data/lib/chef/resources.rb +2 -0
  42. data/lib/chef/run_context/cookbook_compiler.rb +112 -28
  43. data/lib/chef/run_context.rb +31 -1
  44. data/lib/chef/secret_fetcher/akeyless_vault.rb +57 -0
  45. data/lib/chef/secret_fetcher/aws_secrets_manager.rb +1 -1
  46. data/lib/chef/secret_fetcher/azure_key_vault.rb +1 -1
  47. data/lib/chef/secret_fetcher/base.rb +1 -1
  48. data/lib/chef/secret_fetcher/hashi_vault.rb +100 -0
  49. data/lib/chef/secret_fetcher.rb +8 -2
  50. data/lib/chef/version.rb +1 -1
  51. data/spec/data/archive_file/test_archive.tar.gz +0 -0
  52. data/spec/functional/resource/archive_file_spec.rb +87 -0
  53. data/spec/functional/resource/group_spec.rb +5 -1
  54. data/spec/functional/resource/link_spec.rb +8 -0
  55. data/spec/integration/compliance/compliance_spec.rb +60 -0
  56. data/spec/spec_helper.rb +3 -0
  57. data/spec/support/platform_helpers.rb +4 -0
  58. data/spec/support/ruby_installer.rb +51 -0
  59. data/spec/unit/compliance/input_spec.rb +104 -0
  60. data/spec/unit/compliance/profile_spec.rb +120 -0
  61. data/spec/unit/compliance/waiver_spec.rb +104 -0
  62. data/spec/unit/http/basic_client_spec.rb +30 -0
  63. data/spec/unit/http_spec.rb +8 -2
  64. data/spec/unit/provider/link_spec.rb +13 -7
  65. data/spec/unit/provider/remote_file/http_spec.rb +10 -0
  66. data/spec/unit/provider/template_spec.rb +2 -2
  67. data/spec/unit/resource/archive_file_spec.rb +414 -3
  68. data/spec/unit/resource/chef_client_scheduled_task_spec.rb +69 -0
  69. data/spec/unit/resource/file/verification/json_spec.rb +72 -0
  70. data/spec/unit/resource/file/verification/yaml_spec.rb +67 -0
  71. data/spec/unit/resource/inspec_input_spec.rb +300 -0
  72. data/spec/unit/resource/inspec_waiver_spec.rb +312 -0
  73. data/spec/unit/resource/mount_spec.rb +10 -0
  74. data/spec/unit/resource/user_ulimit_spec.rb +14 -1
  75. data/spec/unit/secret_fetcher/akeyless_vault_spec.rb +37 -0
  76. data/spec/unit/secret_fetcher/hashi_vault_spec.rb +80 -0
  77. data/tasks/rspec.rb +2 -1
  78. metadata +60 -6
@@ -81,6 +81,11 @@ class Chef
81
81
  description: "Should the resource overwrite the destination file contents if they already exist? If set to `:auto` the date stamp of files within the archive will be compared to those on disk and disk contents will be overwritten if they differ. This may cause unintended consequences if disk date stamps are changed between runs, which will result in the files being overwritten during each client run. Make sure to properly test any change to this property.",
82
82
  default: false
83
83
 
84
+ property :strip_components, Integer,
85
+ description: "Remove the specified number of leading path elements. Pathnames with fewer elements will be silently skipped. This behaves similarly to tar's --strip-components command line argument.",
86
+ introduced: "17.5",
87
+ default: 0
88
+
84
89
  # backwards compatibility for the legacy cookbook names
85
90
  alias_method :extract_options, :options
86
91
  alias_method :extract_to, :destination
@@ -117,7 +122,7 @@ class Chef
117
122
 
118
123
  if new_resource.owner || new_resource.group
119
124
  converge_by("set owner of files extracted in #{new_resource.destination} to #{new_resource.owner}:#{new_resource.group}") do
120
- archive = Archive::Reader.open_filename(new_resource.path)
125
+ archive = Archive::Reader.open_filename(new_resource.path, nil, strip_components: new_resource.strip_components)
121
126
  archive.each_entry do |e|
122
127
  FileUtils.chown(new_resource.owner, new_resource.group, "#{new_resource.destination}/#{e.pathname}")
123
128
  end
@@ -160,18 +165,16 @@ class Chef
160
165
  # @return [Boolean]
161
166
  def archive_differs_from_disk?(src, dest)
162
167
  modified = false
163
- Dir.chdir(dest) do
164
- archive = Archive::Reader.open_filename(src)
165
- Chef::Log.trace("Beginning the comparison of file mtime between contents of #{src} and #{dest}")
166
- archive.each_entry do |e|
167
- pathname = ::File.expand_path(e.pathname)
168
- if ::File.exist?(pathname)
169
- Chef::Log.trace("#{pathname} mtime is #{::File.mtime(pathname)} and archive is #{e.mtime}")
170
- modified = true unless ::File.mtime(pathname) == e.mtime
171
- else
172
- Chef::Log.trace("#{pathname} doesn't exist on disk, but exists in the archive")
173
- modified = true
174
- end
168
+ archive = Archive::Reader.open_filename(src, nil, strip_components: new_resource.strip_components)
169
+ Chef::Log.trace("Beginning the comparison of file mtime between contents of #{src} and #{dest}")
170
+ archive.each_entry do |e|
171
+ pathname = ::File.expand_path(e.pathname, dest)
172
+ if ::File.exist?(pathname)
173
+ Chef::Log.trace("#{pathname} mtime is #{::File.mtime(pathname)} and archive is #{e.mtime}")
174
+ modified = true unless ::File.mtime(pathname) == e.mtime
175
+ else
176
+ Chef::Log.trace("#{pathname} doesn't exist on disk, but exists in the archive")
177
+ modified = true
175
178
  end
176
179
  end
177
180
  modified
@@ -189,7 +192,7 @@ class Chef
189
192
  flags = [options].flatten.map { |option| extract_option_map[option] }.compact.reduce(:|)
190
193
 
191
194
  Dir.chdir(dest) do
192
- archive = Archive::Reader.open_filename(src)
195
+ archive = Archive::Reader.open_filename(src, nil, strip_components: new_resource.strip_components)
193
196
 
194
197
  archive.each_entry do |e|
195
198
  archive.extract(e, flags.to_i)
@@ -58,6 +58,14 @@ class Chef
58
58
  daemon_options ['-n audit_only']
59
59
  end
60
60
  ```
61
+
62
+ **Run #{ChefUtils::Dist::Infra::PRODUCT} with a persistent delay on every run calculated once, similar to how chef_client_cron resource works**:
63
+
64
+ ```ruby
65
+ chef_client_scheduled_task 'Run chef-client with persistent splay' do
66
+ use_consistent_splay true
67
+ end
68
+ ```
61
69
  DOC
62
70
 
63
71
  resource_name :chef_client_scheduled_task
@@ -104,6 +112,11 @@ class Chef
104
112
  description: "A random number of seconds between 0 and X to add to interval so that all #{ChefUtils::Dist::Infra::CLIENT} commands don't execute at the same time.",
105
113
  default: 300
106
114
 
115
+ property :use_consistent_splay, [true, false],
116
+ description: "Always use the same random splay amount for each node to ensure consistent frequencies between #{ChefUtils::Dist::Infra::CLIENT} execution.",
117
+ introduced: "17.5",
118
+ default: false
119
+
107
120
  property :run_on_battery, [true, false],
108
121
  description: "Run the #{ChefUtils::Dist::Infra::PRODUCT} task when the system is on batteries.",
109
122
  default: true
@@ -129,6 +142,11 @@ class Chef
129
142
  description: "An array of options to pass to the #{ChefUtils::Dist::Infra::CLIENT} command.",
130
143
  default: []
131
144
 
145
+ property :priority, Integer,
146
+ description: "Use to set Priority Levels range from 0 to 10.",
147
+ introduced: "17.5",
148
+ default: 7, callbacks: { "should be in range of 0 to 10" => proc { |v| v >= 0 && v <= 10 } }
149
+
132
150
  action :add, description: "Add a Windows Scheduled Task that runs #{ChefUtils::Dist::Infra::PRODUCT}." do
133
151
  # TODO: Replace this with a :create_if_missing action on directory when that exists
134
152
  unless Dir.exist?(new_resource.log_directory)
@@ -151,8 +169,9 @@ class Chef
151
169
  frequency_modifier new_resource.frequency_modifier if frequency_supports_frequency_modifier?
152
170
  start_time new_resource.start_time
153
171
  start_day new_resource.start_date unless new_resource.start_date.nil?
154
- random_delay new_resource.splay if frequency_supports_random_delay?
172
+ random_delay new_resource.splay if frequency_supports_random_delay? && !new_resource.use_consistent_splay
155
173
  disallow_start_if_on_batteries new_resource.splay unless new_resource.run_on_battery
174
+ priority new_resource.priority
156
175
  action %i{create enable}
157
176
  end
158
177
  end
@@ -173,7 +192,31 @@ class Chef
173
192
  # Fetch path of cmd.exe through environment variable comspec
174
193
  cmd_path = ENV["COMSPEC"]
175
194
 
176
- "#{cmd_path} /c \"#{client_cmd}\""
195
+ "#{cmd_path} /c \"#{consistent_splay_command}#{client_cmd}\""
196
+ end
197
+
198
+ #
199
+ # Generate a uniformly distributed unique number to sleep from 0 to the splay time
200
+ #
201
+ # @param [Integer] splay The number of seconds to splay
202
+ #
203
+ # @return [Integer]
204
+ #
205
+ def splay_sleep_time(splay)
206
+ seed = node["shard_seed"] || Digest::MD5.hexdigest(node.name).to_s.hex
207
+ random = Random.new(seed.to_i)
208
+ random.rand(splay)
209
+ end
210
+
211
+ #
212
+ # The consistent splay sleep time when use_consistent_splay is true.
213
+ #
214
+ # @return [NilClass,String] The prepended sleep command to run prior to executing the full command.
215
+ #
216
+ def consistent_splay_command
217
+ return unless new_resource.use_consistent_splay
218
+
219
+ "C:/windows/system32/windowspowershell/v1.0/powershell.exe Start-Sleep -s #{splay_sleep_time(new_resource.splay)} && "
177
220
  end
178
221
 
179
222
  #
@@ -24,22 +24,22 @@ class Chef
24
24
  description "Use the **chocolatey_config** resource to add or remove Chocolatey configuration keys."
25
25
  introduced "14.3"
26
26
  examples <<~DOC
27
- **Set the Chocolatey cacheLocation config**:
27
+ **Set the Chocolatey cacheLocation config**:
28
28
 
29
- ```ruby
30
- chocolatey_config 'Set cacheLocation config' do
31
- config_key 'cacheLocation'
32
- value 'C:\temp\choco'
33
- end
34
- ```
29
+ ```ruby
30
+ chocolatey_config 'Set cacheLocation config' do
31
+ config_key 'cacheLocation'
32
+ value 'C:\\temp\\choco'
33
+ end
34
+ ```
35
35
 
36
- **Unset a Chocolatey config**:
36
+ **Unset a Chocolatey config**:
37
37
 
38
- ```ruby
39
- chocolatey_config 'BogusConfig' do
40
- action :unset
41
- end
42
- ```
38
+ ```ruby
39
+ chocolatey_config 'BogusConfig' do
40
+ action :unset
41
+ end
42
+ ```
43
43
  DOC
44
44
 
45
45
  property :config_key, String, name_property: true,
@@ -0,0 +1,50 @@
1
+ #
2
+ # Author:: Antony Thomas (<antonydeepak@gmail.com>)
3
+ # Copyright:: Copyright (c) Facebook, Inc. and its affiliates.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ class Chef
20
+ class Resource
21
+ class File
22
+ class Verification
23
+
24
+ #
25
+ # Extends File verification to provide Json verification
26
+ #
27
+ # Example:
28
+ # file 'foo.json' do
29
+ # content '{"foo": "bar"}'
30
+ # verify :json
31
+ # end
32
+ #
33
+ #
34
+
35
+ class Json < Chef::Resource::File::Verification
36
+
37
+ provides :json
38
+
39
+ def verify(path, opts = {})
40
+ Chef::JSONCompat.parse(IO.read(path))
41
+ true
42
+ rescue Chef::Exceptions::JSON::ParseError => e
43
+ Chef::Log.error("Json syntax verify failed with : #{e.message}")
44
+ false
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,52 @@
1
+ #
2
+ # Author:: Antony Thomas (<antonydeepak@gmail.com>)
3
+ # Copyright:: Copyright (c) Chef Software Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require "psych" unless defined?(Psych)
20
+
21
+ class Chef
22
+ class Resource
23
+ class File
24
+ class Verification
25
+
26
+ #
27
+ # Extends File verification to provide a Yaml verification
28
+ #
29
+ # Example:
30
+ # file 'foo.yaml' do
31
+ # content "--- foo: 'foo-"
32
+ # verify :yaml
33
+ # end
34
+ #
35
+ #
36
+
37
+ class Yaml < Chef::Resource::File::Verification
38
+
39
+ provides :yaml
40
+
41
+ def verify(path, opts = {})
42
+ Psych.parse_file(path)
43
+ true
44
+ rescue Psych::SyntaxError => e
45
+ Chef::Log.error("Yaml syntax verify failed with : #{e.message}")
46
+ false
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,128 @@
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 InspecInput < Chef::Resource
22
+ provides :inspec_input
23
+ unified_mode true
24
+
25
+ description "Use the **inspec_input** resource to add an input to the Compliance Phase."
26
+ introduced "17.5"
27
+ examples <<~DOC
28
+
29
+ **Activate the default input in the openssh cookbook's compliance segment**:
30
+
31
+ ```ruby
32
+ inspec_input 'openssh' do
33
+ action :add
34
+ end
35
+ ```
36
+
37
+ **Activate all inputs in the openssh cookbook's compliance segment**:
38
+
39
+ ```ruby
40
+ inspec_input 'openssh::.*' do
41
+ action :add
42
+ end
43
+ ```
44
+
45
+ **Add an InSpec input to the Compliance Phase from a hash**:
46
+
47
+ ```ruby
48
+ inspec_input { ssh_custom_path: '/whatever2' }
49
+ ```
50
+
51
+ **Add an InSpec input to the Compliance Phase using the 'name' property to identify the input**:
52
+
53
+ ```ruby
54
+ inspec_input "setting my input" do
55
+ source( { ssh_custom_path: '/whatever2' })
56
+ end
57
+ ```
58
+
59
+ **Add an InSpec input to the Compliance Phase using a TOML, JSON or YAML file**:
60
+
61
+ ```ruby
62
+ inspec_input "/path/to/my/input.yml"
63
+ ```
64
+
65
+ **Add an InSpec input to the Compliance Phase using a TOML, JSON or YAML file, using the 'name' property**:
66
+
67
+ ```ruby
68
+ inspec_input "setting my input" do
69
+ source "/path/to/my/input.yml"
70
+ end
71
+ ```
72
+
73
+ Note that the inspec_input resource does not update and will not fire notifications (similar to the log resource). This is done to preserve the ability to use
74
+ the resource while not causing the updated resource count to be larger than zero. Since the resource does not update the state of the node being managed this
75
+ behavior is still consistent with the configuration management model. Events should be used to observe configuration changes for the compliance phase. It is
76
+ possible to use the `notify_group` resource to chain notifications of the two resources, but notifications are the wrong model to use and pure ruby conditionals
77
+ should be used instead. Compliance configuration should be independent of other resources and should only be made conditional based on state/attributes not
78
+ on other resources.
79
+ DOC
80
+
81
+ property :name, [ Hash, String ]
82
+
83
+ property :input, [ Hash, String ],
84
+ name_property: true
85
+
86
+ property :source, [ Hash, String ],
87
+ name_property: true
88
+
89
+ action :add, description: "Add an input to the compliance phase" do
90
+ if run_context.input_collection.valid?(new_resource.input)
91
+ include_input(new_resource.input)
92
+ else
93
+ include_input(input_hash)
94
+ end
95
+ end
96
+
97
+ action_class do
98
+ # If the source is nil and the input / name_property contains a file separator and is a string of a
99
+ # file that exists, then use that as the file (similar to the package provider automatic source property). Otherwise
100
+ # just return the source.
101
+ #
102
+ # @api private
103
+ def source
104
+ @source ||= build_source
105
+ end
106
+
107
+ def build_source
108
+ return new_resource.source unless new_resource.source.nil?
109
+ return nil unless new_resource.input.count(::File::SEPARATOR) > 0 || (::File::ALT_SEPARATOR && new_resource.input.count(::File::ALT_SEPARATOR) > 0 )
110
+ return nil unless ::File.exist?(new_resource.input)
111
+
112
+ new_resource.input
113
+ end
114
+
115
+ def input_hash
116
+ case source
117
+ when Hash
118
+ source
119
+ when String
120
+ parse_file(source)
121
+ when nil
122
+ raise Chef::Exceptions::ValidationFailed, "Could not find the input #{new_resource.input} in any cookbook segment."
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,185 @@
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 node being managed this
106
+ behavior is still consistent with the configuration management model. Events should be used 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 pure ruby conditionals
108
+ should be used instead. Compliance configuration should be independent of other resources and should only be made conditional based on state/attributes not
109
+ on other resources.
110
+ DOC
111
+
112
+ property :control, String,
113
+ name_property: true,
114
+ description: "The name of the control being waived"
115
+
116
+ property :expiration, String,
117
+ description: "The expiration date of the waiver - provided in YYYY-MM-DD format",
118
+ callbacks: {
119
+ "Expiration date should be a valid calendar date and match the following format: YYYY-MM-DD" => proc { |e|
120
+ re = Regexp.new('\d{4}-\d{2}-\d{2}$').freeze
121
+ if re.match?(e)
122
+ Date.valid_date?(*e.split("-").map(&:to_i))
123
+ else
124
+ e.nil?
125
+ end
126
+ },
127
+ }
128
+
129
+ property :run_test, [true, false],
130
+ 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."
131
+
132
+ property :justification, String,
133
+ description: "Can be any text you want and might include a reason for the waiver as well as who signed off on the waiver."
134
+
135
+ property :source, [ Hash, String ]
136
+
137
+ action :add, description: "Add a waiver to the compliance phase" do
138
+ if run_context.waiver_collection.valid?(new_resource.control)
139
+ include_waiver(new_resource.control)
140
+ else
141
+ include_waiver(waiver_hash)
142
+ end
143
+ end
144
+
145
+ action_class do
146
+ # If the source is nil and the control / name_property contains a file separator and is a string of a
147
+ # file that exists, then use that as the file (similar to the package provider automatic source property). Otherwise
148
+ # just return the source.
149
+ #
150
+ # @api private
151
+ def source
152
+ @source ||= build_source
153
+ end
154
+
155
+ def build_source
156
+ return new_resource.source unless new_resource.source.nil?
157
+ return nil unless new_resource.control.count(::File::SEPARATOR) > 0 || (::File::ALT_SEPARATOR && new_resource.control.count(::File::ALT_SEPARATOR) > 0 )
158
+ return nil unless ::File.exist?(new_resource.control)
159
+
160
+ new_resource.control
161
+ end
162
+
163
+ def waiver_hash
164
+ case source
165
+ when Hash
166
+ source
167
+ when String
168
+ parse_file(source)
169
+ when nil
170
+ if new_resource.justification.nil? || new_resource.justification == ""
171
+ raise Chef::Exceptions::ValidationFailed, "Entries for an InSpec waiver must have a justification given, this parameter must have a value."
172
+ end
173
+
174
+ control_hash = {}
175
+ control_hash["expiration_date"] = new_resource.expiration.to_s unless new_resource.expiration.nil?
176
+ control_hash["run"] = new_resource.run_test unless new_resource.run_test.nil?
177
+ control_hash["justification"] = new_resource.justification.to_s
178
+
179
+ { new_resource.control => control_hash }
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
185
+ 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,