abide_dev_utils 0.5.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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