abide-data-processor 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b04940d641ff075df44bad1d44db0c5cfb4498c0aacd69c79baf5af9234d5533
4
- data.tar.gz: 4ccc87ba94466281cb4ed8656b3734f07063ada8c113abc2c50e6c9b61d5bed7
3
+ metadata.gz: d0c06067b1e8e9d9fd97a99a4a006fbe5f194103783b086d7be46053468a0f7e
4
+ data.tar.gz: 10b23ed882b6ae68e057c2bde2c31ee7d46b5bee3e28b11223b96d1342666bc8
5
5
  SHA512:
6
- metadata.gz: 2cc5c8a4f39c318f635b84e2413435b0e5e39ce2dfa6c9acee8e1d912b7f4936dbfb131281f571c1de44b7a41d37b6f3650e45eb0ebdd3e6eec75245bad1aac0
7
- data.tar.gz: dc18ff5f2a6c0bb41d5213969643d71261df6b36d9e31af10bd4e1d40bd532633b8bc988e33142af693983cdc1f0deda7f363096fb9e2e5b154f1f2bcaca20d8
6
+ metadata.gz: f1774914d0700a4afdaf9c9f4dc7d92da3811ef9e37a271b1b517d9a37920f7d7c2fd778302c369daab51c28c25f7ac51ddf92cf530ba31190ac06b06017d410
7
+ data.tar.gz: 9f7fcffebc49eb7590b36d2b38caf7fe1126de54414c2267f2b4544928c4c165c862ac345058a08f15fade7a74133c0e232943c0c4ac00e0b8fff6fbb1ee9a07
data/Gemfile.lock CHANGED
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- abide-data-processor (0.3.0)
5
- puppet (>= 6.23)
4
+ abide-data-processor (1.0.0)
5
+ deep_merge (~> 1.2)
6
+ rgl (~> 0.5)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
@@ -39,11 +40,8 @@ GEM
39
40
  concurrent-ruby (1.1.9)
40
41
  console (1.13.1)
41
42
  fiber-local
42
- deep_merge (1.2.1)
43
+ deep_merge (1.2.2)
43
44
  diff-lcs (1.4.4)
44
- facter (4.2.5)
45
- hocon (~> 1.3)
46
- thor (>= 1.0.1, < 2.0)
47
45
  faraday (1.8.0)
48
46
  faraday-em_http (~> 1.0)
49
47
  faraday-em_synchrony (~> 1.0)
@@ -68,6 +66,7 @@ GEM
68
66
  fast_gettext (1.8.0)
69
67
  fiber-local (1.0.0)
70
68
  gem-release (2.2.2)
69
+ generator (0.0.1)
71
70
  github_changelog_generator (1.16.4)
72
71
  activesupport
73
72
  async (>= 1.25.0)
@@ -77,11 +76,9 @@ GEM
77
76
  octokit (~> 4.6)
78
77
  rainbow (>= 2.2.1)
79
78
  rake (>= 10.0)
80
- hiera (3.7.0)
81
- hocon (1.3.1)
82
79
  i18n (1.8.10)
83
80
  concurrent-ruby (~> 1.0)
84
- locale (2.1.3)
81
+ lazy_priority_queue (0.1.1)
85
82
  method_source (1.0.0)
86
83
  minitest (5.14.4)
87
84
  multi_json (1.15.0)
@@ -107,23 +104,13 @@ GEM
107
104
  byebug (~> 11.0)
108
105
  pry (~> 0.10)
109
106
  public_suffix (4.0.6)
110
- puppet (7.12.1)
111
- concurrent-ruby (~> 1.0)
112
- deep_merge (~> 1.0)
113
- facter (> 2.0.1, < 5)
114
- fast_gettext (~> 1.1)
115
- hiera (>= 3.2.1, < 4)
116
- locale (~> 2.1)
117
- multi_json (~> 1.10)
118
- puppet-resource_api (~> 1.5)
119
- scanf (~> 1.0)
120
- semantic_puppet (~> 1.0)
121
- puppet-resource_api (1.8.14)
122
- hocon (>= 1.0)
123
107
  rainbow (3.0.0)
124
108
  rake (12.3.3)
125
109
  regexp_parser (2.1.1)
126
110
  rexml (3.2.5)
111
+ rgl (0.5.7)
112
+ lazy_priority_queue (~> 0.1.0)
113
+ stream (~> 0.5.3)
127
114
  rspec (3.10.0)
128
115
  rspec-core (~> 3.10.0)
129
116
  rspec-expectations (~> 3.10.0)
@@ -160,9 +147,8 @@ GEM
160
147
  sawyer (0.8.2)
161
148
  addressable (>= 2.3.5)
162
149
  faraday (> 0.8, < 2.0)
163
- scanf (1.0.0)
164
- semantic_puppet (1.0.4)
165
- thor (1.1.0)
150
+ stream (0.5.3)
151
+ generator
166
152
  timers (4.3.3)
167
153
  tzinfo (2.0.4)
168
154
  concurrent-ruby (~> 1.0)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'lib/abide-data-processor/version'
2
4
 
3
5
  Gem::Specification.new do |spec|
@@ -28,8 +30,8 @@ Gem::Specification.new do |spec|
28
30
  spec.require_paths = ["lib"]
29
31
 
30
32
  # Prod dependencies
31
- # I'm not too sure about this version
32
- spec.add_dependency 'puppet', '>= 6.23'
33
+ spec.add_dependency 'deep_merge', '~> 1.2'
34
+ spec.add_dependency 'rgl', '~> 0.5'
33
35
 
34
36
  # Dev dependencies
35
37
  spec.add_development_dependency 'bundler'
