abide_dev_utils 0.4.2 → 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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.rubocop.yml +1 -1
  4. data/CODEOWNERS +1 -0
  5. data/README.md +34 -0
  6. data/abide_dev_utils.gemspec +11 -7
  7. data/itests.rb +138 -0
  8. data/lib/abide_dev_utils/cli/abstract.rb +2 -0
  9. data/lib/abide_dev_utils/cli/comply.rb +115 -0
  10. data/lib/abide_dev_utils/cli/jira.rb +2 -2
  11. data/lib/abide_dev_utils/cli/puppet.rb +136 -11
  12. data/lib/abide_dev_utils/cli/xccdf.rb +26 -7
  13. data/lib/abide_dev_utils/cli.rb +2 -0
  14. data/lib/abide_dev_utils/comply.rb +498 -0
  15. data/lib/abide_dev_utils/config.rb +19 -0
  16. data/lib/abide_dev_utils/errors/comply.rb +17 -0
  17. data/lib/abide_dev_utils/errors/gcloud.rb +27 -0
  18. data/lib/abide_dev_utils/errors/general.rb +5 -0
  19. data/lib/abide_dev_utils/errors/ppt.rb +12 -0
  20. data/lib/abide_dev_utils/errors/xccdf.rb +8 -0
  21. data/lib/abide_dev_utils/errors.rb +2 -0
  22. data/lib/abide_dev_utils/gcloud.rb +22 -0
  23. data/lib/abide_dev_utils/jira.rb +15 -0
  24. data/lib/abide_dev_utils/mixins.rb +16 -0
  25. data/lib/abide_dev_utils/output.rb +7 -3
  26. data/lib/abide_dev_utils/ppt/api.rb +219 -0
  27. data/lib/abide_dev_utils/ppt/class_utils.rb +184 -0
  28. data/lib/abide_dev_utils/ppt/coverage.rb +2 -3
  29. data/lib/abide_dev_utils/ppt/score_module.rb +162 -0
  30. data/lib/abide_dev_utils/ppt.rb +138 -49
  31. data/lib/abide_dev_utils/validate.rb +5 -1
  32. data/lib/abide_dev_utils/version.rb +1 -1
  33. data/lib/abide_dev_utils/xccdf.rb +567 -9
  34. data/lib/abide_dev_utils.rb +1 -0
  35. metadata +82 -17
  36. data/lib/abide_dev_utils/utils/general.rb +0 -9
  37. data/lib/abide_dev_utils/xccdf/cis/hiera.rb +0 -161
  38. data/lib/abide_dev_utils/xccdf/cis.rb +0 -3
