Module: CemSpecHelper::ResourceDataSpec

Defined in:
lib/cem_spec_helper/resource_data_spec.rb

Defined Under Namespace

Classes: Resource

Constant Summary collapse

DATA_ROOT =

The root directory for all resource data fixtures

File.join(Dir.pwd, 'spec', 'fixtures', 'data')
REDHAT_FAMILY_ROOT =

The root directory for RedHat family resource data fixtures

File.join(DATA_ROOT, 'RedHat')
REDHAT_ROOT_DIR =

The root directory for RedHat resource data fixtures

File.join(REDHAT_FAMILY_ROOT, 'RedHat')
REDHAT_MAJVER =

The major versions of RedHat resource data fixtures

[7, 8].freeze
CENTOS_ROOT_DIR =

The root directory for CentOS resource data fixtures

File.join(REDHAT_FAMILY_ROOT, 'CentOS')
CENTOS_MAJVER =

The major versions of CentOS resource data fixtures

[7].freeze
ORACLE_ROOT_DIR =

The root directory for OracleLinux resource data fixtures

File.join(REDHAT_FAMILY_ROOT, 'OracleLinux')
ORACLE_MAJVER =

The major versions of OracleLinux resource data fixtures

[7, 8].freeze
ALMA_ROOT_DIR =

The root directory for AlmaLinux resource data fixtures

File.join(REDHAT_FAMILY_ROOT, 'AlmaLinux')
ALMA_MAJVER =

The major versions of AlmaLinux resource data fixtures

[8].freeze
WINDOWS_ROOT_DIR =

The root directory for Windows resource data fixtures

File.join(DATA_ROOT, 'windows', 'windows')
WINDOWS_MAJVER =

The major versions of Windows resource data fixtures

[10, 2016, 2019, 2022].freeze
SYNTHETIC_DATA_ROOT =

The root directory for synthetic resource data fixtures

File.join(Dir.pwd, 'spec', 'fixtures', 'unit', 'puppet_x', 'puppetlabs', 'sce', 'data_processor')
SPECIAL_CONTROLS =

The special controls that are not mapped to a framework

['sce_options', 'sce_protected'].freeze
RESOURCES_KEY =

The key prefix for the resources

"#{CemSpecHelper::MODULE_NAME}::resources"

Instance Method Summary collapse

Instance Method Details

#all_controls(rdata_objects) ⇒ Array<String>

Finds all controls in the given array of Resource objects

Parameters:

  • rdata_objects (Array<Resource>)

    An array of Resource objects

Returns:

  • (Array<String>)

    An array of control names



200
201
202
# File 'lib/cem_spec_helper/resource_data_spec.rb', line 200

def all_controls(rdata_objects)
  rdata_objects.map(&:controls).flatten
end

#alma_resource_data(majver = nil, as_objects: false) ⇒ Array<Hash>, Array<Resource>

Parameters:

  • majver (String) (defaults to: nil)

    The major version of the OS

  • as_objects (Boolean) (defaults to: false)

    Whether or not to return the resource data as objects or hashes

Returns:

  • (Array<Hash>)

    An array of hashes containing the resource data

  • (Array<Resource>)

    An array of Resource objects

Raises:

  • (ArgumentError)

    If the major version is not found



97
98
99
100
101
# File 'lib/cem_spec_helper/resource_data_spec.rb', line 97

def alma_resource_data(majver = nil, as_objects: false)
  raise ArgumentError, "major version #{majver} not found" unless majver.nil? || ALMA_MAJVER.include?(majver.to_i)

  load_resource_data(ALMA_ROOT_DIR, majver, as_objects: as_objects)
end

#centos_resource_data(majver = nil, as_objects: false) ⇒ Array<Hash>, Array<Resource>

Parameters:

  • majver (String) (defaults to: nil)

    The major version of the OS

  • as_objects (Boolean) (defaults to: false)

    Whether or not to return the resource data as objects or hashes

Returns:

  • (Array<Hash>)

    An array of hashes containing the resource data

  • (Array<Resource>)

    An array of Resource objects

Raises:

  • (ArgumentError)

    If the major version is not found



79
80
81
82
83
# File 'lib/cem_spec_helper/resource_data_spec.rb', line 79

def centos_resource_data(majver = nil, as_objects: false)
  raise ArgumentError, "major version #{majver} not found" unless majver.nil? || CENTOS_MAJVER.include?(majver.to_i)

  load_resource_data(CENTOS_ROOT_DIR, majver, as_objects: as_objects)
end

#duplicate_controls(rdata_objects) ⇒ Array<String>

Finds all controls that are duplicated in the given array of Resource objects

Parameters:

  • rdata_objects (Array<Resource>)

    An array of Resource objects

Returns:

  • (Array<String>)

    An array of control names



207
208
209
210
211
# File 'lib/cem_spec_helper/resource_data_spec.rb', line 207

