inspec_tools 2.0.3 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +12 -10
- data/Rakefile +82 -8
- data/lib/data/cis_to_nist_critical_controls +0 -0
- data/lib/data/cis_to_nist_mapping +0 -0
- data/lib/data/rubocop.yml +4 -0
- data/lib/happy_mapper_tools/benchmark.rb +83 -0
- data/lib/happy_mapper_tools/stig_attributes.rb +68 -48
- data/lib/inspec_tools/csv.rb +26 -33
- data/lib/inspec_tools/generate_map.rb +35 -0
- data/lib/inspec_tools/inspec.rb +19 -91
- data/lib/inspec_tools/pdf.rb +2 -13
- data/lib/inspec_tools/plugin_cli.rb +14 -25
- data/lib/inspec_tools/xccdf.rb +1 -0
- data/lib/inspec_tools/xlsx_tool.rb +4 -16
- data/lib/utilities/cci_xml.rb +13 -0
- data/lib/utilities/cis_to_nist.rb +11 -0
- data/lib/utilities/inspec_util.rb +16 -75
- data/lib/utilities/mapping_validator.rb +10 -0
- data/lib/utilities/xccdf/from_inspec.rb +89 -0
- data/lib/utilities/xccdf/to_xccdf.rb +388 -0
- data/lib/utilities/xccdf/xccdf_score.rb +116 -0
- metadata +47 -27
- data/CHANGELOG.md +0 -704
- data/lib/data/NIST_Map_02052020_CIS_Controls_Version_7.1_Implementation_Groups_1.2.xlsx +0 -0
- data/lib/data/NIST_Map_09212017B_CSC-CIS_Critical_Security_Controls_VER_6.1_Excel_9.1.2016.xlsx +0 -0
- data/lib/utilities/extract_nist_cis_mapping.rb +0 -57
@@ -0,0 +1,35 @@
|
|
1
|
+
module InspecTools
|
2
|
+
class GenerateMap
|
3
|
+
attr_accessor :text
|
4
|
+
|
5
|
+
def initialize(text = nil)
|
6
|
+
@text = text.nil? ? default_text : text
|
7
|
+
end
|
8
|
+
|
9
|
+
def generate_example(file)
|
10
|
+
File.write(file, @text)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def default_text
|
16
|
+
<<~YML
|
17
|
+
# Setting csv_header to true will skip the csv file header
|
18
|
+
skip_csv_header: true
|
19
|
+
width : 80
|
20
|
+
|
21
|
+
|
22
|
+
control.id: 0
|
23
|
+
control.title: 15
|
24
|
+
control.desc: 16
|
25
|
+
control.tags:
|
26
|
+
severity: 1
|
27
|
+
rid: 8
|
28
|
+
stig_id: 3
|
29
|
+
cci: 2
|
30
|
+
check: 12
|
31
|
+
fix: 10
|
32
|
+
YML
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/inspec_tools/inspec.rb
CHANGED
@@ -9,17 +9,14 @@ require_relative '../happy_mapper_tools/stig_checklist'
|
|
9
9
|
require_relative '../happy_mapper_tools/benchmark'
|
10
10
|
require_relative '../utilities/inspec_util'
|
11
11
|
require_relative 'csv'
|
12
|
-
|
13
|
-
|
14
|
-
# rubocop:disable Metrics/AbcSize
|
15
|
-
# rubocop:disable Metrics/BlockLength
|
16
|
-
# rubocop:disable Style/GuardClause
|
12
|
+
require_relative '../utilities/xccdf/from_inspec'
|
13
|
+
require_relative '../utilities/xccdf/to_xccdf'
|
17
14
|
|
18
15
|
module InspecTools
|
19
|
-
class Inspec
|
20
|
-
def initialize(inspec_json, metadata =
|
16
|
+
class Inspec # rubocop:disable Metrics/ClassLength
|
17
|
+
def initialize(inspec_json, metadata = {})
|
21
18
|
@json = JSON.parse(inspec_json.gsub(/\\+u0000/, ''))
|
22
|
-
@metadata =
|
19
|
+
@metadata = metadata
|
23
20
|
end
|
24
21
|
|
25
22
|
def to_ckl(title = nil, date = nil, cklist = nil)
|
@@ -36,16 +33,15 @@ module InspecTools
|
|
36
33
|
@checklist.to_xml.encode('UTF-8').gsub('<?xml version="1.0"?>', '<?xml version="1.0" encoding="UTF-8"?>').chomp
|
37
34
|
end
|
38
35
|
|
36
|
+
# Convert Inspec result data to XCCDF
|
37
|
+
#
|
38
|
+
# @param attributes [Hash] Optional input attributes
|
39
|
+
# @return [String] XML formatted String
|
39
40
|
def to_xccdf(attributes, verbose = false)
|
40
|
-
|
41
|
-
@attribute = attributes
|
42
|
-
@attribute = {} if @attribute.eql? false
|
41
|
+
data = Utils::FromInspec.new.parse_data_for_xccdf(@json)
|
43
42
|
@verbose = verbose
|
44
|
-
|
45
|
-
|
46
|
-
# populate_profiles @todo populate profiles; not implemented now because its use is deprecated
|
47
|
-
populate_groups
|
48
|
-
@benchmark.to_xml
|
43
|
+
|
44
|
+
Utils::ToXCCDF.new(attributes || {}, data).to_xml(@metadata)
|
49
45
|
end
|
50
46
|
|
51
47
|
####
|
@@ -70,7 +66,7 @@ module InspecTools
|
|
70
66
|
#
|
71
67
|
# @param inspec_json : an inspec profile formatted as a json object
|
72
68
|
###
|
73
|
-
def inspec_json_to_array(inspec_json)
|
69
|
+
def inspec_json_to_array(inspec_json) # rubocop:disable Metrics/CyclomaticComplexity
|
74
70
|
data = []
|
75
71
|
headers = {}
|
76
72
|
inspec_json['controls'].each do |control|
|
@@ -97,10 +93,11 @@ module InspecTools
|
|
97
93
|
@data['controls'] << control
|
98
94
|
end
|
99
95
|
end
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
96
|
+
|
97
|
+
return unless json['profiles'].nil?
|
98
|
+
|
99
|
+
json['controls'].each do |control|
|
100
|
+
@data['controls'] << control
|
104
101
|
end
|
105
102
|
end
|
106
103
|
|
@@ -161,7 +158,7 @@ module InspecTools
|
|
161
158
|
vuln
|
162
159
|
end
|
163
160
|
|
164
|
-
def generate_asset
|
161
|
+
def generate_asset # rubocop:disable Metrics/AbcSize
|
165
162
|
asset = HappyMapperTools::StigChecklist::Asset.new
|
166
163
|
asset.role = !@metadata['role'].nil? ? @metadata['role'] : 'Workstation'
|
167
164
|
asset.type = !@metadata['type'].nil? ? @metadata['type'] : 'Computing'
|
@@ -223,75 +220,6 @@ module InspecTools
|
|
223
220
|
ip
|
224
221
|
end
|
225
222
|
|
226
|
-
def populate_header
|
227
|
-
@benchmark.title = @attribute['benchmark.title']
|
228
|
-
@benchmark.id = @attribute['benchmark.id']
|
229
|
-
@benchmark.description = @attribute['benchmark.description']
|
230
|
-
@benchmark.version = @attribute['benchmark.version']
|
231
|
-
|
232
|
-
@benchmark.status = HappyMapperTools::Benchmark::Status.new
|
233
|
-
@benchmark.status.status = @attribute['benchmark.status']
|
234
|
-
@benchmark.status.date = @attribute['benchmark.status.date']
|
235
|
-
|
236
|
-
@benchmark.notice = HappyMapperTools::Benchmark::Notice.new
|
237
|
-
@benchmark.notice.id = @attribute['benchmark.notice.id']
|
238
|
-
|
239
|
-
@benchmark.plaintext = HappyMapperTools::Benchmark::Plaintext.new
|
240
|
-
@benchmark.plaintext.plaintext = @attribute['benchmark.plaintext']
|
241
|
-
@benchmark.plaintext.id = @attribute['benchmark.plaintext.id']
|
242
|
-
|
243
|
-
@benchmark.reference = HappyMapperTools::Benchmark::ReferenceBenchmark.new
|
244
|
-
@benchmark.reference.href = @attribute['reference.href']
|
245
|
-
@benchmark.reference.dc_publisher = @attribute['reference.dc.publisher']
|
246
|
-
@benchmark.reference.dc_source = @attribute['reference.dc.source']
|
247
|
-
end
|
248
|
-
|
249
|
-
def populate_groups
|
250
|
-
group_array = []
|
251
|
-
@data['controls'].each do |control|
|
252
|
-
group = HappyMapperTools::Benchmark::Group.new
|
253
|
-
group.id = control['id']
|
254
|
-
group.title = control['gtitle']
|
255
|
-
group.description = "<GroupDescription>#{control['gdescription']}</GroupDescription>"
|
256
|
-
|
257
|
-
group.rule = HappyMapperTools::Benchmark::Rule.new
|
258
|
-
group.rule.id = control['rid']
|
259
|
-
group.rule.severity = control['severity']
|
260
|
-
group.rule.weight = control['rweight']
|
261
|
-
group.rule.version = control['rversion']
|
262
|
-
group.rule.title = control['title'].tr("\n", ' ')
|
263
|
-
group.rule.description = "<VulnDiscussion>#{control['desc'].tr("\n", ' ')}</VulnDiscussion><FalsePositives></FalsePositives><FalseNegatives></FalseNegatives><Documentable>false</Documentable><Mitigations></Mitigations><SeverityOverrideGuidance></SeverityOverrideGuidance><PotentialImpacts></PotentialImpacts><ThirdPartyTools></ThirdPartyTools><MitigationControl></MitigationControl><Responsibility></Responsibility><IAControls></IAControls>"
|
264
|
-
|
265
|
-
group.rule.reference = HappyMapperTools::Benchmark::ReferenceGroup.new
|
266
|
-
group.rule.reference.dc_publisher = @attribute['reference.dc.publisher']
|
267
|
-
group.rule.reference.dc_title = @attribute['reference.dc.title']
|
268
|
-
group.rule.reference.dc_subject = @attribute['reference.dc.subject']
|
269
|
-
group.rule.reference.dc_type = @attribute['reference.dc.type']
|
270
|
-
group.rule.reference.dc_identifier = @attribute['reference.dc.identifier']
|
271
|
-
|
272
|
-
group.rule.ident = HappyMapperTools::Benchmark::Ident.new
|
273
|
-
group.rule.ident.system = 'https://public.cyber.mil/stigs/cci/'
|
274
|
-
group.rule.ident.ident = control['cci']
|
275
|
-
|
276
|
-
group.rule.fixtext = HappyMapperTools::Benchmark::Fixtext.new
|
277
|
-
group.rule.fixtext.fixref = control['fixref']
|
278
|
-
group.rule.fixtext.fixtext = control['fix']
|
279
|
-
|
280
|
-
group.rule.fix = HappyMapperTools::Benchmark::Fix.new
|
281
|
-
group.rule.fix.id = control['fixref']
|
282
|
-
|
283
|
-
group.rule.check = HappyMapperTools::Benchmark::Check.new
|
284
|
-
group.rule.check.system = control['checkref']
|
285
|
-
group.rule.check.content_ref = HappyMapperTools::Benchmark::ContentRef.new
|
286
|
-
group.rule.check.content_ref.name = @attribute['content_ref.name']
|
287
|
-
group.rule.check.content_ref.href = @attribute['content_ref.href']
|
288
|
-
group.rule.check.content = control['check']
|
289
|
-
|
290
|
-
group_array << group
|
291
|
-
end
|
292
|
-
@benchmark.group = group_array
|
293
|
-
end
|
294
|
-
|
295
223
|
def generate_title(title, json, date)
|
296
224
|
title ||= "Untitled - Checklist Created from Automated InSpec Results JSON; Profiles: #{json['profiles'].map { |x| x['name'] }.join(' | ')}"
|
297
225
|
title + " Checklist Date: #{date || Date.today.to_s}"
|
data/lib/inspec_tools/pdf.rb
CHANGED
@@ -2,9 +2,9 @@ require 'digest'
|
|
2
2
|
|
3
3
|
require_relative '../utilities/inspec_util'
|
4
4
|
require_relative '../utilities/extract_pdf_text'
|
5
|
-
require_relative '../utilities/extract_nist_cis_mapping'
|
6
5
|
require_relative '../utilities/parser'
|
7
6
|
require_relative '../utilities/text_cleaner'
|
7
|
+
require_relative '../utilities/cis_to_nist'
|
8
8
|
|
9
9
|
# rubocop:disable Metrics/AbcSize
|
10
10
|
# rubocop:disable Metrics/PerceivedComplexity
|
@@ -24,7 +24,7 @@ module InspecTools
|
|
24
24
|
@controls = []
|
25
25
|
@csv_handle = nil
|
26
26
|
@cci_xml = nil
|
27
|
-
@nist_mapping =
|
27
|
+
@nist_mapping = Utils::CisToNist.get_mapping('cis_to_nist_critical_controls')
|
28
28
|
@pdf_text = ''
|
29
29
|
@clean_text = ''
|
30
30
|
@transformed_data = ''
|
@@ -33,7 +33,6 @@ module InspecTools
|
|
33
33
|
@title ||= extract_title
|
34
34
|
clean_pdf_text
|
35
35
|
transform_data
|
36
|
-
read_excl
|
37
36
|
insert_json_metadata
|
38
37
|
@profile['controls'] = parse_controls
|
39
38
|
@profile['sha256'] = Digest::SHA256.hexdigest @profile.to_s
|
@@ -122,15 +121,5 @@ module InspecTools
|
|
122
121
|
def write_clean_text
|
123
122
|
File.write('debug_text', @clean_text)
|
124
123
|
end
|
125
|
-
|
126
|
-
def read_excl
|
127
|
-
nist_map_path = File.join(File.dirname(__FILE__), '../data/NIST_Map_09212017B_CSC-CIS_Critical_Security_Controls_VER_6.1_Excel_9.1.2016.xlsx')
|
128
|
-
excel = Util::ExtractNistMappings.new(nist_map_path)
|
129
|
-
@nist_mapping = excel.full_excl
|
130
|
-
rescue StandardError => e
|
131
|
-
puts "Exception: #{e.message}"
|
132
|
-
puts 'Existing...'
|
133
|
-
exit
|
134
|
-
end
|
135
124
|
end
|
136
125
|
end
|
@@ -15,6 +15,7 @@ module InspecTools
|
|
15
15
|
autoload :Summary, 'inspec_tools/summary'
|
16
16
|
autoload :Threshold, 'inspec_tools/threshold'
|
17
17
|
autoload :XLSXTool, 'inspec_tools/xlsx_tool'
|
18
|
+
autoload :GenerateMap, 'inspec_tools/generate_map'
|
18
19
|
end
|
19
20
|
|
20
21
|
# rubocop:disable Style/GuardClause
|
@@ -23,7 +24,7 @@ module InspecPlugins
|
|
23
24
|
class CliCommand < Inspec.plugin(2, :cli_command) # rubocop:disable Metrics/ClassLength
|
24
25
|
POSSIBLE_LOG_LEVELS = %w{debug info warn error fatal}.freeze
|
25
26
|
|
26
|
-
class_option :log_directory, type: :string, aliases: :l, desc: '
|
27
|
+
class_option :log_directory, type: :string, aliases: :l, desc: 'Provide log location'
|
27
28
|
class_option :log_level, type: :string, desc: "Set the logging level: #{POSSIBLE_LOG_LEVELS}"
|
28
29
|
|
29
30
|
subcommand_desc 'tools [COMMAND]', 'Runs inspec_tools commands through Inspec'
|
@@ -54,12 +55,18 @@ module InspecPlugins
|
|
54
55
|
|
55
56
|
desc 'inspec2xccdf', 'inspec2xccdf translates an inspec profile and attributes files to an xccdf file'
|
56
57
|
long_desc InspecTools::Help.text(:inspec2xccdf)
|
57
|
-
option :inspec_json, required: true, aliases: '-j'
|
58
|
-
|
59
|
-
option :
|
58
|
+
option :inspec_json, required: true, aliases: '-j',
|
59
|
+
desc: 'path to InSpec JSON file created'
|
60
|
+
option :attributes, required: true, aliases: '-a',
|
61
|
+
desc: 'path to yml file that provides the required attributes for the XCCDF document. These attributes are parts of XCCDF document which do not fit into the InSpec schema.'
|
62
|
+
option :output, required: true, aliases: '-o',
|
63
|
+
desc: 'name or path to create the XCCDF and title to give the XCCDF'
|
64
|
+
option :metadata, required: false, type: :string, aliases: '-m',
|
65
|
+
desc: 'path to JSON file with additional host metadata for the XCCDF file'
|
60
66
|
def inspec2xccdf
|
61
67
|
json = File.read(options[:inspec_json])
|
62
|
-
|
68
|
+
metadata = options[:metadata] ? JSON.parse(File.read(options[:metadata])) : {}
|
69
|
+
inspec_tool = InspecTools::Inspec.new(json, metadata)
|
63
70
|
attr_hsh = YAML.load_file(options[:attributes])
|
64
71
|
xccdf = inspec_tool.to_xccdf(attr_hsh)
|
65
72
|
File.write(options[:output], xccdf)
|
@@ -136,26 +143,8 @@ module InspecPlugins
|
|
136
143
|
|
137
144
|
desc 'generate_map', 'Generates mapping template from CSV to Inspec Controls'
|
138
145
|
def generate_map
|
139
|
-
|
140
|
-
|
141
|
-
skip_csv_header: true
|
142
|
-
width : 80
|
143
|
-
|
144
|
-
|
145
|
-
control.id: 0
|
146
|
-
control.title: 15
|
147
|
-
control.desc: 16
|
148
|
-
control.tags:
|
149
|
-
severity: 1
|
150
|
-
rid: 8
|
151
|
-
stig_id: 3
|
152
|
-
cci: 2
|
153
|
-
check: 12
|
154
|
-
fix: 10
|
155
|
-
'
|
156
|
-
myfile = File.new('mapping.yml', 'w')
|
157
|
-
myfile.puts template
|
158
|
-
myfile.close
|
146
|
+
generator = InspecTools::GenerateMap.new
|
147
|
+
generator.generate_example('mapping.yml')
|
159
148
|
end
|
160
149
|
|
161
150
|
desc 'generate_ckl_metadata', 'Generate metadata file that can be passed to inspec2ckl'
|
data/lib/inspec_tools/xccdf.rb
CHANGED
@@ -140,6 +140,7 @@ module InspecTools
|
|
140
140
|
control['tags']['documentable'] = group.rule.description.documentable if group.rule.description.documentable != ''
|
141
141
|
control['tags']['mitigations'] = group.rule.description.false_negatives if group.rule.description.mitigations != ''
|
142
142
|
control['tags']['severity_override_guidance'] = group.rule.description.severity_override_guidance if group.rule.description.severity_override_guidance != ''
|
143
|
+
control['tags']['security_override_guidance'] = group.rule.description.security_override_guidance if group.rule.description.security_override_guidance != ''
|
143
144
|
control['tags']['potential_impacts'] = group.rule.description.potential_impacts if group.rule.description.potential_impacts != ''
|
144
145
|
control['tags']['third_party_tools'] = group.rule.description.third_party_tools if group.rule.description.third_party_tools != ''
|
145
146
|
control['tags']['mitigation_controls'] = group.rule.description.mitigation_controls if group.rule.description.mitigation_controls != ''
|
@@ -3,9 +3,10 @@ require 'inspec-objects'
|
|
3
3
|
require 'word_wrap'
|
4
4
|
require 'yaml'
|
5
5
|
require 'digest'
|
6
|
-
require 'roo'
|
7
6
|
|
8
7
|
require_relative '../utilities/inspec_util'
|
8
|
+
require_relative '../utilities/cis_to_nist'
|
9
|
+
require_relative '../utilities/mapping_validator'
|
9
10
|
|
10
11
|
# rubocop:disable Metrics/AbcSize
|
11
12
|
# rubocop:disable Metrics/PerceivedComplexity
|
@@ -14,15 +15,14 @@ require_relative '../utilities/inspec_util'
|
|
14
15
|
module InspecTools
|
15
16
|
# Methods for converting from XLS to various formats
|
16
17
|
class XLSXTool
|
17
|
-
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'))
|
18
18
|
LATEST_NIST_REV = 'Rev_4'.freeze
|
19
19
|
|
20
20
|
def initialize(xlsx, mapping, name, verbose = false)
|
21
21
|
@name = name
|
22
22
|
@xlsx = xlsx
|
23
|
-
@mapping = mapping
|
23
|
+
@mapping = Utils::MappingValidator.validate(mapping)
|
24
24
|
@verbose = verbose
|
25
|
-
@cis_to_nist =
|
25
|
+
@cis_to_nist = Utils::CisToNist.get_mapping('cis_to_nist_mapping')
|
26
26
|
end
|
27
27
|
|
28
28
|
def to_ckl
|
@@ -46,18 +46,6 @@ module InspecTools
|
|
46
46
|
|
47
47
|
private
|
48
48
|
|
49
|
-
def get_cis_to_nist_control_mapping(spreadsheet)
|
50
|
-
cis_to_nist = {}
|
51
|
-
spreadsheet.sheet(3).each do |row|
|
52
|
-
if row[3].is_a? Numeric
|
53
|
-
cis_to_nist[row[3].to_s] = row[0]
|
54
|
-
else
|
55
|
-
cis_to_nist[row[2].to_s] = row[0] unless (row[2] == '') || row[2].to_i.nil?
|
56
|
-
end
|
57
|
-
end
|
58
|
-
cis_to_nist
|
59
|
-
end
|
60
|
-
|
61
49
|
def insert_json_metadata
|
62
50
|
@profile['name'] = @name
|
63
51
|
@profile['title'] = 'InSpec Profile'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module Utils
|
4
|
+
class CciXml
|
5
|
+
def self.get_cci_list(cci_list_file)
|
6
|
+
path = File.expand_path(File.join(File.expand_path(__dir__), '..', 'data', cci_list_file))
|
7
|
+
raise "CCI list does not exist at #{path}" unless File.exist?(path)
|
8
|
+
|
9
|
+
cci_list = Nokogiri::XML(File.open(path))
|
10
|
+
cci_list.remove_namespaces!
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Utils
|
2
|
+
class CisToNist
|
3
|
+
def self.get_mapping(mapping_file)
|
4
|
+
path = File.expand_path(File.join(File.expand_path(__dir__), '..', 'data', mapping_file))
|
5
|
+
raise "CIS to NIST control mapping does not exist at #{path}. Has it been generated?" unless File.exist?(path)
|
6
|
+
|
7
|
+
mapping = File.open(path)
|
8
|
+
Marshal.load(mapping)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -11,16 +11,10 @@ require 'overrides/true_class'
|
|
11
11
|
require 'overrides/nil_class'
|
12
12
|
require 'overrides/object'
|
13
13
|
require 'overrides/string'
|
14
|
-
|
15
|
-
# rubocop:disable Metrics/ClassLength
|
16
|
-
# rubocop:disable Metrics/AbcSize
|
17
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
18
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
19
|
-
# rubocop:disable Metrics/MethodLength
|
14
|
+
require 'rubocop'
|
20
15
|
|
21
16
|
module Utils
|
22
|
-
class InspecUtil
|
23
|
-
DATA_NOT_FOUND_MESSAGE = 'N/A'.freeze
|
17
|
+
class InspecUtil # rubocop:disable Metrics/ClassLength
|
24
18
|
WIDTH = 80
|
25
19
|
IMPACT_SCORES = {
|
26
20
|
'none' => 0.0,
|
@@ -30,56 +24,7 @@ module Utils
|
|
30
24
|
'critical' => 0.9
|
31
25
|
}.freeze
|
32
26
|
|
33
|
-
def self.
|
34
|
-
data = {}
|
35
|
-
|
36
|
-
controls = []
|
37
|
-
if json['profiles'].nil?
|
38
|
-
controls = json['controls']
|
39
|
-
elsif json['profiles'].length == 1
|
40
|
-
controls = json['profiles'].last['controls']
|
41
|
-
else
|
42
|
-
json['profiles'].each do |profile|
|
43
|
-
controls.concat(profile['controls'])
|
44
|
-
end
|
45
|
-
end
|
46
|
-
c_data = {}
|
47
|
-
|
48
|
-
controls.each do |control|
|
49
|
-
c_id = control['id'].to_sym
|
50
|
-
c_data[c_id] = {}
|
51
|
-
c_data[c_id]['id'] = control['id'] || DATA_NOT_FOUND_MESSAGE
|
52
|
-
c_data[c_id]['title'] = control['title'] || DATA_NOT_FOUND_MESSAGE
|
53
|
-
c_data[c_id]['desc'] = control['desc'] || DATA_NOT_FOUND_MESSAGE
|
54
|
-
c_data[c_id]['severity'] = control['tags']['severity'] || DATA_NOT_FOUND_MESSAGE
|
55
|
-
c_data[c_id]['gid'] = control['tags']['gid'] || DATA_NOT_FOUND_MESSAGE
|
56
|
-
c_data[c_id]['gtitle'] = control['tags']['gtitle'] || DATA_NOT_FOUND_MESSAGE
|
57
|
-
c_data[c_id]['gdescription'] = control['tags']['gdescription'] || DATA_NOT_FOUND_MESSAGE
|
58
|
-
c_data[c_id]['rid'] = control['tags']['rid'] || DATA_NOT_FOUND_MESSAGE
|
59
|
-
c_data[c_id]['rversion'] = control['tags']['rversion'] || DATA_NOT_FOUND_MESSAGE
|
60
|
-
c_data[c_id]['rweight'] = control['tags']['rweight'] || DATA_NOT_FOUND_MESSAGE
|
61
|
-
c_data[c_id]['stig_id'] = control['tags']['stig_id'] || DATA_NOT_FOUND_MESSAGE
|
62
|
-
c_data[c_id]['cci'] = control['tags']['cci'] || DATA_NOT_FOUND_MESSAGE
|
63
|
-
c_data[c_id]['nist'] = control['tags']['nist'] || ['unmapped']
|
64
|
-
c_data[c_id]['check'] = control['tags']['check'] || DATA_NOT_FOUND_MESSAGE
|
65
|
-
c_data[c_id]['checkref'] = control['tags']['checkref'] || DATA_NOT_FOUND_MESSAGE
|
66
|
-
c_data[c_id]['fix'] = control['tags']['fix'] || DATA_NOT_FOUND_MESSAGE
|
67
|
-
c_data[c_id]['fixref'] = control['tags']['fixref'] || DATA_NOT_FOUND_MESSAGE
|
68
|
-
c_data[c_id]['fix_id'] = control['tags']['fix_id'] || DATA_NOT_FOUND_MESSAGE
|
69
|
-
c_data[c_id]['rationale'] = control['tags']['rationale'] || DATA_NOT_FOUND_MESSAGE
|
70
|
-
c_data[c_id]['cis_family'] = control['tags']['cis_family'] || DATA_NOT_FOUND_MESSAGE
|
71
|
-
c_data[c_id]['cis_rid'] = control['tags']['cis_rid'] || DATA_NOT_FOUND_MESSAGE
|
72
|
-
c_data[c_id]['cis_level'] = control['tags']['cis_level'] || DATA_NOT_FOUND_MESSAGE
|
73
|
-
c_data[c_id]['impact'] = control['impact'].to_s || DATA_NOT_FOUND_MESSAGE
|
74
|
-
c_data[c_id]['code'] = control['code'].to_s || DATA_NOT_FOUND_MESSAGE
|
75
|
-
end
|
76
|
-
|
77
|
-
data['controls'] = c_data.values
|
78
|
-
data['status'] = 'success'
|
79
|
-
data
|
80
|
-
end
|
81
|
-
|
82
|
-
def self.parse_data_for_ckl(json)
|
27
|
+
def self.parse_data_for_ckl(json) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
83
28
|
data = {}
|
84
29
|
|
85
30
|
# Parse for inspec profile results json
|
@@ -220,7 +165,7 @@ module Utils
|
|
220
165
|
end
|
221
166
|
|
222
167
|
private_class_method def self.string_to_impact(severity, use_cvss_terms)
|
223
|
-
if
|
168
|
+
if %r{none|na|n/a|not[_|(\s*)]?applicable}i.match?(severity)
|
224
169
|
impact = 0.0 # Informative
|
225
170
|
elsif /low|cat(egory)?\s*(iii|3)/i.match?(severity)
|
226
171
|
impact = 0.3 # Low Impact
|
@@ -247,13 +192,10 @@ module Utils
|
|
247
192
|
end
|
248
193
|
|
249
194
|
IMPACT_SCORES.reverse_each do |name, impact_score|
|
250
|
-
if name == 'critical' && value >= impact_score && use_cvss_terms
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
else
|
255
|
-
next
|
256
|
-
end
|
195
|
+
return 'high' if name == 'critical' && value >= impact_score && use_cvss_terms
|
196
|
+
return name if value >= impact_score
|
197
|
+
|
198
|
+
next
|
257
199
|
end
|
258
200
|
end
|
259
201
|
|
@@ -276,7 +218,7 @@ module Utils
|
|
276
218
|
WordWrap.ww(str.to_s, width)
|
277
219
|
end
|
278
220
|
|
279
|
-
private_class_method def self.generate_controls(inspec_json)
|
221
|
+
private_class_method def self.generate_controls(inspec_json) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
280
222
|
controls = []
|
281
223
|
inspec_json['controls'].each do |json_control|
|
282
224
|
control = ::Inspec::Object::Control.new
|
@@ -314,6 +256,7 @@ module Utils
|
|
314
256
|
control.add_tag(::Inspec::Object::Tag.new('documentable', json_control['tags']['documentable'])) unless json_control['tags']['documentable'].blank?
|
315
257
|
control.add_tag(::Inspec::Object::Tag.new('mitigations', json_control['tags']['mitigations'])) unless json_control['tags']['mitigations'].blank?
|
316
258
|
control.add_tag(::Inspec::Object::Tag.new('severity_override_guidance', json_control['tags']['severity_override_guidance'])) unless json_control['tags']['severity_override_guidance'].blank?
|
259
|
+
control.add_tag(::Inspec::Object::Tag.new('security_override_guidance', json_control['tags']['security_override_guidance'])) unless json_control['tags']['security_override_guidance'].blank?
|
317
260
|
control.add_tag(::Inspec::Object::Tag.new('potential_impacts', json_control['tags']['potential_impacts'])) unless json_control['tags']['potential_impacts'].blank?
|
318
261
|
control.add_tag(::Inspec::Object::Tag.new('third_party_tools', json_control['tags']['third_party_tools'])) unless json_control['tags']['third_party_tools'].blank?
|
319
262
|
control.add_tag(::Inspec::Object::Tag.new('mitigation_controls', json_control['tags']['mitigation_controls'])) unless json_control['tags']['mitigation_controls'].blank?
|
@@ -382,7 +325,7 @@ module Utils
|
|
382
325
|
myfile.puts readme_contents
|
383
326
|
end
|
384
327
|
|
385
|
-
private_class_method def self.unpack_profile(directory, controls, separated, output_format)
|
328
|
+
private_class_method def self.unpack_profile(directory, controls, separated, output_format) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
386
329
|
FileUtils.rm_rf(directory) if Dir.exist?(directory)
|
387
330
|
Dir.mkdir directory unless Dir.exist?(directory)
|
388
331
|
Dir.mkdir "#{directory}/controls" unless Dir.exist?("#{directory}/controls")
|
@@ -393,7 +336,7 @@ module Utils
|
|
393
336
|
file_name = control.id.to_s
|
394
337
|
myfile = File.new("#{directory}/controls/#{file_name}.rb", 'w')
|
395
338
|
myfile.puts "# encoding: UTF-8\n\n"
|
396
|
-
myfile.puts wrap(control.to_ruby
|
339
|
+
myfile.puts wrap(control.to_ruby, WIDTH) + "\n"
|
397
340
|
myfile.close
|
398
341
|
end
|
399
342
|
else
|
@@ -424,12 +367,10 @@ module Utils
|
|
424
367
|
end
|
425
368
|
myfile.close
|
426
369
|
end
|
370
|
+
config_store = ::RuboCop::ConfigStore.new
|
371
|
+
config_store.options_config = File.join(File.dirname(__FILE__), '../data/rubocop.yml')
|
372
|
+
rubocop = ::RuboCop::Runner.new({ auto_correct: true }, config_store)
|
373
|
+
rubocop.run([directory])
|
427
374
|
end
|
428
375
|
end
|
429
376
|
end
|
430
|
-
|
431
|
-
# rubocop:enable Metrics/ClassLength
|
432
|
-
# rubocop:enable Metrics/AbcSize
|
433
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
434
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
435
|
-
# rubocop:enable Metrics/MethodLength
|