cem_spec_helper 0.1.2 → 0.2.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: 958824c04b72632cdae95ca8d81696f8fb2e350136fec56b77956f0a447b1d3f
4
- data.tar.gz: 9417760548af44edcab45a1630a99376711e0d70a9d8df503351db20c1a7b746
3
+ metadata.gz: c25d50ec3d0761a950dfd6ddfa13e2b0fa23bf560719ae876af59a6936763a0d
4
+ data.tar.gz: cca59a9b38dd4d71159ed5d2470c7bac58ba22b1bc31e7b5401e56f74a4124d2
5
5
  SHA512:
6
- metadata.gz: 1b7f14db0527bba11b2e1fa9074a74e4cde1f73221b00333c0629db4452bd22a10517713f90b9d8ac1711f0f06611377d8392ed7999448d8c457dd78c4ce99e9
7
- data.tar.gz: e16599f307d82bc98d5298d60ebfe6f97103dee035170b874e454f0ca3d01ac2327256fc6e61027657f966e529eb899ddbf5e38dae0ac1204e5cb5ee55713589
6
+ metadata.gz: 37c4136b44f120e95966409d55821c4bc7ab19af6b89951579fbac086b1882cacd36af971af24e9df2697b5222a92395fce90e1d16e9bfa3a2558aa2250bc2b6
7
+ data.tar.gz: db3690625195985e32e4585511cecd646127878cefd85ee7a9d4d12ed4b9422c49f5c7494f0404e2d758949e0693d5404540c3c84a5e01036addc9f325843e17
@@ -4,10 +4,30 @@ require 'yaml'
4
4
 
5
5
  module CemSpecHelper
6
6
  module MappingDataSpec
7
+ # The root directory for mapping data fixtures
7
8
  MAP_ROOT = File.join(Dir.pwd, 'spec', 'fixtures', 'data', 'mapping').freeze
9
+ # The root directory for synthetic mapping data
8
10
  SYNTHETIC_MAP_ROOT = File.join(Dir.pwd, 'spec', 'fixtures', 'unit', 'puppet_x', 'puppetlabs', 'cem', 'data_processor', 'mapping').freeze
9
-
11
+ # The key prefix for the mappings
12
+ MAPPINGS_KEY = "#{CemSpecHelper::MODULE_NAME}::mappings"
13
+ # The top key types for each framework.
14
+ TOP_KEY_TYPES = {
15
+ 'cis' => ['hiera_title', 'hiera_title_num', 'number', 'title'].freeze,
16
+ 'stig' => ['vulnid', 'ruleid'].freeze,
17
+ }.freeze
18
+
19
+ # Because of the slight variation in the directory structure for Windows, we need to
20
+ # load the mapping data differently for Windows than for Linux.
21
+ # @return [Array<Mapping>] An array of Mapping objects
10
22
  def load_mapping_data
23
+ return load_windows_mapping_data if CemSpecHelper::MODULE_NAME.match?(/windows$/)
24
+
25
+ load_linux_mapping_data
26
+ end
27
+
28
+ # Load the mapping data for Linux
29
+ # @return [Array<Mapping>] An array of Mapping objects
30
+ def load_linux_mapping_data
11
31
  # Get frameworks with maps
12
32
  Dir[File.join(MAP_ROOT, '*')].each_with_object([]) do |fw_dir, arr|
13
33
  framework = File.basename(fw_dir)
@@ -29,6 +49,28 @@ module CemSpecHelper
29
49
  end
30
50
  end
31
51
 