@@ -0,0 +1,498 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'yaml'
5
+ require 'selenium-webdriver'
6
+ require 'abide_dev_utils/errors/comply'
7
+ require 'abide_dev_utils/gcloud'
8
+ require 'abide_dev_utils/output'
9
+ require 'abide_dev_utils/prompt'
10
+ require 'pry'
11
+
12
+ module AbideDevUtils
13
+ # Holds module methods and a class for dealing with Puppet Comply
14
+ module Comply
15
+ include AbideDevUtils::Errors::Comply
16
+
17
+ def self.build_report(url, password, config = nil, **opts)
18
+ ReportScraper.new(url, config, **opts).build_report(password)
19
+ end
20
+
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))
27
+ else
28
+ report_name = File.basename(report_b) if report_name.nil?
29
+ ScanReport.new.from_yaml(File.read(report_b))
30
+ end
31
+ result, details = current_report.report_comparison(last_report, check_goodness: true)
32
+ if result
33
+ AbideDevUtils::Output.simple('No negative differences detected...')
34
+ AbideDevUtils::Output.simple(JSON.pretty_generate(details))
35
+ else
36
+ AbideDevUtils::Output.simple('Negative differences detected!', stream: $stderr)
37
+ AbideDevUtils::Output.simple(JSON.pretty_generate(details), stream: $stderr)
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
45
+ end
46
+
47
+ # Class that uses Selenium WebDriver to gather scan reports from Puppet Comply
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
+
58
+ def initialize(url, config = nil, **opts)
59
+ @url = url
60
+ @config = config
61
+ @opts = opts
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)
70
+ end
71
+
72
+ def build_report(password)
73
+ connect(password)
74
+ scrape_report
75
+ ensure
76
+ driver.quit
77
+ end
78
+
79
+ def file_dir
80
+ @file_dir ||= File.expand_path('~/abide_dev_utils')
81
+ end
82
+
83
+ def file_dir=(path)
84
+ @file_dir = new_file_dir(path)
85
+ end
86
+
87
+ private
88
+
89
+ attr_reader :progress
90
+
91
+ def fetch_option(option, default = nil)
92
+ return @opts.fetch(option, default) if @config.nil?
93
+
94
+ @opts.key?(option) ? @opts[option] : @config.fetch(option, default)
95
+ end
96
+
97
+ def node_report_links
98
+ @node_report_links ||= find_node_report_links
99
+ end
100
+
101
+ def driver
102
+ @driver ||= new_driver
103
+ end
104
+
105
+ def output
106
+ AbideDevUtils::Output
107
+ end
108
+
109
+ def prompt
110
+ AbideDevUtils::Prompt
111
+ end
112
+
113
+ def new_progress(node_name)
114
+ @progress = AbideDevUtils::Output.progress title: "Building report for #{node_name}", total: nil
115
+ end
116
+
117
+ def new_driver
118
+ options = Selenium::WebDriver::Chrome::Options.new
119
+ options.args = @opts.fetch(:driveropts, %w[
120
+ --headless
121
+ --test-type
122
+ --disable-gpu
123
+ --no-sandbox
124
+ --no-first-run
125
+ --no-default-browser-check
126
+ --ignore-certificate-errors
127
+ --start-maximized
128
+ ])
129
+ output.simple 'Starting headless Chrome...'
130
+ Selenium::WebDriver.for(:chrome, options: options)
131
+ end
132
+
133
+ def find_element(subject = driver, **kwargs)
134
+ driver.manage.window.resize_to(1920, 1080)
135
+ subject.find_element(**kwargs)
136
+ end
137
+
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)
144
+ raise 'wait_on must be passed a block' unless block
145
+
146
+ value = nil
147
+ if ignore_nse
148
+ begin
149
+ Selenium::WebDriver::Wait.new(ignore: [], timeout: timeout, interval: 1).until do
150
+ value = yield
151
+ end
152
+ rescue Selenium::WebDriver::Error::NoSuchElementError
153
+ return value
154
+ rescue StandardError => e
155
+ raise_error(e, AbideDevUtils::Comply::WaitOnError, quit_driver: quit_driver, quiet: quiet)
156
+ end
157
+ else
158
+ begin
159
+ Selenium::WebDriver::Wait.new(ignore: ignore, timeout: timeout, interval: 1).until do
160
+ value = yield
161
+ end
162
+ rescue StandardError => e
163
+ raise_error(e, AbideDevUtils::Comply::WaitOnError, quit_driver: quit_driver, quiet: quiet)
164
+ end
165
+ end
166
+ value
167
+ end
168
+
169
+ def new_file_dir(path)
170
+ return File.expand_path(path) if Dir.exist?(File.expand_path(path))
171
+
172
+ create_dir = prompt.yes_no("Directory #{path} does not exist. Create directory?")
173
+ return unless create_dir
174
+
175
+ require 'fileutils'
176
+ FileUtils.mkdir_p path
177
+ end
178
+
179
+ def raise_error(original, err_class = nil, quit_driver: true, quiet: false)
180
+ output.simple 'Something went wrong!' unless quiet
181
+ if screenshot_on_error
182
+ output.simple 'Taking a screenshot of current page state...' unless quiet
183
+ screenshot
184
+ end
185
+
186
+ if page_source_on_error
187
+ output.simple 'Saving page source of current page...' unless quiet
188
+ page_source
189
+ end
190
+
191
+ driver.quit if quit_driver
192
+ actual_err_class = err_class.nil? ? original.class : err_class
193
+ raise actual_err_class, original.message
194
+ end
195
+
196
+ def screenshot
197
+ driver.save_screenshot(File.join(file_dir, "comply_error_#{Time.now.to_i}.png"))
198
+ rescue Errno::ENOENT
199
+ save_default = prompt.yes_no(
200
+ "Directory #{file_dir} does not exist. Save screenshot to current directory?"
201
+ )
202
+ driver.save_screenshot(File.join(File.expand_path('.'), "comply_error_#{Time.now.to_i}.png")) if save_default
203
+ end
204
+
205
+ def page_source
206
+ File.open(File.join(file_dir, "comply_error_#{Time.now.to_i}.txt"), 'w') { |f| f.write(driver.page_source) }
207
+ rescue Errno::ENOENT
208
+ save_default = prompt.yes_no(
209
+ "Directory #{file_dir} does not exist. Save page source to current directory?"
210
+ )
211
+ if save_default
212
+ File.open(File.join(File.expand_path('.'), "comply_error_#{Time.now.to_i}.html"), 'w') do |f|
213
+ f.write(driver.page_source)
214
+ end
215
+ end
216
+ end
217
+
218
+ def bypass_ssl_warning_page
219
+ wait_on(ignore_nse: true) do
220
+ find_element(id: 'details-button').click
221
+ find_element(id: 'proceed-link').click
222
+ end
223
+ end
224
+
225
+ def login_to_comply(password)
226
+ output.simple "Logging into Comply at #{@url}..."
227
+ wait_on { driver.find_element(id: 'username') }
228
+ find_element(id: 'username').send_keys username
229
+ find_element(id: 'password').send_keys password
230
+ find_element(id: 'kc-login').click
231
+ error_text = wait_on(ignore_nse: true) { find_element(class: 'kc-feedback-text').text }
232
+ return if error_text.nil? || error_text.empty?
233
+
234
+ raise ComplyLoginFailedError, error_text
235
+ end
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
+
268
+ def find_node_report_links
269
+ output.simple 'Finding nodes with scan reports...'
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)
287
+ end
288
+
289
+ def connect(password)
290
+ output.simple "Connecting to #{@url}..."
291
+ driver.get(@url)
292
+ bypass_ssl_warning_page
293
+ login_to_comply(password)
294
+ end
295
+
296
+ def normalize_cis_rec_name(name)
297
+ nstr = name.downcase
298
+ nstr.delete!('(/|\\|\+|:|\'|")')
299
+ nstr.gsub!(/(\s|\(|\)|-|\.)/, '_')
300
+ nstr.strip!
301
+ nstr
302
+ end
303
+
304
+ def scrape_report
305
+ output.simple 'Building scan reports, this may take a while...'
306
+ all_checks = {}
307
+ original_window = driver.window_handle
308
+ node_report_links.each do |link|
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
333
+ progress.increment
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]] = {}
343
+ end
344
+ report['scan_results'][chk_objs[1]][key] = {
345
+ 'name' => name_parts[2].chomp,
346
+ 'number' => name_parts[1].chomp
347
+ }
348
+ end
349
+ progress.increment
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
358
+ end
359
+ all_checks
360
+ end
361
+ end
362
+
363
+ # Contains multiple NodeScanReport objects
364
+ class ScanReport
365
+ attr_reader :node_scan_reports
366
+
367
+ def from_yaml(report)
368
+ @scan_report = if report.is_a? Hash
369
+ report
370
+ elsif File.file?(report)
371
+ File.open(report.to_s, 'r') { |f| YAML.safe_load(f.read) }
372
+ else
373
+ YAML.safe_load(report)
374
+ end
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]
434
+ end
435
+
436
+ private
437
+
438
+ def build_node_scan_reports
439
+ node_scan_reports = []
440
+ @scan_report.each do |node_name, node_hash|
441
+ node_scan_reports << NodeScanReport.new(node_name, node_hash)
442
+ end
443
+ node_scan_reports.sort_by(&:name)
444
+ end
445
+ end
446
+
447
+ # Class representation of a Comply node scan report
448
+ class NodeScanReport
449
+ attr_reader :name, :passing, :failing, :error, :not_checked, :informational, :benchmark, :last_scan, :profile
450
+
451
+ DIFF_PROPERTIES = %i[passing failing error not_checked informational].freeze
452
+
453
+ def initialize(node_name, node_hash)
454
+ @name = node_name
455
+ @hash = node_hash
456
+ @passing = node_hash.dig('scan_results', 'Pass') || {}
457
+ @failing = node_hash.dig('scan_results', 'Fail') || {}
458
+ @error = node_hash.dig('scan_results', 'Error') || {}
459
+ @not_checked = node_hash.dig('scan_results', 'Not checked') || {}
460
+ @informational = node_hash.dig('scan_results', 'Informational') || {}
461
+ @benchmark = node_hash['benchmark']
462
+ @last_scan = node_hash['last_scan']
463
+ @profile = node_hash.fetch('custom_profile', nil) || node_hash.fetch('profile', nil)
464
+ create_equality_methods
465
+ end
466
+
467
+ def diff(other)
468
+ diff = {}
469
+ DIFF_PROPERTIES.each do |prop|
470
+ diff[prop] = send("#{prop.to_s}_equal?".to_sym, other.send(prop)) ? {} : property_diff(prop, other)
471
+ end
472
+ diff
473
+ end
474
+
475
+ private
476
+
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
484
+ end
485
+
486
+ def property_diff(property, other)
487
+ {
488
+ self: send(property).keys - other.send(property).keys,
489
+ other: other.send(property).keys - send(property).keys
490
+ }
491
+ end
492
+
493
+ def property_equal?(property, other_property)
494
+ send(property) == other_property
495
+ end
496
+ end
497
+ end
498
+ end
@@ -13,6 +13,13 @@ module AbideDevUtils
13
13
  h.transform_keys(&:to_sym)
