inspec_tools 2.0.3 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|