abide_dev_utils 0.18.1 → 0.18.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +6 -6
- data/abide_dev_utils.gemspec +1 -1
- data/lib/abide_dev_utils/cli/sce.rb +6 -8
- data/lib/abide_dev_utils/errors/sce.rb +10 -0
- data/lib/abide_dev_utils/sce/generate/coverage_report.rb +35 -112
- data/lib/abide_dev_utils/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78c9c17693c37ea1fef9d03a39f7694a033a985c162e3c2df82ac3305491e747
|
4
|
+
data.tar.gz: f207165591c42fc17694f792ec17f0ce8e6bf502e14f326135a0bfb02a42a521
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0210948da62d9eecf039617acef3be3fe21143eacd0aa4593ec9d1f3fdfde7ca5d0cc0ef15d60e9dad12432ab170e010e6c28b54f31ca3fa8442820ce64b9cd9'
|
7
|
+
data.tar.gz: c332682a7c2a918ade7f6c8a84f9cb90ebd0d4ab5197f79b9a645db0b5610a37205f7b29797d039e58a27802909ab79303d755ea273d5407e7e77169c2cbe512
|
data/Gemfile.lock
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
abide_dev_utils (0.18.
|
4
|
+
abide_dev_utils (0.18.3)
|
5
5
|
cmdparse (~> 3.0)
|
6
|
-
facterdb (
|
6
|
+
facterdb (~> 2.1.0)
|
7
7
|
google-cloud-storage (~> 1.34)
|
8
8
|
hashdiff (~> 1.0)
|
9
9
|
jira-ruby (~> 2.2)
|
@@ -61,9 +61,9 @@ GEM
|
|
61
61
|
facter (4.4.1)
|
62
62
|
hocon (~> 1.3)
|
63
63
|
thor (>= 1.0.1, < 2.0)
|
64
|
-
facterdb (1.
|
64
|
+
facterdb (2.1.0)
|
65
65
|
facter (< 5.0.0)
|
66
|
-
jgrep
|
66
|
+
jgrep (~> 1.5, >= 1.5.4)
|
67
67
|
faraday (2.3.0)
|
68
68
|
faraday-net_http (~> 2.0)
|
69
69
|
ruby2_keywords (>= 0.0.4)
|
@@ -208,8 +208,8 @@ GEM
|
|
208
208
|
trailblazer-option (>= 0.1.1, < 0.2.0)
|
209
209
|
uber (< 0.2.0)
|
210
210
|
retriable (3.1.2)
|
211
|
-
rexml (3.
|
212
|
-
strscan
|
211
|
+
rexml (3.3.6)
|
212
|
+
strscan
|
213
213
|
rgen (0.9.1)
|
214
214
|
rspec (3.11.0)
|
215
215
|
rspec-core (~> 3.11.0)
|
data/abide_dev_utils.gemspec
CHANGED
@@ -42,7 +42,7 @@ Gem::Specification.new do |spec|
|
|
42
42
|
spec.add_dependency 'selenium-webdriver', '~> 4.0.0.beta4'
|
43
43
|
spec.add_dependency 'google-cloud-storage', '~> 1.34'
|
44
44
|
spec.add_dependency 'hashdiff', '~> 1.0'
|
45
|
-
spec.add_dependency 'facterdb', '
|
45
|
+
spec.add_dependency 'facterdb', '~> 2.1.0'
|
46
46
|
spec.add_dependency 'metadata-json-lint', '~> 4.0'
|
47
47
|
|
48
48
|
# Dev dependencies
|
@@ -54,12 +54,8 @@ module Abide
|
|
54
54
|
options.on('-L [LEVEL]', '--level [LEVEL]', 'Specify the level to show coverage for') do |l|
|
55
55
|
@data[:level] = l
|
56
56
|
end
|
57
|
-
options.on('-I', '--ignore-benchmark-errors', '
|
58
|
-
@data[:
|
59
|
-
end
|
60
|
-
options.on('-X [XCCDF_DIR]', '--xccdf-dir [XCCDF_DIR]',
|
61
|
-
'If specified, the coverage report will be correlated with info from the benchmark XCCDF files') do |d|
|
62
|
-
@data[:xccdf_dir] = d
|
57
|
+
options.on('-I', '--no-ignore-benchmark-errors', 'Does not ignore errors while generating benchmark reports') do
|
58
|
+
@data[:ignore_benchmark_errors] = false
|
63
59
|
end
|
64
60
|
options.on('-v', '--verbose', 'Will output the report to the console') { @data[:verbose] = true }
|
65
61
|
options.on('-q', '--quiet', 'Will not output anything to the console') { @data[:quiet] = true }
|
@@ -70,15 +66,17 @@ module Abide
|
|
70
66
|
out_format = @data.fetch(:format, 'yaml')
|
71
67
|
quiet = @data.fetch(:quiet, false)
|
72
68
|
console = @data.fetch(:verbose, false) && !quiet
|
69
|
+
ignore = @data.fetch(:ignore_benchmark_errors, true)
|
73
70
|
generate_opts = {
|
74
71
|
benchmark: @data[:benchmark],
|
75
72
|
profile: @data[:profile],
|
76
73
|
level: @data[:level],
|
77
|
-
ignore_benchmark_errors:
|
78
|
-
xccdf_dir: @data[:xccdf_dir]
|
74
|
+
ignore_benchmark_errors: ignore
|
79
75
|
}
|
80
76
|
AbideDevUtils::Output.simple('Generating coverage report...') unless quiet
|
81
77
|
coverage = AbideDevUtils::Sce::Generate::CoverageReport.generate(format_func: :to_h, opts: generate_opts)
|
78
|
+
raise 'No coverage data found' if coverage.empty?
|
79
|
+
|
82
80
|
AbideDevUtils::Output.simple("Saving coverage report to #{file_name}...")
|
83
81
|
case out_format
|
84
82
|
when /yaml/i
|
@@ -34,6 +34,16 @@ module AbideDevUtils
|
|
34
34
|
attr_accessor :framework, :osname, :major_version, :module_name, :original_error
|
35
35
|
|
36
36
|
@default = 'Error loading benchmark:'
|
37
|
+
|
38
|
+
def message
|
39
|
+
[
|
40
|
+
"#{super} (#{original_error.class})",
|
41
|
+
"Framework: #{framework}",
|
42
|
+
"OS Name: #{osname}",
|
43
|
+
"OS Version: #{major_version}",
|
44
|
+
"Module Name: #{module_name}"
|
45
|
+
].join(', ')
|
46
|
+
end
|
37
47
|
end
|
38
48
|
end
|
39
49
|
end
|
@@ -14,24 +14,36 @@ module AbideDevUtils
|
|
14
14
|
# Methods and objects used to construct a report of what SCE enforces versus what
|
15
15
|
# the various compliance frameworks expect to be enforced.
|
16
16
|
module CoverageReport
|
17
|
+
# Generate a coverage report for a Puppet module
|
18
|
+
# @param format_func [Symbol] the format function to use
|
19
|
+
# @param opts [Hash] options for generating the report
|
20
|
+
# @option opts [String] :benchmark the benchmark to generate the report for
|
21
|
+
# @option opts [String] :profile the profile to generate the report for
|
22
|
+
# @option opts [String] :level the level to generate the report for
|
23
|
+
# @option opts [Symbol] :format_func the format function to use
|
24
|
+
# @option opts [Boolean] :ignore_benchmark_errors ignore all errors when loading benchmarks
|
17
25
|
def self.generate(format_func: :to_h, opts: {})
|
18
26
|
opts = ReportOptions.new(opts)
|
19
27
|
benchmarks = AbideDevUtils::Sce::BenchmarkLoader.benchmarks_from_puppet_module(
|
20
|
-
ignore_all_errors: opts.
|
28
|
+
ignore_all_errors: opts.ignore_benchmark_errors
|
21
29
|
)
|
22
|
-
benchmarks.
|
30
|
+
benchmarks.filter_map do |b|
|
31
|
+
next if opts.benchmark && !Regexp.new(Regexp.escape(opts.benchmark)).match?(b.title_key)
|
32
|
+
next if opts.profile && b.mapper.profiles.none?(opts.profile)
|
33
|
+
next if opts.level && b.mapper.levels.none?(opts.level)
|
34
|
+
|
23
35
|
BenchmarkReport.new(b, opts).run.send(format_func)
|
24
36
|
end
|
25
37
|
end
|
26
38
|
|
39
|
+
# Holds options for generating a report
|
27
40
|
class ReportOptions
|
28
41
|
DEFAULTS = {
|
29
42
|
benchmark: nil,
|
30
43
|
profile: nil,
|
31
44
|
level: nil,
|
32
45
|
format_func: :to_h,
|
33
|
-
|
34
|
-
xccdf_dir: nil
|
46
|
+
ignore_benchmark_errors: false
|
35
47
|
}.freeze
|
36
48
|
|
37
49
|
attr_reader(*DEFAULTS.keys)
|
@@ -44,7 +56,7 @@ module AbideDevUtils
|
|
44
56
|
end
|
45
57
|
|
46
58
|
def report_type
|
47
|
-
|
59
|
+
:basic_coverage
|
48
60
|
end
|
49
61
|
end
|
50
62
|
|
@@ -150,94 +162,17 @@ module AbideDevUtils
|
|
150
162
|
end
|
151
163
|
end
|
152
164
|
|
153
|
-
class OldReport
|
154
|
-
def initialize(benchmarks)
|
155
|
-
@benchmarks = benchmarks
|
156
|
-
end
|
157
|
-
|
158
|
-
def self.generate
|
159
|
-
coverage = {}
|
160
|
-
coverage['classes'] = {}
|
161
|
-
all_cap = ClassUtils.find_all_classes_and_paths(puppet_class_dir)
|
162
|
-
invalid_classes = find_invalid_classes(all_cap)
|
163
|
-
valid_classes = find_valid_classes(all_cap, invalid_classes)
|
164
|
-
coverage['classes']['invalid'] = invalid_classes
|
165
|
-
coverage['classes']['valid'] = valid_classes
|
166
|
-
hiera = YAML.safe_load(File.open(hiera_path))
|
167
|
-
profile&.gsub!(/^profile_/, '') unless profile.nil?
|
168
|
-
|
169
|
-
matcher = profile.nil? ? /^profile_/ : /^profile_#{profile}/
|
170
|
-
hiera.each do |k, v|
|
171
|
-
key_base = k.split('::')[-1]
|
172
|
-
coverage['benchmark'] = v if key_base == 'title'
|
173
|
-
next unless key_base.match?(matcher)
|
174
|
-
|
175
|
-
coverage[key_base] = generate_uncovered_data(v, valid_classes)
|
176
|
-
end
|
177
|
-
coverage
|
178
|
-
end
|
179
|
-
|
180
|
-
def self.generate_uncovered_data(ctrl_list, valid_classes)
|
181
|
-
out_hash = {}
|
182
|
-
out_hash[:num_total] = ctrl_list.length
|
183
|
-
out_hash[:uncovered] = []
|
184
|
-
out_hash[:covered] = []
|
185
|
-
ctrl_list.each do |c|
|
186
|
-
if valid_classes.include?(c)
|
187
|
-
out_hash[:covered] << c
|
188
|
-
else
|
189
|
-
out_hash[:uncovered] << c
|
190
|
-
end
|
191
|
-
end
|
192
|
-
out_hash[:num_covered] = out_hash[:covered].length
|
193
|
-
out_hash[:num_uncovered] = out_hash[:uncovered].length
|
194
|
-
out_hash[:coverage] = Float(
|
195
|
-
(Float(out_hash[:num_covered]) / Float(out_hash[:num_total])) * 100.0
|
196
|
-
).floor(3)
|
197
|
-
out_hash
|
198
|
-
end
|
199
|
-
|
200
|
-
def self.find_valid_classes(all_cap, invalid_classes)
|
201
|
-
all_classes = all_cap.dup.transpose[0]
|
202
|
-
return [] if all_classes.nil?
|
203
|
-
|
204
|
-
return all_classes - invalid_classes unless invalid_classes.nil?
|
205
|
-
|
206
|
-
all_classes
|
207
|
-
end
|
208
|
-
|
209
|
-
def self.find_invalid_classes(all_cap)
|
210
|
-
invalid_classes = []
|
211
|
-
all_cap.each do |cap|
|
212
|
-
invalid_classes << cap[0] unless class_valid?(cap[1])
|
213
|
-
end
|
214
|
-
invalid_classes
|
215
|
-
end
|
216
|
-
|
217
|
-
def self.class_valid?(manifest_path)
|
218
|
-
compiler = Puppet::Pal::Compiler.new(nil)
|
219
|
-
ast = compiler.parse_file(manifest_path)
|
220
|
-
ast.body.body.statements.each do |s|
|
221
|
-
next unless s.respond_to?(:arguments)
|
222
|
-
next unless s.arguments.respond_to?(:each)
|
223
|
-
|
224
|
-
s.arguments.each do |i|
|
225
|
-
return false if i.value == 'Not implemented'
|
226
|
-
end
|
227
|
-
end
|
228
|
-
true
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
165
|
# Class manages organizing report data into various output formats
|
233
166
|
class ReportOutput
|
234
167
|
attr_reader :controls_in_resource_data, :rules_in_map, :timestamp,
|
235
168
|
:title
|
236
169
|
|
237
|
-
def initialize(benchmark, controls_in_resource_data, rules_in_map)
|
170
|
+
def initialize(benchmark, controls_in_resource_data, rules_in_map, profile: nil, level: nil)
|
238
171
|
@benchmark = benchmark
|
239
172
|
@controls_in_resource_data = controls_in_resource_data
|
240
173
|
@rules_in_map = rules_in_map
|
174
|
+
@profile = profile
|
175
|
+
@level = level
|
241
176
|
@timestamp = DateTime.now.iso8601
|
242
177
|
@title = "Coverage Report for #{@benchmark.title_key}"
|
243
178
|
end
|
@@ -287,7 +222,9 @@ module AbideDevUtils
|
|
287
222
|
{
|
288
223
|
title: @benchmark.title,
|
289
224
|
version: @benchmark.version,
|
290
|
-
framework: @benchmark.framework
|
225
|
+
framework: @benchmark.framework,
|
226
|
+
profile: @profile || 'all',
|
227
|
+
level: @level || 'all'
|
291
228
|
}
|
292
229
|
end
|
293
230
|
|
@@ -310,6 +247,8 @@ module AbideDevUtils
|
|
310
247
|
def initialize(benchmark, opts = ReportOptions.new)
|
311
248
|
@benchmark = benchmark
|
312
249
|
@opts = opts
|
250
|
+
@special_control_names = %w[sce_options sce_protected]
|
251
|
+
@stig_map_types = %w[vulnid ruleid]
|
313
252
|
end
|
314
253
|
|
315
254
|
def run
|
@@ -327,7 +266,7 @@ module AbideDevUtils
|
|
327
266
|
def basic_coverage(level: @opts.level, profile: @opts.profile)
|
328
267
|
map_type = @benchmark.map_type(controls_in_resource_data[0])
|
329
268
|
rules_in_map = @benchmark.rules_in_map(map_type, level: level, profile: profile)
|
330
|
-
ReportOutput.new(@benchmark, controls_in_resource_data, rules_in_map)
|
269
|
+
ReportOutput.new(@benchmark, controls_in_resource_data, rules_in_map, profile: profile, level: level)
|
331
270
|
end
|
332
271
|
|
333
272
|
# def correlated_coverage(level: @opts.level, profile: @opts.profile)
|
@@ -348,35 +287,19 @@ module AbideDevUtils
|
|
348
287
|
end
|
349
288
|
end
|
350
289
|
controls.flatten.uniq.select do |c|
|
351
|
-
|
352
|
-
|
353
|
-
@benchmark.map_type(c) != 'vulnid'
|
354
|
-
when 'stig'
|
355
|
-
@benchmark.map_type(c) == 'vulnid'
|
290
|
+
if @special_control_names.include? c
|
291
|
+
false
|
356
292
|
else
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
mapping.each do |level, profs|
|
365
|
-
next if level == 'benchmark'
|
366
|
-
|
367
|
-
profs.each do |_, ctrls|
|
368
|
-
arr << ctrls.keys
|
369
|
-
arr << ctrls.values
|
293
|
+
case @benchmark.framework
|
294
|
+
when 'cis'
|
295
|
+
@stig_map_types.none? @benchmark.map_type(c)
|
296
|
+
when 'stig'
|
297
|
+
@stig_map_types.include? @benchmark.map_type(c)
|
298
|
+
else
|
299
|
+
raise "Cannot find controls for framework #{@benchmark.framework}"
|
370
300
|
end
|
371
301
|
end
|
372
302
|
end
|
373
|
-
controls.flatten.uniq
|
374
|
-
end
|
375
|
-
end
|
376
|
-
|
377
|
-
class ReportOutputCorrelation
|
378
|
-
def initialize(cov_rep)
|
379
|
-
@cov_rep = cov_rep
|
380
303
|
end
|
381
304
|
end
|
382
305
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: abide_dev_utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.18.
|
4
|
+
version: 0.18.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- abide-team
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -140,16 +140,16 @@ dependencies:
|
|
140
140
|
name: facterdb
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
|
-
- - "
|
143
|
+
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version:
|
145
|
+
version: 2.1.0
|
146
146
|
type: :runtime
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
|
-
- - "
|
150
|
+
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version:
|
152
|
+
version: 2.1.0
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: metadata-json-lint
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -486,7 +486,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
486
486
|
- !ruby/object:Gem::Version
|
487
487
|
version: '0'
|
488
488
|
requirements: []
|
489
|
-
rubygems_version: 3.
|
489
|
+
rubygems_version: 3.5.18
|
490
490
|
signing_key:
|
491
491
|
specification_version: 4
|
492
492
|
summary: Helper utilities for developing compliance Puppet code
|