@@ -0,0 +1,722 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'deep_merge'
4
+ require 'rgl/adjacency'
5
+ require 'rgl/topsort'
6
+ require 'rgl/traversal'
7
+ require 'set'
8
+
9
+ module AbideDataProcessor
10
+ # This module contains the logic for creating resource data from Hiera data.
11
+ module Parser
12
+ MAP_TYPES = %w[hiera_title hiera_title_num number title].freeze
13
+ METAPARAMS = %w[dependent before require subscribe notify].freeze
14
+
15
+ # Parse Hiera data into a resource data Hash
16
+ # @param hiera_data [Hash] Hiera data to parse
17
+ # @param control_maps [Array] Control maps to use
18
+ # @return [Hash] Parsed resource data
19
+ def self.parse(hiera_data, control_maps, control_configs: {}, ignore: [], only: [])
20
+ ResourceDataParser.new(
21
+ hiera_data,
22
+ control_maps,
23
+ control_configs: control_configs,
24
+ ignore: ignore,
25
+ only: only
26
+ ).parse
27
+ end
28
+
29
+ # This module handles data validation for the CIS data parser
30
+ module Validation
31
+ # Validates the hiera_data parameter and either raises an ArgumentError or returns the hiera_data parameter.
32
+ # @param hiera_data [Hash] The Hiera data to be parsed.
33
+ # @return [Hash] The Hiera data to be parsed.
34
+ # @raise [ArgumentError] If the hiera_data parameter is not a non-empty Hash.
35
+ def validate_hiera_data(hiera_data)
36
+ unless not_nil_or_empty?(hiera_data) && hiera_data.is_a?(Hash)
37
+ raise ArgumentError, 'hiera_data must be a non-nil, non-empty Hash'
38
+ end
39
+
40
+ hiera_data
41
+ end
42
+
43
+ # Validates the control_maps parameter and either raises an ArgumentError or returns the control_maps parameter.
44
+ # @param control_maps [Array] The control maps to be parsed.
45
+ # @return [Array] The control maps to be parsed.
46
+ # @raise [ArgumentError] If the control_maps parameter is not a non-empty Array of Hashes.
47
+ def validate_control_maps(control_maps)
48
+ unless not_nil_or_empty?(control_maps) && array_of_hashes?(control_maps)
49
+ raise ArgumentError, 'control_maps must be a non-nil, non-empty Array of Hashes'
50
+ end
51
+
52
+ control_maps
53
+ end
54
+
55
+ # Checks if the value is not nil or empty.
56
+ # @param value [Any] The value to be checked.
57
+ # @return [Boolean] True if the value is not nil or empty, false otherwise.
58
+ def not_nil_or_empty?(value)
59
+ !value.nil? && !value.empty?
60
+ end
61
+
62
+ # Checks if the value is an Array of Hashes.
63
+ # @param value [Any] The value to be checked.
64
+ # @return [Boolean] True if the value is an Array of Hashes, false otherwise.
65
+ def array_of_hashes?(value)
66
+ value.is_a?(Array) && value.all? { |h| h.is_a?(Hash) }
67
+ end
68
+ end
69
+
70
+ # Parser class for resource Hiera data.
71
+ # rubocop:disable Metrics/ClassLength
72
+ class ResourceDataParser
73
+ include Validation
74
+ attr_reader :hiera_data, :control_maps, :resources
75
+
76
+ def initialize(hiera_data, control_maps, control_configs: {}, ignore: [], only: [])
77
+ @hiera_data = validate_hiera_data(hiera_data)
78
+ @control_maps = validate_control_maps(control_maps)
79
+ @control_configs = control_configs
80
+ @ignore = ignore
81
+ @only = only
82
+ @resources = RGL::DirectedAdjacencyGraph.new
83
+ @controls = Set.new
84
+ @filtered = Set.new
85
+ @dependent = {}
86
+ end
87
+
88
+ # Parse the Hiera data into a Hash used by Puppet to create the resources.
89
+ # The way this works is by first creating a DAG and adding all resources to the graph
90
+ # as vertices, with an edge for each resource pointing from a dummy node, :root, to the
91
+ # resource. We then add edges to the graph based on the `before_me` and `after_me` lists
92
+ # of each resource and remove the :root-connected edges for each resource that has a
93
+ # `before_me` list, and remove the :root-connected edges for each resource in a `after_me`
94
+ # list. Finally, we sort the graph into an Array populated with a single Hash of ordered
95
+ # resources and return that Hash.
96
+ # @return [Array] A sorted array of resource hashes.
97
+ # rubocop:disable Metrics/MethodLength
98
+ def parse
99
+ @hiera_data.each do |name, data|
100
+ resource = AbideDataProcessor::Parser.new_resource(name, data, @control_maps)
101
+ add_control_names(resource)
102
+ add_dependent_mapping(resource) # Map any controls this resource depends on
103
+ @resources.add_vertex(resource) # Add all the resources to the graph
104
+ @resources.add_edge(:root, resource) # Establish the root -> resource edges
105
+ add_edge_ordering(resource) # Add resource ordering edges
106
+ end
107
+ # If the resource should be filtered (i.e. only or ignore), remove it from the graph.
108
+ filter_resources!
109
+ # Verify that all dependent resources are in the graph, remove them if not.
110
+ remove_unsatisfied_dependents!
111
+ # Sort the graph and return the array of ordered resource hashes
112
+ sort_resources.map do |r|
113
+ r.add_control_configs(@control_configs)
114
+ resource_data(r)
115
+ end
116
+ end
117
+ # rubocop:enable Metrics/MethodLength
118
+
119
+ private
120
+
121
+ # Adds control neames for the given resource to the @controls set.
122
+ # @param resource [Resource] The resource to add control names for.
123
+ def add_control_names(resource)
124
+ return unless resource.controls
125
+
126
+ @controls.merge(resource.control_names).flatten!
127
+ @controls.merge(resource.mapped_control_names).flatten!
128
+ end
129
+
130
+ # Calls the given Resource's `resource_data` method, filters out any resource references
131
+ # in metaparameters that references filtered resources, and returns the result.
132
+ # @param resource [Resource] The resource to be filtered.
133
+ # @return [Hash] The filtered resource data.
134
+ # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
135
+ def resource_data(resource)
136
+ data = resource.resource_data.dup
137
+ data.each do |_, res_data|
138
+ res_data.each do |_, params|
139
+ METAPARAMS.each do |param|
140
+ next unless params.key?(param)
141
+
142
+ params[param].reject! { |r| @filtered.to_a.map(&:resource_reference).include?(r) }
143
+ params.delete(param) if params[param].empty?
144
+ end
145
+ end
146
+ end
147
+ data
148
+ end
149
+ # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
150
+
151
+ # Removes Resources from the graph if they should be filtered.
152
+ def filter_resources!
153
+ @resources.depth_first_search do |resource|
154
+ next if resource == :root
155
+
156
+ if filter_resource?(resource)
157
+ @resources.remove_vertex(resource) # Remove resource's graph vertex
158
+ @filtered.add(resource) # Add resource to filtered set
159
+ end
160
+ end
161
+ end
162
+
163
+ # Checks whether the resource should be filtered out based on the ignore and only lists.
164
+ # @param resource [Resource] The resource to check.
165
+ # @return [Boolean] True if the resource should be filtered out, false otherwise.
166
+ def filter_resource?(resource)
167
+ return true if control_in?(resource, @ignore)
168
+ return true unless @only.empty? || control_in?(resource, @only)
169
+
170
+ false
171
+ end
172
+
173
+ # Adds a mapping for a dependent control and the resources that depend on it.
174
+ # @param resource [Resource] The resource to add the mapping for.
175
+ def add_dependent_mapping(resource)
176
+ return unless resource.dependent
177
+
178
+ resource.dependent.each do |control_name|
179
+ @dependent[control_name] = [] unless @dependent.key?(control_name)
180
+ @dependent[control_name] << resource
181
+ end
182
+ end
183
+
184
+ # Checks the dependent controls against all controls after filtered resource controls are removed
185
+ # and removes any dependent resources that are not satisfied.
186
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
187
+ def remove_unsatisfied_dependents!
188
+ dependent_set = Set.new(@dependent.keys)
189
+ filtered_set = Set.new(@filtered.to_a.map(&:control_names)).flatten
190
+ filtered_mapped = Set.new(@filtered.to_a.map(&:mapped_control_names)).flatten
191
+
192
+ all_controls = @controls.subtract(filtered_set + filtered_mapped)
193
+ return if dependent_set.proper_subset?(all_controls) # All dependent controls exist in the graph
194
+
195
+ (dependent_set - all_controls).each do |control_name|
196
+ @dependent[control_name].each do |resource|
197
+ @resources.remove_vertex(resource)
198
+ @filtered.add(resource)
199
+ end
200
+ end
201
+ end
202
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
203
+
204
+ # Gets all verticies in the graph that have the associated control
205
+ # @param control_name [String] The name of the control to check.
206
+ # @return [Array] The verticies that have the associated control.
207
+ def collect_verticies_by_control(control_name)
208
+ @resources.vertices.select { |r| r.control?(control_name) }
209
+ end
210
+
211
+ # Checks if the given Resource has a control in the given list.
212
+ # @param resource [Resource] The resource to check.
213
+ # @param control_list [Array] The list of controls to check against.
214
+ # @return [Boolean] True if the resource is in the control list, false otherwise.
215
+ def control_in?(resource, control_list)
216
+ return false if control_list.empty?
217
+
218
+ control_list.each do |ignored_control|
219
+ return true if resource.control?(ignored_control)
220
+ end
221
+ false
222
+ end
223
+
224
+ # Adds edges to the graph based on the given Resource's `before_me` and `after_me` lists.
225
+ # @param resource [Resource] The Resource to add edges for.
226
+ def add_edge_ordering(resource)
227
+ add_before_me_edge(resource)
228
+ add_after_me_edge(resource)
229
+ end
230
+
231
+ # Adds edges to the graph based on the given Resource's `before_me` list.
232
+ # @param resource [Resource] The Resource to add edges for.
233
+ def add_before_me_edge(resource)
234
+ resource.before_me.flatten.each do |before|
235
+ next unless before # Skip if this `before` is nil, empty, or falsy (e.g. false, 0, etc.)
236
+ next if before.equal?(resource) # Skip if this `before` is the same as the current resource
237
+
238
+ # We remove the edge from root to this resource if it exists because this resource is no longer
239
+ # attached to the root of the graph as it has other resources before it.
240
+ @resources.remove_edge(:root, resource) if @resources.has_edge?(:root, resource)
241
+ # Add the edge from the before resource to this resource
242
+ @resources.add_edge(before, resource) unless @resources.has_edge?(before, resource)
243
+ end
244
+ end
245
+
246
+ # Adds edges to the graph based on the given Resource's `after_me` list.
247
+ # @param resource [Resource] The Resource to add edges for.
248
+ def add_after_me_edge(resource)
249
+ resource.after_me.flatten.each do |after|
250
+ next unless after # Skip if this `after` is nil, empty, or falsy (e.g. false, 0, etc.)
251
+ next if after.equal?(resource) # Skip if this `after` is the same as the current resource
252
+
253
+ # We remove the edge from root to the `after` resource if it exists because the `after` resource
254
+ # is no longer attached to the root of the graph as this resources comes before it.
255
+ @resources.remove_edge(:root, after) if @resources.has_edge?(:root, after)
256
+ # Add the edge from this resource to the after resource
257
+ @resources.add_edge(resource, after) unless @resources.has_edge?(resource, after)
258
+ end
259
+ end
260
+
261
+ # This method validates that the resources graph has no cycles and then returns a topological sort of the graph
262
+ # as an Array of Resource objects.
263
+ # @return [Array] The sorted Resources.
264
+ # @raise [ArgumentError] If the resources graph has any cycles.
265
+ def sort_resources
266
+ raise "Resource cyclic ordering detected: #{@resources.cycles}" unless @resources.acyclic?
267
+
268
+ # We call topsort on the graph to get the sorted list of resources, convert it to an array, and
269
+ # remove the root node.
270
+ @resources.topsort_iterator.to_a.flatten.uniq.reject { |r| r == :root }
271
+ end
272
+ end
273
+ # rubocop:enable Metrics/ClassLength
274
+
275
+ # This class holds all base attributes and methods for every syntax object.
276
+ # rubocop:disable Metrics/ClassLength
277
+ class ProcessorObject
278
+ include Validation
279
+ attr_reader :name, *METAPARAMS.map(&:to_sym)
280
+
281
+ def initialize(name, data, control_maps)
282
+ @name = name
283
+ @data = validate_hiera_data(data)
284
+ @control_maps = validate_control_maps(control_maps)
285
+ @dependent = Set.new
286
+ initialize_metaparams(@data, @control_maps)
287
+ end
288
+
289
+ # Determines if the name supplied is equal to the name of the object.
290
+ # This is overridden by subclasses to implement name mapped matches.
291
+ # @param name [String] The name to be compared to the object's name.
292
+ # @return [Boolean] True if the name is equal to the object's name, false otherwise.
293
+ def name?(_name)
294
+ raise NotImplementedError, 'This method must be implemented by a subclass'
295
+ end
296
+
297
+ # Abstract method to be implemented by subclasses.
298
+ # Returns a representation of this object as a Hash usable by Puppet's
299
+ # create_resources function.
300
+ def resource_data
301
+ raise NotImplementedError, 'This method must be implemented by a subclass'
302
+ end
303
+
304
+ # Returns any Resource objects that must be ordered before this object.
305
+ # @return [Array] The Resources that must be ordered before this object.
306
+ def before_me
307
+ defined?(@before_me) ? @before_me : initialize_before_me
308
+ end
309
+
310
+ # Returns any Resource objects that must be ordered after this object.
311
+ # @return [Array] The Resources that must be ordered after this object.
312
+ def after_me
313
+ defined?(@after_me) ? @after_me : initialize_after_me
314
+ end
315
+
316
+ # Converts this object to a String.
317
+ # @return [String] The class and name of this object.
318
+ def to_s
319
+ "#{self.class.name}('#{@name}')"
320
+ end
321
+
322
+ # Gives a more detailed String representation of this object.
323
+ # @return [String] The class, object id, and name of this object.
324
+ def inspect
325
+ "#<#{self.class.name}:#{object_id} '#{@name}'>"
326
+ end
327
+
328
+ private
329
+
330
+ # This method normalizes an array of Resources, or anything really, by
331
+ # flattening it, removing any nil values, removing any duplicates, and
332
+ # rejecting any empty objects if they respond to `empty?`. It then
333
+ # returns the new array.
334
+ # @param resources [Array] The array of Resources to be normalized.
335
+ # @return [Array] The normalized array of Resources.
336
+ def normalize_resource_array(array)
337
+ array.flatten.compact.uniq.reject { |r| r.empty? if r.respond_to?(:empty?) }
338
+ end
339
+
340
+ # This method normalizes an array of Resources, or anything really, by
341
+ # flattening it, removing any nil values, removing any duplicates, and
342
+ # rejecting any empty objects if they respond to `empty?`. It does this
343
+ # in place, directly modifying the input array.
344
+ # @param resources [Array] The array of Resources to be normalized.
345
+ def normalize_resource_array!(array)
346
+ array.flatten!
347
+ array.compact!
348
+ array.uniq!
349
+ array.reject! { |r| r.empty? if r.respond_to?(:empty?) }
350
+ end
351
+
352
+ # Initializes any relevant metaparameters based on the data supplied.
353
+ # @param data [Hash] The resource data to be parsed.
354
+ # @param control_maps [Array] The control maps to be used.
355
+ def initialize_metaparams(data, control_maps)
356
+ METAPARAMS.each do |param|
357
+ value, bool_value = parse_metaparam(data[param], control_maps)
358
+ raw_value, raw_bool_value = parse_raw_metaparam(data, param)
359
+ set_metaparam_instance_vars(param, value, raw_value)
360
+ define_metaparam_bool_methods(param, raw_bool_value, bool_value)
361
+ end
362
+ end
363
+
364
+ # Initilizes the before_me instance variable with a list of Resources
365
+ # that must be ordered before this object.
366
+ # @return [Array] The list of Resources that must be ordered before this object.
367
+ def initialize_before_me
368
+ ctrls = @controls ? calculate_ordered_controls('before_me') : []
369
+ this = calculate_self_ordering('require', 'subscribe')
370
+ @before_me = normalize_resource_array(this.concat(ctrls))
371
+ @before_me
372
+ end
373
+
374
+ # Initializes the after_me instance variable with a list of Resources
375
+ # that must be ordered after this object.
376
+ # @return [Array] The list of Resources that must be ordered after this object.
377
+ def initialize_after_me
378
+ ctrls = @controls ? calculate_ordered_controls('after_me') : []
379
+ this = calculate_self_ordering('notify', 'subscribe')
380
+ @after_me = normalize_resource_array(this.concat(ctrls))
381
+ @after_me
382
+ end
383
+
384
+ # This method adds the supplied Resource to the inverse ordering list of this
385
+ # object based on the supplied metaparameter. This method is never directly used
386
+ # by an object on itself, rather it is called by other objects when they establish
387
+ # ordering relationships with this object. Because this method is private, other
388
+ # objects must use `send` to call it.
389
+ # @param metaparam [String] The metaparameter to inverse
390
+ # @param resource [Resource] The Resource to be added to the inverse ordering list.
391
+ def add_inverse_ordered_resource(metaparam, resource)
392
+ if %w[require subscribe].include?(metaparam)
393
+ add_after_me(resource)
394
+ elsif %w[before notify].include?(metaparam)
395
+ add_before_me(resource)
396
+ end
397
+ end
398
+
399
+ # This method calculates the ordering of this object based on the
400
+ # ordering of the controls that are defined for this object.
401
+ # @param order_function [String] The function to use to calculate the ordering (before_me or after_me).
402
+ # @return [Array] The list of Resources gathered from the order function return of all controls.
403
+ def calculate_ordered_controls(order_function)
404
+ @controls.each_with_object([]) do |control, ary|
405
+ ary << control.send(order_function.to_sym)
406
+ end
407
+ end
408
+
409
+ # This method calculates the ordering of this object based on the
410
+ # the supplied metaparameters. This function is used with "like pairs"
411
+ # of metaparameters, such as "require" and "subscribe".
412
+ # @param metaparameters [Array] The metaparameters to use to calculate the ordering.
413
+ # @return [Array] The list of Resources gathered from this object's metaparameters.
414
+ def calculate_self_ordering(*metaparams)
415
+ ordered = metaparams.each_with_object([]) do |mparam, ary|
416
+ next unless send("#{mparam}?".to_sym)
417
+
418
+ ordered_resources = send(mparam.to_sym)
419
+ ordered_resources.each { |r| r.send(:add_inverse_ordered_resource, mparam, self) }
420
+
421
+ ary << ordered_resources
422
+ end
423
+ normalize_resource_array(ordered)
424
+ end
425
+
426
+ # Returns appropriate values for instance variables of the given metaparam based off the supplied value.
427
+ # @param value [Array] The metaparameter declaration value from Hiera.
428
+ # @param control_maps [Array] The relevant control maps used in Resource creation.
429
+ # @return [Array] Values for the instance variables of the given metaparam. The order of the values
430
+ # is: Resource collection value, boolean value.
431
+ def parse_metaparam(value, control_maps)
432
+ return [nil, false] unless not_nil_or_empty?(value)
433
+
434
+ return parse_dependent_param(value) if value.is_a?(Array)
435
+
436
+ objects = value.each_with_object([]) do |(k, v), a|
437
+ a << AbideDataProcessor::Parser.new_resource(k, v, control_maps)
438
+ end
439
+ [normalize_resource_array(objects), !objects.empty?]
440
+ end
441
+
442
+ # Adds a each dependent control from a list of dependent controls to the
443
+ # @dependent instance variable.
444
+ # @param value [Array] The dependent controls to be added to the @dependent instance variable.
445
+ def parse_dependent_param(value)
446
+ value.each { |x| @dependent.add(x) }
447
+ end
448
+
449
+ # Returns appropriate raw value for instance variables of the given metaparam based off the supplied value.
450
+ # The raw value is the text values for the metaparameter declaration supplied via the resource data.
451
+ # @param data [Hash] The resource data to be parsed.
452
+ # @param param [String] The metaparameter to be parsed.
453
+ # @return [Array] Values for the instance variables of the given metaparam. The order of the values
454
+ # is: raw value, boolean raw value.
455
+ def parse_raw_metaparam(data, param)
456
+ raw_value = data.fetch(param, nil)
457
+ [raw_value, (!raw_value.nil? && !raw_value.empty?)]
458
+ end
459
+
460
+ # Sets the instance variables of the given metaparam based off the supplied values.
461
+ # @param param [String] The metaparameter to be set.
462
+ # @param value [Array] The Resource value to be set.
463
+ # @param raw_value [Array] The raw value to be set.
464
+ def set_metaparam_instance_vars(param, value, raw_value)
465
+ instance_variable_set("@#{param}", value)
466
+ instance_variable_set("@#{param}_raw", raw_value)
467
+ end
468
+
469
+ # Defines singleton methods for this instance of ProcessorObject that are used to determine
470
+ # if the metaparameter is set.
471
+ # @param param [String] The metaparameter that will have boolean methods defined.
472
+ # @param raw_value [Boolean] The boolean value for the <metaparam>_raw? method.
473
+ # @param value [Boolean] The boolean value for the <metaparam>? method.
474
+ def define_metaparam_bool_methods(param, raw_value, value)
475
+ define_singleton_method("#{param}_raw?".to_sym) { raw_value }
476
+ define_singleton_method("#{param}?".to_sym) { value }
477
+ end
478
+
479
+ # Returns the mapped names for the given control identifier.
480
+ # @param identifier [String] The control identifier to be mapped.
481
+ # @return [Array] The mapped names for the given control identifier.
482
+ def find_mapped_names(identifier)
483
+ @control_maps.each do |control_map|
484
+ return control_map[identifier] if control_map.include?(identifier)
485
+ end
486
+ []
487
+ end
488
+ end
489
+
490
+ # This class represents a single control in the data structure.
491
+ class Control < ProcessorObject
492
+ attr_reader :mapped_names, :params, :param_names, :resource_params
493
+
494
+ def initialize(name, data, control_maps)
495
+ super(name, data, control_maps)
496
+ @mapped_names = find_mapped_names(@name)
497
+ @params = @data
498
+ @resource_params = @data.reject { |k, _v| METAPARAMS.include?(k) }
499
+ @param_names = Set.new(@params.keys)
500
+ end
501
+
502
+ def name?(name)
503
+ @name == name || @mapped_names.include?(name)
504
+ end
505
+
506
+ def param?(param_name)
507
+ @param_names.include?(param_name)
508
+ end
509
+
510
+ def param(param_name)
511
+ @params[param_name]
512
+ end
513
+
514
+ def resource_data
515
+ @resource_params
516
+ end
517
+ end
518
+ # rubocop:enable Metrics/ClassLength
519
+
520
+ # This class represents a single Puppet resource (class, defined type, etc.)
521
+ class Resource < ProcessorObject
522
+ attr_reader :name, :type, :controls, :control_names, :mapped_control_names
523
+
524
+ def initialize(name, data, control_maps)
525
+ super(name, data, control_maps)
526
+ @type = @data['type']
527
+ @controls = create_control_classes(@data['controls'])
528
+ @control_names = Set.new(@controls.map(&:name)).flatten
529
+ @mapped_control_names = Set.new(@controls.map(&:mapped_names).flatten).flatten
530
+ initialize_control_metaparams
531
+ end
532
+
533
+ # Adds overriding parameter values to controls in this resource
534
+ # if this resource has a matching control.
535
+ # @param data [Hash] The resource data to be parsed.
536
+ def add_control_configs(control_configs)
537
+ control_configs.each do |control, configs|
538
+ next unless control?(control)
539
+
540
+ @controls.each do |control_class|
541
+ next unless control_class.name?(control)
542
+
543
+ control_class.resource_params.deep_merge!(configs)
544
+ end
545
+ end
546
+ end
547
+
548
+ # Outputs a representation of this object as a Hash usable by Puppet's
549
+ # create_resources function.
550
+ def resource_data
551
+ control_params = control_parameters
552
+ METAPARAMS.each do |mparam|
553
+ next if mparam == 'dependent'
554
+
555
+ refs = resource_references(mparam, control_params)
556
+ next if refs.nil?
557
+
558
+ control_params[mparam] = refs
559
+ end
560
+ { @type => { @name => control_params } }
561
+ end
562
+
563
+ # This method returns a string representation of this Resource in the resource reference
564
+ # format used by Puppet.
565
+ # @return [String] A string representation of this Resource in the resource reference format.
566
+ def resource_reference
567
+ type_ref = @type.split('::').map(&:capitalize).join('::')
568
+ "#{type_ref}['#{@name}']"
569
+ end
570
+
571
+ # This method checks if this Resource contains the given control.
572
+ # @param control [String] The control to be checked.
573
+ # @return [Boolean] True if this Resource contains the given control, false otherwise.
574
+ def control?(control_name)
575
+ @control_names.include?(control_name) || @mapped_control_names.include?(control_name)
576
+ end
577
+
578
+ # This method checks if this Resource contains the given parameter.
579
+ # @param param_name [String] The parameter to be checked.
580
+ # @return [Boolean] True if this Resource contains the given parameter, false otherwise.
581
+ def param?(param_name)
582
+ if param_name.respond_to?(:each)
583
+ param_name.all? { |name| param?(name) }
584
+ else
585
+ @param_names.include?(param_name)
586
+ end
587
+ end
588
+
589
+ private
590
+
591
+ # This method gathers the resource data for each control this Resource contains.
592
+ # @return [Hash] The resource data for each control this Resource contains.
593
+ def control_parameters
594
+ @controls.each_with_object({}) do |control, h|
595
+ h.deep_merge(control.resource_data)
596
+ end
597
+ end
598
+
599
+ # This method gets the resource references for the given metaparameter and control parameters.
600
+ # @param mparam [String] The metaparameter to be checked.
601
+ # @param control_params [Hash] The control parameters to be checked.
602
+ # @return [Array] The resource references for the given metaparameter and control parameters.
603
+ # @return [nil] If the given metaparameter is not set on this Resource.
604
+ def resource_references(mparam, control_params)
605
+ # rubocop:disable Style/RedundantSelf
606
+ # we use self here because `require` is a metaparam and we don't want to
607
+ # call `Kernel#require` accidentally.
608
+ this_mparam = self.send(mparam.to_sym)
609
+ # rubocop:enable Style/RedundantSelf
610
+ return if this_mparam.nil? || this_mparam.compact.empty?
611
+
612
+ if control_params.key?(mparam)
613
+ control_params[mparam].concat(this_mparam.map(&:resource_reference))
614
+ else
615
+ this_mparam.map(&:resource_reference)
616
+ end
617
+ end
618
+
619
+ # Adds a Resource to the before_me list.
620
+ # @param resource [Resource] The Resource to be added to the before_me list.
621
+ def add_before_me(resource)
622
+ before_me.append(resource)
623
+ end
624
+
625
+ # Adds a Resource to the after_me list.
626
+ # @param resource [Resource] The Resource to be added to the after_me list.
627
+ def add_after_me(resource)
628
+ after_me.append(resource)
629
+ end
630
+
631
+ # Initializes all metaparameter values of all controls that this Resource contains
632
+ # and brings those values into the scope of this Resource. Also initializes the
633
+ # @before_me and @after_me instance variables.
634
+ def initialize_control_metaparams
635
+ METAPARAMS.each { |mparam| initialize_control_metaparameter(mparam) }
636
+ @before_me = initialize_before_me
637
+ @after_me = initialize_after_me
638
+ end
639
+
640
+ # Initializes a single supplied metaparameter for all controls that this Resource
641
+ # contains and brings those values into the scope of this Resource.
642
+ # @param mparam [String] The metaparameter to be initialized.
643
+ def initialize_control_metaparameter(mparam)
644
+ ctrl_objects = @controls.map { |c| c.send(mparam.to_sym) }.flatten
645
+ return if ctrl_objects.empty?
646
+
647
+ current_objects = instance_variable_get("@#{mparam}") || []
648
+ all_meta_objects = ctrl_objects.concat(current_objects)
649
+ instance_variable_set("@#{mparam}", all_meta_objects.flatten.compact.uniq)
650
+ define_singleton_method("#{mparam}?".to_sym) { all_meta_objects.any? }
651
+ end
652
+
653
+ # Creates a new Control class for each control in the data structure if that Control class
654
+ # does not already exist in the cache.
655
+ # @param control_data [Array] The control data of the resource from the Hiera data.
656
+ def create_control_classes(control_data)
657
+ control_data.map { |cname, cdata| AbideDataProcessor::Parser.new_control(cname, cdata, @control_maps) }
658
+ end
659
+ end
660
+
661
+ class << self
662
+ # Creates a new Resource object. If an object with the same resource name, resource data, and control maps
663
+ # already exists, it will be returned instead of creating a new one.
664
+ # @param resource_name [String] The name of the resource.
665
+ # @param resource_data [Hash] The data for the resource.
666
+ # @param control_maps [Array] The control maps for the resource.
667
+ # @return [Resource] The new or cached Resource object.
668
+ def new_resource(resource_name, resource_data, control_maps)
669
+ cache_key = [Resource.name, resource_name, resource_data, control_maps]
670
+ cached = cache_get(cache_key)
671
+ return cached unless cached.nil?
672
+
673
+ new_resource = Resource.new(resource_name, resource_data, control_maps)
674
+ cache_add(cache_key, new_resource)
675
+ new_resource
676
+ end
677
+
678
+ # Creates a new Control object. If an object with the same control name, control data, and control maps
679
+ # already exists, it will be returned instead of creating a new one.
680
+ # @param control_name [String] The name of the control.
681
+ # @param control_data [Hash] The data for the control.
682
+ # @param control_maps [Array] The control maps for the control.
683
+ # @return [Control] The new or cached Control object.
684
+ def new_control(control_name, control_data, control_maps)
685
+ cache_key = [Control.name, control_name, control_data, control_maps]
686
+ cached = cache_get(cache_key)
687
+ return cached unless cached.nil?
688
+
689
+ new_control = Control.new(control_name, control_data, control_maps)
690
+ cache_add(cache_key, new_control)
691
+ new_control
692
+ end
693
+
694
+ # Clears the current cache. Used in testing.
695
+ def clear_cache
696
+ @object_cache = {}
697
+ end
698
+
699
+ private
700
+
701
+ # Helper method to add a ProcessorObject (or subclass of one) to the cache.
702
+ # @param key [Array] The key for the cache. An array comprised of the object name, object data,
703
+ # and control maps.
704
+ # @param resource [ProcessorObject] The object to add to the cache.
705
+ def cache_add(key, object)
706
+ object_cache[key] = object
707
+ end
708
+
709
+ # Helper method to retrieve a ProcessorObject from the cache.
710
+ # @param key [Array] The key for the cache. An array comprised of the resource name, resource data, and control maps.
711
+ # @return [ProcessorObject] The object from the cache, or nil if the object doesn't exist.
712
+ def cache_get(key)
713
+ object_cache.fetch(key, nil)
714
+ end
715
+
716
+ # Holds the object cache. If the object cache doesn't exist, it will be created.
717
+ def object_cache
718
+ @object_cache ||= {}
719
+ end
720
+ end
721
+ end
722
+ end
@@ -1,283 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'deep_merge'
4
- require 'set'
3
+ require 'abide-data-processor/parser'
5
4
 
