abide_dev_utils 0.11.0 → 0.11.1

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