52
+ # Load the mapping data for Windows
53
+ # @return [Array<Mapping>] An array of Mapping objects
54
+ def load_windows_mapping_data
55
+ # Get frameworks with maps
56
+ Dir[File.join(MAP_ROOT, '*')].each_with_object([]) do |fw_dir, arr|
57
+ framework = File.basename(fw_dir)
58
+ # Get OS major versions in frameworks
59
+ Dir[File.join(fw_dir, '*')].each do |ver_dir|
60
+ ver = File.basename(ver_dir)
61
+ mapping = Mapping.new(framework, 'windows', ver)
62
+ # Get map names and load map files
63
+ Dir[File.join(ver_dir, '*.yaml')].each do |map_file|
64
+ map_type = File.basename(map_file, '.yaml')
65
+ mapping.add_map(map_type, map_file)
66
+ end
67
+ arr << mapping
68
+ end
69
+ end
70
+ end
71
+
72
+ # Load the synthetic mapping data
73
+ # @return [Array<Mapping>] An array of Mapping objects
32
74
  def load_synthetic_mapping_data
33
75
  # Get frameworks with maps
34
76
  Dir[File.join(SYNTHETIC_MAP_ROOT, '*')].each_with_object([]) do |fw_dir, arr|
@@ -43,37 +85,74 @@ module CemSpecHelper
43
85
  end
44
86
  end
45
87
 
88
+ # Find the mapping data for a given framework, OS, and major OS version, and return the maps
89
+ # filtered by level and profile.
90
+ # @param framework [String] The framework to find the mapping data for
91
+ # @param os [String] The OS to find the mapping data for
92
+ # @param majver [String] The major OS version to find the mapping data for
93
+ # @param level [String] The level to filter the maps by. For STIG, this is the MAC.
94
+ # @param profile [String] The profile to filter the maps by. For STIG, this is the confidentiality.
95
+ # @return [Array<Hash>] An array of hashes representing the maps
96
+ def find_mapping_data(framework, os, majver = nil, level = 'level_1', profile = 'server')
97
+ majver = 1 if os == 'Synthetic'
98
+ md = (os == 'Synthetic') ? synthetic_mapping_data : mapping_data
99
+ md.find { |m| m.framework == framework && m.os == os && m.majver == majver.to_s }.maps
100
+ .map do |m|
101
+ top_key = TOP_KEY_TYPES[framework]&.find do |key|
102
+ m.key?("#{MAPPINGS_KEY}::#{framework}::#{key}")
103
+ end
104
+ raise "No top key found for #{framework}" if top_key.nil?
105
+
106
+ m["#{MAPPINGS_KEY}::#{framework}::#{top_key}"][level][profile]
107
+ end
108
+ end
109
+
110
+ # @return [Array<Mapping>] An array of Mapping objects
46
111
  def synthetic_mapping_data
47
112
  @synthetic_mapping_data ||= load_synthetic_mapping_data
48
113
  end
49
114
 
115
+ # @return [Array<Mapping>] An array of Mapping objects
50
116
  def mapping_data
51
117
  @mapping_data ||= load_mapping_data
52
118
  end
53
119
 
120
+ # This class represents a mapping of a framework, OS, and major OS version.
54
121
  class Mapping
55
122
  attr_reader :framework, :os, :majver, :module_name
56
123
 
57
- def initialize(framework, os, majver, module_name: 'cem_linux')
124
+ # @param framework [String] The framework to create the mapping for
125
+ # @param os [String] The OS to create the mapping for
126
+ # @param majver [String] The major OS version to create the mapping for
127
+ def initialize(framework, os, majver)
58
128
  @framework = framework
59
129
  @os = os
60
130
  @majver = majver
61
- @module_name = module_name
131
+ @module_name = CemSpecHelper::MODULE_NAME
62
132
  @maps = {}
63
133
  end
64
134
 
135
+ # @return [Array<Hash>] An array of hashes representing the maps
65
136
  def maps
66
137
  @maps.values
67
138
  end
68
139
 
140
+ # Add a map to the mapping
141
+ # @param type [String] The type of map to add
142
+ # @param map_file [String] The path to the map file to add
69
143
  def add_map(type, map_file)
70
144
  @maps[type] = YAML.load_file(map_file)
71
145
  end
72
146
 
147
+ # @return [Array<String>] An array of the map types
73
148
  def map_types
