abide-data-processor 0.1.1 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9b34c8ea700003b6bed175a9c803ee51d9e8b3ef5945552da9bbf6cffdc8e74a
4
- data.tar.gz: 93592aa2722ca69519973cac8a310b9d80141a729acf5d63d44de95b73da0204
3
+ metadata.gz: 3e7c05a1569fd1f40b4ee3474364ea6928a77b7cd34e7eb6432672c374d11517
4
+ data.tar.gz: 6b5fa97224644b96c61432c6b80a65e40e31c0593d77dee04d9914658d1e0b08
5
5
  SHA512:
6
- metadata.gz: a420b94d17d727e13ba44b73eae2cbdf8283b0685eb01992afc559baa27447611b901ce88fc66eb49cb0cf6556988510cfa996b2f4694167a66040049898321e
7
- data.tar.gz: 6a44c40bcfbdd8a3b1ad4e1a27e662b205d5cf929ae1680bf1e65f543d3a674aac341473865f80b1cf7d5d87e3d3aeceb1a41704101780b74dd74a3e154cf63e
6
+ metadata.gz: fc161a33e338ab7c85140abaddf4488dde3f1dd5a65d84dfd20057f99acc01e8f70f5c3819f4d5f3bd68a2d0c53effd1741ccfa605c18a25138688b01b64a89c
7
+ data.tar.gz: bd65068b4582730d4f6406ce806e78d298d9e78ff6998c73abdfc600e1cfd83beab568fc47090ccd680da21fc7ed200e8e9da8998d454ff930dd11e64bd75f89
data/Gemfile.lock CHANGED
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- abide-data-processor (0.1.1)
5
- puppet (>= 6.23)
4
+ abide-data-processor (1.0.1)
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,282 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'deep_merge'
4
- require 'set'
5
- require 'pry'
3
+ require 'abide-data-processor/parser'
6
4
 
7
5
  module AbideDataProcessor
8
6
  module Processor