def duplicate_controls(rdata_objects)
  all = all_controls(rdata_objects)
  # Lets go O(n^2) solution!
  all.select { |c| all.count(c) > 1 }.reject { |c| SPECIAL_CONTROLS.include?(c) }.uniq
end

#find_resource_data(osname, majver = nil, as_objects: false) ⇒ Array<Hash>, Array<Resource>

Finds and loads resource data for a given OS and major version

Parameters:

  • osname (String)

    The name of the OS

  • majver (String) (defaults to: nil)

    The major version of the OS

  • as_objects (Boolean) (defaults to: false)

    Whether or not to return the resource data as objects or hashes

Returns:

  • (Array<Hash>)

    An array of hashes containing the resource data

  • (Array<Resource>)

    An array of Resource objects

Raises:

  • (ArgumentError)

    If the OS name or major version is not found



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/cem_spec_helper/resource_data_spec.rb', line 45

def find_resource_data(osname, majver = nil, as_objects: false)
  case osname
  when 'RedHat'
    redhat_resource_data(majver, as_objects: as_objects)
  when 'CentOS'
    centos_resource_data(majver, as_objects: as_objects)
  when 'OracleLinux'
    oracle_resource_data(majver, as_objects: as_objects)
  when 'AlmaLinux'
    alma_resource_data(majver, as_objects: as_objects)
  when /^[Ww]indows$/
    windows_resource_data(majver, as_objects: as_objects)
  when /^[Ss]ynthetic/
    synthetic_resource_data(as_objects: as_objects)
  else
    raise "Unknown OS: #{osname}"
  end
end

#load_resource_data(root_dir, majver = nil, as_objects: false) ⇒ Array<Hash>, ...

Loads resource data from a given root directory and major version

Parameters:

  • root_dir (String)

    The root directory to load resource data from

  • majver (Integer, String, nil) (defaults to: nil)

    The major version of the OS. If nil, loads all resource data from the root directory.

  • as_objects (Boolean) (defaults to: false)

    Whether or not to return the resource data as objects or hashes

Returns:

  • (Array<Hash>)

    An array of hashes containing the resource data

  • (Array<Resource>)

    An array of Resource objects

  • (Hash)

    A hash of found major versions => resource data arrays. Is only returned if the majver parameter is nil.

Raises:

  • (ArgumentError)

    If the root directory is not a valid path

  • (RuntimeError)

    If the resource data file is not found



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/cem_spec_helper/resource_data_spec.rb', line 178

def load_resource_data(root_dir, majver = nil, as_objects: false)
  raise ArgumentError, "root_dir \"#{root_dir}\" is not a valid path" unless File.directory?(root_dir)

  unless majver.nil?
    file_path = File.join(root_dir, "#{majver}.yaml")
    raise "Resource data file \"#{file_path}\" not found" unless File.file?(file_path)

    resources = YAML.load_file(file_path)[RESOURCES_KEY]
    final_resources = as_objects ? resources.map { |k, v| Resource.new(k, v) } : resources
    return final_resources
  end

  Dir[File.join(root_dir, '*')].each_with_object({}) do |rdata, hsh|
    resources = YAML.load_file(rdata)[RESOURCES_KEY]
    final_resources = as_objects ? resources.map { |k, v| Resource.new(k, v) } : resources
    hsh[File.basename(rdata, '.yaml')] = final_resources
  end
end

#multi_control_resources(distro, majver = nil, benchmark = 'cis', max: nil) ⇒ Hash

Finds all resources that implement multiple controls

Parameters:

  • distro (String)
  • majver (String) (defaults to: nil)
  • benchmark (String) (defaults to: 'cis')

    either cis or stig

  • max (nil, Integer) (defaults to: nil)

    maximum number of resources to return

Returns:

  • (Hash)

    A hash of control_name => [resource type, resource title]



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/cem_spec_helper/resource_data_spec.rb', line 149

def multi_control_resources(distro, majver = nil, benchmark = 'cis', max: nil)
  resources = find_resource_data(distro, majver, as_objects: true)
  resources.select! { |res| res.controls(include_special: false).length > 1 }
  resources = max.nil? ? resources : resources.first(max)
  resources.map! do |res|
    [res.controls, [res.type, res.title]]
  end
  resources = resources.to_h
  # Reduce to just benchmark-related keypairs
  case benchmark
  when 'cis'
    resources.reject! { |k, _v| k.match?(%r{^V-}) }
  when 'stig'
    resources.select! { |k, _v| k.match?(%r{^V-}) }
  end
  resources
end

#not_in_mapping_data(rdata_objects, mdata_array) ⇒ Array<String>

Finds all controls that are not mapped in the given array of Resource objects and mapping data array

Parameters:

  • rdata_objects (Array<Resource>)

    An array of Resource objects

  • mdata_array (Array<Hash>)

    An array of hashes containing mapping data

Returns:

  • (Array<String>)

    An array of control names



