abide_dev_utils 0.11.0 → 0.12.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|