74
149
  @maps.keys
75
150
  end
76
151
 
152
+ # Verify that all the mappings have the same size
153
+ # @param keys_with_array_val [Hash] A hash of keys with array values
154
+ # @return [TrueClass] True if all the mappings have the same size
155
+ # @raise [RuntimeError] If the mappings do not have the same size
77
156
  def verify_map_size(keys_with_array_val = find_keys_with_array_val(@maps.dup))
78
157
  result = keys_with_array_val.each_with_object([]) do |(id, map), res|
79
158
  actual_length = 1 + map.length
@@ -84,6 +163,10 @@ module CemSpecHelper
84
163
  true
85
164
  end
86
165
 
166
+ # Verify that all mappings are one-to-one, or that there are no duplicate IDs shared between
167
+ # maps.
168
+ # @return [TrueClass] True if all mappings are one-to-one
169
+ # @raise [RuntimeError] If there are duplicate IDs shared between maps
87
170
  def verify_one_to_one
88
171
  results = @maps.keys.each_with_object([]) do |t, arr|
89
172
  keys_with_array_val = find_keys_with_array_val(@maps[t])
@@ -103,6 +186,7 @@ module CemSpecHelper
103
186
  true
104
187
  end
105
188
 
189
+ # @return [String] A string representation of the mapping
106
190
  def to_s
107
191
  "Mapping[#{framework}, #{os}, #{majver}]"
108
192
  end
@@ -110,7 +194,7 @@ module CemSpecHelper
110
194
  private
111
195
 
112
196
  def top_key(type)
113
- [module_name, 'mappings', framework, type].join('::')
197
+ [MAPPINGS_KEY, framework, type].join('::')
114
198
  end
115
199
 
116
200
  def find_keys_with_array_val(hsh)
@@ -4,25 +4,46 @@ require 'yaml'
4
4
 
5
5
  module CemSpecHelper
6
6
  module ResourceDataSpec
7
+ # The root directory for all resource data fixtures
7
8
  DATA_ROOT = File.join(Dir.pwd, 'spec', 'fixtures', 'data')
9
+ # The root directory for RedHat family resource data fixtures
8
10
  REDHAT_FAMILY_ROOT = File.join(DATA_ROOT, 'RedHat')
11
+ # The root directory for RedHat resource data fixtures
9
12
  REDHAT_ROOT_DIR = File.join(REDHAT_FAMILY_ROOT, 'RedHat')
13
+ # The major versions of RedHat resource data fixtures
10
14
  REDHAT_MAJVER = [7, 8].freeze
15
+ # The root directory for CentOS resource data fixtures
11
16
  CENTOS_ROOT_DIR = File.join(REDHAT_FAMILY_ROOT, 'CentOS')
17
+ # The major versions of CentOS resource data fixtures
12
18
  CENTOS_MAJVER = [7].freeze
19
+ # The root directory for OracleLinux resource data fixtures
13
20
  ORACLE_ROOT_DIR = File.join(REDHAT_FAMILY_ROOT, 'OracleLinux')
21
+ # The major versions of OracleLinux resource data fixtures
14
22
  ORACLE_MAJVER = [7, 8].freeze
23
+ # The root directory for AlmaLinux resource data fixtures
15
24
  ALMA_ROOT_DIR = File.join(REDHAT_FAMILY_ROOT, 'AlmaLinux')
25
+ # The major versions of AlmaLinux resource data fixtures
16
26
  ALMA_MAJVER = [8].freeze
27
+ # The root directory for Windows resource data fixtures
17
28
  WINDOWS_ROOT_DIR = File.join(DATA_ROOT, 'windows', 'windows')
29
+ # The major versions of Windows resource data fixtures
18
30
  WINDOWS_MAJVER = [10, 2016, 2019, 2022].freeze
19
-
31
+ # The root directory for synthetic resource data fixtures
20
32
  SYNTHETIC_DATA_ROOT = File.join(Dir.pwd, 'spec', 'fixtures', 'unit', 'puppet_x', 'puppetlabs', 'cem', 'data_processor')
