abide_dev_utils 0.11.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +18 -31
- data/lib/abide_dev_utils/cem/benchmark.rb +335 -136
- data/lib/abide_dev_utils/cem/generate/coverage_report.rb +380 -0
- data/lib/abide_dev_utils/cem/generate/reference.rb +238 -35
- data/lib/abide_dev_utils/cem/generate.rb +5 -4
- data/lib/abide_dev_utils/cem/hiera_data/mapping_data/map_data.rb +110 -0
- data/lib/abide_dev_utils/cem/hiera_data/mapping_data/mixins.rb +46 -0
- data/lib/abide_dev_utils/cem/hiera_data/mapping_data.rb +146 -0
- data/lib/abide_dev_utils/cem/hiera_data/resource_data/control.rb +127 -0
- data/lib/abide_dev_utils/cem/hiera_data/resource_data/parameters.rb +90 -0
- data/lib/abide_dev_utils/cem/hiera_data/resource_data/resource.rb +102 -0
- data/lib/abide_dev_utils/cem/hiera_data/resource_data.rb +310 -0
- data/lib/abide_dev_utils/cem/hiera_data.rb +7 -0
- data/lib/abide_dev_utils/cem/mapping/mapper.rb +161 -34
- data/lib/abide_dev_utils/cem/validate/resource_data.rb +33 -0
- data/lib/abide_dev_utils/cem/validate.rb +10 -0
- data/lib/abide_dev_utils/cem.rb +0 -1
- data/lib/abide_dev_utils/cli/cem.rb +20 -2
- data/lib/abide_dev_utils/dot_number_comparable.rb +75 -0
- data/lib/abide_dev_utils/errors/cem.rb +10 -0
- data/lib/abide_dev_utils/ppt/class_utils.rb +1 -1
- data/lib/abide_dev_utils/ppt/code_gen/data_types.rb +64 -0
- data/lib/abide_dev_utils/ppt/code_gen/generate.rb +15 -0
- data/lib/abide_dev_utils/ppt/code_gen/resource.rb +59 -0
- data/lib/abide_dev_utils/ppt/code_gen/resource_types/base.rb +93 -0
- data/lib/abide_dev_utils/ppt/code_gen/resource_types/class.rb +17 -0
- data/lib/abide_dev_utils/ppt/code_gen/resource_types/manifest.rb +16 -0
- data/lib/abide_dev_utils/ppt/code_gen/resource_types/parameter.rb +16 -0
- data/lib/abide_dev_utils/ppt/code_gen/resource_types/strings.rb +13 -0
- data/lib/abide_dev_utils/ppt/code_gen/resource_types.rb +6 -0
- data/lib/abide_dev_utils/ppt/code_gen.rb +15 -0
- data/lib/abide_dev_utils/ppt/code_introspection.rb +102 -0
- data/lib/abide_dev_utils/ppt/hiera.rb +4 -1
- data/lib/abide_dev_utils/ppt/puppet_module.rb +2 -1
- data/lib/abide_dev_utils/ppt.rb +3 -0
- data/lib/abide_dev_utils/version.rb +1 -1
- data/lib/abide_dev_utils/xccdf/parser/helpers.rb +146 -0
- data/lib/abide_dev_utils/xccdf/parser/objects.rb +87 -144
- data/lib/abide_dev_utils/xccdf/parser.rb +5 -0
- data/lib/abide_dev_utils/xccdf/utils.rb +89 -0
- data/lib/abide_dev_utils/xccdf.rb +193 -63
- metadata +27 -3
- data/lib/abide_dev_utils/cem/coverage_report.rb +0 -348
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6f05434761a55369ffb231c1573ba627aa5c9ebef29d198ccfa16c422d05c48
|
4
|
+
data.tar.gz: 534968456e7eefca691fa6a3cdc46a170dc3ee12060261225fc35adadbc27d18
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9907ee602b3367d4692b5c2102f0c769614f33d22980d5b8c0a14ea7dd15ac19947800eed399e6d68215ea2c21ab670b233209bf62e79399795fc5cc0ca68c2
|
7
|
+
data.tar.gz: edbeac0d044795300b42ac1ddd70623abc9c9e7d322ecf1e5d6356c8b4f875a31e31e02c96397b0bc9ee1a6a815fa342401916d9f87696f0ad68f0bd9d887b75
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
abide_dev_utils (0.
|
4
|
+
abide_dev_utils (0.12.1)
|
5
5
|
amatch (~> 0.4)
|
6
6
|
cmdparse (~> 3.0)
|
7
7
|
facterdb (>= 1.18)
|
@@ -60,10 +60,10 @@ GEM
|
|
60
60
|
diff-lcs (1.5.0)
|
61
61
|
digest-crc (0.6.4)
|
62
62
|
rake (>= 12.0.0, < 14.0.0)
|
63
|
-
facter (4.2.
|
63
|
+
facter (4.2.11)
|
64
64
|
hocon (~> 1.3)
|
65
65
|
thor (>= 1.0.1, < 2.0)
|
66
|
-
facterdb (1.
|
66
|
+
facterdb (1.19.0)
|
67
67
|
facter (< 5.0.0)
|
68
68
|
jgrep
|
69
69
|
faraday (2.3.0)
|
@@ -84,7 +84,7 @@ GEM
|
|
84
84
|
octokit (~> 4.6)
|
85
85
|
rainbow (>= 2.2.1)
|
86
86
|
rake (>= 10.0)
|
87
|
-
google-apis-core (0.
|
87
|
+
google-apis-core (0.7.0)
|
88
88
|
addressable (~> 2.5, >= 2.5.1)
|
89
89
|
googleauth (>= 0.16.2, < 2.a)
|
90
90
|
httpclient (>= 2.8.1, < 3.a)
|
@@ -93,25 +93,25 @@ GEM
|
|
93
93
|
retriable (>= 2.0, < 4.a)
|
94
94
|
rexml
|
95
95
|
webrick
|
96
|
-
google-apis-iamcredentials_v1 (0.
|
97
|
-
google-apis-core (>= 0.
|
98
|
-
google-apis-storage_v1 (0.
|
99
|
-
google-apis-core (>= 0.
|
96
|
+
google-apis-iamcredentials_v1 (0.13.0)
|
97
|
+
google-apis-core (>= 0.7, < 2.a)
|
98
|
+
google-apis-storage_v1 (0.17.0)
|
99
|
+
google-apis-core (>= 0.7, < 2.a)
|
100
100
|
google-cloud-core (1.6.0)
|
101
101
|
google-cloud-env (~> 1.0)
|
102
102
|
google-cloud-errors (~> 1.0)
|
103
103
|
google-cloud-env (1.6.0)
|
104
104
|
faraday (>= 0.17.3, < 3.0)
|
105
105
|
google-cloud-errors (1.2.0)
|
106
|
-
google-cloud-storage (1.
|
106
|
+
google-cloud-storage (1.38.0)
|
107
107
|
addressable (~> 2.8)
|
108
108
|
digest-crc (~> 0.4)
|
109
109
|
google-apis-iamcredentials_v1 (~> 0.1)
|
110
|
-
google-apis-storage_v1 (~> 0.
|
110
|
+
google-apis-storage_v1 (~> 0.17.0)
|
111
111
|
google-cloud-core (~> 1.6)
|
112
112
|
googleauth (>= 0.16.2, < 2.a)
|
113
113
|
mini_mime (~> 1.0)
|
114
|
-
googleauth (1.
|
114
|
+
googleauth (1.2.0)
|
115
115
|
faraday (>= 0.17.3, < 3.a)
|
116
116
|
jwt (>= 1.4, < 3.0)
|
117
117
|
memoist (~> 0.16)
|
@@ -119,7 +119,7 @@ GEM
|
|
119
119
|
os (>= 0.9, < 2.0)
|
120
120
|
signet (>= 0.16, < 2.a)
|
121
121
|
hashdiff (1.0.1)
|
122
|
-
hiera (3.
|
122
|
+
hiera (3.10.0)
|
123
123
|
hocon (1.3.1)
|
124
124
|
httpclient (2.8.3)
|
125
125
|
i18n (1.10.0)
|
@@ -130,7 +130,7 @@ GEM
|
|
130
130
|
atlassian-jwt
|
131
131
|
multipart-post
|
132
132
|
oauth (~> 0.5, >= 0.5.0)
|
133
|
-
jwt (2.
|
133
|
+
jwt (2.4.1)
|
134
134
|
locale (2.1.3)
|
135
135
|
memoist (0.16.2)
|
136
136
|
method_source (1.0.0)
|
@@ -139,11 +139,9 @@ GEM
|
|
139
139
|
mize (0.4.0)
|
140
140
|
protocol (~> 2.0)
|
141
141
|
multi_json (1.15.0)
|
142
|
-
multipart-post (2.
|
142
|
+
multipart-post (2.2.3)
|
143
143
|
nio4r (2.5.8)
|
144
|
-
nokogiri (1.13.
|
145
|
-
racc (~> 1.4)
|
146
|
-
nokogiri (1.13.6-x86_64-linux)
|
144
|
+
nokogiri (1.13.8-x86_64-darwin)
|
147
145
|
racc (~> 1.4)
|
148
146
|
oauth (0.5.10)
|
149
147
|
octokit (4.25.0)
|
@@ -166,18 +164,7 @@ GEM
|
|
166
164
|
coderay (~> 1.1)
|
167
165
|
method_source (~> 1.0)
|
168
166
|
public_suffix (4.0.7)
|
169
|
-
puppet (7.
|
170
|
-
concurrent-ruby (~> 1.0)
|
171
|
-
deep_merge (~> 1.0)
|
172
|
-
facter (> 2.0.1, < 5)
|
173
|
-
fast_gettext (>= 1.1, < 3)
|
174
|
-
hiera (>= 3.2.1, < 4)
|
175
|
-
locale (~> 2.1)
|
176
|
-
multi_json (~> 1.10)
|
177
|
-
puppet-resource_api (~> 1.5)
|
178
|
-
scanf (~> 1.0)
|
179
|
-
semantic_puppet (~> 1.0)
|
180
|
-
puppet (7.17.0-universal-darwin)
|
167
|
+
puppet (7.18.0-universal-darwin)
|
181
168
|
CFPropertyList (~> 2.2)
|
182
169
|
concurrent-ruby (~> 1.0)
|
183
170
|
deep_merge (~> 1.0)
|
@@ -247,9 +234,9 @@ GEM
|
|
247
234
|
rubyzip (>= 1.2.2)
|
248
235
|
semantic_puppet (1.0.4)
|
249
236
|
sexp_processor (4.16.1)
|
250
|
-
signet (0.
|
237
|
+
signet (0.17.0)
|
251
238
|
addressable (~> 2.8)
|
252
|
-
faraday (>= 0.17.5, < 3.
|
239
|
+
faraday (>= 0.17.5, < 3.a)
|
253
240
|
jwt (>= 1.5, < 3.0)
|
254
241
|
multi_json (~> 1.10)
|
255
242
|
sync (0.5.0)
|
@@ -1,14 +1,318 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'set'
|
4
|
+
require 'abide_dev_utils/dot_number_comparable'
|
3
5
|
require 'abide_dev_utils/errors'
|
4
|
-
require 'abide_dev_utils/ppt
|
6
|
+
require 'abide_dev_utils/ppt'
|
5
7
|
require 'abide_dev_utils/cem/mapping/mapper'
|
6
8
|
|
7
9
|
module AbideDevUtils
|
8
10
|
module CEM
|
9
|
-
#
|
11
|
+
# Represents a resource data resource statement
|
12
|
+
class Resource
|
13
|
+
attr_reader :title, :type
|
14
|
+
|
15
|
+
def initialize(title, data, framework, mapper)
|
16
|
+
@title = title
|
17
|
+
@data = data
|
18
|
+
@type = data['type']
|
19
|
+
@framework = framework
|
20
|
+
@mapper = mapper
|
21
|
+
@dependent = []
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns a representation of the actual manifest backing this resource.
|
25
|
+
# This is used to gather information from the Puppet code about this
|
26
|
+
# resource.
|
27
|
+
# @return [AbideDevUtils::Ppt::CodeIntrospection::Manifest]
|
28
|
+
# @return [nil] if the manifest could not be found or could not be parsed
|
29
|
+
def manifest
|
30
|
+
@manifest ||= load_manifest
|
31
|
+
end
|
32
|
+
|
33
|
+
def manifest?
|
34
|
+
!manifest.nil?
|
35
|
+
end
|
36
|
+
|
37
|
+
def file_path
|
38
|
+
@file_path ||= AbideDevUtils::Ppt::ClassUtils.path_from_class_name((type == 'class' ? title : type))
|
39
|
+
end
|
40
|
+
|
41
|
+
def controls
|
42
|
+
@controls || load_controls
|
43
|
+
end
|
44
|
+
|
45
|
+
def cem_options?
|
46
|
+
!cem_options.empty?
|
47
|
+
end
|
48
|
+
|
49
|
+
def cem_options
|
50
|
+
@cem_options ||= resource_properties('cem_options')
|
51
|
+
end
|
52
|
+
|
53
|
+
def cem_protected?
|
54
|
+
!cem_protected.empty?
|
55
|
+
end
|
56
|
+
|
57
|
+
def cem_protected
|
58
|
+
@cem_protected ||= resource_properties('cem_protected')
|
59
|
+
end
|
60
|
+
|
61
|
+
def dependent_controls
|
62
|
+
@dependent_controls ||= @dependent.flatten.uniq.filter_map { |x| controls.find { |y| y.id == x } }
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_reference
|
66
|
+
"#{type.split('::').map(&:capitalize).join('::')}['#{title}']"
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
attr_reader :data, :framework, :mapper
|
72
|
+
|
73
|
+
def load_manifest
|
74
|
+
AbideDevUtils::Ppt::CodeIntrospection::Manifest.new(file_path)
|
75
|
+
rescue StandardError
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def resource_properties(prop_name)
|
80
|
+
props = Set.new
|
81
|
+
return props unless data.key?(prop_name)
|
82
|
+
|
83
|
+
data[prop_name].each do |param, param_val|
|
84
|
+
props << { name: param,
|
85
|
+
type: ruby_class_to_puppet_type(param_val.class.to_s),
|
86
|
+
default: param_val }
|
87
|
+
end
|
88
|
+
props
|
89
|
+
end
|
90
|
+
|
91
|
+
def load_controls
|
92
|
+
if data['controls'].respond_to?(:keys)
|
93
|
+
load_hash_controls(data['controls'], framework, mapper)
|
94
|
+
elsif data['controls'].respond_to?(:each_with_index)
|
95
|
+
load_array_controls(data['controls'], framework, mapper)
|
96
|
+
else
|
97
|
+
raise "Control type is invalid. Type: #{data['controls'].class}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def load_hash_controls(ctrls, framework, mapper)
|
102
|
+
ctrls.each_with_object([]) do |(name, data), arr|
|
103
|
+
if name == 'dependent'
|
104
|
+
@dependent << data
|
105
|
+
next
|
106
|
+
end
|
107
|
+
ctrl = Control.new(name, data, self, framework, mapper)
|
108
|
+
arr << ctrl
|
109
|
+
rescue AbideDevUtils::Errors::ControlIdFrameworkMismatchError,
|
110
|
+
AbideDevUtils::Errors::NoMappingDataForControlError
|
111
|
+
next
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def load_array_controls(ctrls, framework, mapper)
|
116
|
+
ctrls.each_with_object([]) do |c, arr|
|
117
|
+
if c == 'dependent'
|
118
|
+
@dependent << c
|
119
|
+
next
|
120
|
+
end
|
121
|
+
ctrl = Control.new(c, 'no_params', self, framework, mapper)
|
122
|
+
arr << ctrl
|
123
|
+
rescue AbideDevUtils::Errors::ControlIdFrameworkMismatchError,
|
124
|
+
AbideDevUtils::Errors::NoMappingDataForControlError
|
125
|
+
next
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def ruby_class_to_puppet_type(class_name)
|
130
|
+
pup_type = class_name.split('::').last.capitalize
|
131
|
+
case pup_type
|
132
|
+
when %r{(Trueclass|Falseclass)}
|
133
|
+
'Boolean'
|
134
|
+
when %r{(String|Pathname)}
|
135
|
+
'String'
|
136
|
+
when %r{(Integer|Fixnum)}
|
137
|
+
'Integer'
|
138
|
+
when %r{(Float|Double)}
|
139
|
+
'Float'
|
140
|
+
when %r{Nilclass}
|
141
|
+
'Optional'
|
142
|
+
else
|
143
|
+
pup_type
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Represents a singular rule in a benchmark
|
149
|
+
class Control
|
150
|
+
include AbideDevUtils::DotNumberComparable
|
151
|
+
attr_reader :id, :params, :resource, :framework, :dependent
|
152
|
+
|
153
|
+
def initialize(id, params, resource, framework, mapper)
|
154
|
+
validate_id_with_framework(id, framework, mapper)
|
155
|
+
@id = id
|
156
|
+
@params = params
|
157
|
+
@resource = resource
|
158
|
+
@framework = framework
|
159
|
+
@mapper = mapper
|
160
|
+
raise AbideDevUtils::Errors::NoMappingDataForControlError, @id unless @mapper.get(id)
|
161
|
+
end
|
162
|
+
|
163
|
+
def params?
|
164
|
+
!(params.nil? || params.empty? || params == 'no_params') || (resource.cem_options? || resource.cem_protected?)
|
165
|
+
end
|
166
|
+
|
167
|
+
def resource_properties?
|
168
|
+
resource.cem_options? || resource.cem_protected?
|
169
|
+
end
|
170
|
+
|
171
|
+
def param_hashes
|
172
|
+
return [no_params] unless params?
|
173
|
+
|
174
|
+
params.each_with_object([]) do |(param, param_val), ar|
|
175
|
+
ar << { name: param,
|
176
|
+
type: ruby_class_to_puppet_type(param_val.class.to_s),
|
177
|
+
default: param_val }
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def alternate_ids(level: nil, profile: nil)
|
182
|
+
id_map = @mapper.get(id, level: level, profile: profile)
|
183
|
+
if display_title_type.to_s == @mapper.map_type(id)
|
184
|
+
id_map
|
185
|
+
else
|
186
|
+
alt_ids = id_map.each_with_object([]) do |mapval, arr|
|
187
|
+
arr << if display_title_type.to_s == @mapper.map_type(mapval)
|
188
|
+
@mapper.get(mapval, level: level, profile: profile)
|
189
|
+
else
|
190
|
+
mapval
|
191
|
+
end
|
192
|
+
end
|
193
|
+
alt_ids.flatten.uniq
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def id_map_type
|
198
|
+
@mapper.map_type(id)
|
199
|
+
end
|
200
|
+
|
201
|
+
def display_title
|
202
|
+
send(display_title_type) unless display_title_type.nil?
|
203
|
+
end
|
204
|
+
|
205
|
+
def levels
|
206
|
+
levels_and_profiles[0]
|
207
|
+
end
|
208
|
+
|
209
|
+
def profiles
|
210
|
+
levels_and_profiles[1]
|
211
|
+
end
|
212
|
+
|
213
|
+
def valid_maps?
|
214
|
+
valid = AbideDevUtils::CEM::Mapping::FRAMEWORK_TYPES[framework].each_with_object([]) do |mtype, arr|
|
215
|
+
arr << if @mapper.map_type(id) == mtype
|
216
|
+
id
|
217
|
+
else
|
218
|
+
@mapper.get(id).find { |x| @mapper.map_type(x) == mtype }
|
219
|
+
end
|
220
|
+
end
|
221
|
+
valid.compact.length == AbideDevUtils::CEM::Mapping::FRAMEWORK_TYPES[framework].length
|
222
|
+
end
|
223
|
+
|
224
|
+
def method_missing(meth, *args, &block)
|
225
|
+
meth_s = meth.to_s
|
226
|
+
if AbideDevUtils::CEM::Mapping::ALL_TYPES.include?(meth_s)
|
227
|
+
@mapper.get(id).find { |x| @mapper.map_type(x) == meth_s }
|
228
|
+
else
|
229
|
+
super
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def respond_to_missing?(meth, include_private = false)
|
234
|
+
AbideDevUtils::CEM::Mapping::ALL_TYPES.include?(meth.to_s) || super
|
235
|
+
end
|
236
|
+
|
237
|
+
def to_h
|
238
|
+
{
|
239
|
+
id: id,
|
240
|
+
display_title: display_title,
|
241
|
+
alternate_ids: alternate_ids,
|
242
|
+
levels: levels,
|
243
|
+
profiles: profiles,
|
244
|
+
params: param_hashes,
|
245
|
+
resource: resource.to_stubbed_h,
|
246
|
+
}
|
247
|
+
end
|
248
|
+
|
249
|
+
private
|
250
|
+
|
251
|
+
def display_title_type
|
252
|
+
if (!vulnid.nil? && !vulnid.is_a?(String)) || !title.is_a?(String)
|
253
|
+
nil
|
254
|
+
elsif framework == 'stig' && vulnid
|
255
|
+
:vulnid
|
256
|
+
else
|
257
|
+
:title
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def validate_id_with_framework(id, framework, mapper)
|
262
|
+
mtype = mapper.map_type(id)
|
263
|
+
return if AbideDevUtils::CEM::Mapping::FRAMEWORK_TYPES[framework].include?(mtype)
|
264
|
+
|
265
|
+
raise AbideDevUtils::Errors::ControlIdFrameworkMismatchError, [id, mtype, framework]
|
266
|
+
end
|
267
|
+
|
268
|
+
def map
|
269
|
+
@map ||= @mapper.get(id)
|
270
|
+
end
|
271
|
+
|
272
|
+
def levels_and_profiles
|
273
|
+
@levels_and_profiles ||= find_levels_and_profiles
|
274
|
+
end
|
275
|
+
|
276
|
+
def find_levels_and_profiles
|
277
|
+
lvls = []
|
278
|
+
profs = []
|
279
|
+
@mapper.levels.each do |lvl|
|
280
|
+
@mapper.profiles.each do |prof|
|
281
|
+
unless @mapper.get(id, level: lvl, profile: prof).nil?
|
282
|
+
lvls << lvl
|
283
|
+
profs << prof
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
[lvls.flatten.compact.uniq, profs.flatten.compact.uniq]
|
288
|
+
end
|
289
|
+
|
290
|
+
def ruby_class_to_puppet_type(class_name)
|
291
|
+
pup_type = class_name.split('::').last.capitalize
|
292
|
+
case pup_type
|
293
|
+
when %r{(Trueclass|Falseclass)}
|
294
|
+
'Boolean'
|
295
|
+
when %r{(String|Pathname)}
|
296
|
+
'String'
|
297
|
+
when %r{(Integer|Fixnum)}
|
298
|
+
'Integer'
|
299
|
+
when %r{(Float|Double)}
|
300
|
+
'Float'
|
301
|
+
when %r{Nilclass}
|
302
|
+
'Optional'
|
303
|
+
else
|
304
|
+
pup_type
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
def no_params
|
309
|
+
{ name: 'No parameters', type: nil, default: nil }
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# Repesents a benchmark based on resource and mapping data
|
10
314
|
class Benchmark
|
11
|
-
attr_reader :osname, :major_version, :os_facts, :osfamily, :hiera_conf, :module_name, :framework
|
315
|
+
attr_reader :osname, :major_version, :os_facts, :osfamily, :hiera_conf, :module_name, :framework
|
12
316
|
|
13
317
|
def initialize(osname, major_version, hiera_conf, module_name, framework: 'cis')
|
14
318
|
@osname = osname
|
@@ -18,10 +322,8 @@ module AbideDevUtils
|
|
18
322
|
@hiera_conf = hiera_conf
|
19
323
|
@module_name = module_name
|
20
324
|
@framework = framework
|
21
|
-
@rules = {}
|
22
325
|
@map_cache = {}
|
23
326
|
@rules_in_map = {}
|
24
|
-
load_rules
|
25
327
|
end
|
26
328
|
|
27
329
|
# Creates Benchmark objects from a Puppet module
|
@@ -38,23 +340,47 @@ module AbideDevUtils
|
|
38
340
|
if majver.is_a?(Array)
|
39
341
|
majver.sort.each do |v|
|
40
342
|
frameworks.each do |fw|
|
41
|
-
benchmark = Benchmark.new(osname,
|
343
|
+
benchmark = Benchmark.new(osname,
|
344
|
+
v,
|
345
|
+
pupmod.hiera_conf,
|
346
|
+
pupmod.name(strip_namespace: true),
|
347
|
+
framework: fw)
|
348
|
+
benchmark.controls
|
42
349
|
ary << benchmark
|
350
|
+
rescue AbideDevUtils::Errors::MappingDataFrameworkMismatchError => e
|
351
|
+
raise e unless ignore_all_errors || ignore_framework_mismatch
|
43
352
|
rescue StandardError => e
|
44
|
-
raise e unless ignore_all_errors
|
353
|
+
raise e unless ignore_all_errors
|
45
354
|
end
|
46
355
|
end
|
47
356
|
else
|
48
357
|
frameworks.each do |fw|
|
49
|
-
benchmark = Benchmark.new(osname,
|
358
|
+
benchmark = Benchmark.new(osname,
|
359
|
+
majver,
|
360
|
+
pupmod.hiera_conf,
|
361
|
+
pupmod.name(strip_namespace: true),
|
362
|
+
framework: fw)
|
363
|
+
benchmark.controls
|
50
364
|
ary << benchmark
|
365
|
+
rescue AbideDevUtils::Errors::MappingDataFrameworkMismatchError => e
|
366
|
+
raise e unless ignore_all_errors || ignore_framework_mismatch
|
51
367
|
rescue StandardError => e
|
52
|
-
raise e unless ignore_all_errors
|
368
|
+
raise e unless ignore_all_errors
|
53
369
|
end
|
54
370
|
end
|
55
371
|
end
|
56
372
|
end
|
57
373
|
|
374
|
+
def resources
|
375
|
+
@resources ||= resource_data["#{module_name}::resources"].each_with_object([]) do |(rtitle, rdata), arr|
|
376
|
+
arr << Resource.new(rtitle, rdata, framework, mapper)
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
def controls
|
381
|
+
@controls ||= resources.map(&:controls).flatten.sort
|
382
|
+
end
|
383
|
+
|
58
384
|
def mapper
|
59
385
|
@mapper ||= AbideDevUtils::CEM::Mapping::Mapper.new(module_name, framework, load_mapping_data)
|
60
386
|
end
|
@@ -113,131 +439,6 @@ module AbideDevUtils
|
|
113
439
|
|
114
440
|
private
|
115
441
|
|
116
|
-
def load_rules
|
117
|
-
resource_data["#{module_name}::resources"].each do |_, rdata|
|
118
|
-
unless rdata.key?('controls')
|
119
|
-
puts "Controls key not found in #{rdata}"
|
120
|
-
next
|
121
|
-
end
|
122
|
-
rdata['controls'].each do |control, control_data|
|
123
|
-
rule_title = map(control)
|
124
|
-
next if rule_title.nil? || rule_title.empty?
|
125
|
-
|
126
|
-
rule_title.find { |id| map_type(id) == 'title' }
|
127
|
-
alternate_ids = map(rule_title)
|
128
|
-
|
129
|
-
next unless rule_title.is_a?(String)
|
130
|
-
|
131
|
-
@rules[rule_title] = {} unless @rules&.key?(rule_title)
|
132
|
-
@rules[rule_title]['number'] = alternate_ids.find { |id| map_type(id) == 'number' }
|
133
|
-
@rules[rule_title]['alternate_ids'] = alternate_ids
|
134
|
-
@rules[rule_title]['params'] = [] unless @rules[rule_title].key?('params')
|
135
|
-
@rules[rule_title]['level'] = [] unless @rules[rule_title].key?('level')
|
136
|
-
@rules[rule_title]['profile'] = [] unless @rules[rule_title].key?('profile')
|
137
|
-
param_hashes(control_data).each do |param_hash|
|
138
|
-
next if @rules[rule_title]['params'].include?(param_hash[:name])
|
139
|
-
|
140
|
-
@rules[rule_title]['params'] << param_hash
|
141
|
-
end
|
142
|
-
levels, profiles = find_levels_and_profiles(control)
|
143
|
-
unless @rules[rule_title]['level'] == levels
|
144
|
-
@rules[rule_title]['level'] = @rules[rule_title]['level'] | levels
|
145
|
-
end
|
146
|
-
unless @rules[rule_title]['profile'] == profiles
|
147
|
-
@rules[rule_title]['profile'] = @rules[rule_title]['profile'] | profiles
|
148
|
-
end
|
149
|
-
@rules[rule_title]['resource'] = rdata['type']
|
150
|
-
end
|
151
|
-
end
|
152
|
-
@rules = sort_rules
|
153
|
-
end
|
154
|
-
|
155
|
-
def param_hashes(control_data)
|
156
|
-
return [] if control_data.nil? || control_data.empty?
|
157
|
-
|
158
|
-
p_hashes = []
|
159
|
-
if !control_data.respond_to?(:each) && control_data == 'no_params'
|
160
|
-
p_hashes << no_params
|
161
|
-
else
|
162
|
-
control_data.each do |param, param_val|
|
163
|
-
p_hashes << {
|
164
|
-
name: param,
|
165
|
-
type: ruby_class_to_puppet_type(param_val.class.to_s),
|
166
|
-
default: param_val,
|
167
|
-
}
|
168
|
-
end
|
169
|
-
end
|
170
|
-
p_hashes
|
171
|
-
end
|
172
|
-
|
173
|
-
def no_params
|
174
|
-
{ name: 'No parameters', type: nil, default: nil }
|
175
|
-
end
|
176
|
-
|
177
|
-
# We sort the rules by their control number so they
|
178
|
-
# appear in the REFERENCE in benchmark order
|
179
|
-
def sort_rules
|
180
|
-
sorted = @rules.dup.sort_by do |_, v|
|
181
|
-
control_num_to_int(v['number'])
|
182
|
-
end
|
183
|
-
sorted.to_h
|
184
|
-
end
|
185
|
-
|
186
|
-
# In order to sort the rules by their control number,
|
187
|
-
# we need to convert the control number to an integer.
|
188
|
-
# This is a rough conversion, but should be sufficient
|
189
|
-
# for the purposes of sorting. The multipliers are
|
190
|
-
# the 20th, 15th, 10th, and 5th numbers in the Fibonacci
|
191
|
-
# sequence, then 1 after that. The reason for this is to
|
192
|
-
# ensure a "spiraled" wieghting of the sections in the control
|
193
|
-
# number, with 1st section having the most sorting weight, 2nd
|
194
|
-
# having second most, etc. However, the differences in the multipliers
|
195
|
-
# are such that it would be difficult for the product of a lesser-weighted
|
196
|
-
# section to be greater than a greater-weighted section.
|
197
|
-
def control_num_to_int(control_num)
|
198
|
-
multipliers = [6765, 610, 55, 5, 1]
|
199
|
-
nsum = 0
|
200
|
-
midx = 0
|
201
|
-
control_num.split('.').each do |num|
|
202
|
-
multiplier = midx >= multipliers.length ? 1 : multipliers[midx]
|
203
|
-
nsum += num.to_i * multiplier
|
204
|
-
midx += 1
|
205
|
-
end
|
206
|
-
nsum
|
207
|
-
end
|
208
|
-
|
209
|
-
def find_levels_and_profiles(control_id)
|
210
|
-
levels = []
|
211
|
-
profiles = []
|
212
|
-
mapper.each_like(control_id) do |lvl, profile_hash|
|
213
|
-
next if lvl == 'benchmark'
|
214
|
-
|
215
|
-
profile_hash.each do |prof, _|
|
216
|
-
unless map(control_id, level: lvl, profile: prof).nil?
|
217
|
-
levels << lvl
|
218
|
-
profiles << prof
|
219
|
-
end
|
220
|
-
end
|
221
|
-
end
|
222
|
-
[levels, profiles]
|
223
|
-
end
|
224
|
-
|
225
|
-
def ruby_class_to_puppet_type(class_name)
|
226
|
-
pup_type = class_name.split('::').last.capitalize
|
227
|
-
case pup_type
|
228
|
-
when %r{(Trueclass|Falseclass)}
|
229
|
-
'Boolean'
|
230
|
-
when %r{(String|Pathname)}
|
231
|
-
'String'
|
232
|
-
when %r{(Integer|Fixnum)}
|
233
|
-
'Integer'
|
234
|
-
when %r{(Float|Double)}
|
235
|
-
'Float'
|
236
|
-
else
|
237
|
-
pup_type
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
442
|
def load_mapping_data
|
242
443
|
files = case module_name
|
243
444
|
when /_windows$/
|
@@ -248,8 +449,6 @@ module AbideDevUtils
|
|
248
449
|
raise "Module name '#{module_name}' is not a CEM module"
|
249
450
|
end
|
250
451
|
validate_mapping_files_framework(files).each_with_object({}) do |f, h|
|
251
|
-
next unless f.path.include?(framework)
|
252
|
-
|
253
452
|
h[File.basename(f.path, '.yaml')] = YAML.load_file(f.path)
|
254
453
|
end
|
255
454
|
end
|