14
14
  end
15
15
 
16
+ def to_h(path = DEFAULT_PATH)
17
+ return {} unless File.file?(path)
18
+
19
+ h = YAML.safe_load(File.open(path), [Symbol])
20
+ h.transform_keys(&:to_sym)
21
+ end
22
+
16
23
  def self.config_section(section, path = DEFAULT_PATH)
17
24
  h = to_h(path)
18
25
  s = h.fetch(section.to_sym, nil)
@@ -21,8 +28,20 @@ module AbideDevUtils
21
28
  s.transform_keys(&:to_sym)
22
29
  end
23
30
 
31
+ def config_section(section, path = DEFAULT_PATH)
32
+ h = to_h(path)
33
+ s = h.fetch(section.to_sym, nil)
34
+ return {} if s.nil?
35
+
36
+ s.transform_keys(&:to_sym)
37
+ end
38
+
24
39
  def self.fetch(key, default = nil, path = DEFAULT_PATH)
25
40
  to_h(path).fetch(key, default)
26
41
  end
42
+
43
+ def fetch(key, default = nil, path = DEFAULT_PATH)
44
+ to_h(path).fetch(key, default)
45
+ end
27
46
  end
28
47
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'abide_dev_utils/errors/base'
4
+
5
+ module AbideDevUtils
6
+ module Errors
7
+ module Comply
8
+ class ComplyLoginFailedError < GenericError
9
+ @default = 'Failed to login to Comply:'
10
+ end
11
+
12
+ class WaitOnError < GenericError
13
+ @default = 'wait_on failed due to error:'
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'abide_dev_utils/errors/base'
4
+
5
+ module AbideDevUtils
6
+ module Errors
7
+ module GCloud
8
+ class MissingCredentialsError < GenericError
9
+ @default = <<~EOERR
10
+ Storage credentials not given. Please set environment variable ABIDE_GCLOUD_CREDENTIALS.
11
+ EOERR
12
+ end
13
+
14
+ class MissingProjectError < GenericError
15
+ @default = <<~EOERR
16
+ Storage project not given. Please set the environment variable ABIDE_GCLOUD_PROJECT.
17
+ EOERR
18
+ end
19
+
20
+ class MissingBucketNameError < GenericError
21
+ @default = <<~EOERR
22
+ Storage bucket name not given. Please set the environment variable ABIDE_GCLOUD_BUCKET.
23
+ EOERR
24
+ end
25
+ end
26
+ end
27
+ 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:'
@@ -24,6 +24,18 @@ module AbideDevUtils
24
24
  class FailedToCreateFileError < GenericError