21
-
33
+ # The special controls that are not mapped to a framework
22
34
  SPECIAL_CONTROLS = ['cem_options', 'cem_protected'].freeze
35
+ # The key prefix for the resources
36
+ RESOURCES_KEY = "#{CemSpecHelper::MODULE_NAME}::resources"
23
37
 
24
- def find_resource_data(distro, majver = nil, as_objects: false)
25
- case distro
38
+ # Finds and loads resource data for a given OS and major version
39
+ # @param osname [String] The name of the OS
40
+ # @param majver [String] The major version of the OS
41
+ # @param as_objects [Boolean] Whether or not to return the resource data as objects or hashes
42
+ # @return [Array<Hash>] An array of hashes containing the resource data
43
+ # @return [Array<Resource>] An array of Resource objects
44
+ # @raise [ArgumentError] If the OS name or major version is not found
45
+ def find_resource_data(osname, majver = nil, as_objects: false)
46
+ case osname
26
47
  when 'RedHat'
27
48
  redhat_resource_data(majver, as_objects: as_objects)
28
49
  when 'CentOS'
@@ -31,45 +52,66 @@ module CemSpecHelper
31
52
  oracle_resource_data(majver, as_objects: as_objects)
32
53
  when 'AlmaLinux'
33
54
  alma_resource_data(majver, as_objects: as_objects)
34
- when 'Windows'
55
+ when /^[Ww]indows$/
35
56
  windows_resource_data(majver, as_objects: as_objects)
36
- when 'Synthetic'
37
- load_resource_data(SYNTHETIC_DATA_ROOT, 'test_resource_data', as_objects: as_objects)
57
+ when /^[Ss]ynthetic/
58
+ synthetic_resource_data(as_objects: as_objects)
38
59
  else
39
- raise "Unknown distro: #{distro}"
60
+ raise "Unknown OS: #{osname}"
40
61
  end
41
62
  end
42
63
 
64
+ # Shortcut methods for loading resource data for a specific OS
65
+ # @param majver [String] The major version of the OS
66
+ # @param as_objects [Boolean] Whether or not to return the resource data as objects or hashes
67
+ # @return [Array<Hash>] An array of hashes containing the resource data
68
+ # @return [Array<Resource>] An array of Resource objects
69
+ # @raise [ArgumentError] If the major version is not found
43
70
  def redhat_resource_data(majver = nil, as_objects: false)
44
71
  raise ArgumentError, "major version #{majver} not found" unless majver.nil? || REDHAT_MAJVER.include?(majver.to_i)
45
72
 
46
73
  load_resource_data(REDHAT_ROOT_DIR, majver, as_objects: as_objects)
47
74
  end
48
75
 
76
+ # @param (see #redhat_resource_data)
77
+ # @return (see #redhat_resource_data)
78
+ # @raise (see #redhat_resource_data)
49
79
  def centos_resource_data(majver = nil, as_objects: false)
50
80
  raise ArgumentError, "major version #{majver} not found" unless majver.nil? || CENTOS_MAJVER.include?(majver.to_i)
51
81
 
52
82
  load_resource_data(CENTOS_ROOT_DIR, majver, as_objects: as_objects)
53
83
  end
54
84
 
85
+ # @param (see #redhat_resource_data)
86
+ # @return (see #redhat_resource_data)
87
+ # @raise (see #redhat_resource_data)
55
88
  def oracle_resource_data(majver = nil, as_objects: false)
56
89
  raise ArgumentError, "major version #{majver} not found" unless majver.nil? || ORACLE_MAJVER.include?(majver.to_i)
57
90
 
58
91
  load_resource_data(ORACLE_ROOT_DIR, majver, as_objects: as_objects)
59
92
  end
60
93
 
