abide_dev_utils 0.11.0 → 0.11.1

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -14
  3. data/lib/abide_dev_utils/cem/benchmark.rb +330 -136
  4. data/lib/abide_dev_utils/cem/generate/coverage_report.rb +380 -0
  5. data/lib/abide_dev_utils/cem/generate/reference.rb +157 -33
  6. data/lib/abide_dev_utils/cem/generate.rb +5 -4
  7. data/lib/abide_dev_utils/cem/hiera_data/mapping_data/map_data.rb +110 -0
  8. data/lib/abide_dev_utils/cem/hiera_data/mapping_data/mixins.rb +46 -0
  9. data/lib/abide_dev_utils/cem/hiera_data/mapping_data.rb +146 -0
  10. data/lib/abide_dev_utils/cem/hiera_data/resource_data/control.rb +127 -0
  11. data/lib/abide_dev_utils/cem/hiera_data/resource_data/parameters.rb +90 -0
  12. data/lib/abide_dev_utils/cem/hiera_data/resource_data/resource.rb +102 -0
  13. data/lib/abide_dev_utils/cem/hiera_data/resource_data.rb +310 -0
  14. data/lib/abide_dev_utils/cem/hiera_data.rb +7 -0
  15. data/lib/abide_dev_utils/cem/mapping/mapper.rb +161 -34
  16. data/lib/abide_dev_utils/cem/validate/resource_data.rb +33 -0
  17. data/lib/abide_dev_utils/cem/validate.rb +10 -0
  18. data/lib/abide_dev_utils/cem.rb +0 -1
  19. data/lib/abide_dev_utils/cli/cem.rb +20 -2
  20. data/lib/abide_dev_utils/dot_number_comparable.rb +75 -0
  21. data/lib/abide_dev_utils/errors/cem.rb +10 -0
  22. data/lib/abide_dev_utils/ppt/class_utils.rb +1 -1
  23. data/lib/abide_dev_utils/ppt/code_gen/data_types.rb +51 -0
  24. data/lib/abide_dev_utils/ppt/code_gen/generate.rb +15 -0
  25. data/lib/abide_dev_utils/ppt/code_gen/resource.rb +59 -0
  26. data/lib/abide_dev_utils/ppt/code_gen/resource_types/base.rb +93 -0
  27. data/lib/abide_dev_utils/ppt/code_gen/resource_types/class.rb +17 -0
  28. data/lib/abide_dev_utils/ppt/code_gen/resource_types/manifest.rb +16 -0
  29. data/lib/abide_dev_utils/ppt/code_gen/resource_types/parameter.rb +16 -0
  30. data/lib/abide_dev_utils/ppt/code_gen/resource_types/strings.rb +13 -0
  31. data/lib/abide_dev_utils/ppt/code_gen/resource_types.rb +6 -0
  32. data/lib/abide_dev_utils/ppt/code_gen.rb +15 -0
  33. data/lib/abide_dev_utils/ppt/code_introspection.rb +102 -0
  34. data/lib/abide_dev_utils/ppt/hiera.rb +4 -1
  35. data/lib/abide_dev_utils/ppt/puppet_module.rb +2 -1
  36. data/lib/abide_dev_utils/ppt.rb +3 -0
  37. data/lib/abide_dev_utils/version.rb +1 -1
  38. data/lib/abide_dev_utils/xccdf/parser/helpers.rb +146 -0
  39. data/lib/abide_dev_utils/xccdf/parser/objects.rb +87 -144
  40. data/lib/abide_dev_utils/xccdf/parser.rb +5 -0
  41. data/lib/abide_dev_utils/xccdf/utils.rb +89 -0
  42. data/lib/abide_dev_utils/xccdf.rb +3 -0
  43. metadata +27 -3
  44. data/lib/abide_dev_utils/cem/coverage_report.rb +0 -348