217
218
219
220
221
222
223
# File 'lib/cem_spec_helper/resource_data_spec.rb', line 217

def not_in_mapping_data(rdata_objects, mdata_array)
  all = all_controls(rdata_objects)
  mdata_array.compact.each do |m|
    all -= m.keys
  end
  all.reject { |c| SPECIAL_CONTROLS.include?(c) }.uniq
end

#oracle_resource_data(majver = nil, as_objects: false) ⇒ Array<Hash>, Array<Resource>

Parameters:

  • majver (String) (defaults to: nil)

    The major version of the OS

  • as_objects (Boolean) (defaults to: false)

    Whether or not to return the resource data as objects or hashes

Returns:

  • (Array<Hash>)

    An array of hashes containing the resource data

  • (Array<Resource>)

    An array of Resource objects

Raises:

  • (ArgumentError)

    If the major version is not found



88
89
90
91
92
# File 'lib/cem_spec_helper/resource_data_spec.rb', line 88

def oracle_resource_data(majver = nil, as_objects: false)
  raise ArgumentError, "major version #{majver} not found" unless majver.nil? || ORACLE_MAJVER.include?(majver.to_i)

  load_resource_data(ORACLE_ROOT_DIR, majver, as_objects: as_objects)
end

#redhat_resource_data(majver = nil, as_objects: false) ⇒ Array<Hash>, Array<Resource>

Shortcut methods for loading resource data for a specific OS

Parameters:

  • majver (String) (defaults to: nil)

    The major version of the OS

  • as_objects (Boolean) (defaults to: false)

    Whether or not to return the resource data as objects or hashes

Returns:

  • (Array<Hash>)

    An array of hashes containing the resource data

  • (Array<Resource>)

    An array of Resource objects

Raises:

  • (ArgumentError)

    If the major version is not found



70
71
72
73
74
# File 'lib/cem_spec_helper/resource_data_spec.rb', line 70

def redhat_resource_data(majver = nil, as_objects: false)
  raise ArgumentError, "major version #{majver} not found" unless majver.nil? || REDHAT_MAJVER.include?(majver.to_i)

  load_resource_data(REDHAT_ROOT_DIR, majver, as_objects: as_objects)
end

#single_control_resources(distro, majver = nil, benchmark = 'cis', max: nil) ⇒ Hash

Finds all resources that only implement a single control

Parameters:

  • distro (String)
  • majver (String) (defaults to: nil)
  • benchmark (String) (defaults to: 'cis')

    either cis or stig

  • max (nil, Integer) (defaults to: nil)

    maximum number of resources to return. If nil, returns all

Returns:

  • (Hash)

    A hash of control_name => [resource type, resource title]



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/cem_spec_helper/resource_data_spec.rb', line 125

def single_control_resources(distro, majver = nil, benchmark = 'cis', max: nil)
  resources = find_resource_data(distro, majver, as_objects: true)
  resources.select! { |res| res.controls(include_special: false).length == 1 }
  resources = max.nil? ? resources : resources.first(max)
  resources.map! do |res|
    [res.controls.first, [res.type, res.title]]
  end
  resources = resources.to_h
  # Reduce to just benchmark-related keypairs
  case benchmark
  when 'cis'
    resources.reject! { |k, _v| k.match?(%r{^V-}) }
  when 'stig'
    resources.select! { |k, _v| k.match?(%r{^V-}) }
  end
  resources
end

#synthetic_resource_data(as_objects: false) ⇒ Array<Hash>, Array<Resource>

Shortcut method for loading synthetic resource data

Parameters:

  • as_objects (Boolean) (defaults to: false)

    Whether or not to return the resource data as objects or hashes

Returns:

  • (Array<Hash>)

    An array of hashes containing the resource data

  • (Array<Resource>)

    An array of Resource objects



115
116
117
# File 'lib/cem_spec_helper/resource_data_spec.rb', line 115

def synthetic_resource_data(as_objects: false)
  load_resource_data(SYNTHETIC_DATA_ROOT, 'test_resource_data', as_objects: as_objects)
end

#windows_resource_data(majver = nil, as_objects: false) ⇒ Array<Hash>, Array<Resource>

Parameters:

  • majver (String) (defaults to: nil)

    The major version of the OS

  • as_objects (Boolean) (defaults to: false)

    Whether or not to return the resource data as objects or hashes

Returns:

  • (Array<Hash>)

    An array of hashes containing the resource data

  • (Array<Resource>)

    An array of Resource objects

Raises:

  • (ArgumentError)

    If the major version is not found



106
107
108
109
110
# File 'lib/cem_spec_helper/resource_data_spec.rb', line 106

def windows_resource_data(majver = nil, as_objects: false)
  raise ArgumentError, "major version #{majver} not found" unless majver.nil? || WINDOWS_MAJVER.include?(majver.to_i)

  load_resource_data(WINDOWS_ROOT_DIR, majver, as_objects: as_objects)
end