class InspecTools::XLSXTool

Methods for converting from XLS to various formats

Constants

LATEST_NIST_REV

Public Class Methods

new(xlsx, mapping, name, verbose = false) click to toggle source
# File lib/inspec_tools/xlsx_tool.rb, line 16
def initialize(xlsx, mapping, name, verbose = false)
  @name = name
  @xlsx = xlsx
  @mapping = Utils::MappingValidator.validate(mapping)
  @verbose = verbose
  @cis_to_nist = Utils::CisToNist.get_mapping('cis_to_nist_mapping')
end

Public Instance Methods

to_ckl() click to toggle source
# File lib/inspec_tools/xlsx_tool.rb, line 24
def to_ckl
  # TODO
end
to_inspec(control_prefix) click to toggle source
# File lib/inspec_tools/xlsx_tool.rb, line 32
def to_inspec(control_prefix)
  @controls = []
  @cci_xml = nil
  @profile = {}
  insert_json_metadata
  parse_cis_controls(control_prefix)
  @profile['controls'] = @controls
  @profile['sha256'] = Digest::SHA256.hexdigest @profile.to_s
  @profile
end
to_xccdf() click to toggle source
# File lib/inspec_tools/xlsx_tool.rb, line 28
def to_xccdf
  # TODO
end

Private Instance Methods

apply_cis_and_nist_controls(control, cis_tags) click to toggle source
# File lib/inspec_tools/xlsx_tool.rb, line 105
def apply_cis_and_nist_controls(control, cis_tags)
  control['tags']['cis_controls'] = []
  control['tags']['nist'] = []

  if cis_tags[:sub_section].nil? || cis_tags[:sub_section].blank?
    control['tags']['cis_controls'] << cis_tags[:section]
    control['tags']['nist'] << get_nist_control_for_cis(cis_tags[:section])
  else
    control['tags']['cis_controls'] << "#{cis_tags[:section]}.#{cis_tags[:sub_section]}"
    control['tags']['nist'] << get_nist_control_for_cis(cis_tags[:section], cis_tags[:sub_section])
  end

  control['tags']['nist'] << LATEST_NIST_REV unless control['tags']['nist'].nil?
  control['tags']['cis_controls'] << "Rev_#{cis_tags[:revision]}" unless cis_tags[:revision].nil?

  control
end
cell_empty?(cell) click to toggle source
# File lib/inspec_tools/xlsx_tool.rb, line 99
def cell_empty?(cell)
  return cell.empty? if cell.respond_to?(:empty?)

  cell.nil?
end
get_nist_control_for_cis(section, sub_section = nil) click to toggle source
# File lib/inspec_tools/xlsx_tool.rb, line 123
def get_nist_control_for_cis(section, sub_section = nil)
  return @cis_to_nist[section] if sub_section.nil?

  @cis_to_nist["#{section}.#{sub_section}"]
end
insert_json_metadata() click to toggle source
# File lib/inspec_tools/xlsx_tool.rb, line 45
def insert_json_metadata
  @profile['name'] = @name
  @profile['title'] = 'InSpec Profile'
  @profile['maintainer'] = 'The Authors'
  @profile['copyright'] = 'The Authors'
  @profile['copyright_email'] = 'you@example.com'
  @profile['license'] = 'Apache-2.0'
  @profile['summary'] = 'An InSpec Compliance Profile'
  @profile['version'] = '0.1.0'
  @profile['supports'] = []
  @profile['attributes'] = []
  @profile['generator'] = {
    name: 'inspec_tools',
    version: ::InspecTools::VERSION
  }
end
parse_cis_controls(control_prefix) click to toggle source
# File lib/inspec_tools/xlsx_tool.rb, line 62
def parse_cis_controls(control_prefix)
  [1, 2].each do |level|
    @xlsx.sheet(level).each_row_streaming do |row|
      if row[@mapping['control.id']].nil? || !/^\d+(\.?\d)*$/.match(row[@mapping['control.id']].formatted_value)
        next
      end

      tag_pos = @mapping['control.tags']
      control = {}
      control['tags'] = {}
      control['id'] = "#{control_prefix}-#{row[@mapping['control.id']].formatted_value}" unless cell_empty?(@mapping['control.id']) || cell_empty?(row[@mapping['control.id']])
      control['title']  = row[@mapping['control.title']].formatted_value unless cell_empty?(@mapping['control.title']) || cell_empty?(row[@mapping['control.title']])
      control['desc'] = ''
      control['desc'] = row[@mapping['control.desc']].formatted_value unless cell_empty?(row[@mapping['control.desc']])
      control['tags']['rationale'] = row[tag_pos['rationale']].formatted_value unless cell_empty?(row[tag_pos['rationale']])

      control['tags']['severity'] = level == 1 ? 'medium' : 'high'
      control['impact'] = Utils::InspecUtil.get_impact(control['tags']['severity'])
      control['tags']['ref'] = row[@mapping['control.ref']].formatted_value unless cell_empty?(@mapping['control.ref']) || cell_empty?(row[@mapping['control.ref']])
      control['tags']['cis_level'] = level unless level.nil?

      unless cell_empty?(row[tag_pos['cis_controls']])
        # cis_control must be extracted from CIS control column via regex
        cis_tags_array = row[tag_pos['cis_controls']].formatted_value.scan(/CONTROL:v(\d) (\d+)\.?(\d*)/).flatten
        cis_tags = %i(revision section sub_section).zip(cis_tags_array).to_h
        control = apply_cis_and_nist_controls(control, cis_tags)
      end

      control['tags']['cis_rid'] = row[@mapping['control.id']].formatted_value unless cell_empty?(@mapping['control.id']) || cell_empty?(row[@mapping['control.id']])
      control['tags']['check'] = row[tag_pos['check']].formatted_value unless cell_empty?(tag_pos['check']) || cell_empty?(row[tag_pos['check']])
      control['tags']['fix'] = row[tag_pos['fix']].formatted_value unless cell_empty?(tag_pos['fix']) || cell_empty?(row[tag_pos['fix']])

      @controls << control
    end
  end
end