94
+ # @param (see #redhat_resource_data)
95
+ # @return (see #redhat_resource_data)
96
+ # @raise (see #redhat_resource_data)
61
97
  def alma_resource_data(majver = nil, as_objects: false)
62
98
  raise ArgumentError, "major version #{majver} not found" unless majver.nil? || ALMA_MAJVER.include?(majver.to_i)
63
99
 
64
100
  load_resource_data(ALMA_ROOT_DIR, majver, as_objects: as_objects)
65
101
  end
66
102
 
103
+ # @param (see #redhat_resource_data)
104
+ # @return (see #redhat_resource_data)
105
+ # @raise (see #redhat_resource_data)
67
106
  def windows_resource_data(majver = nil, as_objects: false)
68
107
  raise ArgumentError, "major version #{majver} not found" unless majver.nil? || WINDOWS_MAJVER.include?(majver.to_i)
69
108
 
70
109
  load_resource_data(WINDOWS_ROOT_DIR, majver, as_objects: as_objects)
71
110
  end
72
111
 
112
+ # Shortcut method for loading synthetic resource data
113
+ # @param as_objects [Boolean] Whether or not to return the resource data as objects or hashes
114
+ # @return (see #redhat_resource_data)
73
115
  def synthetic_resource_data(as_objects: false)
74
116
  load_resource_data(SYNTHETIC_DATA_ROOT, 'test_resource_data', as_objects: as_objects)
75
117
  end
@@ -78,10 +120,12 @@ module CemSpecHelper
78
120
  # @param distro [String]
79
121
  # @param majver [String]
80
122
  # @param benchmark [String] either cis or stig
123
+ # @param max [nil, Integer] maximum number of resources to return. If nil, returns all
81
124
  # @return [Hash] A hash of control_name => [resource type, resource title]
82
- def single_control_resources(distro, majver = nil, benchmark = 'cis')
125
+ def single_control_resources(distro, majver = nil, benchmark = 'cis', max: nil)
83
126
  resources = find_resource_data(distro, majver, as_objects: true)
84
127
  resources.select! { |res| res.controls(include_special: false).length == 1 }
128
+ resources = max.nil? ? resources : resources.first(max)
85
129
  resources.map! do |res|
86
130
  [res.controls.first, [res.type, res.title]]
87
131
  end
@@ -96,34 +140,94 @@ module CemSpecHelper
96
140
  resources
97
141
  end
98
142
 
143
+ # Finds all resources that implement multiple controls
144
+ # @param distro [String]
145
+ # @param majver [String]
146
+ # @param benchmark [String] either cis or stig
147
+ # @param max [nil, Integer] maximum number of resources to return
148
+ # @return [Hash] A hash of control_name => [resource type, resource title]
149
+ def multi_control_resources(distro, majver = nil, benchmark = 'cis', max: nil)
150
+ resources = find_resource_data(distro, majver, as_objects: true)
151
+ resources.select! { |res| res.controls(include_special: false).length > 1 }
152
+ resources = max.nil? ? resources : resources.first(max)
153
+ resources.map! do |res|
154
+ [res.controls, [res.type, res.title]]
155
+ end
156
+ resources = resources.to_h
157
+ # Reduce to just benchmark-related keypairs
158
+ case benchmark
159
+ when 'cis'
160
+ resources.reject! { |k, _v| k.match?(%r{^V-}) }
161
+ when 'stig'
162
+ resources.select! { |k, _v| k.match?(%r{^V-}) }
163
+ end
164
+ resources
165
+ end
166
+
167
+ # Loads resource data from a given root directory and major version
168
+ # @param root_dir [String] The root directory to load resource data from
169
+ # @param majver [Integer, String, nil] The major version of the OS. If nil,
170
+ # loads all resource data from the root directory.
171
+ # @param as_objects [Boolean] Whether or not to return the resource data as objects or hashes
172
+ # @return [Array<Hash>] An array of hashes containing the resource data
173
+ # @return [Array<Resource>] An array of Resource objects
174
+ # @return [Hash] A hash of found major versions => resource data arrays. Is only returned
175
+ # if the majver parameter is nil.
176
+ # @raise [ArgumentError] If the root directory is not a valid path
177
+ # @raise [RuntimeError] If the resource data file is not found
99
178
  def load_resource_data(root_dir, majver = nil, as_objects: false)
