abide_dev_utils 0.5.2 → 0.9.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.
@@ -1,130 +1,498 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
3
4
  require 'yaml'
4
5
  require 'selenium-webdriver'
6
+ require 'abide_dev_utils/errors/comply'
7
+ require 'abide_dev_utils/gcloud'
5
8
  require 'abide_dev_utils/output'
9
+ require 'abide_dev_utils/prompt'
10
+ require 'pry'
6
11
 
7
12
  module AbideDevUtils
13
+ # Holds module methods and a class for dealing with Puppet Comply
8
14
  module Comply
9
- def self.scan_report(url, password, username: 'comply', status: nil, ignorelist: nil, onlylist: nil)
10
- begin
11
- AbideDevUtils::Output.simple 'Starting headless Chrome...'
12
- options = Selenium::WebDriver::Chrome::Options.new
13
- options.args = %w[
14
- --headless
15
- --test-type
16
- --disable-gpu
17
- --no-first-run
18
- --no-default-browser-check
19
- --ignore-certificate-errors
20
- --start-maximized
21
- ]
22
- driver = Selenium::WebDriver.for :chrome, options: options
23
- driver.get(url)
24
- bypass_ssl_warning_page(driver)
25
- AbideDevUtils::Output.simple "Logging into Comply at #{url}..."
26
- login_to_comply(driver, username: username, password: password)
27
- AbideDevUtils::Output.simple 'Finding nodes with scan reports...'
28
- links = find_node_report_links(driver)
29
- AbideDevUtils::Output.simple 'Building scan reports, this may take a while...'
30
- build_report(driver, links, status: status, ignorelist: ignorelist, onlylist: onlylist)
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
31
75
  ensure
32
76
  driver.quit
33
77
  end
34
- end
35
78
 
36
- def self.ignore_no_such_element
37
- begin
38
- yield
39
- rescue Selenium::WebDriver::Error::NoSuchElementError => e
40
- AbideDevUtils::Output.simple "Ignored exception #{e}", stream: $stderr
79
+ def file_dir
80
+ @file_dir ||= File.expand_path('~/abide_dev_utils')
41
81
  end
42
- end
43
82
 
44
- def self.wait_on(timeout = 10)
45
- Selenium::WebDriver::Wait.new(timeout: timeout).until do
46
- yield
83
+ def file_dir=(path)
84
+ @file_dir = new_file_dir(path)
47
85
  end
48
- end
49
86
 
50
- def self.bypass_ssl_warning_page(driver)
51
- ignore_no_such_element do
52
- driver.find_element(id: 'details-button').click
53
- driver.find_element(id: 'proceed-link').click
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)
54
95
  end
55
- end
56
96
 
57
- def self.login_to_comply(driver, username: 'comply', password: 'compliance')
58
- wait_on { driver.find_element(id: 'username') }
59
- driver.find_element(id: 'username').send_keys username
60
- driver.find_element(id: 'password').send_keys password
61
- driver.find_element(id: 'kc-login').click
62
- end
97
+ def node_report_links
98
+ @node_report_links ||= find_node_report_links
99
+ end
63
100
 
64
- def self.find_node_report_links(driver)
65
- wait_on { driver.find_element(class: 'metric-containers-failed-hosts-count') }
66
- hosts = driver.find_element(class: 'metric-containers-failed-hosts-count')
67
- table = hosts.find_element(class: 'rc-table')
68
- table_body = table.find_element(tag_name: 'tbody')
69
- wait_on { table_body.find_element(tag_name: 'a') }
70
- table_body.find_elements(tag_name: 'a')
71
- end
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
72
242
 
73
- def self.build_report(driver, links, status: nil, ignorelist: nil, onlylist: nil)
74
- all_checks = {}
75
- original_window = driver.window_handle
76
- links.each do |link|
77
- if !onlylist.nil? && !onlylist.empty?
78
- next unless onlylist.include?(link.text)
79
- elsif !ignorelist.nil? && !ignorelist.empty?
80
- next if ignorelist.include?(link.text)
243
+ unless onlylist.empty?
244
+ output.simple 'Onlylist found, filtering node reports...'
245
+ return node_report_links.select { |l| onlylist.include?(l[:name]) }
81
246
  end
82
- begin
83
- node_name = link.text
84
- progress = AbideDevUtils::Output.progress title: "Builingd report for #{node_name}", total: nil
85
- link_url = link.attribute('href')
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)
86
312
  driver.manage.new_window(:tab)
313
+ progress.increment
87
314
  wait_on { driver.window_handles.length == 2 }
88
315
  progress.increment
89
316
  driver.switch_to.window driver.window_handles[1]
90
317
  driver.get(link_url)
91
- wait_on { driver.find_element(class: 'details-scan-info') }
318
+ wait_on { find_element(class: 'details-scan-info') }
92
319
  progress.increment
93
- wait_on { driver.find_element(class: 'details-table') }
320
+ wait_on { find_element(class: 'details-table') }
94
321
  progress.increment
95
- report = {}
96
- report['scan_results'] = {}
97
- scan_info_table = driver.find_element(class: 'details-scan-info')
322
+ report = { 'scan_results' => {} }
323
+ scan_info_table = find_element(class: 'details-scan-info')
98
324
  scan_info_table_rows = scan_info_table.find_elements(tag_name: 'tr')
99
325
  progress.increment
100
- check_table_body = driver.find_element(tag_name: 'tbody')
326
+ check_table_body = find_element(tag_name: 'tbody')
101
327
  check_table_rows = check_table_body.find_elements(tag_name: 'tr')
102
328
  progress.increment
103
329
  scan_info_table_rows.each do |row|
104
- key = row.find_element(tag_name: 'h5').text
105
- value = row.find_element(tag_name: 'strong').text
106
- report[key.downcase.gsub(/:/, '').gsub(/ /, '_')] = value
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
107
333
  progress.increment
108
334
  end
109
335
  check_table_rows.each do |row|
110
336
  chk_objs = row.find_elements(tag_name: 'td')
111
337
  chk_objs.map!(&:text)
112
338
  if status.nil? || status.include?(chk_objs[1].downcase)
113
- report['scan_results'][chk_objs[0][/^[0-9.]+/, 0]] = {
114
- 'name' => chk_objs[0].gsub(/\n/, ' '),
115
- 'status' => chk_objs[1]
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
116
347
  }
117
348
  end
118
349
  progress.increment
119
350
  end
120
351
  all_checks[node_name] = report
121
352
  driver.close
122
- AbideDevUtils::Output.simple "Created report for #{node_name}"
353
+ output.simple "Created report for #{node_name}"
354
+ rescue ::StandardError => e
355
+ raise_error(e)
123
356
  ensure
124
357
  driver.switch_to.window original_window
125
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
126
495
  end
127
- all_checks
128
496
  end
129
497
  end
130
498
  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:'
@@ -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
@@ -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,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