@@ -0,0 +1,380 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+ require 'json'
5
+ require 'pathname'
6
+ require 'yaml'
7
+ require 'abide_dev_utils/ppt'
8
+ require 'abide_dev_utils/validate'
9
+ require 'abide_dev_utils/cem/benchmark'
10
+
11
+ module AbideDevUtils
12
+ module CEM
13
+ module Generate
14
+ # Methods and objects used to construct a report of what CEM enforces versus what
15
+ # the various compliance frameworks expect to be enforced.
16
+ module CoverageReport
17
+ def self.generate(format_func: :to_h, opts: {})
18
+ opts = AbideDevUtils::CEM::CoverageReport::ReportOptions.new(opts)
19
+ pupmod = AbideDevUtils::Ppt::PuppetModule.new
20
+ benchmarks = AbideDevUtils::CEM::Benchmark.benchmarks_from_puppet_module(pupmod,
21
+ ignore_all_errors: opts.ignore_all_errors)
22
+ benchmarks.map do |b|
23
+ AbideDevUtils::CEM::CoverageReport::BenchmarkReport.new(b)
24
+ .send(report_type, **{ profile: profile, level: level })
25
+ .send(format_func)
26
+ end
27
+ end
28
+
29
+ class ReportOptions
30
+ DEFAULTS = {
31
+ benchmark: nil,
32
+ profile: nil,
33
+ level: nil,
34
+ format_func: :to_h,
35
+ ignore_all_errors: false,
36
+ xccdf_dir: nil,
37
+ }.freeze
38
+
39
+ attr_reader(*DEFAULTS.keys)
40
+
41
+ def initialize(opts = {})
42
+ @opts = DEFAULTS.merge(opts)
43
+ DEFAULTS.each_key do |k|
44
+ instance_variable_set "@#{k}", @opts[k]
45
+ end
46
+ end
47
+
48
+ def report_type
49
+ @report_type ||= (xccdf_dir.nil? ? :basic_coverage : :correlated_coverage)
50
+ end
51
+ end
52
+
53
+ class Filter
54
+ KEY_FACT_MAP = {
55
+ os_family: 'os.family',
56
+ os_name: 'os.name',
57
+ os_release_major: 'os.release.major',
58
+ }.freeze
59
+
60
+ attr_reader(*KEY_FACT_MAP.keys)
61
+
62
+ def initialize(pupmod, **filters)
63
+ @pupmod = pupmod
64
+ @benchmark = filters[:benchmark]
65
+ @profile = filters[:profile]
66
+ @level = filters[:level]
67
+ KEY_FACT_MAP.each_key do |k|
68
+ instance_variable_set "@#{k}", filters[k]
69
+ end
70
+ end
71
+
72
+ def resource_data
73
+ @resource_data ||= find_resource_data
74
+ end
75
+
76
+ def mapping_data
77
+ @mapping_data ||= find_mapping_data
78
+ end
79
+
80
+ private
81
+
82
+ def find_resource_data
83
+ fact_array = fact_array_for(:os_family, :os_name, :os_release_major)
84
+ @pupmod.hiera_conf.local_hiera_files_with_facts(*fact_array, hierarchy_name: 'Resource Data').map do |f|
85
+ YAML.load_file(f.path)
86
+ end
87
+ rescue NoMethodError
88
+ @pupmod.hiera_conf.local_hiera_files(hierarchy_name: 'Resource Data').map { |f| YAML.load_file(f.path) }
89
+ end
90
+
91
+ def find_mapping_data
92
+ fact_array = fact_array_for(:os_name, :os_release_major)
93
+ begin
94
+ data_array = @pupmod.hiera_conf.local_hiera_files_with_facts(*fact_array, hierarchy_name: 'Mapping Data').map do |f|
95
+ YAML.load_file(f.path)
96
+ end
97
+ rescue NoMethodError
98
+ data_array = @pupmod.hiera_conf.local_hiera_files(hierarchy_name: 'Mapping Data').map { |f| YAML.load_file(f.path) }
99
+ end
100
+ filter_mapping_data_array_by_benchmark!(data_array)
101
+ filter_mapping_data_array_by_profile!(data_array)
102
+ filter_mapping_data_array_by_level!(data_array)
103
+ data_array
104
+ end
105
+
106
+ def filter_mapping_data_array_by_benchmark!(data_array)
107
+ return unless @benchmark
108
+
109
+ data_array.select! do |d|
110
+ d.keys.all? do |k|
111
+ k == 'benchmark' || k.match?(/::#{@benchmark}::/)
112
+ end
113
+ end
114
+ end
115
+
116
+ def filter_mapping_data_array_by_profile!(data_array)
117
+ return unless @profile
118
+
119
+ data_array.reject! { |d| nested_hash_value(d, @profile).nil? }
120
+ end
121
+
122
+ def filter_mapping_data_array_by_level!(data_array)
123
+ return unless @level
124
+
125
+ data_array.reject! { |d| nested_hash_value(d, @level).nil? }
126
+ end
127
+
128
+ def nested_hash_value(obj, key)
129
+ if obj.respond_to?(:key?) && obj.key?(key)
130
+ obj[key]
131
+ elsif obj.respond_to?(:each)
132
+ r = nil
133
+ obj.find { |*a| r = nested_hash_value(a.last, key) }
134
+ r
135
+ end
136
+ end
137
+
138
+ def filter_stig_mapping_data(data_array); end
139
+
140
+ def fact_array_for(*keys)
141
+ keys.each_with_object([]) { |(k, _), a| a << fact_filter_value(k) }.compact
142
+ end
143
+
144
+ def fact_filter_value(key)
145
+ value = instance_variable_get("@#{key}")
146
+ return if value.nil? || value.empty?
147
+
148
+ [KEY_FACT_MAP[key], value]
149
+ end
150
+ end
151
+
152
+ class OldReport
153
+ def initialize(benchmarks)
154
+ @benchmarks = benchmarks
155
+ end
156
+
157
+ def self.generate
158
+ coverage = {}
159
+ coverage['classes'] = {}
160
+ all_cap = ClassUtils.find_all_classes_and_paths(puppet_class_dir)
161
+ invalid_classes = find_invalid_classes(all_cap)
162
+ valid_classes = find_valid_classes(all_cap, invalid_classes)
163
+ coverage['classes']['invalid'] = invalid_classes
164
+ coverage['classes']['valid'] = valid_classes
165
+ hiera = YAML.safe_load(File.open(hiera_path))
166
+ profile&.gsub!(/^profile_/, '') unless profile.nil?
167
+
168
+ matcher = profile.nil? ? /^profile_/ : /^profile_#{profile}/
169
+ hiera.each do |k, v|
170
+ key_base = k.split('::')[-1]
171
+ coverage['benchmark'] = v if key_base == 'title'
172
+ next unless key_base.match?(matcher)
173
+
174
+ coverage[key_base] = generate_uncovered_data(v, valid_classes)
175
+ end
176
+ coverage
177
+ end
178
+
179
+ def self.generate_uncovered_data(ctrl_list, valid_classes)
180
+ out_hash = {}
181
+ out_hash[:num_total] = ctrl_list.length
182
+ out_hash[:uncovered] = []
183
+ out_hash[:covered] = []
184
+ ctrl_list.each do |c|
185
+ if valid_classes.include?(c)
186
+ out_hash[:covered] << c
187
+ else
188
+ out_hash[:uncovered] << c
189
+ end
190
+ end
191
+ out_hash[:num_covered] = out_hash[:covered].length
192
+ out_hash[:num_uncovered] = out_hash[:uncovered].length
193
+ out_hash[:coverage] = Float(
194
+ (Float(out_hash[:num_covered]) / Float(out_hash[:num_total])) * 100.0
195
+ ).floor(3)
196
+ out_hash
197
+ end
198
+
199
+ def self.find_valid_classes(all_cap, invalid_classes)
200
+ all_classes = all_cap.dup.transpose[0]
201
+ return [] if all_classes.nil?
202
+
203
+ return all_classes - invalid_classes unless invalid_classes.nil?
204
+
205
+ all_classes
206
+ end
207
+
208
+ def self.find_invalid_classes(all_cap)
209
+ invalid_classes = []
210
+ all_cap.each do |cap|
211
+ invalid_classes << cap[0] unless class_valid?(cap[1])
212
+ end
213
+ invalid_classes
214
+ end
215
+
216
+ def self.class_valid?(manifest_path)
217
+ compiler = Puppet::Pal::Compiler.new(nil)
218
+ ast = compiler.parse_file(manifest_path)
219
+ ast.body.body.statements.each do |s|
220
+ next unless s.respond_to?(:arguments)
221
+ next unless s.arguments.respond_to?(:each)
222
+
223
+ s.arguments.each do |i|
224
+ return false if i.value == 'Not implemented'
225
+ end
226
+ end
227
+ true
228
+ end
229
+ end
230
+
231
+ # Class manages organizing report data into various output formats
232
+ class ReportOutput
233
+ attr_reader :controls_in_resource_data, :rules_in_map, :timestamp,
234
+ :title
235
+
236
+ def initialize(benchmark, controls_in_resource_data, rules_in_map)
237
+ @benchmark = benchmark
238
+ @controls_in_resource_data = controls_in_resource_data
239
+ @rules_in_map = rules_in_map
240
+ @timestamp = DateTime.now.iso8601
241
+ @title = "Coverage Report for #{@benchmark.title_key}"
242
+ end
243
+
244
+ def uncovered
245
+ @uncovered ||= rules_in_map - controls_in_resource_data
246
+ end
247
+
248
+ def uncovered_count
249
+ @uncovered_count ||= uncovered.length
250
+ end
251
+
252
+ def covered
253
+ @covered ||= rules_in_map - uncovered
254
+ end
255
+
256
+ def covered_count
257
+ @covered_count ||= covered.length
258
+ end
259
+
260
+ def total_count
261
+ @total_count ||= rules_in_map.length
262
+ end
263
+
264
+ def percentage
265
+ @percentage ||= covered_count.to_f / total_count
266
+ end
267
+
268
+ def to_h
269
+ {
270
+ title: title,
271
+ timestamp: timestamp,
272
+ benchmark: benchmark_hash,
273
+ coverage: coverage_hash,
274
+ }
275
+ end
276
+
277
+ def to_json(opts = nil)
278
+ JSON.generate(to_h, opts)
279
+ end
280
+
281
+ def to_yaml
282
+ to_h.to_yaml
283
+ end
284
+
285
+ def benchmark_hash
286
+ {
287
+ title: @benchmark.title,
288
+ version: @benchmark.version,
289
+ framework: @benchmark.framework,
290
+ }
291
+ end
292
+
293
+ def coverage_hash
294
+ {
295
+ total_count: total_count,
296
+ uncovered_count: uncovered_count,
297
+ uncovered: uncovered,
298
+ covered_count: covered_count,
299
+ covered: covered,
300
+ percentage: percentage,
301
+ controls_in_resource_data: controls_in_resource_data,
302
+ rules_in_map: rules_in_map,
303
+ }
304
+ end
305
+ end
306
+
307
+ # Creates ReportOutput objects based on the given Benchmark
308
+ class BenchmarkReport
309
+ def initialize(benchmark, opts = AbideDevUtils::CEM::CoverageReport::ReportOptions.new)
310
+ @benchmark = benchmark
311
+ @opts = opts
312
+ end
313
+
314
+ def controls_in_resource_data
315
+ @controls_in_resource_data ||= find_controls_in_resource_data
316
+ end
317
+
318
+ def controls_in_mapping_data
319
+ @controls_in_mapping_data ||= find_controls_in_mapping_data
320
+ end
321
+
322
+ def basic_coverage(level: @opts.level, profile: @opts.profile)
323
+ map_type = @benchmark.map_type(controls_in_resource_data[0])
324
+ rules_in_map = @benchmark.rules_in_map(map_type, level: level, profile: profile)
325
+ AbideDevUtils::CEM::CoverageReport::ReportOutput.new(@benchmark, controls_in_resource_data, rules_in_map)
326
+ end
327
+
328
+ # def correlated_coverage(level: @opts.level, profile: @opts.profile)
329
+ # correlation = ReportOutputCorrelation.new(basic_coverage(level: level, profile: profile))
330
+ # end
331
+
332
+ private
333
+
334
+ def find_controls_in_resource_data
335
+ controls = @benchmark.resource_data["#{@benchmark.module_name}::resources"].each_with_object([]) do |(rname, rval), arr|
336
+ arr << case rval['controls'].class.to_s
337
+ when 'Hash'
338
+ rval['controls'].keys
339
+ when 'Array'
340
+ rval['controls']
341
+ else
342
+ raise "Invalid controls type: #{rval['controls'].class}"
343
+ end
344
+ end
345
+ controls.flatten.uniq.select do |c|
346
+ case @benchmark.framework
347
+ when 'cis'
348
+ @benchmark.map_type(c) != 'vulnid'
349
+ when 'stig'
350
+ @benchmark.map_type(c) == 'vulnid'
351
+ else
352
+ raise "Cannot find controls for framework #{@benchmark.framework}"
353
+ end
354
+ end
355
+ end
356
+
357
+ def find_controls_in_mapping_data
358
+ controls = @benchmark.map_data[0].each_with_object([]) do |(_, mapping), arr|
359
+ mapping.each do |level, profs|
360
+ next if level == 'benchmark'
361
+
362
+ profs.each do |_, ctrls|
363
+ arr << ctrls.keys
364
+ arr << ctrls.values
365
+ end
366
+ end
367
+ end
368
+ controls.flatten.uniq
369
+ end
370
+ end
371
+
372
+ class ReportOutputCorrelation
373
+ def initialize(cov_rep)
374
+ @cov_rep = cov_rep
375
+ end
376
+ end
377
+ end
378
+ end
379
+ end
380
+ end
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
+ require 'timeout'
4
5
  require 'yaml'
5
6
  require 'abide_dev_utils/markdown'
7
+ require 'abide_dev_utils/output'
6
8
  require 'abide_dev_utils/ppt'
7
9
  require 'abide_dev_utils/cem/benchmark'
8
10
 
@@ -27,7 +29,8 @@ module AbideDevUtils
27
29
  benchmarks = AbideDevUtils::CEM::Benchmark.benchmarks_from_puppet_module(pupmod)
28
30
  case data.fetch(:format, 'markdown')
29
31
  when 'markdown'
30
- MarkdownGenerator.new(benchmarks).generate(doc_title)
32
+ file = data[:out_file] || 'REFERENCE.md'
33
+ MarkdownGenerator.new(benchmarks, pupmod.name, file: file).generate(doc_title)
31
34
  else
32
35
  raise "Format #{data[:format]} is unsupported! Only `markdown` format supported"
33
36
  end
@@ -55,59 +58,180 @@ module AbideDevUtils
55
58
 
56
59
  # Generates a markdown reference doc
57
60
  class MarkdownGenerator
58
- def initialize(benchmarks)
61
+ def initialize(benchmarks, module_name, file: 'REFERENCE.md')
59
62
  @benchmarks = benchmarks
60
- @md = AbideDevUtils::Markdown.new('REFERENCE.md')
63
+ @module_name = module_name
64
+ @file = file
65
+ @md = AbideDevUtils::Markdown.new(@file)
61
66
  end
62
67
 
63
68
  def generate(doc_title = 'Reference')
64
69
  md.add_title(doc_title)
65
70
  benchmarks.each do |benchmark|
71
+ progress_bar = AbideDevUtils::Output.progress(title: "Generating Markdown for #{benchmark.title_key}",
72
+ total: benchmark.controls.length)
66
73
  md.add_h1(benchmark.title_key)
67
- benchmark.rules.each do |title, rule|
68
- md.add_h2("#{rule['number']} #{title}")
69
- md.add_ul('Parameters:')
70
- rule['params'].each do |p|
71
- md.add_ul("#{md.code(p[:name])} - [ #{md.code(p[:type])} ] - #{md.italic('Default:')} #{md.code(p[:default])}", indent: 1)
72
- end
73
- md.add_ul('Config Example:')
74
- example = config_example(benchmark.module_name, title, rule['params'])
75
- md.add_code_block(example, language: 'yaml')
76
- md.add_ul('Supported Levels:')
77
- rule['level'].each do |l|
78
- md.add_ul(md.code(l), indent: 1)
79
- end
80
- md.add_ul('Supported Profiles:')
81
- rule['profile'].each do |l|
82
- md.add_ul(md.code(l), indent: 1)
83
- end
84
- md.add_ul('Alternate Config IDs:')
85
- rule['alternate_ids'].each do |l|
86
- md.add_ul(md.code(l), indent: 1)
87
- end
88
- md.add_ul("Resource: #{md.code(rule['resource'].capitalize)}")
74
+ benchmark.controls.each do |control|
75
+ next if ['cem_options', 'cem_protected', 'dependent'].include? control.id
76
+ next if benchmark.framework == 'stig' && control.id_map_type != 'vulnid'
77
+
78
+ control_md = ControlMarkdown.new(control, @md, @module_name, benchmark.framework)
79
+ control_md.generate!
80
+ progress_bar.increment
81
+ rescue StandardError => e
82
+ raise "Failed to generate markdown for control #{control.id}. Original message: #{e.message}"
89
83
  end
90
84
  end
85
+ AbideDevUtils::Output.simple("Saving markdown to #{@file}")
91
86
  md.to_file
92
87
  end
93
88
 
94
89
  private
95
90
 
96
91
  attr_reader :benchmarks, :md
92
+ end
93
+
94
+ class ControlMarkdown
95
+ def initialize(control, md, module_name, framework)
96
+ @control = control
97
+ @md = md
98
+ @module_name = module_name
99
+ @framework = framework
100
+ @control_data = {}
101
+ end
102
+
103
+ def generate!
104
+ heading_builder
105
+ control_params_builder
106
+ control_levels_builder
107
+ control_profiles_builder
108
+ config_example_builder
109
+ control_alternate_ids_builder
110
+ dependent_controls_builder
111
+ resource_reference_builder
112
+ end
113
+
114
+ private
115
+
116
+ def heading_builder
117
+ @md.add_h2("#{@control.number} - #{@control.title}")
118
+ end
119
+
120
+ def control_has_valid_params?
121
+ return true if @control.params? || @control.resource.cem_options? || @control.resource.cem_protected?
122
+ return true if @control.resource.manifest? && @control.resource.manifest.declaration.parameters?
123
+
124
+ false
125
+ end
126
+
127
+ def resource_param(ctrl_param)
128
+ return unless @control.resource.manifest?
129
+
130
+ @control.resource.manifest.declaration.parameters&.find { |x| x.name == "$#{ctrl_param[:name]}" }
131
+ #raise "Cannot find resource parameter for param #{ctrl_param[:name]}" unless rparam
132
+ end
133
+
134
+ def param_type_expr(ctrl_param, rsrc_param)
135
+ @control_data[ctrl_param[:name]] = {} unless @control_data.key?(ctrl_param[:name])
136
+ @control_data[ctrl_param[:name]][:type_expr] = rsrc_param&.type_expr? ? rsrc_param&.type_expr : ctrl_param[:type]
137
+ return unless @control_data[ctrl_param[:name]][:type_expr]
138
+
139
+ " - [ #{@md.code(@control_data[ctrl_param[:name]][:type_expr])} ]"
140
+ end
141
+
142
+ def param_default_value(ctrl_param, rsrc_param)
143
+ @control_data[ctrl_param[:name]] = {} unless @control_data.key?(ctrl_param[:name])
144
+ @control_data[ctrl_param[:name]][:default] = ctrl_param[:default] || rsrc_param&.value
145
+ return unless @control_data[ctrl_param[:name]][:default]
146
+
147
+ " - #{@md.italic('Default:')} #{@md.code(@control_data[ctrl_param[:name]][:default])}"
148
+ end
149
+
150
+ def control_params_builder
151
+ return unless control_has_valid_params?
152
+
153
+ @md.add_ul('Parameters:')
154
+ [@control.param_hashes, @control.resource.cem_options, @control.resource.cem_protected].each do |collection|
155
+ collection.each do |hsh|
156
+ rparam = resource_param(hsh)
157
+ str_array = [@md.code(hsh[:name]), param_type_expr(hsh, rparam), param_default_value(hsh, rparam)]
158
+ @md.add_ul(str_array.compact.join, indent: 1)
159
+ end
160
+ end
161
+ end
162
+
163
+ def control_levels_builder
164
+ return unless @control.levels
165
+
166
+ @md.add_ul('Supported Levels:')
167
+ @control.levels.each do |l|
168
+ @md.add_ul(@md.code(l), indent: 1)
169
+ end
170
+ end
171
+
172
+ def control_profiles_builder
173
+ return unless @control.profiles
174
+
175
+ @md.add_ul('Supported Profiles:')
176
+ @control.profiles.each do |l|
177
+ @md.add_ul(@md.code(l), indent: 1)
178
+ end
179
+ end
180
+
181
+ def control_alternate_ids_builder
182
+ return if @framework == 'stig'
97
183
 
98
- def config_example(module_name, control, params_array)
99
- out_str = ["#{module_name}::config:", ' control_configs:', " \"#{control}\":"]
184
+ @md.add_ul('Alternate Config IDs:')
185
+ @control.alternate_ids.each do |l|
186
+ @md.add_ul(@md.code(l), indent: 1)
187
+ end
188
+ end
189
+
190
+ def dependent_controls_builder
191
+ dep_ctrls = @control.resource.dependent_controls
192
+ return if dep_ctrls.nil? || dep_ctrls.empty?
193
+
194
+ @md.add_ul('Dependent controls:')
195
+ dep_ctrls.each do |ctrl|
196
+ puts "DEPENDENT: #{ctrl.id}"
197
+ @md.add_ul(@md.code(ctrl.display_title), indent: 1)
198
+ end
199
+ end
200
+
201
+ def config_example_builder
202
+ out_str = []
100
203
  indent = ' '
101
- params_array.each do |param_hash|
102
- val = case param_hash[:type]
103
- when 'String'
104
- "'#{param_hash[:default]}'"
204
+ @control.param_hashes.each do |param_hash|
205
+ next if param_hash[:name] == 'No parameters'
206
+
207
+ val = if @control_data[param_hash[:name]][:default] &&
208
+ @control_data[param_hash[:name]][:type_expr]&.match?(/String|Path/)
209
+ "'#{@control_data[param_hash[:name]][:default]}'"
210
+ elsif @control_data[param_hash[:name]][:default]
211
+ @control_data[param_hash[:name]][:default]
212
+ elsif @control_data[param_hash[:name]][:type_expr]
213
+ "<#{@control_data[param_hash[:name]][:type_expr]}>"
105
214
  else
106
- param_hash[:default]
215
+ 'undef'
107
216
  end
108
217
  out_str << "#{indent}#{param_hash[:name]}: #{val}"
109
218
  end
110
- out_str.join("\n")
219
+ return if out_str.empty?
220
+
221
+ begin
222
+ out_str.unshift(" #{@control.title.dump}:")
223
+ rescue NoMethodError
224
+ require 'pry'
225
+ binding.pry
226
+ end
227
+ out_str.unshift(' control_configs:')
228
+ out_str.unshift("#{@module_name}::config:")
229
+ @md.add_ul('Hiera Configuration Example:')
230
+ @md.add_code_block(out_str.join("\n"), language: 'yaml')
231
+ end
232
+
233
+ def resource_reference_builder
234
+ @md.add_ul("Resource: #{@md.code(@control.resource.to_reference)}")
111
235
  end
112
236
  end
113
237
  end
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'abide_dev_utils/cem/generate/reference'
4
+ require 'abide_dev_utils/cem/generate/coverage_report'
5
+
3
6
  module AbideDevUtils
4
7
  module CEM
5
- # Holds objects and methods for `abide cem generate` subcommands
6
- module Generate
7
- require 'abide_dev_utils/cem/generate/reference'
8
- end
8
+ # Namespace for objects and methods used in `abide cem generate` subcommands
9
+ module Generate; end
9
10
  end
10
11
  end