100
- raise "root_dir \"#{root_dir}\" is not a valid path" unless File.directory?(root_dir)
179
+ raise ArgumentError, "root_dir \"#{root_dir}\" is not a valid path" unless File.directory?(root_dir)
101
180
 
102
181
  unless majver.nil?
103
182
  file_path = File.join(root_dir, "#{majver}.yaml")
104
183
  raise "Resource data file \"#{file_path}\" not found" unless File.file?(file_path)
105
184
 
106
- resources = YAML.load_file(file_path)['cem_linux::resources']
185
+ resources = YAML.load_file(file_path)[RESOURCES_KEY]
107
186
  final_resources = as_objects ? resources.map { |k, v| Resource.new(k, v) } : resources
108
187
  return final_resources
109
188
  end
110
189
 
111
190
  Dir[File.join(root_dir, '*')].each_with_object({}) do |rdata, hsh|
112
- resources = YAML.load_file(rdata)['cem_linux::resources']
191
+ resources = YAML.load_file(rdata)[RESOURCES_KEY]
113
192
  final_resources = as_objects ? resources.map { |k, v| Resource.new(k, v) } : resources
114
193
  hsh[File.basename(rdata, '.yaml')] = final_resources
115
194
  end
116
195
  end
117
196
 
197
+ # Finds all controls in the given array of Resource objects
198
+ # @param rdata_objects [Array<Resource>] An array of Resource objects
199
+ # @return [Array<String>] An array of control names
200
+ def all_controls(rdata_objects)
201
+ rdata_objects.map(&:controls).flatten
202
+ end
203
+
204
+ # Finds all controls that are duplicated in the given array of Resource objects
205
+ # @param rdata_objects [Array<Resource>] An array of Resource objects
206
+ # @return [Array<String>] An array of control names
118
207
  def duplicate_controls(rdata_objects)
119
- all_controls = rdata_objects.map(&:controls).flatten
208
+ all = all_controls(rdata_objects)
120
209
  # Lets go O(n^2) solution!
121
- all_controls.select { |c| all_controls.count(c) > 1 }.reject { |c| SPECIAL_CONTROLS.include?(c) }.uniq
210
+ all.select { |c| all.count(c) > 1 }.reject { |c| SPECIAL_CONTROLS.include?(c) }.uniq
211
+ end
212
+
213
+ # Finds all controls that are not mapped in the given array of Resource objects and mapping data array
214
+ # @param rdata_objects [Array<Resource>] An array of Resource objects
215
+ # @param mdata_array [Array<Hash>] An array of hashes containing mapping data
216
+ # @return [Array<String>] An array of control names
217
+ def not_in_mapping_data(rdata_objects, mdata_array)
218
+ all = all_controls(rdata_objects)
219
+ mdata_array.compact.each do |m|
220
+ all -= m.keys
221
+ end
222
+ all.reject { |c| SPECIAL_CONTROLS.include?(c) }.uniq
122
223
  end
123
224
 
225
+ # The Resource class represents a single resource from the resource data file
124
226
  class Resource
125
227
  attr_reader :title, :type
126
228
 
229
+ # @param title [String] The title of the resource
230
+ # @param data [Hash] The resource data
127
231
  def initialize(title, data)
128
232
  @title = title
129
233
  @data = data
@@ -132,6 +236,8 @@ module CemSpecHelper
132
236
  @control_data = load_control_data
133
237
  end
134
238
 
239
+ # @return [Array<String>] An array of control names implemented by the resource
240
+ # @param include_special [Boolean] Whether or not to include special controls (cem_options, cem_protected)
135
241
  def controls(include_special: true)
