abide_dev_utils 0.6.0 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -2
- data/.rubocop.yml +1 -1
- data/CODEOWNERS +1 -0
- data/Gemfile.lock +273 -0
- data/abide_dev_utils.gemspec +7 -6
- data/lib/abide_dev_utils/cli/comply.rb +26 -7
- data/lib/abide_dev_utils/cli/puppet.rb +18 -0
- data/lib/abide_dev_utils/cli/xccdf.rb +77 -11
- data/lib/abide_dev_utils/comply.rb +240 -169
- data/lib/abide_dev_utils/errors/comply.rb +4 -0
- data/lib/abide_dev_utils/errors/general.rb +9 -0
- data/lib/abide_dev_utils/errors/xccdf.rb +12 -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 +627 -11
- metadata +30 -16
- data/.dockerignore +0 -1
- data/Dockerfile +0 -23
- 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,37 @@ module AbideDevUtils
|
|
133
135
|
subject.find_element(**kwargs)
|
134
136
|
end
|
135
137
|
|
136
|
-
def
|
138
|
+
def find_elements(subject = driver, **kwargs)
|
139
|
+
driver.manage.window.resize_to(1920, 1080)
|
140
|
+
subject.find_elements(**kwargs)
|
141
|
+
end
|
142
|
+
|
143
|
+
def wait_on(timeout: @timeout,
|
144
|
+
ignore_nse: false,
|
145
|
+
quit_driver: true,
|
146
|
+
quiet: false,
|
147
|
+
ignore: [Selenium::WebDriver::Error::NoSuchElementError],
|
148
|
+
&block)
|
137
149
|
raise 'wait_on must be passed a block' unless block
|
138
150
|
|
139
151
|
value = nil
|
140
152
|
if ignore_nse
|
141
153
|
begin
|
142
|
-
Selenium::WebDriver::Wait.new(ignore: [], timeout: timeout).until do
|
154
|
+
Selenium::WebDriver::Wait.new(ignore: [], timeout: timeout, interval: 1).until do
|
143
155
|
value = yield
|
144
156
|
end
|
145
157
|
rescue Selenium::WebDriver::Error::NoSuchElementError
|
146
158
|
return value
|
147
|
-
rescue => e
|
148
|
-
raise_error(e)
|
159
|
+
rescue StandardError => e
|
160
|
+
raise_error(e, AbideDevUtils::Comply::WaitOnError, quit_driver: quit_driver, quiet: quiet)
|
149
161
|
end
|
150
162
|
else
|
151
163
|
begin
|
152
|
-
Selenium::WebDriver::Wait.new(ignore: ignore, timeout: timeout).until do
|
164
|
+
Selenium::WebDriver::Wait.new(ignore: ignore, timeout: timeout, interval: 1).until do
|
153
165
|
value = yield
|
154
166
|
end
|
155
|
-
rescue => e
|
156
|
-
raise_error(e)
|
167
|
+
rescue StandardError => e
|
168
|
+
raise_error(e, AbideDevUtils::Comply::WaitOnError, quit_driver: quit_driver, quiet: quiet)
|
157
169
|
end
|
158
170
|
end
|
159
171
|
value
|
@@ -169,20 +181,21 @@ module AbideDevUtils
|
|
169
181
|
FileUtils.mkdir_p path
|
170
182
|
end
|
171
183
|
|
172
|
-
def raise_error(
|
173
|
-
output.simple 'Something went wrong!'
|
184
|
+
def raise_error(original, err_class = nil, quit_driver: true, quiet: false)
|
185
|
+
output.simple 'Something went wrong!' unless quiet
|
174
186
|
if screenshot_on_error
|
175
|
-
output.simple 'Taking a screenshot of current page state...'
|
187
|
+
output.simple 'Taking a screenshot of current page state...' unless quiet
|
176
188
|
screenshot
|
177
189
|
end
|
178
190
|
|
179
191
|
if page_source_on_error
|
180
|
-
output.simple 'Saving page source of current page...'
|
192
|
+
output.simple 'Saving page source of current page...' unless quiet
|
181
193
|
page_source
|
182
194
|
end
|
183
195
|
|
184
|
-
driver.quit
|
185
|
-
|
196
|
+
driver.quit if quit_driver
|
197
|
+
actual_err_class = err_class.nil? ? original.class : err_class
|
198
|
+
raise actual_err_class, original.message
|
186
199
|
end
|
187
200
|
|
188
201
|
def screenshot
|
@@ -223,15 +236,59 @@ module AbideDevUtils
|
|
223
236
|
error_text = wait_on(ignore_nse: true) { find_element(class: 'kc-feedback-text').text }
|
224
237
|
return if error_text.nil? || error_text.empty?
|
225
238
|
|
226
|
-
raise ComplyLoginFailedError, error_text
|
239
|
+
raise AbideDevUtils::Comply::ComplyLoginFailedError, error_text
|
240
|
+
end
|
241
|
+
|
242
|
+
def filter_node_report_links(node_report_links)
|
243
|
+
if onlylist.empty? && ignorelist.empty?
|
244
|
+
output.simple 'No filters set, using all node reports...'
|
245
|
+
return node_report_links
|
246
|
+
end
|
247
|
+
|
248
|
+
unless onlylist.empty?
|
249
|
+
output.simple 'Onlylist found, filtering node reports...'
|
250
|
+
return node_report_links.select { |l| onlylist.include?(l[:name]) }
|
251
|
+
end
|
252
|
+
|
253
|
+
output.simple 'Ignorelist found, filtering node reports...'
|
254
|
+
node_report_links.reject { |l| ignorelist.include?(l[:name]) }
|
255
|
+
end
|
256
|
+
|
257
|
+
def find_node_report_table(subject)
|
258
|
+
wait_on { find_element(subject, class: 'metric-containers-failed-hosts-count') }
|
259
|
+
hosts = find_element(subject, class: 'metric-containers-failed-hosts-count')
|
260
|
+
table = find_element(hosts, class: 'rc-table')
|
261
|
+
wait_on { find_element(table, tag_name: 'tbody') }
|
262
|
+
find_element(table, tag_name: 'tbody')
|
263
|
+
end
|
264
|
+
|
265
|
+
def wait_for_node_report_links(table_body)
|
266
|
+
wait_on(timeout: 2, quit_driver: false, quiet: true) { table_body.find_element(tag_name: 'a') }
|
267
|
+
output.simple 'Found node report links...'
|
268
|
+
table_body.find_elements(tag_name: 'a')
|
269
|
+
rescue AbideDevUtils::Comply::WaitOnError
|
270
|
+
[]
|
227
271
|
end
|
228
272
|
|
229
273
|
def find_node_report_links
|
230
274
|
output.simple 'Finding nodes with scan reports...'
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
275
|
+
node_report_links = []
|
276
|
+
(1..max_pagination).each do |page|
|
277
|
+
output.simple "Trying page #{page}..."
|
278
|
+
driver.get("#{@url}/dashboard?page=#{page}&limit=50")
|
279
|
+
table_body = find_node_report_table(driver)
|
280
|
+
elems = wait_for_node_report_links(table_body)
|
281
|
+
if elems.empty?
|
282
|
+
output.simple "No links found on page #{page}, stopping search..."
|
283
|
+
break
|
284
|
+
end
|
285
|
+
|
286
|
+
elems.each do |elem|
|
287
|
+
node_report_links << { name: elem.text, url: elem.attribute('href') }
|
288
|
+
end
|
289
|
+
end
|
290
|
+
driver.get(@url)
|
291
|
+
filter_node_report_links(node_report_links)
|
235
292
|
end
|
236
293
|
|
237
294
|
def connect(password)
|
@@ -249,67 +306,69 @@ module AbideDevUtils
|
|
249
306
|
nstr
|
250
307
|
end
|
251
308
|
|
309
|
+
def wait_on_element_and_increment(subject = driver, **element_id)
|
310
|
+
element = wait_on { find_element(subject, **element_id) }
|
311
|
+
progress.increment
|
312
|
+
element
|
313
|
+
end
|
314
|
+
|
315
|
+
def wait_on_elements_and_increment(subject = driver, **element_id)
|
316
|
+
elements = wait_on { find_elements(subject, **element_id) }
|
317
|
+
progress.increment
|
318
|
+
elements
|
319
|
+
end
|
320
|
+
|
252
321
|
def scrape_report
|
253
322
|
output.simple 'Building scan reports, this may take a while...'
|
254
323
|
all_checks = {}
|
255
324
|
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
325
|
node_report_links.each do |link|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
326
|
+
node_name = link[:name]
|
327
|
+
link_url = link[:url]
|
328
|
+
new_progress(node_name)
|
329
|
+
driver.manage.new_window(:tab)
|
330
|
+
progress.increment
|
331
|
+
wait_on { driver.window_handles.length == 2 }
|
332
|
+
progress.increment
|
333
|
+
driver.switch_to.window driver.window_handles[1]
|
334
|
+
driver.get(link_url)
|
335
|
+
wait_on_element_and_increment(class: 'details-header')
|
336
|
+
wait_on_element_and_increment(class: 'details-scan-info')
|
337
|
+
wait_on_element_and_increment(class: 'details-table')
|
338
|
+
report = { 'scan_results' => {} }
|
339
|
+
scan_info_table = wait_on_element_and_increment(class: 'details-scan-info')
|
340
|
+
scan_info_table_rows = wait_on_elements_and_increment(scan_info_table, tag_name: 'tr')
|
341
|
+
check_table_body = wait_on_element_and_increment(tag_name: 'tbody')
|
342
|
+
check_table_rows = wait_on_elements_and_increment(check_table_body, tag_name: 'tr')
|
343
|
+
scan_info_table_rows.each do |row|
|
344
|
+
key = find_element(row, tag_name: 'h5').text
|
345
|
+
value = find_element(row, tag_name: 'strong').text
|
346
|
+
report[key.downcase.tr(':', '').tr(' ', '_')] = value
|
267
347
|
progress.increment
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
scan_info_table = find_element(class: 'details-scan-info')
|
278
|
-
scan_info_table_rows = scan_info_table.find_elements(tag_name: 'tr')
|
279
|
-
progress.increment
|
280
|
-
check_table_body = find_element(tag_name: 'tbody')
|
281
|
-
check_table_rows = check_table_body.find_elements(tag_name: 'tr')
|
282
|
-
progress.increment
|
283
|
-
scan_info_table_rows.each do |row|
|
284
|
-
key = find_element(row, tag_name: 'h5').text
|
285
|
-
value = find_element(row, tag_name: 'strong').text
|
286
|
-
report[key.downcase.tr(':', '').tr(' ', '_')] = value
|
287
|
-
progress.increment
|
288
|
-
end
|
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
|
-
}
|
348
|
+
end
|
349
|
+
check_table_rows.each do |row|
|
350
|
+
chk_objs = row.find_elements(tag_name: 'td')
|
351
|
+
chk_objs.map!(&:text)
|
352
|
+
if status.nil? || status.include?(chk_objs[1].downcase)
|
353
|
+
name_parts = chk_objs[0].match(/^([0-9.]+) (.+)$/)
|
354
|
+
key = normalize_cis_rec_name(name_parts[2])
|
355
|
+
unless report['scan_results'].key?(chk_objs[1])
|
356
|
+
report['scan_results'][chk_objs[1]] = {}
|
302
357
|
end
|
303
|
-
|
358
|
+
report['scan_results'][chk_objs[1]][key] = {
|
359
|
+
'name' => name_parts[2].chomp,
|
360
|
+
'number' => name_parts[1].chomp
|
361
|
+
}
|
304
362
|
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
|
363
|
+
progress.increment
|
312
364
|
end
|
365
|
+
all_checks[node_name] = report
|
366
|
+
driver.close
|
367
|
+
output.simple "Created report for #{node_name}"
|
368
|
+
rescue ::StandardError => e
|
369
|
+
raise_error(e)
|
370
|
+
ensure
|
371
|
+
driver.switch_to.window original_window
|
313
372
|
end
|
314
373
|
all_checks
|
315
374
|
end
|
@@ -317,6 +376,8 @@ module AbideDevUtils
|
|
317
376
|
|
318
377
|
# Contains multiple NodeScanReport objects
|
319
378
|
class ScanReport
|
379
|
+
attr_reader :node_scan_reports
|
380
|
+
|
320
381
|
def from_yaml(report)
|
321
382
|
@scan_report = if report.is_a? Hash
|
322
383
|
report
|
@@ -325,7 +386,65 @@ module AbideDevUtils
|
|
325
386
|
else
|
326
387
|
YAML.safe_load(report)
|
327
388
|
end
|
328
|
-
build_node_scan_reports
|
389
|
+
@node_scan_reports = build_node_scan_reports
|
390
|
+
self
|
391
|
+
end
|
392
|
+
|
393
|
+
def to_h
|
394
|
+
node_scan_reports.each_with_object({}) do |node, h|
|
395
|
+
h[node.name] = node.hash
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
def to_yaml
|
400
|
+
to_h.to_yaml
|
401
|
+
end
|
402
|
+
|
403
|
+
def self.storage_bucket
|
404
|
+
@storage_bucket ||= AbideDevUtils::GCloud.storage_bucket
|
405
|
+
end
|
406
|
+
|
407
|
+
def self.fetch_report(name: 'comply_report.yaml')
|
408
|
+
report = storage_bucket.file(name)
|
409
|
+
report.download.read
|
410
|
+
end
|
411
|
+
|
412
|
+
def self.upload_report(report, name: 'comply_report.yaml')
|
413
|
+
storage_bucket.create_file(report, name)
|
414
|
+
end
|
415
|
+
|
416
|
+
def report_comparison(other, check_goodness: false)
|
417
|
+
comparison = []
|
418
|
+
node_scan_reports.zip(other.node_scan_reports).each do |cr, lr|
|
419
|
+
comparison << { cr.name => { diff: {}, node_presense: :new } } if lr.nil?
|
420
|
+
comparison << { lr.name => { diff: {}, node_presense: :dropped } } if cr.nil?
|
421
|
+
comparison << { cr.name => { diff: cr.diff(lr), node_presence: :same } } unless cr.nil? || lr.nil?
|
422
|
+
end
|
423
|
+
comparison.inject(&:merge)
|
424
|
+
return good_comparison?(comparison) if check_goodness
|
425
|
+
|
426
|
+
compairison
|
427
|
+
end
|
428
|
+
|
429
|
+
def good_comparison?(report_comparison)
|
430
|
+
good = true
|
431
|
+
not_good = {}
|
432
|
+
report_comparison.each do |node_report|
|
433
|
+
node_name = node_report.keys[0]
|
434
|
+
report = node_report[node_name]
|
435
|
+
next if report[:diff].empty?
|
436
|
+
|
437
|
+
not_good[node_name] = {}
|
438
|
+
unless report.dig(:diff, :passing, :other).nil?
|
439
|
+
good = false
|
440
|
+
not_good[node_name][:new_not_passing] = report[:diff][:passing][:other]
|
441
|
+
end
|
442
|
+
unless report.dig(:diff, :failing, :self).nil?
|
443
|
+
good = false
|
444
|
+
not_good[node_name][:new_failing] = report[:diff][:failing][:self]
|
445
|
+
end
|
446
|
+
end
|
447
|
+
[good, not_good]
|
329
448
|
end
|
330
449
|
|
331
450
|
private
|
@@ -341,20 +460,22 @@ module AbideDevUtils
|
|
341
460
|
|
342
461
|
# Class representation of a Comply node scan report
|
343
462
|
class NodeScanReport
|
344
|
-
attr_reader :name, :passing, :failing, :not_checked, :informational, :benchmark, :last_scan, :profile
|
463
|
+
attr_reader :name, :passing, :failing, :error, :not_checked, :informational, :benchmark, :last_scan, :profile
|
345
464
|
|
346
|
-
DIFF_PROPERTIES = %i[passing failing not_checked informational].freeze
|
465
|
+
DIFF_PROPERTIES = %i[passing failing error not_checked informational].freeze
|
347
466
|
|
348
467
|
def initialize(node_name, node_hash)
|
349
468
|
@name = node_name
|
350
469
|
@hash = node_hash
|
351
470
|
@passing = node_hash.dig('scan_results', 'Pass') || {}
|
352
471
|
@failing = node_hash.dig('scan_results', 'Fail') || {}
|
472
|
+
@error = node_hash.dig('scan_results', 'Error') || {}
|
353
473
|
@not_checked = node_hash.dig('scan_results', 'Not checked') || {}
|
354
474
|
@informational = node_hash.dig('scan_results', 'Informational') || {}
|
355
475
|
@benchmark = node_hash['benchmark']
|
356
476
|
@last_scan = node_hash['last_scan']
|
357
477
|
@profile = node_hash.fetch('custom_profile', nil) || node_hash.fetch('profile', nil)
|
478
|
+
create_equality_methods
|
358
479
|
end
|
359
480
|
|
360
481
|
def diff(other)
|
@@ -365,21 +486,17 @@ module AbideDevUtils
|
|
365
486
|
diff
|
366
487
|
end
|
367
488
|
|
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
|
489
|
+
private
|
376
490
|
|
377
|
-
def
|
378
|
-
|
491
|
+
def create_equality_methods
|
492
|
+
DIFF_PROPERTIES.each do |prop|
|
493
|
+
meth_name = "#{prop.to_s}_equal?"
|
494
|
+
self.class.define_method(meth_name) do |other|
|
495
|
+
property_equal?(prop, other)
|
496
|
+
end
|
497
|
+
end
|
379
498
|
end
|
380
499
|
|
381
|
-
private
|
382
|
-
|
383
500
|
def property_diff(property, other)
|
384
501
|
{
|
385
502
|
self: send(property).keys - other.send(property).keys,
|
@@ -388,54 +505,8 @@ module AbideDevUtils
|
|
388
505
|
end
|
389
506
|
|
390
507
|
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
|
508
|
+
send(property) == other_property
|
437
509
|
end
|
438
|
-
[good, not_good]
|
439
510
|
end
|
440
511
|
end
|
441
512
|
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:'
|
@@ -48,5 +53,9 @@ module AbideDevUtils
|
|
48
53
|
class NotHashableError < GenericError
|
49
54
|
@default = 'Object does not respond to #to_hash or #to_h:'
|
50
55
|
end
|
56
|
+
|
57
|
+
class CliOptionsConflict < GenericError
|
58
|
+
@default = "Console options conflict."
|
59
|
+
end
|
51
60
|
end
|
52
61
|
end
|
@@ -12,5 +12,17 @@ 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
|
23
|
+
|
24
|
+
class UnsupportedXCCDFError < GenericError
|
25
|
+
@default = "XCCDF type is unsupported!"
|
26
|
+
end
|
15
27
|
end
|
16
28
|
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
|