25
25
  @default = 'Failed to create file:'
26
26
  end
27
+
28
+ class ClassFileNotFoundError < GenericError
29
+ @default = 'Class file was not found:'
30
+ end
31
+
32
+ class ClassDeclarationNotFoundError < GenericError
33
+ @default = 'Class declaration was not found:'
34
+ end
35
+
36
+ class InvalidClassNameError < GenericError
37
+ @default = 'Not a valid Puppet class name:'
38
+ end
27
39
  end
28
40
  end
29
41
  end
@@ -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,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'abide_dev_utils/errors/base'
4
+ require 'abide_dev_utils/errors/comply'
5
+ require 'abide_dev_utils/errors/gcloud'
4
6
  require 'abide_dev_utils/errors/general'
5
7
  require 'abide_dev_utils/errors/jira'
6
8
  require 'abide_dev_utils/errors/xccdf'
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'abide_dev_utils/errors/gcloud'
5
+
6
+ module AbideDevUtils
7
+ module GCloud
8
+ include AbideDevUtils::Errors::GCloud
9
+
10
+ def self.storage_bucket(name: nil, project: nil, credentials: nil)
11
+ raise MissingProjectError if project.nil? && ENV['ABIDE_GCLOUD_PROJECT'].nil?
12
+ raise MissingCredentialsError if credentials.nil? && ENV['ABIDE_GCLOUD_CREDENTIALS'].nil?
13
+ raise MissingBucketNameError if name.nil? && ENV['ABIDE_GCLOUD_BUCKET'].nil?
14
+
15
+ require 'google/cloud/storage'
16
+ @bucket = Google::Cloud::Storage.new(
17
+ project_id: project || ENV['ABIDE_GCLOUD_PROJECT'],
18
+ credentials: credentials || JSON.parse(ENV['ABIDE_GCLOUD_CREDENTIALS'])
19
+ ).bucket(name || ENV['ABIDE_GCLOUD_BUCKET'])
20
+ end
21
+ end
22
+ end
@@ -135,6 +135,16 @@ module AbideDevUtils
135
135
  end
136
136
  end
137
137
 
138
+ # def self.new_issues_from_comply_report(client, project, report, dry_run: false)
139
+ # dr_prefix = dry_run ? 'DRY RUN: ' : ''
140
+ # i_attrs = all_project_issues_attrs(project)
141
+ # rep_sums = summaries_from_coverage_report(report)
142
+ # rep_sums.each do |k, v|
143
+ # next if summary_exist?(k, i_attrs)
144
+
145
+ # progress = AbideDevUtils::Output.progress(title: "#{dr_prefix}Creating Tasks", total: nil)
146
+ # v.each do |s|
147
+
138
148
  def self.merge_options(options)
139
149
  config.merge(options)
140
150
  end
@@ -167,6 +177,11 @@ module AbideDevUtils
167
177
  summaries.transform_keys { |k| "#{COV_PARENT_SUMMARY_PREFIX}#{benchmark}-#{k}"}
168
178
  end
169
179
 
180
+ # def self.summaries_from_comply_report(report)
181
+ # summaries = {}
182
+ # report.each do |_, v|
183
+ # end
184
+
170
185
  class Dummy
171
186
  def attrs
172
187
  { 'fields' => {