136
242
  ctrls = @no_params ? @control_data : @control_data.keys
137
243
  return ctrls if include_special
@@ -139,12 +245,14 @@ module CemSpecHelper
139
245
  ctrls.reject { |c| SPECIAL_CONTROLS.include?(c) }
140
246
  end
141
247
 
248
+ # @return [Hash] A hash of parameter names => default values
142
249
  def params
143
250
  # rubocop:disable Style/CollectionMethods
144
251
  control_data.map { |_, v| v if v.is_a?(Hash) }.flatten.compact.uniq.inject(:merge)
145
252
  # rubocop:enable Style/CollectionMethods
146
253
  end
147
254
 
255
+ # @return [TrueClass, FalseClass] Whether or not the resource has any duplicate control names
148
256
  def verify_no_duplicate_controls
149
257
  controls.uniq == controls
150
258
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CemSpecHelper
4
- VERSION = '0.1.2'
4
+ VERSION = '0.2.0'
5
5
  end
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # This module is meant to be included in the spec_helper.rb file.
4
+ # It is not meant to be used directly.
3
5
  module CemSpecHelper
6
+ MODULE_NAME = File.basename(Dir.pwd).gsub(/^puppetlabs-/, '')
7
+
4
8
  # Makes it so the CemSpecHelper module has to be included in the spec_helper.rb file.
5
9
  def self.included(base)
6
10
  require 'cem_spec_helper/mapping_data_spec'
@@ -8,10 +12,60 @@ module CemSpecHelper
8
12
  require 'cem_spec_helper/version'
9
13
 
10
14
  RSpec.configure do |config|
15
+ config.include CemSpecHelper::GeneralSpec
16
+ config.extend CemSpecHelper::GeneralSpec
11
17
  config.include CemSpecHelper::MappingDataSpec
12
18
  config.extend CemSpecHelper::MappingDataSpec
13
19
  config.include CemSpecHelper::ResourceDataSpec
14
20
  config.extend CemSpecHelper::ResourceDataSpec
15
21
  end
16
22
  end
23
+
24
+ module GeneralSpec
25
+ # The type of control ID used in the mapping data, resource data, or control configs.
26
+ # @param id [String] The control ID
27
+ # @param framework [String] The framework to use. If nil, will try both CIS and STIG.
28
+ # @return [Symbol] The type of control ID
29
+ def control_id_type(id, framework = nil)
30
+ case framework
31
+ when 'cis'
32
+ cis_control_id_type(id)
33
+ when 'stig'
34
+ stig_control_id_type(id)
35
+ else
36
+ # stig_control_id_type can return nil, cis_control_id_type will return 'title'
37
+ stig_control_id_type(id) || cis_control_id_type(id)
38
+ end
39
+ end
40
+
41
+ # The type of control ID used in the CIS mapping data, resource data, or control configs.
42
+ # @param id [String] The control ID
43
+ # @return (see #control_id_type)
44
+ def cis_control_id_type(id)
45
+ case id
46
+ when /^([0-9]\.)+/
47
+ :number
48
+ when /^[A-Za-z0-9_]+$/
49
+ :hiera_title
50
+ when /^c[0-9_]+$/
51
+ :hiera_title_num
52
+ else
53
+ :title
54
+ end
55
+ end
56
+
57
+ # The type of control ID used in the STIG mapping data, resource data, or control configs.
58
+ # @param id [String] The control ID
59
+ # @return (see #control_id_type)
60
+ def stig_control_id_type(id)
61
+ case id
62
+ when /^V-\d{6}$/
63
+ :vulnid
64
+ when /^SV-\d{6}r\d{6}_rule$/
65
+ :ruleid
66
+ else
67
+ nil
68
+ end
69
+ end
70
+ end
17
71
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cem_spec_helper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - abide-team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-21 00:00:00.000000000 Z
11
+ date: 2023-09-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Provides helper methods, classes, modules, etc. for RSpec testing the
14
14
  CEM modules