9
- # Here lies the class that will be use to create/extract resources
10
- class ResourceCreator
11
-
12
- # @param control_maps: The control mappings to valid IDs
13
- # @param module_name: The name of the module
14
- # @param logger: The logger that we will use to log information for the user
15
- def initialize(control_maps, logger)
16
- @control_maps = control_maps
17
- @logger = logger
18
- end
19
-
20
- # control_key_maps
21
- # Gets all control key maps from Hiera for indexed control ID permutation searches
22
- # @return An array of four control ID maps, each indexed by one of the four different valid permutations of a control ID
23
- def self.control_key_maps(module_name)
24
- key_prefix = "#{module_name}::mappings::cis"
25
- %w[hiera_title hiera_title_num number title].each_with_object([]) do |key, ary|
26
- ary << [key_prefix, key].join('::')
27
- end
28
- end
29
-
30
- def cis_hiera_key(prefix, key)
31
- "#{prefix}::#{key}"
32
- end
33
-
34
- # create_resources
35
- # @param resources_hash: the hash of controls to be enforces, user will provide this
36
- # @param only: the list of controls to be enforce only, pulled from cis.pp
37
- # @param ignore: the list of controls to be ignore, pulled from cis.pp
38
- # @param control_configs: the custom control configurations pulled from cis.pp
39
- # Return a hash to be convert to Puppet code.
40
- def create_resources(resources_hash, only, ignore, control_configs)
41
- resources = real_resources(resources_hash, 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
-
93
- # Only and ignore list check
94
- next unless only_and_ignore_check(name, name_map, only, ignore)
95
-
96
- # Control dependent check
97
- if params.key?('dependent')
98
- unless dependent_check(all_controls_name, params['dependent'], ignore, only)
99
- # Below is just a sure fire way to make sure that we will never use the resource
100
- only.delete(name) # Remove from the only list
101
- ignore.add(name) # Add the name of the current control to the ignore list if we're not gonna enforce it
102
- @logger.inform("Control #{name} will not be enforced because the controls that it depends on is invalid.")
103
- next
104
- end
105
- end
106
- # Find if there are any custom control configs from the cis.pp based on the control's name and its permutation
107
- customized = find_control_customization(name, name_map[name], control_configs)
108
- params.deep_merge!(customized, merge_hash_arrays: true)
109
- control_params.deep_merge!(params, merge_hash_arrays: true)
110
- end
111
- control_params
112
- end
113
-
114
- # dependent_check
115
- # @param all_controls_name: Set of all controls name that parsed from the hiera data
116
- # @param all_dependent_resources: An array of all the resources that is relied upon
117
- # @param ignore: List of controls to be ignore
118
- # @param only: List of only controls that need to be enforce
119
- # return true if a dependent control is
120
- def dependent_check(all_controls_name, all_dependent_resources, ignore, only)
121
- all_dependent_resources.each do |resource_name|
122
- valid_resource_name = map_for_control_name(resource_name, @control_maps)
123
- # Bounce immediately if it is not a part of the controls we're enforcing
124
- return false unless filter_function(resource_name, valid_resource_name, all_controls_name)
125
-
126
- if !ignore.empty?
127
- return false if filter_function(resource_name, valid_resource_name, ignore)
128
- elsif !only.empty?
129
- return false unless filter_function(resource_name, valid_resource_name, only)
130
- end
131
- end
132
- end
133
-
134
- # order_resources
135
- # A work in progress to integrate more metaparamenters in
136
- # Checks for and creates resources based off of `before`, `after`, `notify`, `require` parameters
137
- # specified in a controls hash
138
- # @param resources Output of real_resources()
139
- # @return An array of resource hashes indexed in the order their contents should be created
140
- def order_resources(resources)
141
- before = {}
142
- after = {}
143
- req = {}
144
- notify = {}
145
- resources.each do |_, data|
146
- create_ordered_resource!('before', before, data)
147
- create_ordered_resource!('notify', notify, data)
148
- create_ordered_resource!('after', after, data)
149
- create_ordered_resource!('require', req, data)
150
- end
151
-
152
- before.deep_merge!(notify)
153
- after.deep_merge!(req)
154
-
155
- [before, resources, after]
156
- end
157
-
158
- # filter_function
159
- # A general function to see if a control name is in a supply list of control name
160
- # @param name: The name of the control that we have
161
- # @param name_map: All valid control ID permutation of the param name
162
- # @set_of_control: Either the ignore or the only list to go through
163
- # return true if control ID is found in set_of_control
164
- def filter_function(name, name_map, set_of_control)
165
- name_list = name_map[name]
166
- return true if set_of_control.include?(name)
167
-
168
- name_list.each do |n|
169
- return true if set_of_control.include?(n)
170
- end
171
-
172
- false
173
- end
174
-
175
- # only_and_ignore_check
176
- # @param name: name of the control to check if it's in either only or ignore list
177
- # @param name_map: the name map of valid ID permutation for the `name` param
178
- # @param only: the list of controls that will get enforced only
179
- # @param ignore: the list of controls that will be ignored
180
- # @return false when control is either not in the only list or is in the ignore list.
181
- # else return true
182
- def only_and_ignore_check(name, name_map, only, ignore)
183
- if !only.empty? && !filter_function(name, name_map, only)
184
- @logger.inform("Control #{name} will be skipped because it is not in the only list.")
185
- return false
186
- end
187
-
188
- if !ignore.empty? && filter_function(name, name_map, ignore)
189
- @logger.inform("Control #{name} will be skipped because it is in the ignore list.")
190
- return false
191
- end
192
- true
193
- end
194
-
195
- # create_ordered_resource!
196
- # Creates a resource hash from a resource declaration found in a `before`, `after`, `require`, or `notify` parameter
197
- # @param order_key Either 'before', 'after', `notify`, or `require`
198
- # @param container Either the before hash, the notify hash, the require hash or the after hash.
199
- # The container is modified in place.
200
- # @param res_data Resource data from the real_resources hash
201
- def create_ordered_resource!(order_key, container, res_data)
202
- res_data.each do |_, data|
203
- next unless data.key?(order_key)
204
-
205
- data[order_key].each do |title, params|
206
- container[params['type']] = {} unless container.key?(params['type'])
207
- container[params['type']][title] = params.reject { |k, _| k == 'type' }
208
- end
209
- end
210
- end
211
-
212
- # mutate_ordering_params!
213
- # This takes the Hiera resource declarations in a `before` or `after` param and transforms
214
- # them into and array of Puppet resource references. Puppet resource references take the
215
- # form: Resource::Type['<resource title'].
216
- # @param resources Output from real_resources()
217
- def mutate_ordering_params!(resources)
218
- resources.each do |res_type, res_data|
219
- %w[before notify after require].each do |order_key|
220
- res_data.each do |res_title, params|
221
- next unless params.key?(order_key)
222
-
223
- references = []
224
- params[order_key].each do |k, v|
225
- references << resource_reference(v['type'], k)
226
- end
227
- resources[res_type][res_title][order_key] = references
228
- end
229
- end
230
- end
231
- end
232
-
233
- # resource_reference
234
- # Returns a Puppet resource reference string
235
- # @param res_type A Puppet resource type
236
- # @param title A Puppet resource title
237
- def resource_reference(res_type, title)
238
- type_ref = res_type.split('::').map(&:capitalize).join('::')
239
- "#{type_ref}[#{title}]"
240
- end
241
-
242
- # find_control_customization
243
- # Finds any control parameter customizations passed in via control_configs
244
- # @param name The control name (or other valid permutation)
245
- # @param control_configs The $control_configs parameter from cis.pp
246
- # @param name_map: The array of valid permutation of name
247
- # @return A hash of customized parameters. If none were found, nil
248
- def find_control_customization(name, name_map, control_configs)
249
- return {} if control_configs.empty?
250
-
251
- mapped_key(control_configs, name, name_map)
252
- end
253
-
254
- # map_for_control_name
255
- # Returns a hash of all valid permutations of the given control id
256
- # @param name The control name or other valid permutation
257
- # @param maps All maps
258
- def map_for_control_name(name, maps)
259
- maps.each do |map|
260
- return map if map&.fetch(name, false) # returns the map if fetch returns false
261
- end
262
- nil
263
- end
264
-
265
- # mapped_key
266
- # Finds an item in the given hash that matches one of the values in name_map
267
- # @param hsh The hash to search i.e the custom config hash
268
- # @param name The name of the current control that we're looking to see if it has any custom configs
269
- # @param name_map An array name for valid control permutations
270
- # @return The value from the hash if found, or nil
271
- def mapped_key(hsh, name, name_map)
272
- return hsh[name] if hsh&.fetch(name, false)
273
-
274
- name_map.each do |pkey|
275
- return hsh[pkey] if hsh&.fetch(pkey, false)
276
- end
277
- nil
278
- end
279
-
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: only, ignore: ignore, control_configs: control_configs)
280
10
  end
281
11
  end
282
12
  end
@@ -1,3 +1,3 @@
1
1
  module AbideDataProcessor
2
- VERSION = "0.1.1"
2
+ VERSION = "1.0.1"
3
3
  end
@@ -1,4 +1,6 @@
1
1
  require 'abide-data-processor/version'
2
2
  require 'abide-data-processor/processor'
3
+ require 'abide-data-processor/logger'
4
+
3
5
  # Root namespace for all modules / classes
4
6
  module AbideDataProcessor; 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.1.1
4
+ version: 1.0.1
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-18 00:00:00.000000000 Z
11
+ date: 2022-01-18 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