abide_dev_utils 0.10.0 → 0.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +7 -1
  4. data/Gemfile.lock +54 -65
  5. data/Rakefile +28 -0
  6. data/abide_dev_utils.gemspec +2 -1
  7. data/lib/abide_dev_utils/cem/benchmark.rb +485 -0
  8. data/lib/abide_dev_utils/cem/generate/coverage_report.rb +380 -0
  9. data/lib/abide_dev_utils/cem/generate/reference.rb +240 -0
  10. data/lib/abide_dev_utils/cem/generate.rb +11 -0
  11. data/lib/abide_dev_utils/cem/hiera_data/mapping_data/map_data.rb +110 -0
  12. data/lib/abide_dev_utils/cem/hiera_data/mapping_data/mixins.rb +46 -0
  13. data/lib/abide_dev_utils/cem/hiera_data/mapping_data.rb +146 -0
  14. data/lib/abide_dev_utils/cem/hiera_data/resource_data/control.rb +127 -0
  15. data/lib/abide_dev_utils/cem/hiera_data/resource_data/parameters.rb +90 -0
  16. data/lib/abide_dev_utils/cem/hiera_data/resource_data/resource.rb +102 -0
  17. data/lib/abide_dev_utils/cem/hiera_data/resource_data.rb +310 -0
  18. data/lib/abide_dev_utils/cem/hiera_data.rb +7 -0
  19. data/lib/abide_dev_utils/cem/mapping/mapper.rb +282 -0
  20. data/lib/abide_dev_utils/cem/validate/resource_data.rb +33 -0
  21. data/lib/abide_dev_utils/cem/validate.rb +10 -0
  22. data/lib/abide_dev_utils/cem.rb +1 -0
  23. data/lib/abide_dev_utils/cli/cem.rb +98 -0
  24. data/lib/abide_dev_utils/cli/jira.rb +1 -1
  25. data/lib/abide_dev_utils/cli/xccdf.rb +3 -0
  26. data/lib/abide_dev_utils/dot_number_comparable.rb +75 -0
  27. data/lib/abide_dev_utils/errors/cem.rb +32 -0
  28. data/lib/abide_dev_utils/errors/general.rb +8 -2
  29. data/lib/abide_dev_utils/errors/ppt.rb +4 -0
  30. data/lib/abide_dev_utils/errors.rb +6 -0
  31. data/lib/abide_dev_utils/markdown.rb +104 -0
  32. data/lib/abide_dev_utils/ppt/class_utils.rb +1 -1
  33. data/lib/abide_dev_utils/ppt/code_gen/data_types.rb +51 -0
  34. data/lib/abide_dev_utils/ppt/code_gen/generate.rb +15 -0
  35. data/lib/abide_dev_utils/ppt/code_gen/resource.rb +59 -0
  36. data/lib/abide_dev_utils/ppt/code_gen/resource_types/base.rb +93 -0
  37. data/lib/abide_dev_utils/ppt/code_gen/resource_types/class.rb +17 -0
  38. data/lib/abide_dev_utils/ppt/code_gen/resource_types/manifest.rb +16 -0
  39. data/lib/abide_dev_utils/ppt/code_gen/resource_types/parameter.rb +16 -0
  40. data/lib/abide_dev_utils/ppt/code_gen/resource_types/strings.rb +13 -0
  41. data/lib/abide_dev_utils/ppt/code_gen/resource_types.rb +6 -0
  42. data/lib/abide_dev_utils/ppt/code_gen.rb +15 -0
  43. data/lib/abide_dev_utils/ppt/code_introspection.rb +102 -0
  44. data/lib/abide_dev_utils/ppt/facter_utils.rb +140 -0
  45. data/lib/abide_dev_utils/ppt/hiera.rb +300 -0
  46. data/lib/abide_dev_utils/ppt/puppet_module.rb +75 -0
  47. data/lib/abide_dev_utils/ppt.rb +6 -5
  48. data/lib/abide_dev_utils/validate.rb +14 -0
  49. data/lib/abide_dev_utils/version.rb +1 -1
  50. data/lib/abide_dev_utils/xccdf/parser/helpers.rb +146 -0
  51. data/lib/abide_dev_utils/xccdf/parser/objects.rb +87 -144
  52. data/lib/abide_dev_utils/xccdf/parser.rb +5 -0
  53. data/lib/abide_dev_utils/xccdf/utils.rb +89 -0
  54. data/lib/abide_dev_utils/xccdf.rb +8 -2
  55. metadata +52 -5
  56. data/lib/abide_dev_utils/ppt/coverage.rb +0 -86
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AbideDevUtils
4
+ module CEM
5
+ module HieraData
6
+ module MappingData
7
+ # Represents a single map data file
8
+ class MapData
9
+ def initialize(data)
10
+ @raw_data = data
11
+ end
12
+
13
+ def method_missing(meth, *args, &block)
14
+ if data.respond_to?(meth)
15
+ data.send(meth, *args, &block)
16
+ else
17
+ super
18
+ end
19
+ end
20
+
21
+ def respond_to_missing?(meth, include_private = false)
22
+ data.respond_to?(meth) || super
23
+ end
24
+
25
+ def find(identifier, level: nil, profile: nil)
26
+ levels.each do |lvl|
27
+ next unless level.nil? || lvl != level
28
+
29
+ data[lvl].each do |prof, prof_data|
30
+ if prof_data.respond_to?(:keys)
31
+ next unless profile.nil? || prof != profile
32
+
33
+ return prof_data[identifier] if prof_data.key?(identifier)
34
+ elsif prof == identifier
35
+ return prof_data
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ def get(identifier, level: nil, profile: nil)
42
+ raise "Invalid level: #{level}" unless profile.nil? || levels.include?(level)
43
+ raise "Invalid profile: #{profile}" unless profile.nil? || profiles.include?(profile)
44
+ return find(identifier, level: level, profile: profile) if level.nil? || profile.nil?
45
+
46
+ begin
47
+ data.dig(level, profile, identifier)
48
+ rescue TypeError
49
+ data.dig(level, identifier)
50
+ end
51
+ end
52
+
53
+ def module_name
54
+ top_key_parts[0]
55
+ end
56
+
57
+ def framework
58
+ top_key_parts[2]
59
+ end
60
+
61
+ def type
62
+ top_key_parts[3]
63
+ end
64
+
65
+ def benchmark
66
+ @raw_data[top_key]['benchmark']
67
+ end
68
+
69
+ def levels_and_profiles
70
+ @levels_and_profiles ||= find_levels_and_profiles
71
+ end
72
+
73
+ def levels
74
+ levels_and_profiles[0]
75
+ end
76
+
77
+ def profiles
78
+ levels_and_profiles[1]
79
+ end
80
+
81
+ def top_key
82
+ @top_key ||= @raw_data.keys.first
83
+ end
84
+
85
+ private
86
+
87
+ def top_key_parts
88
+ @top_key_parts ||= top_key.split('::')
89
+ end
90
+
91
+ def data
92
+ @data ||= @raw_data[top_key].reject { |k, _| k == 'benchmark' }
93
+ end
94
+
95
+ def find_levels_and_profiles
96
+ lvls = []
97
+ profs = []
98
+ data.each do |lvl, prof_hash|
99
+ lvls << lvl
100
+ prof_hash.each do |prof, prof_data|
101
+ profs << prof if prof_data.respond_to?(:keys)
102
+ end
103
+ end
104
+ [lvls.flatten.compact.uniq, profs.flatten.compact.uniq]
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AbideDevUtils
4
+ module CEM
5
+ module HieraData
6
+ module MappingData
7
+ # Mixin module used by Mapper to implement CIS-specific mapping behavior
8
+ module MixinCIS
9
+ def get_map(control_id, level: nil, profile: nil, **_)
10
+ identified_map_data(control_id, valid_types: CIS_TYPES).get(control_id, level: level, profile: profile)
11
+ return unless imdata
12
+
13
+ if level.nil? || profile.nil?
14
+ map_data[mtype][mtop].each do |lvl, profile_hash|
15
+ next if lvl == 'benchmark' || (level && level != lvl)
16
+
17
+ profile_hash.each do |prof, control_hash|
18
+ next if profile && profile != prof
19
+
20
+ return control_hash[control_id] if control_hash.key?(control_id)
21
+ end
22
+ end
23
+ else
24
+ imdata[level][profile][control_id]
25
+ end
26
+ end
27
+ end
28
+
29
+ # Mixin module used by Mapper to implement STIG-specific mapping behavior
30
+ module MixinSTIG
31
+ def get_map(control_id, level: nil, **_)
32
+ mtype, mtop = map_type_and_top_key(control_id)
33
+ return unless STIG_TYPES.include?(mtype)
34
+ return map_data[mtype][mtop][level][control_id] unless level.nil?
35
+
36
+ map_data[mtype][mtop].each do |lvl, control_hash|
37
+ next if lvl == 'benchmark'
38
+
39
+ return control_hash[control_id] if control_hash.key?(control_id)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'abide_dev_utils/cem/hiera_data/mapping_data/map_data'
4
+ require 'abide_dev_utils/cem/hiera_data/mapping_data/mixins'
5
+
6
+ module AbideDevUtils
7
+ module CEM
8
+ module HieraData
9
+ module MappingData
10
+ ALL_TYPES = %w[hiera_title_num number hiera_title vulnid title].freeze
11
+ FRAMEWORK_TYPES = {
12
+ 'cis' => %w[hiera_title_num number hiera_title title],
13
+ 'stig' => %w[hiera_title_num number hiera_title vulnid title],
14
+ }.freeze
15
+ CIS_TYPES = %w[hiera_title_num number hiera_title title].freeze
16
+ STIG_TYPES = %w[hiera_title_num number hiera_title vulnid title].freeze
17
+
18
+ # Handles interacting with mapping data
19
+ class Mapper
20
+ attr_reader :module_name, :framework, :map_data
21
+
22
+ def initialize(module_name, framework, map_data)
23
+ @module_name = module_name
24
+ @framework = framework
25
+ load_framework(@framework)
26
+ @map_data = map_data.map { |_, v| MapData.new(v) }
27
+ @cache = {}
28
+ @rule_cache = {}
29
+ end
30
+
31
+ def title
32
+ @title ||= benchmark_data['title']
33
+ end
34
+
35
+ def version
36
+ @version ||= benchmark_data['version']
37
+ end
38
+
39
+ def levels
40
+ @levels ||= default_map_data.levels
41
+ end
42
+
43
+ def profiles
44
+ @profiles ||= default_map_data.profiles
45
+ end
46
+
47
+ def each_like(identifier)
48
+ identified_map_data(identifier)&.each { |key, val| yield key, val }
49
+ end
50
+
51
+ def each_with_array_like(identifier)
52
+ identified_map_data(identifier)&.each_with_object([]) { |(key, val), ary| yield [key, val], ary }
53
+ end
54
+
55
+ def get(control_id, level: nil, profile: nil)
56
+ identified_map_data(control_id)&.get(control_id, level: level, profile: profile)
57
+ end
58
+
59
+ def map_type(control_id)
60
+ return control_id if ALL_TYPES.include?(control_id)
61
+
62
+ case control_id
63
+ when %r{^c[0-9_]+$}
64
+ 'hiera_title_num'
65
+ when %r{^[0-9][0-9.]*$}
66
+ 'number'
67
+ when %r{^[a-z][a-z0-9_]+$}
68
+ 'hiera_title'
69
+ when %r{^V-[0-9]{6}$}
70
+ 'vulnid'
71
+ else
72
+ 'title'
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def load_framework(framework)
79
+ case framework.downcase
80
+ when 'cis'
81
+ self.class.include AbideDevUtils::CEM::HieraData::MappingData::MixinCIS
82
+ extend AbideDevUtils::CEM::HieraData::MappingData::MixinCIS
83
+ when 'stig'
84
+ self.class.include AbideDevUtils::CEM::HieraData::MappingData::MixinSTIG
85
+ extend AbideDevUtils::CEM::HieraData::MappingData::MixinSTIG
86
+ else
87
+ raise "Invalid framework: #{framework}"
88
+ end
89
+ end
90
+
91
+ def map_data_by_type(map_type)
92
+ found_map_data = map_data.find { |x| x.type == map_type }
93
+ raise "Failed to find map data with type #{map_type}; Meta: #{{framework: framework, module_name: module_name}}" unless found_map_data
94
+
95
+ found_map_data
96
+ end
97
+
98
+ def identified_map_data(identifier, valid_types: ALL_TYPES)
99
+ mtype = map_type(identifier)
100
+ return unless FRAMEWORK_TYPES[framework].include?(mtype)
101
+
102
+ map_data_by_type(mtype)
103
+ end
104
+
105
+ def map_type_and_top_key(identifier)
106
+ mtype = ALL_TYPES.include?(identifier) ? identifier : map_type(identifier)
107
+ [mtype, map_top_key(mtype)]
108
+ end
109
+
110
+ def cached?(control_id, *args)
111
+ @cache.key?(cache_key(control_id, *args))
112
+ end
113
+
114
+ def cache_get(control_id, *args)
115
+ ckey = cache_key(control_id, *args)
116
+ @cache[ckey] if cached?(control_id, *args)
117
+ end
118
+
119
+ def cache_set(value, control_id, *args)
120
+ @cache[cache_key(control_id, *args)] = value unless value.nil?
121
+ end
122
+
123
+ def default_map_type
124
+ @default_map_type ||= (framework == 'stig' ? 'vulnid' : map_data.first.type)
125
+ end
126
+
127
+ def default_map_data
128
+ @default_map_data ||= map_data.first
129
+ end
130
+
131
+ def benchmark_data
132
+ @benchmark_data ||= default_map_data.benchmark
133
+ end
134
+
135
+ def cache_key(control_id, *args)
136
+ args.unshift(control_id).compact.join('-')
137
+ end
138
+
139
+ def map_top_key(mtype)
140
+ [module_name, 'mappings', framework, mtype].join('::')
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'abide_dev_utils/dot_number_comparable'
4
+ require 'abide_dev_utils/errors'
5
+ require 'abide_dev_utils/cem/hiera_data/mapping_data'
6
+ require 'abide_dev_utils/cem/hiera_data/resource_data/parameters'
7
+
8
+ module AbideDevUtils
9
+ module CEM
10
+ module HieraData
11
+ module ResourceData
12
+ # Represents a singular rule in a benchmark
13
+ class Control
14
+ include AbideDevUtils::DotNumberComparable
15
+ attr_reader :id, :parameters, :resource, :framework
16
+
17
+ def initialize(id, params, resource, framework, mapper)
18
+ validate_id_with_framework(id, framework, mapper)
19
+ @id = id
20
+ @parameters = Parameters.new(params)
21
+ @resource = resource
22
+ @framework = framework
23
+ @mapper = mapper
24
+ raise AbideDevUtils::Errors::NoMappingDataForControlError, @id unless @mapper.get(id)
25
+ end
26
+
27
+ def alternate_ids(level: nil, profile: nil)
28
+ id_map = @mapper.get(id, level: level, profile: profile)
29
+ if display_title_type.to_s == @mapper.map_type(id)
30
+ id_map
31
+ else
32
+ alt_ids = id_map.each_with_object([]) do |mapval, arr|
33
+ arr << if display_title_type.to_s == @mapper.map_type(mapval)
34
+ @mapper.get(mapval, level: level, profile: profile)
35
+ else
36
+ mapval
37
+ end
38
+ end
39
+ alt_ids.flatten.uniq
40
+ end
41
+ end
42
+
43
+ def id_map_type
44
+ @mapper.map_type(id)
45
+ end
46
+
47
+ def display_title
48
+ send(display_title_type) unless display_title_type.nil?
49
+ end
50
+
51
+ def levels
52
+ levels_and_profiles[0]
53
+ end
54
+
55
+ def profiles
56
+ levels_and_profiles[1]
57
+ end
58
+
59
+ def method_missing(meth, *args, &block)
60
+ meth_s = meth.to_s
61
+ if AbideDevUtils::CEM::HieraData::MappingData::ALL_TYPES.include?(meth_s)
62
+ @mapper.get(id).find { |x| @mapper.map_type(x) == meth_s }
63
+ else
64
+ super
65
+ end
66
+ end
67
+
68
+ def respond_to_missing?(meth, include_private = false)
69
+ AbideDevUtils::CEM::HieraData::MappingData::ALL_TYPES.include?(meth.to_s) || super
70
+ end
71
+
72
+ def to_h
73
+ {
74
+ id: id,
75
+ display_title: display_title,
76
+ alternate_ids: alternate_ids,
77
+ levels: levels,
78
+ profiles: profiles,
79
+ resource: resource,
80
+ }.merge(parameters.to_h)
81
+ end
82
+
83
+ private
84
+
85
+ def display_title_type
86
+ if (!vulnid.nil? && !vulnid.is_a?(String)) || !title.is_a?(String)
87
+ nil
88
+ elsif framework == 'stig' && vulnid
89
+ :vulnid
90
+ else
91
+ :title
92
+ end
93
+ end
94
+
95
+ def validate_id_with_framework(id, framework, mapper)
96
+ mtype = mapper.map_type(id)
97
+ return if AbideDevUtils::CEM::HieraData::MappingData::FRAMEWORK_TYPES[framework].include?(mtype)
98
+
99
+ raise AbideDevUtils::Errors::ControlIdFrameworkMismatchError, [id, mtype, framework]
100
+ end
101
+
102
+ def map
103
+ @map ||= @mapper.get(id)
104
+ end
105
+
106
+ def levels_and_profiles
107
+ @levels_and_profiles ||= find_levels_and_profiles
108
+ end
109
+
110
+ def find_levels_and_profiles
111
+ lvls = []
112
+ profs = []
113
+ @mapper.levels.each do |lvl|
114
+ @mapper.profiles.each do |prof|
115
+ unless @mapper.get(id, level: lvl, profile: prof).nil?
116
+ lvls << lvl
117
+ profs << prof
118
+ end
119
+ end
120
+ end
121
+ [lvls.flatten.compact.uniq, profs.flatten.compact.uniq]
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module AbideDevUtils
6
+ module CEM
7
+ module HieraData
8
+ module ResourceData
9
+ class Parameters
10
+ def initialize(*param_collections)
11
+ @param_collections = param_collections
12
+ end
13
+
14
+ def exist?
15
+ !@param_collections.nil? && !@param_collections.empty?
16
+ end
17
+
18
+ def to_h
19
+ @to_h ||= { parameters: @param_collections.map { |x| collection_to_h(x) unless x.nil? || x.empty? } }
20
+ end
21
+
22
+ def to_puppet_code
23
+ parray = to_h[:parameters].each_with_object([]) do |x, arr|
24
+ x.each do |_, val|
25
+ arr << param_to_code(**val[:display_value]) if val.respond_to?(:key)
26
+ end
27
+ end
28
+ parray.reject { |x| x.nil? || x.empty? }.compact.join("\n")
29
+ end
30
+
31
+ def to_display_fmt
32
+ to_h[:parameters].values.map { |x| x[:display_value] }
33
+ end
34
+
35
+ private
36
+
37
+ def collection_to_h(collection)
38
+ return no_params_display if collection == 'no_params'
39
+
40
+ collection.each_with_object({}) do |(param, param_val), hsh|
41
+ hsh[param] = {
42
+ raw_value: param_val,
43
+ display_value: param_display(param, param_val),
44
+ }
45
+ end
46
+ end
47
+
48
+ def param_display(param, param_val)
49
+ {
50
+ name: param,
51
+ type: ruby_class_to_puppet_type(param_val.class.to_s),
52
+ default: param_val,
53
+ }
54
+ end
55
+
56
+ def no_params_display
57
+ { name: 'No parameters', type: nil, default: nil }
58
+ end
59
+
60
+ def param_to_code(name: nil, type: nil, default: nil)
61
+ return if name.nil?
62
+ return " #{name}," if default.nil?
63
+ return " #{name} => #{default}," if %w[Boolean Integer Float].include?(type)
64
+ return " #{name} => '#{default}'," if type == 'String'
65
+
66
+ " #{name} => undef,"
67
+ end
68
+
69
+ def ruby_class_to_puppet_type(class_name)
70
+ pup_type = class_name.split('::').last.capitalize
71
+ case pup_type
72
+ when %r{(Trueclass|Falseclass)}
73
+ 'Boolean'
74
+ when %r{(String|Pathname)}
75
+ 'String'
76
+ when %r{(Integer|Fixnum)}
77
+ 'Integer'
78
+ when %r{(Float|Double)}
79
+ 'Float'
80
+ when %r{Nilclass}
81
+ 'Optional'
82
+ else
83
+ pup_type
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+ require 'abide_dev_utils/errors'
5
+ require 'abide_dev_utils/cem/hiera_data/resource_data/control'
6
+ require 'abide_dev_utils/cem/hiera_data/resource_data/parameters'
7
+
8
+ module AbideDevUtils
9
+ module CEM
10
+ module HieraData
11
+ module ResourceData
12
+ # Represents a resource data resource statement
13
+ class Resource
14
+ attr_reader :title, :type
15
+
16
+ def initialize(title, data, framework, mapper)
17
+ @title = title
18
+ @data = data
19
+ @type = data['type']
20
+ @framework = framework
21
+ @mapper = mapper
22
+ end
23
+
24
+ def controls
25
+ @controls ||= load_controls
26
+ end
27
+
28
+ def cem_options
29
+ @cem_options ||= Parameters.new(data['cem_options'])
30
+ end
31
+
32
+ def cem_protected
33
+ @cem_protected ||= Parameters.new(data['cem_protected'])
34
+ end
35
+
36
+ def to_stubbed_h
37
+ {
38
+ title: title,
39
+ type: type,
40
+ cem_options: cem_options.to_h,
41
+ cem_protected: cem_protected.to_h,
42
+ reference: to_reference,
43
+ }
44
+ end
45
+
46
+ def to_reference
47
+ "#{type.split('::').map(&:capitalize).join('::')}['#{title}']"
48
+ end
49
+
50
+ def to_puppet_code
51
+ parray = controls.map { |x| x.parameters.to_puppet_code if x.parameters.exist? }.flatten.compact.uniq
52
+ return "#{type} { '#{title}': }" if parray.empty? || parray.all?(&:empty?) || parray.all?("\n")
53
+
54
+ # if title == 'cem_linux::utils::packages::linux::auditd::time_change'
55
+ # require 'pry'
56
+ # binding.pry
57
+ # end
58
+ <<~EOPC
59
+ #{type} { '#{title}':
60
+ #{parray.join("\n")}
61
+ }
62
+ EOPC
63
+ end
64
+
65
+ private
66
+
67
+ attr_reader :data, :framework, :mapper
68
+
69
+ def load_controls
70
+ if data['controls'].respond_to?(:keys)
71
+ load_hash_controls(data['controls'], framework, mapper)
72
+ elsif data['controls'].respond_to?(:each_with_index)
73
+ load_array_controls(data['controls'], framework, mapper)
74
+ else
75
+ raise "Control type is invalid. Type: #{data['controls'].class}"
76
+ end
77
+ end
78
+
79
+ def load_hash_controls(ctrls, framework, mapper)
80
+ ctrls.each_with_object([]) do |(name, data), arr|
81
+ ctrl = Control.new(name, data, to_stubbed_h, framework, mapper)
82
+ arr << ctrl
83
+ rescue AbideDevUtils::Errors::ControlIdFrameworkMismatchError,
84
+ AbideDevUtils::Errors::NoMappingDataForControlError
85
+ next
86
+ end
87
+ end
88
+
89
+ def load_array_controls(ctrls, framework, mapper)
90
+ ctrls.each_with_object([]) do |c, arr|
91
+ ctrl = Control.new(c, 'no_params', to_stubbed_h, framework, mapper)
92
+ arr << ctrl
93
+ rescue AbideDevUtils::Errors::ControlIdFrameworkMismatchError,
94
+ AbideDevUtils::Errors::NoMappingDataForControlError
95
+ next
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end