6
5
  module AbideDataProcessor
7
6
  module Processor
8
- # Here lies the class that will be use to create/extract resources
9
- class ResourceCreator
10
-
11
- # @param control_maps: The control mappings to valid IDs
12
- # @param module_name: The name of the module
13
- # @param logger: The logger that we will use to log information for the user
14
- def initialize(control_maps, logger)
15
- @control_maps = control_maps
16
- @logger = logger
17
- end
18
-
19
- # control_key_maps
20
- # Gets all control key maps from Hiera for indexed control ID permutation searches
21
- # @return An array of four control ID maps, each indexed by one of the four different valid permutations of a control ID
22
- def self.control_key_maps(module_name)
23
- key_prefix = "#{module_name}::mappings::cis"
24
- %w[hiera_title hiera_title_num number title].each_with_object([]) do |key, ary|
25
- ary << [key_prefix, key].join('::')
26
- end
27
- end
28
-
29
- def cis_hiera_key(prefix, key)
30
- "#{prefix}::#{key}"
31
- end
32
-
33
- # create_resources
34
- # @param resources_hash: the hash of controls to be enforces, user will provide this
35
- # @param only: the list of controls to be enforce only, pulled from cis.pp
36
- # @param ignore: the list of controls to be ignore, pulled from cis.pp
37
- # @param control_configs: the custom control configurations pulled from cis.pp
38
- # Return a hash to be convert to Puppet code.
39
- def create_resources(resources_hash, only, ignore, control_configs)
40
- unfreezed_resources = Marshal.load(Marshal.dump(resources_hash))
41
- resources = real_resources(unfreezed_resources, only.to_set, ignore.to_set, control_configs)
42
- ordered_resources = order_resources(resources)
43
-
44
- mutate_ordering_params!(ordered_resources[1])
45
- ordered_resources
46
- end
47
-
48
- # Everything else except the create_resource function will be private
49
- private
50
-
51
- # real_resources
52
- # Formats a Hiera resources hash into a hash used by order_resources()
53
- # @param resources_hash The raw resources hash pulled from hiera
54
- # @param only The $only parameter from cis.pp
55
- # @param ignore The $ignore parameter from cis.pp
56
- # @param control_configs The $control_configs parameter from cis.pp
57
- def real_resources(resources_hash, only, ignore, control_configs)
58
- real_resources = {}
59
- all_controls_name = Set.new # subject to change
60
-
61
- # Grabbing all the control name here into a set
62
- resources_hash.each do |_title, data|
63
- all_controls_name |= data['controls'].keys.to_set
64
- end
65
-
66
- resources_hash.each do |title, data|
67
- resource_params = if data.key?('controls')
68
- extract_control_params(data['controls'], only, ignore, control_configs, all_controls_name)
69
- else
70
- {}
71
- end
72
- if real_resources.key?(data['type']) && real_resources[data['type']].key?(title)
73
- real_resources[data['type']][title].deep_merge!(resource_params, merge_hash_arrays: true)
74
- else
75
- real_resources[data['type']] = { title => resource_params }
76
- end
77
- end
78
- real_resources
79
- end
80
-
81
- # extract_control_params
82
- # Extracts resource parameters from a Hiera resource hash item's `controls` key
83
- # @param control_data The resource hash item's `controls` key-value pair (i.e. data['controls'])
84
- # @param only The $only parameter from cis.pp
85
- # @param ignore The $ignore parameter from cis.pp
86
- # @param control_configs The $control_configs parameter from cis.pp
87
- # @param all_controls_name: All of the controls name
88
- def extract_control_params(control_data, only, ignore, control_configs, all_controls_name)
89
- control_params = {}
90
- control_data.each do |name, params|
91
- name_map = map_for_control_name(name, @control_maps)
92
- next if name_map.nil?
93
- # Only and ignore list check
94
- # The name_map that got passed in here is a hash
95
- next unless only_and_ignore_check(name, name_map, only, ignore)
96
-
97
- # Control dependent check
98
- if params.key?('dependent')
99
- unless dependent_check(all_controls_name, params['dependent'], ignore, only)
100
- # Below is just a sure fire way to make sure that we will never use the resource
101
- only.delete(name) # Remove from the only list
102
- ignore.add(name) # Add the name of the current control to the ignore list if we're not gonna enforce it
103
- @logger.debug("Control #{name} will not be enforced because the controls that it depends on is invalid.")
104
- next
105
- end
106
- end
107
- # Find if there are any custom control configs from the cis.pp based on the control's name and its permutation
108
- customized = find_control_customization(name, name_map[name], control_configs) # Check for failuer here
109
- params.deep_merge!(customized, merge_hash_arrays: true)
110
- control_params.deep_merge!(params, merge_hash_arrays: true)
111
- end
112
- control_params
113
- end
114
-
115
- # dependent_check
116
- # @param all_controls_name: Set of all controls name that parsed from the hiera data
117
- # @param all_dependent_resources: An array of all the resources that is relied upon
118
- # @param ignore: List of controls to be ignore
119
- # @param only: List of only controls that need to be enforce
120
- # return true if a dependent control is
121
- def dependent_check(all_controls_name, all_dependent_resources, ignore, only)
122
- all_dependent_resources.each do |resource_name|
123
- valid_resource_name = map_for_control_name(resource_name, @control_maps)
124
- # Bounce immediately if it is not a part of the controls we're enforcing
125
- return false unless filter_function(resource_name, valid_resource_name, all_controls_name)
126
-
127
- if !ignore.empty?
128
- return false if filter_function(resource_name, valid_resource_name, ignore)
129
- elsif !only.empty?
130
- return false unless filter_function(resource_name, valid_resource_name, only)
131
- end
132
- end
133
- end
134
-
135
- # order_resources
136
- # A work in progress to integrate more metaparamenters in
137
- # Checks for and creates resources based off of `before`, `after`, `notify`, `require` parameters
138
- # specified in a controls hash
139
- # @param resources Output of real_resources()
140
- # @return An array of resource hashes indexed in the order their contents should be created
141
- def order_resources(resources)
142
- before = {}
143
- after = {}
144
- req = {}
145
- notify = {}
146
- resources.each do |_, data|
147
- create_ordered_resource!('before', before, data)
148
- create_ordered_resource!('notify', notify, data)
149
- create_ordered_resource!('after', after, data)
150
- create_ordered_resource!('require', req, data)
151
- end
152
-
153
- before.deep_merge!(notify)
154
- after.deep_merge!(req)
155
-
156
- [before, resources, after]
157
- end
158
-
159
- # filter_function
160
- # A general function to see if a control name is in a supply list of control name
161
- # @param name: The name of the control that we have
162
- # @param name_map: Hash that contains all valid control ID permutation of the param name
163
- # @set_of_control: Either the ignore or the only list to go through
164
- # return true if control ID is found in set_of_control
165
- def filter_function(name, name_map, set_of_control)
166
- name_list = name_map[name] # Grab the array that contain all valid permutation of the ID
167
- return true if set_of_control.include?(name)
168
-
169
- name_list.each do |n|
170
- return true if set_of_control.include?(n)
171
- end
172
-
173
- false
174
- end
175
-
176
- # only_and_ignore_check
177
- # @param name: name of the control to check if it's in either only or ignore list
178
- # @param name_map: a hash of the name map of valid ID permutation for the `name` param
179
- # @param only: the list of controls that will get enforced only
180
- # @param ignore: the list of controls that will be ignored
181
- # @return false when control is either not in the only list or is in the ignore list.
182
- # else return true
183
- def only_and_ignore_check(name, name_map, only, ignore)
184
- if !only.empty? && !filter_function(name, name_map, only)
185
- @logger.debug("Control #{name} will be skipped because it is not in the only list.")
186
- return false
187
- end
188
-
189
- if !ignore.empty? && filter_function(name, name_map, ignore)
190
- @logger.debug("Control #{name} will be skipped because it is in the ignore list.")
191
- return false
192
- end
193
- true
194
- end
195
-
196
- # create_ordered_resource!
197
- # Creates a resource hash from a resource declaration found in a `before`, `after`, `require`, or `notify` parameter
198
- # @param order_key Either 'before', 'after', `notify`, or `require`
199
- # @param container Either the before hash, the notify hash, the require hash or the after hash.
200
- # The container is modified in place.
201
- # @param res_data Resource data from the real_resources hash
202
- def create_ordered_resource!(order_key, container, res_data)
203
- res_data.each do |_, data|
204
- next unless data.key?(order_key)
205
-
206
- data[order_key].each do |title, params|
207
- container[params['type']] = {} unless container.key?(params['type'])
208
- container[params['type']][title] = params.reject { |k, _| k == 'type' }
209
- end
210
- end
211
- end
212
-
213
- # mutate_ordering_params!
214
- # This takes the Hiera resource declarations in a `before` or `after` param and transforms
215
- # them into and array of Puppet resource references. Puppet resource references take the
216
- # form: Resource::Type['<resource title'].
217
- # @param resources Output from real_resources()
218
- def mutate_ordering_params!(resources)
219
- resources.each do |res_type, res_data|
220
- %w[before notify after require].each do |order_key|
221
- res_data.each do |res_title, params|
222
- next unless params.key?(order_key)
223
-
224
- references = []
225
- params[order_key].each do |k, v|
226
- references << resource_reference(v['type'], k)
227
- end
228
- resources[res_type][res_title][order_key] = references
229
- end
230
- end
231
- end
232
- end
233
-
234
- # resource_reference
235
- # Returns a Puppet resource reference string
236
- # @param res_type A Puppet resource type
237
- # @param title A Puppet resource title
238
- def resource_reference(res_type, title)
239
- type_ref = res_type.split('::').map(&:capitalize).join('::')
240
- "#{type_ref}[#{title}]"
241
- end
242
-
243
- # find_control_customization
244
- # Finds any control parameter customizations passed in via control_configs
245
- # @param name The control name (or other valid permutation)
246
- # @param control_configs The $control_configs parameter from cis.pp
247
- # @param name_map: The array of valid permutation of name
248
- # @return A hash of customized parameters. If none were found, nil
249
- def find_control_customization(name, name_map, control_configs)
250
- return {} if control_configs.empty?
251
-
252
- mapped_key(control_configs, name, name_map)
253
- end
254
-
255
- # map_for_control_name
256
- # Returns a hash of all valid permutations of the given control id
257
- # @param name The control name or other valid permutation
258
- # @param maps All maps
259
- def map_for_control_name(name, maps)
260
- maps.each do |map|
261
- return map if map&.fetch(name, false) # returns the map if fetch returns false
262
- end
263
- nil
264
- end
265
-
266
- # mapped_key
267
- # Finds an item in the given hash that matches one of the values in name_map
268
- # @param hsh The hash to search i.e the custom config hash
269
- # @param name The name of the current control that we're looking to see if it has any custom configs
270
- # @param name_map An array name for valid control permutations
271
- # @return The value from the hash if found, or nil
272
- def mapped_key(hsh, name, name_map)
273
- return hsh[name] if hsh&.fetch(name, false)
274
-
275
- name_map.each do |pkey|
276
- return hsh[pkey] if hsh&.fetch(pkey, false)
277
- end
278
- nil
279
- end
280
-
7
+ def self.create_resources(resources_hash, control_maps, only, ignore, control_configs)
8
+ unfrozen_resources = Marshal.load(Marshal.dump(resources_hash))
9
+ AbideDataProcessor::Parser.parse(unfrozen_resources, control_maps, only, ignore, control_configs)
281
10
  end
282
11
  end
283
12
  end
@@ -1,3 +1,3 @@
1
1
  module AbideDataProcessor
2
- VERSION = "0.3.0"
2
+ VERSION = "1.0.0"
3
3
  end
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: abide-data-processor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - abide-team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-30 00:00:00.000000000 Z
11
+ date: 2022-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: puppet
14
+ name: deep_merge
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '6.23'
19
+ version: '1.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rgl
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: '6.23'
40
+ version: '0.5'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -241,6 +255,7 @@ files:
241
255
  - bin/setup
242
256
  - lib/abide-data-processor.rb
243
257
  - lib/abide-data-processor/logger.rb
258
+ - lib/abide-data-processor/parser.rb
244
259
  - lib/abide-data-processor/processor.rb
245
260
  - lib/abide-data-processor/version.rb
246
261
  homepage: https://github.com/puppetlabs/abide-data-processor