abide_dev_utils 0.6.0 → 0.8.0
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/.gitignore +2 -1
- data/.rubocop.yml +1 -1
- data/CODEOWNERS +1 -0
- data/abide_dev_utils.gemspec +7 -6
- data/itests.rb +138 -0
- data/lib/abide_dev_utils/cli/comply.rb +23 -7
- data/lib/abide_dev_utils/cli/puppet.rb +18 -0
- data/lib/abide_dev_utils/cli/xccdf.rb +26 -7
- data/lib/abide_dev_utils/comply.rb +225 -168
- data/lib/abide_dev_utils/errors/comply.rb +4 -0
- data/lib/abide_dev_utils/errors/general.rb +5 -0
- data/lib/abide_dev_utils/errors/xccdf.rb +8 -0
- data/lib/abide_dev_utils/gcloud.rb +2 -1
- data/lib/abide_dev_utils/output.rb +7 -3
- data/lib/abide_dev_utils/ppt/api.rb +219 -0
- data/lib/abide_dev_utils/ppt/score_module.rb +162 -0
- data/lib/abide_dev_utils/ppt.rb +22 -19
- data/lib/abide_dev_utils/validate.rb +5 -1
- data/lib/abide_dev_utils/version.rb +1 -1
- data/lib/abide_dev_utils/xccdf.rb +565 -12
- metadata +30 -14
- data/lib/abide_dev_utils/xccdf/cis/hiera.rb +0 -166
- data/lib/abide_dev_utils/xccdf/cis.rb +0 -3
- data/lib/abide_dev_utils/xccdf/utils.rb +0 -85
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'json'
|
|
3
4
|
require 'yaml'
|
|
4
5
|
require 'selenium-webdriver'
|
|
5
6
|
require 'abide_dev_utils/errors/comply'
|
|
6
7
|
require 'abide_dev_utils/gcloud'
|
|
7
8
|
require 'abide_dev_utils/output'
|
|
8
9
|
require 'abide_dev_utils/prompt'
|
|
10
|
+
require 'pry'
|
|
9
11
|
|
|
10
12
|
module AbideDevUtils
|
|
11
13
|
# Holds module methods and a class for dealing with Puppet Comply
|
|
@@ -16,56 +18,55 @@ module AbideDevUtils
|
|
|
16
18
|
ReportScraper.new(url, config, **opts).build_report(password)
|
|
17
19
|
end
|
|
18
20
|
|
|
19
|
-
def self.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
def self.compare_reports(report_a, report_b, **opts)
|
|
22
|
+
report_name = opts.fetch(:report_name, nil)
|
|
23
|
+
current_report = ScanReport.new.from_yaml(report_a)
|
|
24
|
+
last_report = if opts.fetch(:remote_storage, '') == 'gcloud'
|
|
25
|
+
report_name = report_b if report_name.nil?
|
|
26
|
+
ScanReport.new.from_yaml(ScanReport.fetch_report(name: report_b))
|
|
23
27
|
else
|
|
24
|
-
File.
|
|
28
|
+
report_name = File.basename(report_b) if report_name.nil?
|
|
29
|
+
ScanReport.new.from_yaml(File.read(report_b))
|
|
25
30
|
end
|
|
26
|
-
result, details =
|
|
31
|
+
result, details = current_report.report_comparison(last_report, check_goodness: true)
|
|
27
32
|
if result
|
|
28
|
-
|
|
33
|
+
AbideDevUtils::Output.simple('No negative differences detected...')
|
|
34
|
+
AbideDevUtils::Output.simple(JSON.pretty_generate(details))
|
|
29
35
|
else
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
AbideDevUtils::Output.simple('Negative differences detected!', stream: $stderr)
|
|
37
|
+
AbideDevUtils::Output.simple(JSON.pretty_generate(details), stream: $stderr)
|
|
32
38
|
end
|
|
39
|
+
if opts.fetch(:upload, false) && !opts.fetch(:remote_storage, '').empty? && !report_name.nil?
|
|
40
|
+
AbideDevUtils::Output.simple('Uploading current report...')
|
|
41
|
+
ScanReport.upload_report(File.expand_path(report_a), name: report_name)
|
|
42
|
+
AbideDevUtils::Output.simple('Successfully uploaded report.')
|
|
43
|
+
end
|
|
44
|
+
result
|
|
33
45
|
end
|
|
34
46
|
|
|
35
47
|
# Class that uses Selenium WebDriver to gather scan reports from Puppet Comply
|
|
36
48
|
class ReportScraper
|
|
49
|
+
attr_reader :timeout,
|
|
50
|
+
:username,
|
|
51
|
+
:status,
|
|
52
|
+
:ignorelist,
|
|
53
|
+
:onlylist,
|
|
54
|
+
:max_pagination,
|
|
55
|
+
:screenshot_on_error,
|
|
56
|
+
:page_source_on_error
|
|
57
|
+
|
|
37
58
|
def initialize(url, config = nil, **opts)
|
|
38
59
|
@url = url
|
|
39
60
|
@config = config
|
|
40
61
|
@opts = opts
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
@
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
@
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def status
|
|
52
|
-
@status ||= fetch_option(:status)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def ignorelist
|
|
56
|
-
@ignorelist ||= fetch_option(:ignorelist, [])
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def onlylist
|
|
60
|
-
@onlylist ||= fetch_option(:onlylist, [])
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def screenshot_on_error
|
|
64
|
-
@screenshot_on_error ||= fetch_option(:screenshot_on_error, true)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def page_source_on_error
|
|
68
|
-
@page_source_on_error ||= fetch_option(:page_source_on_error, true)
|
|
62
|
+
@timeout = fetch_option(:timeout, 10).to_i
|
|
63
|
+
@username = fetch_option(:username, 'comply')
|
|
64
|
+
@status = fetch_option(:status)
|
|
65
|
+
@ignorelist = fetch_option(:ignorelist, [])
|
|
66
|
+
@onlylist = fetch_option(:onlylist, [])
|
|
67
|
+
@max_pagination = fetch_option(:max_pagination, 5).to_i
|
|
68
|
+
@screenshot_on_error = fetch_option(:screenshot_on_error, false)
|
|
69
|
+
@page_source_on_error = fetch_option(:page_source_on_error, false)
|
|
69
70
|
end
|
|
70
71
|
|
|
71
72
|
def build_report(password)
|
|
@@ -119,6 +120,7 @@ module AbideDevUtils
|
|
|
119
120
|
--headless
|
|
120
121
|
--test-type
|
|
121
122
|
--disable-gpu
|
|
123
|
+
--no-sandbox
|
|
122
124
|
--no-first-run
|
|
123
125
|
--no-default-browser-check
|
|
124
126
|
--ignore-certificate-errors
|
|
@@ -133,27 +135,32 @@ module AbideDevUtils
|
|
|
133
135
|
subject.find_element(**kwargs)
|
|
134
136
|
end
|
|
135
137
|
|
|
136
|
-
def wait_on(
|
|
138
|
+
def wait_on(timeout: @timeout,
|
|
139
|
+
ignore_nse: false,
|
|
140
|
+
quit_driver: true,
|
|
141
|
+
quiet: false,
|
|
142
|
+
ignore: [Selenium::WebDriver::Error::NoSuchElementError],
|
|
143
|
+
&block)
|
|
137
144
|
raise 'wait_on must be passed a block' unless block
|
|
138
145
|
|
|
139
146
|
value = nil
|
|
140
147
|
if ignore_nse
|
|
141
148
|
begin
|
|
142
|
-
Selenium::WebDriver::Wait.new(ignore: [], timeout: timeout).until do
|
|
149
|
+
Selenium::WebDriver::Wait.new(ignore: [], timeout: timeout, interval: 1).until do
|
|
143
150
|
value = yield
|
|
144
151
|
end
|
|
145
152
|
rescue Selenium::WebDriver::Error::NoSuchElementError
|
|
146
153
|
return value
|
|
147
|
-
rescue => e
|
|
148
|
-
raise_error(e)
|
|
154
|
+
rescue StandardError => e
|
|
155
|
+
raise_error(e, AbideDevUtils::Comply::WaitOnError, quit_driver: quit_driver, quiet: quiet)
|
|
149
156
|
end
|
|
150
157
|
else
|
|
151
158
|
begin
|
|
152
|
-
Selenium::WebDriver::Wait.new(ignore: ignore, timeout: timeout).until do
|
|
159
|
+
Selenium::WebDriver::Wait.new(ignore: ignore, timeout: timeout, interval: 1).until do
|
|
153
160
|
value = yield
|
|
154
161
|
end
|
|
155
|
-
rescue => e
|
|
156
|
-
raise_error(e)
|
|
162
|
+
rescue StandardError => e
|
|
163
|
+
raise_error(e, AbideDevUtils::Comply::WaitOnError, quit_driver: quit_driver, quiet: quiet)
|
|
157
164
|
end
|
|
158
165
|
end
|
|
159
166
|
value
|
|
@@ -169,20 +176,21 @@ module AbideDevUtils
|
|
|
169
176
|
FileUtils.mkdir_p path
|
|
170
177
|
end
|
|
171
178
|
|
|
172
|
-
def raise_error(
|
|
173
|
-
output.simple 'Something went wrong!'
|
|
179
|
+
def raise_error(original, err_class = nil, quit_driver: true, quiet: false)
|
|
180
|
+
output.simple 'Something went wrong!' unless quiet
|
|
174
181
|
if screenshot_on_error
|
|
175
|
-
output.simple 'Taking a screenshot of current page state...'
|
|
182
|
+
output.simple 'Taking a screenshot of current page state...' unless quiet
|
|
176
183
|
screenshot
|
|
177
184
|
end
|
|
178
185
|
|
|
179
186
|
if page_source_on_error
|
|
180
|
-
output.simple 'Saving page source of current page...'
|
|
187
|
+
output.simple 'Saving page source of current page...' unless quiet
|
|
181
188
|
page_source
|
|
182
189
|
end
|
|
183
190
|
|
|
184
|
-
driver.quit
|
|
185
|
-
|
|
191
|
+
driver.quit if quit_driver
|
|
192
|
+
actual_err_class = err_class.nil? ? original.class : err_class
|
|
193
|
+
raise actual_err_class, original.message
|
|
186
194
|
end
|
|
187
195
|
|
|
188
196
|
def screenshot
|
|
@@ -226,12 +234,56 @@ module AbideDevUtils
|
|
|
226
234
|
raise ComplyLoginFailedError, error_text
|
|
227
235
|
end
|
|
228
236
|
|
|
237
|
+
def filter_node_report_links(node_report_links)
|
|
238
|
+
if onlylist.empty? && ignorelist.empty?
|
|
239
|
+
output.simple 'No filters set, using all node reports...'
|
|
240
|
+
return node_report_links
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
unless onlylist.empty?
|
|
244
|
+
output.simple 'Onlylist found, filtering node reports...'
|
|
245
|
+
return node_report_links.select { |l| onlylist.include?(l[:name]) }
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
output.simple 'Ignorelist found, filtering node reports...'
|
|
249
|
+
node_report_links.reject { |l| ignorelist.include?(l[:name]) }
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def find_node_report_table(subject)
|
|
253
|
+
wait_on { find_element(subject, class: 'metric-containers-failed-hosts-count') }
|
|
254
|
+
hosts = find_element(subject, class: 'metric-containers-failed-hosts-count')
|
|
255
|
+
table = find_element(hosts, class: 'rc-table')
|
|
256
|
+
wait_on { find_element(table, tag_name: 'tbody') }
|
|
257
|
+
find_element(table, tag_name: 'tbody')
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def wait_for_node_report_links(table_body)
|
|
261
|
+
wait_on(timeout: 2, quit_driver: false, quiet: true) { table_body.find_element(tag_name: 'a') }
|
|
262
|
+
output.simple 'Found node report links...'
|
|
263
|
+
table_body.find_elements(tag_name: 'a')
|
|
264
|
+
rescue AbideDevUtils::Comply::WaitOnError
|
|
265
|
+
[]
|
|
266
|
+
end
|
|
267
|
+
|
|
229
268
|
def find_node_report_links
|
|
230
269
|
output.simple 'Finding nodes with scan reports...'
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
270
|
+
node_report_links = []
|
|
271
|
+
(1..max_pagination).each do |page|
|
|
272
|
+
output.simple "Trying page #{page}..."
|
|
273
|
+
driver.get("#{@url}/dashboard?page=#{page}&limit=50")
|
|
274
|
+
table_body = find_node_report_table(driver)
|
|
275
|
+
elems = wait_for_node_report_links(table_body)
|
|
276
|
+
if elems.empty?
|
|
277
|
+
output.simple "No links found on page #{page}, stopping search..."
|
|
278
|
+
break
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
elems.each do |elem|
|
|
282
|
+
node_report_links << { name: elem.text, url: elem.attribute('href') }
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
driver.get(@url)
|
|
286
|
+
filter_node_report_links(node_report_links)
|
|
235
287
|
end
|
|
236
288
|
|
|
237
289
|
def connect(password)
|
|
@@ -253,63 +305,56 @@ module AbideDevUtils
|
|
|
253
305
|
output.simple 'Building scan reports, this may take a while...'
|
|
254
306
|
all_checks = {}
|
|
255
307
|
original_window = driver.window_handle
|
|
256
|
-
if !onlylist.empty?
|
|
257
|
-
node_report_links.reject! { |l| !onlylist.include?(l.text) }
|
|
258
|
-
elsif !ignorelist.empty?
|
|
259
|
-
node_report_links.reject! { |l| ignorelist.include?(l.text) }
|
|
260
|
-
end
|
|
261
308
|
node_report_links.each do |link|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
309
|
+
node_name = link[:name]
|
|
310
|
+
link_url = link[:url]
|
|
311
|
+
new_progress(node_name)
|
|
312
|
+
driver.manage.new_window(:tab)
|
|
313
|
+
progress.increment
|
|
314
|
+
wait_on { driver.window_handles.length == 2 }
|
|
315
|
+
progress.increment
|
|
316
|
+
driver.switch_to.window driver.window_handles[1]
|
|
317
|
+
driver.get(link_url)
|
|
318
|
+
wait_on { find_element(class: 'details-scan-info') }
|
|
319
|
+
progress.increment
|
|
320
|
+
wait_on { find_element(class: 'details-table') }
|
|
321
|
+
progress.increment
|
|
322
|
+
report = { 'scan_results' => {} }
|
|
323
|
+
scan_info_table = find_element(class: 'details-scan-info')
|
|
324
|
+
scan_info_table_rows = scan_info_table.find_elements(tag_name: 'tr')
|
|
325
|
+
progress.increment
|
|
326
|
+
check_table_body = find_element(tag_name: 'tbody')
|
|
327
|
+
check_table_rows = check_table_body.find_elements(tag_name: 'tr')
|
|
328
|
+
progress.increment
|
|
329
|
+
scan_info_table_rows.each do |row|
|
|
330
|
+
key = find_element(row, tag_name: 'h5').text
|
|
331
|
+
value = find_element(row, tag_name: 'strong').text
|
|
332
|
+
report[key.downcase.tr(':', '').tr(' ', '_')] = value
|
|
279
333
|
progress.increment
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
check_table_rows.each do |row|
|
|
290
|
-
chk_objs = row.find_elements(tag_name: 'td')
|
|
291
|
-
chk_objs.map!(&:text)
|
|
292
|
-
if status.nil? || status.include?(chk_objs[1].downcase)
|
|
293
|
-
name_parts = chk_objs[0].match(/^([0-9.]+) (.+)$/)
|
|
294
|
-
key = normalize_cis_rec_name(name_parts[2])
|
|
295
|
-
unless report['scan_results'].key?(chk_objs[1])
|
|
296
|
-
report['scan_results'][chk_objs[1]] = {}
|
|
297
|
-
end
|
|
298
|
-
report['scan_results'][chk_objs[1]][key] = {
|
|
299
|
-
'name' => name_parts[2].chomp,
|
|
300
|
-
'number' => name_parts[1].chomp
|
|
301
|
-
}
|
|
334
|
+
end
|
|
335
|
+
check_table_rows.each do |row|
|
|
336
|
+
chk_objs = row.find_elements(tag_name: 'td')
|
|
337
|
+
chk_objs.map!(&:text)
|
|
338
|
+
if status.nil? || status.include?(chk_objs[1].downcase)
|
|
339
|
+
name_parts = chk_objs[0].match(/^([0-9.]+) (.+)$/)
|
|
340
|
+
key = normalize_cis_rec_name(name_parts[2])
|
|
341
|
+
unless report['scan_results'].key?(chk_objs[1])
|
|
342
|
+
report['scan_results'][chk_objs[1]] = {}
|
|
302
343
|
end
|
|
303
|
-
|
|
344
|
+
report['scan_results'][chk_objs[1]][key] = {
|
|
345
|
+
'name' => name_parts[2].chomp,
|
|
346
|
+
'number' => name_parts[1].chomp
|
|
347
|
+
}
|
|
304
348
|
end
|
|
305
|
-
|
|
306
|
-
driver.close
|
|
307
|
-
output.simple "Created report for #{node_name}"
|
|
308
|
-
rescue => e
|
|
309
|
-
raise_error(e)
|
|
310
|
-
ensure
|
|
311
|
-
driver.switch_to.window original_window
|
|
349
|
+
progress.increment
|
|
312
350
|
end
|
|
351
|
+
all_checks[node_name] = report
|
|
352
|
+
driver.close
|
|
353
|
+
output.simple "Created report for #{node_name}"
|
|
354
|
+
rescue ::StandardError => e
|
|
355
|
+
raise_error(e)
|
|
356
|
+
ensure
|
|
357
|
+
driver.switch_to.window original_window
|
|
313
358
|
end
|
|
314
359
|
all_checks
|
|
315
360
|
end
|
|
@@ -317,6 +362,8 @@ module AbideDevUtils
|
|
|
317
362
|
|
|
318
363
|
# Contains multiple NodeScanReport objects
|
|
319
364
|
class ScanReport
|
|
365
|
+
attr_reader :node_scan_reports
|
|
366
|
+
|
|
320
367
|
def from_yaml(report)
|
|
321
368
|
@scan_report = if report.is_a? Hash
|
|
322
369
|
report
|
|
@@ -325,7 +372,65 @@ module AbideDevUtils
|
|
|
325
372
|
else
|
|
326
373
|
YAML.safe_load(report)
|
|
327
374
|
end
|
|
328
|
-
build_node_scan_reports
|
|
375
|
+
@node_scan_reports = build_node_scan_reports
|
|
376
|
+
self
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def to_h
|
|
380
|
+
node_scan_reports.each_with_object({}) do |node, h|
|
|
381
|
+
h[node.name] = node.hash
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def to_yaml
|
|
386
|
+
to_h.to_yaml
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def self.storage_bucket
|
|
390
|
+
@storage_bucket ||= AbideDevUtils::GCloud.storage_bucket
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def self.fetch_report(name: 'comply_report.yaml')
|
|
394
|
+
report = storage_bucket.file(name)
|
|
395
|
+
report.download.read
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
def self.upload_report(report, name: 'comply_report.yaml')
|
|
399
|
+
storage_bucket.create_file(report, name)
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
def report_comparison(other, check_goodness: false)
|
|
403
|
+
comparison = []
|
|
404
|
+
node_scan_reports.zip(other.node_scan_reports).each do |cr, lr|
|
|
405
|
+
comparison << { cr.name => { diff: {}, node_presense: :new } } if lr.nil?
|
|
406
|
+
comparison << { lr.name => { diff: {}, node_presense: :dropped } } if cr.nil?
|
|
407
|
+
comparison << { cr.name => { diff: cr.diff(lr), node_presence: :same } } unless cr.nil? || lr.nil?
|
|
408
|
+
end
|
|
409
|
+
comparison.inject(&:merge)
|
|
410
|
+
return good_comparison?(comparison) if check_goodness
|
|
411
|
+
|
|
412
|
+
compairison
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
def good_comparison?(report_comparison)
|
|
416
|
+
good = true
|
|
417
|
+
not_good = {}
|
|
418
|
+
report_comparison.each do |node_report|
|
|
419
|
+
node_name = node_report.keys[0]
|
|
420
|
+
report = node_report[node_name]
|
|
421
|
+
next if report[:diff].empty?
|
|
422
|
+
|
|
423
|
+
not_good[node_name] = {}
|
|
424
|
+
unless report.dig(:diff, :passing, :other).nil?
|
|
425
|
+
good = false
|
|
426
|
+
not_good[node_name][:new_not_passing] = report[:diff][:passing][:other]
|
|
427
|
+
end
|
|
428
|
+
unless report.dig(:diff, :failing, :self).nil?
|
|
429
|
+
good = false
|
|
430
|
+
not_good[node_name][:new_failing] = report[:diff][:failing][:self]
|
|
431
|
+
end
|
|
432
|
+
end
|
|
433
|
+
[good, not_good]
|
|
329
434
|
end
|
|
330
435
|
|
|
331
436
|
private
|
|
@@ -341,20 +446,22 @@ module AbideDevUtils
|
|
|
341
446
|
|
|
342
447
|
# Class representation of a Comply node scan report
|
|
343
448
|
class NodeScanReport
|
|
344
|
-
attr_reader :name, :passing, :failing, :not_checked, :informational, :benchmark, :last_scan, :profile
|
|
449
|
+
attr_reader :name, :passing, :failing, :error, :not_checked, :informational, :benchmark, :last_scan, :profile
|
|
345
450
|
|
|
346
|
-
DIFF_PROPERTIES = %i[passing failing not_checked informational].freeze
|
|
451
|
+
DIFF_PROPERTIES = %i[passing failing error not_checked informational].freeze
|
|
347
452
|
|
|
348
453
|
def initialize(node_name, node_hash)
|
|
349
454
|
@name = node_name
|
|
350
455
|
@hash = node_hash
|
|
351
456
|
@passing = node_hash.dig('scan_results', 'Pass') || {}
|
|
352
457
|
@failing = node_hash.dig('scan_results', 'Fail') || {}
|
|
458
|
+
@error = node_hash.dig('scan_results', 'Error') || {}
|
|
353
459
|
@not_checked = node_hash.dig('scan_results', 'Not checked') || {}
|
|
354
460
|
@informational = node_hash.dig('scan_results', 'Informational') || {}
|
|
355
461
|
@benchmark = node_hash['benchmark']
|
|
356
462
|
@last_scan = node_hash['last_scan']
|
|
357
463
|
@profile = node_hash.fetch('custom_profile', nil) || node_hash.fetch('profile', nil)
|
|
464
|
+
create_equality_methods
|
|
358
465
|
end
|
|
359
466
|
|
|
360
467
|
def diff(other)
|
|
@@ -365,21 +472,17 @@ module AbideDevUtils
|
|
|
365
472
|
diff
|
|
366
473
|
end
|
|
367
474
|
|
|
368
|
-
|
|
369
|
-
case method_name
|
|
370
|
-
when method_name.match?(/^(passing|failing|not_checked|informational)_equal?$/)
|
|
371
|
-
property_equal?(method_name.delete_suffix('_equal?'), *args)
|
|
372
|
-
when method_name.match?(/^(to_h|to_yaml)$/)
|
|
373
|
-
@hash.send(method_name.to_sym)
|
|
374
|
-
end
|
|
375
|
-
end
|
|
475
|
+
private
|
|
376
476
|
|
|
377
|
-
def
|
|
378
|
-
|
|
477
|
+
def create_equality_methods
|
|
478
|
+
DIFF_PROPERTIES.each do |prop|
|
|
479
|
+
meth_name = "#{prop.to_s}_equal?"
|
|
480
|
+
self.class.define_method(meth_name) do |other|
|
|
481
|
+
property_equal?(prop, other)
|
|
482
|
+
end
|
|
483
|
+
end
|
|
379
484
|
end
|
|
380
485
|
|
|
381
|
-
private
|
|
382
|
-
|
|
383
486
|
def property_diff(property, other)
|
|
384
487
|
{
|
|
385
488
|
self: send(property).keys - other.send(property).keys,
|
|
@@ -388,54 +491,8 @@ module AbideDevUtils
|
|
|
388
491
|
end
|
|
389
492
|
|
|
390
493
|
def property_equal?(property, other_property)
|
|
391
|
-
send(property
|
|
392
|
-
end
|
|
393
|
-
end
|
|
394
|
-
|
|
395
|
-
def self.storage_bucket
|
|
396
|
-
@storage_bucket ||= AbideDevUtils::GCloud.storage_bucket
|
|
397
|
-
end
|
|
398
|
-
|
|
399
|
-
def self.fetch_report
|
|
400
|
-
report = storage_bucket.file('comply_report.yaml')
|
|
401
|
-
report.download.read
|
|
402
|
-
end
|
|
403
|
-
|
|
404
|
-
def self.upload_report(report)
|
|
405
|
-
file_to_upload = report.is_a?(Hash) ? report.to_yaml : report
|
|
406
|
-
storage_bucket.create_file(file_to_upload, 'comply_report.yaml')
|
|
407
|
-
end
|
|
408
|
-
|
|
409
|
-
def self.report_comparison(current, last)
|
|
410
|
-
current_report = ScanReport.new.from_yaml(current)
|
|
411
|
-
last_report = ScanReport.new.from_yaml(last)
|
|
412
|
-
|
|
413
|
-
comparison = []
|
|
414
|
-
current_report.zip(last_report).each do |cr, lr|
|
|
415
|
-
comparison << { cr.name => { diff: {}, node_presense: :new } } if lr.nil?
|
|
416
|
-
comparison << { lr.name => { diff: {}, node_presense: :dropped } } if cr.nil?
|
|
417
|
-
comparison << { cr.name => { diff: cr.diff(lr), node_presence: :same } } unless cr.nil? || lr.nil?
|
|
418
|
-
end
|
|
419
|
-
comparison.inject(&:merge)
|
|
420
|
-
end
|
|
421
|
-
|
|
422
|
-
def self.good_comparison?(report_comparison)
|
|
423
|
-
good = true
|
|
424
|
-
not_good = {}
|
|
425
|
-
report_comparison.each do |node_name, report|
|
|
426
|
-
next if report[:diff].empty?
|
|
427
|
-
|
|
428
|
-
not_good[node_name] = {}
|
|
429
|
-
unless report[:diff][:passing][:other].empty?
|
|
430
|
-
good = false
|
|
431
|
-
not_good[node_name][:new_not_passing] = report[:diff][:passing][:other]
|
|
432
|
-
end
|
|
433
|
-
unless report[:diff][:failing][:self].empty?
|
|
434
|
-
good = false
|
|
435
|
-
not_good[node_name][:new_failing] = report[:diff][:failing][:self]
|
|
436
|
-
end
|
|
494
|
+
send(property) == other_property
|
|
437
495
|
end
|
|
438
|
-
[good, not_good]
|
|
439
496
|
end
|
|
440
497
|
end
|
|
441
498
|
end
|
|
@@ -29,6 +29,11 @@ module AbideDevUtils
|
|
|
29
29
|
@default = 'Path is not a directory:'
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
# Raised when a file extension is not correct
|
|
33
|
+
class FileExtensionIncorrectError < GenericError
|
|
34
|
+
@default = 'File extension does not match specified extension:'
|
|
35
|
+
end
|
|
36
|
+
|
|
32
37
|
# Raised when a searched for service is not found in the parser
|
|
33
38
|
class ServiceNotFoundError < GenericError
|
|
34
39
|
@default = 'Service not found:'
|
|
@@ -12,5 +12,13 @@ module AbideDevUtils
|
|
|
12
12
|
class StrategyInvalidError < GenericError
|
|
13
13
|
@default = 'Invalid strategy selected. Should be either \'name\' or \'num\''
|
|
14
14
|
end
|
|
15
|
+
|
|
16
|
+
class ControlPartsError < GenericError
|
|
17
|
+
@default = 'Failed to extract parts from control name:'
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class ProfilePartsError < GenericError
|
|
21
|
+
@default = 'Failed to extract parts from profile name:'
|
|
22
|
+
end
|
|
15
23
|
end
|
|
16
24
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'json'
|
|
3
4
|
require 'abide_dev_utils/errors/gcloud'
|
|
4
5
|
|
|
5
6
|
module AbideDevUtils
|
|
@@ -14,7 +15,7 @@ module AbideDevUtils
|
|
|
14
15
|
require 'google/cloud/storage'
|
|
15
16
|
@bucket = Google::Cloud::Storage.new(
|
|
16
17
|
project_id: project || ENV['ABIDE_GCLOUD_PROJECT'],
|
|
17
|
-
credentials: credentials || ENV['ABIDE_GCLOUD_CREDENTIALS']
|
|
18
|
+
credentials: credentials || JSON.parse(ENV['ABIDE_GCLOUD_CREDENTIALS'])
|
|
18
19
|
).bucket(name || ENV['ABIDE_GCLOUD_BUCKET'])
|
|
19
20
|
end
|
|
20
21
|
end
|
|
@@ -22,9 +22,13 @@ module AbideDevUtils
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def self.yaml(in_obj, console: false, file: nil)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
yaml_out = if in_obj.is_a? String
|
|
26
|
+
in_obj
|
|
27
|
+
else
|
|
28
|
+
AbideDevUtils::Validate.hashable(in_obj)
|
|
29
|
+
# Use object's #to_yaml method if it exists, convert to hash if not
|
|
30
|
+
in_obj.respond_to?(:to_yaml) ? in_obj.to_yaml : in_obj.to_h.to_yaml
|
|
31
|
+
end
|
|
28
32
|
simple(yaml_out) if console
|
|
29
33
|
FWRITER.write_yaml(yaml_out, file: file) unless file.nil?
|
|
30
34
|
end
|