chef 17.0.242-universal-mingw32 → 17.1.35-universal-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -12
- data/Rakefile +2 -2
- data/chef.gemspec +9 -20
- data/lib/chef/chef_fs/file_pattern.rb +2 -2
- data/lib/chef/compliance/default_attributes.rb +1 -1
- data/lib/chef/compliance/reporter/automate.rb +1 -1
- data/lib/chef/compliance/runner.rb +2 -2
- data/lib/chef/cookbook/cookbook_version_loader.rb +3 -3
- data/lib/chef/cookbook/gem_installer.rb +5 -1
- data/lib/chef/dsl/declare_resource.rb +5 -10
- data/lib/chef/formatters/doc.rb +2 -1
- data/lib/chef/node.rb +1 -1
- data/lib/chef/provider/directory.rb +6 -6
- data/lib/chef/provider/link.rb +1 -1
- data/lib/chef/provider/package/dnf/dnf_helper.py +11 -10
- data/lib/chef/provider/package/dnf/python_helper.rb +9 -8
- data/lib/chef/provider/package/yum.rb +1 -4
- data/lib/chef/provider/package/yum/python_helper.rb +15 -10
- data/lib/chef/provider/package/yum/yum_helper.py +46 -62
- data/lib/chef/provider/registry_key.rb +1 -1
- data/lib/chef/provider/service/systemd.rb +1 -1
- data/lib/chef/provider/systemd_unit.rb +1 -1
- data/lib/chef/provider/template/content.rb +1 -1
- data/lib/chef/provider/windows_script.rb +1 -1
- data/lib/chef/resource.rb +6 -7
- data/lib/chef/resource/execute.rb +2 -2
- data/lib/chef/resource/inspec_waiver_file_entry.rb +155 -0
- data/lib/chef/resource/lwrp_base.rb +17 -2
- data/lib/chef/resource/remote_file.rb +2 -2
- data/lib/chef/resource/windows_env.rb +1 -1
- data/lib/chef/resource/windows_font.rb +1 -1
- data/lib/chef/resource/windows_pagefile.rb +2 -2
- data/lib/chef/resource/windows_path.rb +2 -2
- data/lib/chef/resource/windows_security_policy.rb +5 -2
- data/lib/chef/resource/windows_task.rb +1 -1
- data/lib/chef/resource_builder.rb +8 -2
- data/lib/chef/resources.rb +1 -0
- data/lib/chef/run_lock.rb +1 -1
- data/lib/chef/runner.rb +1 -1
- data/lib/chef/shell/ext.rb +3 -3
- data/lib/chef/version.rb +1 -1
- data/lib/chef/win32/api.rb +9 -2
- data/spec/data/knife-home/.chef/plugins/knife/example_home_subcommand.rb +0 -0
- data/spec/data/knife-site-subcommands/plugins/knife/example_subcommand.rb +0 -0
- data/spec/data/knife_subcommand/test_explicit_category.rb +7 -0
- data/spec/data/knife_subcommand/test_name_mapping.rb +4 -0
- data/spec/data/knife_subcommand/test_yourself.rb +21 -0
- data/spec/functional/resource/dnf_package_spec.rb +857 -537
- data/spec/functional/resource/group_spec.rb +1 -1
- data/spec/functional/resource/link_spec.rb +1 -1
- data/spec/functional/resource/remote_file_spec.rb +1 -1
- data/spec/functional/resource/windows_env_spec.rb +2 -2
- data/spec/functional/resource/yum_package_spec.rb +495 -428
- data/spec/integration/client/client_spec.rb +0 -20
- data/spec/integration/recipes/unified_mode_spec.rb +70 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/chef_helpers.rb +1 -1
- data/spec/support/shared/functional/execute_resource.rb +1 -1
- data/spec/support/shared/functional/knife.rb +37 -0
- data/spec/support/shared/integration/knife_support.rb +192 -0
- data/spec/support/shared/unit/knife_shared.rb +39 -0
- data/spec/support/shared/unit/provider/file.rb +1 -1
- data/spec/unit/chef_fs/file_system/repository/directory_spec.rb +1 -1
- data/spec/unit/compliance/runner_spec.rb +1 -1
- data/spec/unit/provider/link_spec.rb +1 -1
- data/spec/unit/provider/package/dnf/python_helper_spec.rb +1 -0
- data/spec/unit/provider/package/yum/python_helper_spec.rb +1 -0
- data/spec/unit/provider/service/systemd_service_spec.rb +2 -2
- data/spec/unit/provider/systemd_unit_spec.rb +2 -2
- data/spec/unit/resource/inspec_waiver_file_entry_spec.rb +80 -0
- data/tasks/rspec.rb +4 -9
- metadata +16 -160
- data/lib/chef/provider/package/yum/simplejson/LICENSE.txt +0 -79
- data/lib/chef/provider/package/yum/simplejson/__init__.py +0 -318
- data/lib/chef/provider/package/yum/simplejson/__init__.pyc +0 -0
- data/lib/chef/provider/package/yum/simplejson/decoder.py +0 -354
- data/lib/chef/provider/package/yum/simplejson/decoder.pyc +0 -0
- data/lib/chef/provider/package/yum/simplejson/encoder.py +0 -440
- data/lib/chef/provider/package/yum/simplejson/encoder.pyc +0 -0
- data/lib/chef/provider/package/yum/simplejson/scanner.py +0 -65
- data/lib/chef/provider/package/yum/simplejson/scanner.pyc +0 -0
- data/lib/chef/provider/package/yum/simplejson/tool.py +0 -37
@@ -2,45 +2,26 @@
|
|
2
2
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
3
3
|
|
4
4
|
#
|
5
|
-
# NOTE: this actually needs to run under python2.
|
6
|
-
# please manually test changes on
|
5
|
+
# NOTE: this actually needs to run under python2.7 and centos 6.x through python3 and centos 7.x
|
6
|
+
# please manually test changes on centos6 boxes or you will almost certainly break things.
|
7
7
|
#
|
8
8
|
|
9
9
|
import sys
|
10
10
|
import yum
|
11
11
|
import signal
|
12
12
|
import os
|
13
|
-
|
14
|
-
|
15
|
-
except ImportError: import simplejson as json
|
13
|
+
import fcntl
|
14
|
+
import json
|
16
15
|
import re
|
17
16
|
from rpmUtils.miscutils import stringToVersion,compareEVR
|
18
17
|
from rpmUtils.arch import getBaseArch, getArchList
|
19
|
-
|
20
|
-
|
21
|
-
try: from yum.misc import string_to_prco_tuple
|
22
|
-
except ImportError:
|
23
|
-
# RHEL5 compat
|
24
|
-
def string_to_prco_tuple(prcoString):
|
25
|
-
prco_split = prcoString.split()
|
26
|
-
n, f, v = prco_split
|
27
|
-
(prco_e, prco_v, prco_r) = stringToVersion(v)
|
28
|
-
return (n, f, (prco_e, prco_v, prco_r))
|
18
|
+
from yum.misc import string_to_prco_tuple
|
29
19
|
|
30
20
|
# hack to work around https://github.com/chef/chef/issues/7126
|
31
21
|
# see https://bugzilla.redhat.com/show_bug.cgi?id=1396248
|
32
22
|
if not hasattr(yum.packages.FakeRepository, 'compare_providers_priority'):
|
33
23
|
yum.packages.FakeRepository.compare_providers_priority = 99
|
34
24
|
|
35
|
-
base = None
|
36
|
-
|
37
|
-
def get_base():
|
38
|
-
global base
|
39
|
-
if base is None:
|
40
|
-
base = yum.YumBase()
|
41
|
-
setup_exit_handler()
|
42
|
-
return base
|
43
|
-
|
44
25
|
def versioncompare(versions):
|
45
26
|
arch_list = getArchList()
|
46
27
|
candidate_arch1 = versions[0].split(".")[-1]
|
@@ -51,9 +32,9 @@ def versioncompare(versions):
|
|
51
32
|
# then we'll chop the arch component (assuming it *is* a valid one) from the first version string
|
52
33
|
# so we're only comparing the evr portions.
|
53
34
|
if (candidate_arch2 not in arch_list) and (candidate_arch1 in arch_list):
|
54
|
-
|
35
|
+
final_version1 = versions[0].replace("." + candidate_arch1,"")
|
55
36
|
else:
|
56
|
-
|
37
|
+
final_version1 = versions[0]
|
57
38
|
|
58
39
|
final_version2 = versions[1]
|
59
40
|
|
@@ -64,37 +45,24 @@ def versioncompare(versions):
|
|
64
45
|
outpipe.write("%(e)s\n" % { 'e': evr_comparison })
|
65
46
|
outpipe.flush()
|
66
47
|
|
67
|
-
def install_only_packages(name):
|
68
|
-
base = get_base()
|
48
|
+
def install_only_packages(base, name):
|
69
49
|
if name in base.conf.installonlypkgs:
|
70
|
-
|
50
|
+
outpipe.write('True\n')
|
71
51
|
else:
|
72
|
-
|
52
|
+
outpipe.write('False\n')
|
73
53
|
outpipe.flush()
|
74
54
|
|
75
|
-
|
76
|
-
try:
|
77
|
-
any
|
78
|
-
except NameError:
|
79
|
-
def any(s):
|
80
|
-
for v in s:
|
81
|
-
if v:
|
82
|
-
return True
|
83
|
-
return False
|
84
|
-
|
85
|
-
def query(command):
|
86
|
-
base = get_base()
|
87
|
-
|
55
|
+
def query(base, command):
|
88
56
|
enabled_repos = base.repos.listEnabled()
|
89
57
|
|
90
58
|
# Handle any repocontrols passed in with our options
|
91
59
|
|
92
60
|
if 'repos' in command:
|
93
|
-
|
94
|
-
|
95
|
-
|
61
|
+
for repo in command['repos']:
|
62
|
+
if 'enable' in repo:
|
63
|
+
base.repos.enableRepo(repo['enable'])
|
96
64
|
if 'disable' in repo:
|
97
|
-
|
65
|
+
base.repos.disableRepo(repo['disable'])
|
98
66
|
|
99
67
|
args = { 'name': command['provides'] }
|
100
68
|
do_nevra = False
|
@@ -136,7 +104,7 @@ def query(command):
|
|
136
104
|
# returnPackages and searchProvides and then apply the Nevra filters to those results.
|
137
105
|
pkgs = obj.searchNevra(**args)
|
138
106
|
if (command['action'] == "whatinstalled") and (not pkgs):
|
139
|
-
|
107
|
+
pkgs = obj.searchNevra(name=args['name'], arch=desired_arch)
|
140
108
|
else:
|
141
109
|
pats = [command['provides']]
|
142
110
|
pkgs = obj.returnPackages(patterns=pats)
|
@@ -157,13 +125,13 @@ def query(command):
|
|
157
125
|
|
158
126
|
# Reset any repos we were passed in enablerepo/disablerepo to the original state in enabled_repos
|
159
127
|
if 'repos' in command:
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
128
|
+
for repo in command['repos']:
|
129
|
+
if 'enable' in repo:
|
130
|
+
if base.repos.getRepo(repo['enable']) not in enabled_repos:
|
131
|
+
base.repos.disableRepo(repo['enable'])
|
164
132
|
if 'disable' in repo:
|
165
|
-
|
166
|
-
|
133
|
+
if base.repos.getRepo(repo['disable']) in enabled_repos:
|
134
|
+
base.repos.enableRepo(repo['disable'])
|
167
135
|
|
168
136
|
# the design of this helper is that it should try to be 'brittle' and fail hard and exit in order
|
169
137
|
# to keep process tables clean. additional error handling should probably be added to the retry loop
|
@@ -179,21 +147,29 @@ def setup_exit_handler():
|
|
179
147
|
signal.signal(signal.SIGPIPE, exit_handler)
|
180
148
|
signal.signal(signal.SIGQUIT, exit_handler)
|
181
149
|
|
150
|
+
def set_blocking(fd):
|
151
|
+
old_flags = fcntl.fcntl(fd, fcntl.F_GETFL)
|
152
|
+
fcntl.fcntl(fd, fcntl.F_SETFL, old_flags & ~os.O_NONBLOCK)
|
153
|
+
|
154
|
+
base = None
|
155
|
+
|
182
156
|
if len(sys.argv) < 3:
|
183
|
-
|
184
|
-
|
157
|
+
inpipe = sys.stdin
|
158
|
+
outpipe = sys.stdout
|
185
159
|
else:
|
186
|
-
|
187
|
-
|
160
|
+
set_blocking(int(sys.argv[1]))
|
161
|
+
set_blocking(int(sys.argv[2]))
|
162
|
+
inpipe = os.fdopen(int(sys.argv[1]), "r")
|
163
|
+
outpipe = os.fdopen(int(sys.argv[2]), "w")
|
188
164
|
|
189
165
|
try:
|
166
|
+
setup_exit_handler()
|
190
167
|
while 1:
|
191
168
|
# stop the process if the parent proc goes away
|
192
169
|
ppid = os.getppid()
|
193
170
|
if ppid == 1:
|
194
171
|
raise RuntimeError("orphaned")
|
195
172
|
|
196
|
-
setup_exit_handler()
|
197
173
|
line = inpipe.readline()
|
198
174
|
|
199
175
|
# only way to detect EOF in python
|
@@ -205,14 +181,22 @@ try:
|
|
205
181
|
except ValueError, e:
|
206
182
|
raise RuntimeError("bad json parse")
|
207
183
|
|
184
|
+
if base is None:
|
185
|
+
base = yum.YumBase()
|
186
|
+
|
208
187
|
if command['action'] == "whatinstalled":
|
209
|
-
query(command)
|
188
|
+
query(base, command)
|
210
189
|
elif command['action'] == "whatavailable":
|
211
|
-
query(command)
|
190
|
+
query(base, command)
|
212
191
|
elif command['action'] == "versioncompare":
|
213
192
|
versioncompare(command['versions'])
|
214
193
|
elif command['action'] == "installonlypkgs":
|
215
|
-
|
194
|
+
install_only_packages(base, command['package'])
|
195
|
+
elif command['action'] == "close_rpmdb":
|
196
|
+
base.closeRpmDB()
|
197
|
+
base = None
|
198
|
+
outpipe.write('nil nil nil\n')
|
199
|
+
outpipe.flush()
|
216
200
|
else:
|
217
201
|
raise RuntimeError("bad command")
|
218
202
|
finally:
|
@@ -78,7 +78,7 @@ class Chef
|
|
78
78
|
def define_resource_requirements
|
79
79
|
requirements.assert(:create, :create_if_missing, :delete, :delete_key) do |a|
|
80
80
|
a.assertion { registry.hive_exists?(new_resource.key) }
|
81
|
-
a.failure_message(Chef::Exceptions::Win32RegHiveMissing, "Hive #{new_resource.key.split(
|
81
|
+
a.failure_message(Chef::Exceptions::Win32RegHiveMissing, "Hive #{new_resource.key.split("\\").shift} does not exist")
|
82
82
|
end
|
83
83
|
|
84
84
|
requirements.assert(:create) do |a|
|
@@ -80,7 +80,7 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
|
|
80
80
|
@systemd_service_status ||= begin
|
81
81
|
# Collect all the status information for a service and returns it at once
|
82
82
|
options, args = get_systemctl_options_args
|
83
|
-
s = shell_out!(systemctl_path, args, "show", "-p", "UnitFileState", "-p", "ActiveState", new_resource.service_name, options)
|
83
|
+
s = shell_out!(systemctl_path, args, "show", "-p", "UnitFileState", "-p", "ActiveState", new_resource.service_name, **options)
|
84
84
|
# e.g. /bin/systemctl --system show -p UnitFileState -p ActiveState sshd.service
|
85
85
|
# Returns something like:
|
86
86
|
# ActiveState=active
|
@@ -60,7 +60,7 @@ class Chef
|
|
60
60
|
# Collect all the status information for a unit and return it at once
|
61
61
|
# This may fail if we are managing a template unit (e.g. with '@'), in which case
|
62
62
|
# we just ignore the error because unit status is irrelevant in that case
|
63
|
-
s = shell_out(*systemctl_cmd, "show", "-p", "UnitFileState", "-p", "ActiveState", new_resource.unit_name, systemctl_opts)
|
63
|
+
s = shell_out(*systemctl_cmd, "show", "-p", "UnitFileState", "-p", "ActiveState", new_resource.unit_name, **systemctl_opts)
|
64
64
|
# e.g. /bin/systemctl --system show -p UnitFileState -p ActiveState syslog.socket
|
65
65
|
# Returns something like:
|
66
66
|
# ActiveState=inactive
|
@@ -63,7 +63,7 @@ class Chef
|
|
63
63
|
context[:template_finder] = template_finder
|
64
64
|
|
65
65
|
# helper variables
|
66
|
-
context[:cookbook_name] = new_resource.cookbook_name unless context.keys.include?(:
|
66
|
+
context[:cookbook_name] = new_resource.cookbook_name unless context.keys.include?(:cookbook_name)
|
67
67
|
context[:recipe_name] = new_resource.recipe_name unless context.keys.include?(:recipe_name)
|
68
68
|
context[:recipe_line_string] = new_resource.source_line unless context.keys.include?(:recipe_line_string)
|
69
69
|
context[:recipe_path] = new_resource.source_line_file unless context.keys.include?(:recipe_path)
|
@@ -83,7 +83,7 @@ class Chef
|
|
83
83
|
username = new_resource.user
|
84
84
|
|
85
85
|
if new_resource.domain
|
86
|
-
username = new_resource.domain +
|
86
|
+
username = new_resource.domain + "\\" + new_resource.user
|
87
87
|
end
|
88
88
|
|
89
89
|
# Create an ACE that allows the alternate user read access to the script
|
data/lib/chef/resource.rb
CHANGED
@@ -42,6 +42,7 @@ require_relative "mixin/deprecation"
|
|
42
42
|
require_relative "mixin/properties"
|
43
43
|
require_relative "mixin/provides"
|
44
44
|
require_relative "dsl/universal"
|
45
|
+
require_relative "constants"
|
45
46
|
|
46
47
|
class Chef
|
47
48
|
class Resource
|
@@ -1362,8 +1363,9 @@ class Chef
|
|
1362
1363
|
#
|
1363
1364
|
# @param arg [String] version constraint to match against (e.g. "> 14")
|
1364
1365
|
#
|
1365
|
-
def self.chef_version_for_provides(constraint)
|
1366
|
-
@chef_version_for_provides = constraint
|
1366
|
+
def self.chef_version_for_provides(constraint = NOT_PASSED)
|
1367
|
+
@chef_version_for_provides = constraint unless constraint == NOT_PASSED
|
1368
|
+
@chef_version_for_provides ||= nil
|
1367
1369
|
end
|
1368
1370
|
|
1369
1371
|
# Mark this resource as providing particular DSL.
|
@@ -1376,14 +1378,11 @@ class Chef
|
|
1376
1378
|
def self.provides(name, **options, &block)
|
1377
1379
|
name = name.to_sym
|
1378
1380
|
|
1379
|
-
# quell warnings
|
1380
|
-
@chef_version_for_provides = nil unless defined?(@chef_version_for_provides)
|
1381
|
-
|
1382
1381
|
# deliberately do not go through the accessor here
|
1383
1382
|
@resource_name = name if resource_name.nil?
|
1384
1383
|
|
1385
|
-
if
|
1386
|
-
options[:chef_version] =
|
1384
|
+
if chef_version_for_provides && !options.include?(:chef_version)
|
1385
|
+
options[:chef_version] = chef_version_for_provides
|
1387
1386
|
end
|
1388
1387
|
|
1389
1388
|
result = Chef.resource_handler_map.set(name, self, **options, &block)
|
@@ -633,13 +633,13 @@ class Chef
|
|
633
633
|
end
|
634
634
|
|
635
635
|
# if domain is provided in both username and domain
|
636
|
-
if specified_user.is_a?(String) && ((specified_user.include?
|
636
|
+
if specified_user.is_a?(String) && ((specified_user.include? "\\") || (specified_user.include? "@")) && specified_domain
|
637
637
|
raise ArgumentError, "The domain is provided twice. Username: `#{specified_user}`, Domain: `#{specified_domain}`. Please specify domain only once."
|
638
638
|
end
|
639
639
|
|
640
640
|
if specified_user.is_a?(String) && specified_domain.nil?
|
641
641
|
# Splitting username of format: Domain\Username
|
642
|
-
domain_and_user = user.split(
|
642
|
+
domain_and_user = user.split("\\")
|
643
643
|
|
644
644
|
if domain_and_user.length == 2
|
645
645
|
domain = domain_and_user[0]
|
@@ -0,0 +1,155 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Davin Taddeo (<davin@chef.io>)
|
3
|
+
# Copyright:: Copyright (c) Chef Software Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require_relative "../resource"
|
19
|
+
require "yaml"
|
20
|
+
require "date"
|
21
|
+
|
22
|
+
class Chef
|
23
|
+
class Resource
|
24
|
+
class InspecWaiverFileEntry < Chef::Resource
|
25
|
+
provides :inspec_waiver_file_entry
|
26
|
+
unified_mode true
|
27
|
+
|
28
|
+
description "Use the **inspec_waiver_file_entry** resource to add or remove entries from an InSpec waiver file. This can be used in conjunction with the Compliance Phase."
|
29
|
+
introduced "17.1"
|
30
|
+
examples <<~DOC
|
31
|
+
**Add an InSpec waiver entry to a given waiver file**:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
inspec_waiver_file_entry 'Add waiver entry for control' do
|
35
|
+
file_path 'C:\\chef\\inspec_waiver_file.yml'
|
36
|
+
control 'my_inspec_control_01'
|
37
|
+
run_test false
|
38
|
+
justification "The subject of this control is not managed by Chef on the systems in policy group \#{node['policy_group']}"
|
39
|
+
expiration '2022-01-01'
|
40
|
+
action :add
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
**Add an InSpec waiver entry to a given waiver file using the 'name' property to identify the control**:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
inspec_waiver_file_entry 'my_inspec_control_01' do
|
48
|
+
justification "The subject of this control is not managed by Chef on the systems in policy group \#{node['policy_group']}"
|
49
|
+
action :add
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
**Remove an InSpec waiver entry to a given waiver file**:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
inspec_waiver_file_entry "my_inspec_control_01" do
|
57
|
+
action :remove
|
58
|
+
end
|
59
|
+
```
|
60
|
+
DOC
|
61
|
+
|
62
|
+
property :control, String,
|
63
|
+
name_property: true,
|
64
|
+
description: "The name of the control being added or removed to the waiver file"
|
65
|
+
|
66
|
+
property :file_path, String,
|
67
|
+
required: true,
|
68
|
+
description: "The path to the waiver file being modified",
|
69
|
+
default: "#{ChefConfig::Config.etc_chef_dir}/inspec_waivers.yml",
|
70
|
+
default_description: "`/etc/chef/inspec_waivers.yml` on Linux/Unix and `C:\\chef\\inspec_waivers.yml` on Windows"
|
71
|
+
|
72
|
+
property :expiration, String,
|
73
|
+
description: "The expiration date of the given waiver - provided in YYYY-MM-DD format",
|
74
|
+
callbacks: {
|
75
|
+
"Expiration date should be a valid calendar date and match the following format: YYYY-MM-DD" => proc { |e|
|
76
|
+
re = Regexp.new('\d{4}-\d{2}-\d{2}$').freeze
|
77
|
+
if re.match?(e)
|
78
|
+
Date.valid_date?(*e.split("-").map(&:to_i))
|
79
|
+
else
|
80
|
+
e.nil?
|
81
|
+
end
|
82
|
+
},
|
83
|
+
}
|
84
|
+
|
85
|
+
property :run_test, [true, false],
|
86
|
+
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."
|
87
|
+
|
88
|
+
property :justification, String,
|
89
|
+
description: "Can be any text you want and might include a reason for the waiver as well as who signed off on the waiver."
|
90
|
+
|
91
|
+
property :backup, [false, Integer],
|
92
|
+
description: "The number of backups to be kept in /var/chef/backup (for UNIX- and Linux-based platforms) or C:/chef/backup (for the Microsoft Windows platform). Set to false to prevent backups from being kept.",
|
93
|
+
default: false
|
94
|
+
|
95
|
+
action :add do
|
96
|
+
if new_resource.justification.nil? || new_resource.justification == ""
|
97
|
+
raise Chef::Exceptions::ValidationFailed, "Entries in the InSpec waiver file must have a justification given, this parameter must have a value."
|
98
|
+
end
|
99
|
+
|
100
|
+
filename = new_resource.file_path
|
101
|
+
waiver_hash = load_waiver_file_to_hash(filename)
|
102
|
+
control_hash = {}
|
103
|
+
control_hash["expiration_date"] = new_resource.expiration.to_s unless new_resource.expiration.nil?
|
104
|
+
control_hash["run"] = new_resource.run_test unless new_resource.run_test.nil?
|
105
|
+
control_hash["justification"] = new_resource.justification.to_s
|
106
|
+
|
107
|
+
unless waiver_hash[new_resource.control] == control_hash
|
108
|
+
waiver_hash[new_resource.control] = control_hash
|
109
|
+
waiver_hash = waiver_hash.sort.to_h
|
110
|
+
|
111
|
+
file "Update Waiver File #{new_resource.file_path} to update waiver for control #{new_resource.control}" do
|
112
|
+
path new_resource.file_path
|
113
|
+
content waiver_hash.to_yaml
|
114
|
+
backup new_resource.backup
|
115
|
+
action :create
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
action :remove do
|
121
|
+
filename = new_resource.file_path
|
122
|
+
waiver_hash = load_waiver_file_to_hash(filename)
|
123
|
+
if waiver_hash.key?(new_resource.control)
|
124
|
+
waiver_hash.delete(new_resource.control)
|
125
|
+
waiver_hash = waiver_hash.sort.to_h
|
126
|
+
file "Update Waiver File #{new_resource.file_path} to remove waiver for control #{new_resource.control}" do
|
127
|
+
path new_resource.file_path
|
128
|
+
content waiver_hash.to_yaml
|
129
|
+
backup new_resource.backup
|
130
|
+
action :create
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
action_class do
|
136
|
+
def load_waiver_file_to_hash(file_name)
|
137
|
+
if file_name =~ %r{(/|C:\\).*(.yaml|.yml)}i
|
138
|
+
if ::File.exist?(file_name)
|
139
|
+
hash = ::YAML.load_file(file_name)
|
140
|
+
if hash == false || hash.nil? || hash == ""
|
141
|
+
{}
|
142
|
+
else
|
143
|
+
::YAML.load_file(file_name)
|
144
|
+
end
|
145
|
+
else
|
146
|
+
{}
|
147
|
+
end
|
148
|
+
else
|
149
|
+
raise "Waiver files needs to be a YAML file which should have a .yaml or .yml extension -\"#{file_name}\" does not have an appropriate extension"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|