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