cem_spec_helper 0.1.1 → 0.2.0

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: 13ed1d8194b996d8c6b7a5c6587e204613b00ebdc5f26747b4e1400b24babfad
4
- data.tar.gz: 2af6929929c73b5d404880be49eeb098c18435f41217c3ef24158422f67c780e
3
+ metadata.gz: c25d50ec3d0761a950dfd6ddfa13e2b0fa23bf560719ae876af59a6936763a0d
4
+ data.tar.gz: cca59a9b38dd4d71159ed5d2470c7bac58ba22b1bc31e7b5401e56f74a4124d2
5
5
  SHA512:
6
- metadata.gz: e9c670adca166a00df16646471eac02f8f5b82a0fd47c519fc7611adcd286fb4c3ddbdb871e5b350451def292ed6c0134e5fec96ae47aaeb65af4d0ad4423821
7
- data.tar.gz: 5d416dfe3b698d935a9ca2677f553e239a7234a8d49d91c00f4b48ec7c8684859d7dde32c951fe508339d9bd46991da6823da6f18e878eae5334737498cbb4a9
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.1"
4
+ VERSION = '0.2.0'
5
5
  end
@@ -1,20 +1,71 @@
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'
7
11
  require 'cem_spec_helper/resource_data_spec'
8
12
  require 'cem_spec_helper/version'
9
13
 
10
- module PuppetX; end
11
- module PuppetX::CEM; end
12
-
13
14
  RSpec.configure do |config|
15
+ config.include CemSpecHelper::GeneralSpec
16
+ config.extend CemSpecHelper::GeneralSpec
14
17
  config.include CemSpecHelper::MappingDataSpec
15
18
  config.extend CemSpecHelper::MappingDataSpec
16
19
  config.include CemSpecHelper::ResourceDataSpec
17
20
  config.extend CemSpecHelper::ResourceDataSpec
18
21
  end
19
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
20
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.1
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