lib/inspec_tools/xlsx.rb in inspec_tools-2.0.1.pre2 vs lib/inspec_tools/xlsx.rb in inspec_tools-2.0.1.pre3

- old
+ new

@@ -11,15 +11,19 @@ # rubocop:disable Metrics/CyclomaticComplexity module InspecTools # Methods for converting from XLS to various formats class XLSXTool + CIS_2_NIST_XLSX = Roo::Spreadsheet.open(File.join(File.dirname(__FILE__), '../data/NIST_Map_02052020_CIS_Controls_Version_7.1_Implementation_Groups_1.2.xlsx')) + LATEST_NIST_REV = 'Rev_4'.freeze + def initialize(xlsx, mapping, name, verbose = false) @name = name @xlsx = xlsx @mapping = mapping @verbose = verbose + @cis_to_nist = get_cis_to_nist_control_mapping(CIS_2_NIST_XLSX) end def to_ckl # TODO end @@ -39,10 +43,22 @@ @profile end private + def get_cis_to_nist_control_mapping(spreadsheet) + cis_to_nist = {} + spreadsheet.sheet(3).each do |row| + if row[3].is_a? Numeric + cis_to_nist[row[3].to_s] = row[0] + else + cis2Nist[row[2].to_s] = row[0] unless (row[2] == '') || row[2].to_i.nil? + end + end + cis_to_nist + end + def insert_json_metadata @profile['name'] = @name @profile['title'] = 'InSpec Profile' @profile['maintainer'] = 'The Authors' @profile['copyright'] = 'The Authors' @@ -57,69 +73,75 @@ 'version': VERSION } end def parse_cis_controls(control_prefix) - cis2NistXls = Roo::Spreadsheet.open(File.join(File.dirname(__FILE__), "../data/NIST_Map_02052020_CIS_Controls_Version_7.1_Implementation_Groups_1.2.xlsx")) - cis2Nist = {} - cis2NistXls.sheet(3).each do |row| - if row[3].is_a? Numeric - cis2Nist[row[3].to_s] = row[0] - else - cis2Nist[row[2].to_s] = row[0] unless (row[2] == "") || (row[2].to_i.nil?) - end - end - [ 1, 2 ].each do |level| + [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 @mapping['control.id'].nil? || row[@mapping['control.id']].nil? - control['title'] = row[@mapping['control.title']].formatted_value unless @mapping['control.title'].nil? || row[@mapping['control.title']].nil? - control['desc'] = "" - control['desc'] = row[@mapping['control.desc']].formatted_value unless row[@mapping['control.desc']].nil? - control['tags']['rationale'] = row[tag_pos['rationale']].formatted_value unless row[tag_pos['rationale']].empty? + 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 @mapping['control.ref'].nil? || row[@mapping['control.ref']].nil? + 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 row[tag_pos['cis_controls']].empty? + unless cell_empty?(row[tag_pos['cis_controls']]) # cis_control must be extracted from CIS control column via regex - control = handle_cis_tags(control, row[tag_pos['cis_controls']].formatted_value.scan(/CONTROL:v(\d) (\d+)\.?(\d*)/)) + 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 @mapping['control.id'].nil? || row[@mapping['control.id']].nil? - control['tags']['check'] = row[tag_pos['check']].formatted_value unless tag_pos['check'].nil? || row[tag_pos['check']].empty? - control['tags']['fix'] = row[tag_pos['fix']].formatted_value unless tag_pos['fix'].nil? || row[tag_pos['fix']].empty? + 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 - def handle_cis_tags(control, cis_tags) - control['tags']['cis_controls'] = [] - control['tags']['nist'] = [] + def cell_empty?(cell) + return cell.empty? if cell.respond_to?(:empty?) - cis_tags.each do |cis_tag| - if cis_tag[2].nil? || cis_tag[2] == "" - control['tags']['cis_controls'] << cis_tag[1].to_s - control['tags']['nist'] << cis2Nist[cis_tag[1]] - else - control['tags']['cis_controls'] << cis_tag[1].to_s + "." + cis_tag[2].to_s - control['tags']['nist'] << cis2Nist[cis_tag[1].to_s + "." + cis_tag[2].to_s] - end - end + cell.nil? + end - if not control['tags']['nist'].nil? - control['tags']['nist'] << "Rev_4" + 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']['cis_controls'] << "Rev_" + cis_tags.first[0] unless cis_tags[0].nil? + + 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 + + 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 end end + +# rubocop:enable Metrics/AbcSize +# rubocop:enable Metrics/PerceivedComplexity +# rubocop:enable Metrics/CyclomaticComplexity