inspec_tools 0.0.0.1.ENOTAG
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 +7 -0
- data/CHANGELOG.md +662 -0
- data/LICENSE.md +15 -0
- data/README.md +329 -0
- data/Rakefile +30 -0
- data/exe/inspec_tools +14 -0
- 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/data/README.TXT +25 -0
- data/lib/data/U_CCI_List.xml +38403 -0
- data/lib/data/attributes.yml +23 -0
- data/lib/data/cci2html.xsl +136 -0
- data/lib/data/mapping.yml +17 -0
- data/lib/data/stig.csv +1 -0
- data/lib/data/threshold.yaml +83 -0
- data/lib/exceptions/impact_input_error.rb +6 -0
- data/lib/exceptions/severity_input_error.rb +6 -0
- data/lib/happy_mapper_tools/benchmark.rb +161 -0
- data/lib/happy_mapper_tools/cci_attributes.rb +66 -0
- data/lib/happy_mapper_tools/stig_attributes.rb +196 -0
- data/lib/happy_mapper_tools/stig_checklist.rb +99 -0
- data/lib/inspec_tools.rb +17 -0
- data/lib/inspec_tools/ckl.rb +20 -0
- data/lib/inspec_tools/cli.rb +31 -0
- data/lib/inspec_tools/csv.rb +101 -0
- data/lib/inspec_tools/help.rb +9 -0
- data/lib/inspec_tools/help/compliance.md +7 -0
- data/lib/inspec_tools/help/csv2inspec.md +5 -0
- data/lib/inspec_tools/help/inspec2ckl.md +5 -0
- data/lib/inspec_tools/help/inspec2csv.md +5 -0
- data/lib/inspec_tools/help/inspec2xccdf.md +5 -0
- data/lib/inspec_tools/help/pdf2inspec.md +6 -0
- data/lib/inspec_tools/help/summary.md +5 -0
- data/lib/inspec_tools/help/xccdf2inspec.md +5 -0
- data/lib/inspec_tools/inspec.rb +331 -0
- data/lib/inspec_tools/pdf.rb +136 -0
- data/lib/inspec_tools/plugin.rb +15 -0
- data/lib/inspec_tools/plugin_cli.rb +278 -0
- data/lib/inspec_tools/summary.rb +126 -0
- data/lib/inspec_tools/version.rb +8 -0
- data/lib/inspec_tools/xccdf.rb +155 -0
- data/lib/inspec_tools/xlsx_tool.rb +148 -0
- data/lib/inspec_tools_plugin.rb +7 -0
- data/lib/overrides/false_class.rb +5 -0
- data/lib/overrides/nil_class.rb +5 -0
- data/lib/overrides/object.rb +5 -0
- data/lib/overrides/string.rb +5 -0
- data/lib/overrides/true_class.rb +5 -0
- data/lib/utilities/csv_util.rb +14 -0
- data/lib/utilities/extract_nist_cis_mapping.rb +57 -0
- data/lib/utilities/extract_pdf_text.rb +20 -0
- data/lib/utilities/inspec_util.rb +435 -0
- data/lib/utilities/parser.rb +373 -0
- data/lib/utilities/text_cleaner.rb +69 -0
- metadata +359 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'happymapper'
|
4
|
+
require 'nokogiri'
|
5
|
+
|
6
|
+
# rubocop:disable Naming/ClassAndModuleCamelCase
|
7
|
+
|
8
|
+
module HappyMapperTools
|
9
|
+
module CCIAttributes
|
10
|
+
class Reference
|
11
|
+
include HappyMapper
|
12
|
+
tag 'reference'
|
13
|
+
|
14
|
+
attribute :creator, String, tag: 'creator'
|
15
|
+
attribute :title, String, tag: 'title'
|
16
|
+
attribute :version, String, tag: 'version'
|
17
|
+
attribute :location, String, tag: 'location'
|
18
|
+
attribute :index, String, tag: 'index'
|
19
|
+
end
|
20
|
+
|
21
|
+
class CCI_Item
|
22
|
+
include HappyMapper
|
23
|
+
tag 'cci_item'
|
24
|
+
|
25
|
+
attribute :id, String, tag: 'id'
|
26
|
+
element :status, String, tag: 'status'
|
27
|
+
element :publishdate, String, tag: 'publishdate'
|
28
|
+
element :contributor, String, tag: 'contributor'
|
29
|
+
element :definition, String, tag: 'definition'
|
30
|
+
element :type, String, tag: 'type'
|
31
|
+
has_many :references, Reference, xpath: 'xmlns:references'
|
32
|
+
end
|
33
|
+
|
34
|
+
class Metadata
|
35
|
+
include HappyMapper
|
36
|
+
tag 'metadata'
|
37
|
+
|
38
|
+
element :version, String, tag: 'version'
|
39
|
+
element :publishdate, String, tag: 'publishdate'
|
40
|
+
end
|
41
|
+
|
42
|
+
class CCI_List
|
43
|
+
include HappyMapper
|
44
|
+
tag 'cci_list'
|
45
|
+
|
46
|
+
attribute :xsi, String, tag: 'xsi', namespace: 'xmlns'
|
47
|
+
attribute :schemaLocation, String, tag: 'schemaLocation', namespace: 'xmlns'
|
48
|
+
has_one :metadata, Metadata, tag: 'metadata'
|
49
|
+
has_many :cci_items, CCI_Item, xpath: 'xmlns:cci_items'
|
50
|
+
|
51
|
+
def fetch_nists(ccis)
|
52
|
+
ccis = [ccis] unless ccis.is_a?(Array)
|
53
|
+
|
54
|
+
# some of the XCCDF files were having CCE- tags show up which
|
55
|
+
# we don't support, not sure if this is a typo on their part or
|
56
|
+
# we need to see about supporting CCE tags but ... for now
|
57
|
+
filtered_ccis = ccis.select { |f| /CCI-/.match(f) }
|
58
|
+
filtered_ccis.map do |cci|
|
59
|
+
cci_items.find { |item| item.id == cci }.references.max_by(&:version).index
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# rubocop:enable Naming/ClassAndModuleCamelCase
|
@@ -0,0 +1,196 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module HappyMapperTools
|
4
|
+
module StigAttributes
|
5
|
+
require 'happymapper'
|
6
|
+
require 'nokogiri'
|
7
|
+
require 'colorize'
|
8
|
+
|
9
|
+
class ContentRef
|
10
|
+
include HappyMapper
|
11
|
+
tag 'check-content-ref'
|
12
|
+
attribute :name, String, tag: 'name'
|
13
|
+
attribute :href, String, tag: 'href'
|
14
|
+
end
|
15
|
+
|
16
|
+
class Check
|
17
|
+
include HappyMapper
|
18
|
+
tag 'check'
|
19
|
+
|
20
|
+
element :content_ref, ContentRef, tag: 'check-content-ref'
|
21
|
+
element :content, String, tag: 'check-content'
|
22
|
+
end
|
23
|
+
|
24
|
+
class Fix
|
25
|
+
include HappyMapper
|
26
|
+
tag 'fix'
|
27
|
+
|
28
|
+
attribute :id, String, tag: 'id'
|
29
|
+
end
|
30
|
+
|
31
|
+
class DescriptionDetails
|
32
|
+
include HappyMapper
|
33
|
+
tag 'Details'
|
34
|
+
|
35
|
+
element :vuln_discussion, String, tag: 'VulnDiscussion'
|
36
|
+
element :false_positives, String, tag: 'FalsePositives'
|
37
|
+
element :false_negatives, String, tag: 'FalseNegatives'
|
38
|
+
element :documentable, Boolean, tag: 'Documentable'
|
39
|
+
element :mitigations, String, tag: 'Mitigations'
|
40
|
+
element :severity_override_guidance, String, tag: 'SeverityOverrideGuidance'
|
41
|
+
element :potential_impacts, String, tag: 'PotentialImpacts'
|
42
|
+
element :third_party_tools, String, tag: 'ThirdPartyTools'
|
43
|
+
element :mitigation_controls, String, tag: 'MitigationControl'
|
44
|
+
element :responsibility, String, tag: 'Responsibility'
|
45
|
+
element :ia_controls, String, tag: 'IAControls'
|
46
|
+
end
|
47
|
+
|
48
|
+
class Description
|
49
|
+
include HappyMapper
|
50
|
+
tag 'description'
|
51
|
+
|
52
|
+
content :details, DescriptionDetails
|
53
|
+
|
54
|
+
detail_tags = %i(vuln_discussion false_positives false_negatives documentable
|
55
|
+
mitigations severity_override_guidance potential_impacts
|
56
|
+
third_party_tools mitigation_controls responsibility ia_controls)
|
57
|
+
|
58
|
+
detail_tags.each do |name|
|
59
|
+
define_method name do
|
60
|
+
details.send(name)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class ReferenceInfo
|
66
|
+
include HappyMapper
|
67
|
+
tag 'reference'
|
68
|
+
|
69
|
+
attribute :href, String, tag: 'href'
|
70
|
+
element :dc_publisher, String, tag: 'publisher', namespace: 'dc'
|
71
|
+
element :dc_source, String, tag: 'source', namespace: 'dc'
|
72
|
+
element :dc_title, String, tag: 'title', namespace: 'dc'
|
73
|
+
element :dc_type, String, tag: 'type', namespace: 'dc'
|
74
|
+
element :dc_subject, String, tag: 'subject', namespace: 'dc'
|
75
|
+
element :dc_identifier, String, tag: 'identifier', namespace: 'dc'
|
76
|
+
end
|
77
|
+
|
78
|
+
class Rule
|
79
|
+
include HappyMapper
|
80
|
+
tag 'Rule'
|
81
|
+
|
82
|
+
attribute :id, String, tag: 'id'
|
83
|
+
attribute :severity, String, tag: 'severity'
|
84
|
+
element :version, String, tag: 'version'
|
85
|
+
element :title, String, tag: 'title'
|
86
|
+
has_one :description, Description, tag: 'description'
|
87
|
+
element :reference, ReferenceInfo, tag: 'reference'
|
88
|
+
has_many :idents, String, tag: 'ident'
|
89
|
+
element :fixtext, String, tag: 'fixtext'
|
90
|
+
has_one :fix, Fix, tag: 'fix'
|
91
|
+
has_one :check, Check, tag: 'check'
|
92
|
+
end
|
93
|
+
|
94
|
+
class Group
|
95
|
+
include HappyMapper
|
96
|
+
tag 'Group'
|
97
|
+
|
98
|
+
attribute :id, String, tag: 'id'
|
99
|
+
element :title, String, tag: 'title'
|
100
|
+
element :description, String, tag: 'description'
|
101
|
+
has_one :rule, Rule, tag: 'Rule'
|
102
|
+
end
|
103
|
+
|
104
|
+
class ReleaseDate
|
105
|
+
include HappyMapper
|
106
|
+
tag 'status'
|
107
|
+
|
108
|
+
attribute :release_date, String, tag: 'date'
|
109
|
+
end
|
110
|
+
|
111
|
+
class Notice
|
112
|
+
include HappyMapper
|
113
|
+
tag 'notice'
|
114
|
+
attribute :id, String, tag: 'id'
|
115
|
+
attribute :xml_lang, String, namespace: 'xml', tag: 'lang'
|
116
|
+
content :notice, String, tag: 'notice'
|
117
|
+
end
|
118
|
+
|
119
|
+
class Plaintext
|
120
|
+
include HappyMapper
|
121
|
+
tag 'plain-text'
|
122
|
+
attribute :id, String, tag: 'id'
|
123
|
+
content :plaintext, String
|
124
|
+
end
|
125
|
+
|
126
|
+
class Benchmark
|
127
|
+
include HappyMapper
|
128
|
+
tag 'Benchmark'
|
129
|
+
|
130
|
+
has_one :release_date, ReleaseDate, tag: 'status'
|
131
|
+
attribute :id, String, tag: 'id'
|
132
|
+
element :status, String, tag: 'status'
|
133
|
+
element :title, String, tag: 'title'
|
134
|
+
element :description, String, tag: 'description'
|
135
|
+
element :version, String, tag: 'version'
|
136
|
+
element :notice, Notice, tag: 'notice'
|
137
|
+
has_one :reference, ReferenceInfo, tag: 'reference'
|
138
|
+
element :plaintext, Plaintext, tag: 'plain-text'
|
139
|
+
has_many :group, Group, tag: 'Group'
|
140
|
+
end
|
141
|
+
|
142
|
+
class DescriptionDetailsType
|
143
|
+
def self.type
|
144
|
+
DescriptionDetails
|
145
|
+
end
|
146
|
+
|
147
|
+
def self.apply(value) # rubocop:disable Metrics/AbcSize
|
148
|
+
value = value.gsub('&', 'and')
|
149
|
+
DescriptionDetails.parse "<Details>#{value}</Details>"
|
150
|
+
rescue Nokogiri::XML::SyntaxError
|
151
|
+
allowed_tags = %w{VulnDiscussion FalsePositives FalseNegatives Documentable
|
152
|
+
Mitigations SeverityOverrideGuidance PotentialImpacts
|
153
|
+
PotentialImpacts ThirdPartyTools MitigationControl
|
154
|
+
Responsibility IAControls}
|
155
|
+
|
156
|
+
tags_found = value.scan(%r{(?<=<)([^\/]*?)((?= \/>)|(?=>))}).to_a
|
157
|
+
|
158
|
+
tags_found = tags_found.uniq.flatten.reject!(&:empty?)
|
159
|
+
offending_tags = tags_found - allowed_tags
|
160
|
+
|
161
|
+
if offending_tags.count > 1
|
162
|
+
puts "\n\nThe non-standard tags: #{offending_tags.to_s.colorize(:red)}" \
|
163
|
+
' were found in: ' + "\n\n#{value}"
|
164
|
+
else
|
165
|
+
puts "\n\nThe non-standard tag: #{offending_tags.to_s.colorize(:red)}" \
|
166
|
+
' was found in: ' + "\n\n#{value}"
|
167
|
+
end
|
168
|
+
puts "\n\nPlease:\n "
|
169
|
+
option_one = '(1) ' + '(best)'.colorize(:green) + ' Use the ' +
|
170
|
+
'`-r --replace-tags array` '.colorize(:light_yellow) +
|
171
|
+
'(case sensitive) option to replace the offending tags ' \
|
172
|
+
'during processing of the XCCDF ' \
|
173
|
+
'file to use the ' +
|
174
|
+
"`$#{offending_tags[0]}` " .colorize(:light_green) +
|
175
|
+
'syntax in your InSpec profile.'
|
176
|
+
option_two = '(2) Update your XCCDF file to *not use* non-standard XCCDF ' \
|
177
|
+
'elements within ' +
|
178
|
+
'`<`,`>`, `<` '.colorize(:red) +
|
179
|
+
'or '.colorize(:default) +
|
180
|
+
'`>` '.colorize(:red) +
|
181
|
+
'as "placeholders", and use something that doesn\'t confuse ' \
|
182
|
+
'the XML parser, such as : ' +
|
183
|
+
"`$#{offending_tags[0]}`" .colorize(:light_green)
|
184
|
+
puts option_one
|
185
|
+
puts "\n"
|
186
|
+
puts option_two
|
187
|
+
# exit
|
188
|
+
end
|
189
|
+
|
190
|
+
def self.apply?(value, _convert_to_type)
|
191
|
+
value.is_a?(String)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
HappyMapper::SupportedTypes.register DescriptionDetailsType
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'happymapper'
|
4
|
+
require 'nokogiri'
|
5
|
+
|
6
|
+
module HappyMapperTools
|
7
|
+
module StigChecklist
|
8
|
+
# see: https://github.com/dam5s/happymapper
|
9
|
+
# Class Asset maps from the 'Asset' from Checklist XML file using HappyMapper
|
10
|
+
class Asset
|
11
|
+
include HappyMapper
|
12
|
+
tag 'ASSET'
|
13
|
+
element :role, String, tag: 'ROLE'
|
14
|
+
element :type, String, tag: 'ASSET_TYPE'
|
15
|
+
element :host_name, String, tag: 'HOST_NAME'
|
16
|
+
element :host_ip, String, tag: 'HOST_IP'
|
17
|
+
element :host_mac, String, tag: 'HOST_MAC'
|
18
|
+
element :host_guid, String, tag: 'HOST_GUID'
|
19
|
+
element :host_fqdn, String, tag: 'HOST_FQDN'
|
20
|
+
element :tech_area, String, tag: 'TECH_AREA'
|
21
|
+
element :target_key, String, tag: 'TARGET_KEY'
|
22
|
+
element :web_or_database, String, tag: 'WEB_OR_DATABASE'
|
23
|
+
element :web_db_site, String, tag: 'WEB_DB_SITE'
|
24
|
+
element :web_db_instance, String, tag: 'WEB_DB_INSTANCE'
|
25
|
+
end
|
26
|
+
|
27
|
+
# Class Asset maps from the 'SI_DATA' from Checklist XML file using HappyMapper
|
28
|
+
class SiData
|
29
|
+
include HappyMapper
|
30
|
+
tag 'SI_DATA'
|
31
|
+
element :name, String, tag: 'SID_NAME'
|
32
|
+
element :data, String, tag: 'SID_DATA'
|
33
|
+
end
|
34
|
+
|
35
|
+
# Class Asset maps from the 'STIG_INFO' from Checklist XML file using HappyMapper
|
36
|
+
class StigInfo
|
37
|
+
include HappyMapper
|
38
|
+
tag 'STIG_INFO'
|
39
|
+
has_many :si_data, SiData, tag: 'SI_DATA'
|
40
|
+
end
|
41
|
+
|
42
|
+
# Class Asset maps from the 'STIG_DATA' from Checklist XML file using HappyMapper
|
43
|
+
class StigData
|
44
|
+
include HappyMapper
|
45
|
+
|
46
|
+
def initialize(attrib = nil, data = nil)
|
47
|
+
self.attrib = attrib
|
48
|
+
self.data = data
|
49
|
+
end
|
50
|
+
|
51
|
+
tag 'STIG_DATA'
|
52
|
+
has_one :attrib, String, tag: 'VULN_ATTRIBUTE'
|
53
|
+
has_one :data, String, tag: 'ATTRIBUTE_DATA'
|
54
|
+
end
|
55
|
+
|
56
|
+
# Class Asset maps from the 'VULN' from Checklist XML file using HappyMapper
|
57
|
+
class Vuln
|
58
|
+
include HappyMapper
|
59
|
+
tag 'VULN'
|
60
|
+
has_many :stig_data, StigData, tag: 'STIG_DATA'
|
61
|
+
has_one :status, String, tag: 'STATUS'
|
62
|
+
has_one :finding_details, String, tag: 'FINDING_DETAILS'
|
63
|
+
has_one :comments, String, tag: 'COMMENTS'
|
64
|
+
has_one :severity_override, String, tag: 'SEVERITY_OVERRIDE'
|
65
|
+
has_one :severity_justification, String, tag: 'SEVERITY_JUSTIFICATION'
|
66
|
+
end
|
67
|
+
|
68
|
+
# Class Asset maps from the 'iSTIG' from Checklist XML file using HappyMapper
|
69
|
+
class IStig
|
70
|
+
include HappyMapper
|
71
|
+
tag 'iSTIG'
|
72
|
+
has_one :stig_info, StigInfo, tag: 'STIG_INFO'
|
73
|
+
has_many :vuln, Vuln, tag: 'VULN'
|
74
|
+
end
|
75
|
+
|
76
|
+
# Class Asset maps from the 'STIGS' from Checklist XML file using HappyMapper
|
77
|
+
class Stigs
|
78
|
+
include HappyMapper
|
79
|
+
tag 'STIGS'
|
80
|
+
has_one :istig, IStig, tag: 'iSTIG'
|
81
|
+
end
|
82
|
+
|
83
|
+
class Checklist
|
84
|
+
include HappyMapper
|
85
|
+
tag 'CHECKLIST'
|
86
|
+
has_one :asset, Asset, tag: 'ASSET'
|
87
|
+
has_one :stig, Stigs, tag: 'STIGS'
|
88
|
+
|
89
|
+
def where(attrib, data)
|
90
|
+
stig.istig.vuln.each do |vuln|
|
91
|
+
if vuln.stig_data.any? { |element| element.attrib == attrib && element.data == data }
|
92
|
+
# TODO: Handle multiple objects that match the condition
|
93
|
+
return vuln
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lib/inspec_tools.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path(__dir__))
|
2
|
+
require 'inspec_tools/version'
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
module InspecTools
|
6
|
+
autoload :Help, 'inspec_tools/help'
|
7
|
+
autoload :Command, 'inspec_tools/command'
|
8
|
+
autoload :CLI, 'inspec_tools/cli'
|
9
|
+
autoload :XCCDF, 'inspec_tools/xccdf'
|
10
|
+
autoload :PDF, 'inspec_tools/pdf'
|
11
|
+
autoload :CSV, 'inspec_tools/csv'
|
12
|
+
autoload :CKL, 'inspec_tools/ckl'
|
13
|
+
autoload :Inspec, 'inspec_tools/inspec'
|
14
|
+
autoload :Summary, 'inspec_tools/summary'
|
15
|
+
autoload :Threshold, 'inspec_tools/threshold'
|
16
|
+
autoload :XLSXTool, 'inspec_tools/xlsx_tool'
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module InspecTools
|
2
|
+
# Methods for converting from CKL to various formats
|
3
|
+
class CKL
|
4
|
+
def initialize(ckl)
|
5
|
+
@ckl = ckl
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_csv
|
9
|
+
# TODO: to_csv
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_xccdf
|
13
|
+
# TODO: to_xccdf
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_inspec
|
17
|
+
# TODO: to_inspec
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require 'inspec-objects'
|
5
|
+
require 'inspec'
|
6
|
+
require_relative './plugin_cli.rb'
|
7
|
+
|
8
|
+
# This tells the ruby cli app to use the same argument parsing as the plugin
|
9
|
+
module InspecTools
|
10
|
+
CLI = InspecPlugins::InspecToolsPlugin::CliCommand
|
11
|
+
end
|
12
|
+
|
13
|
+
#=====================================================================#
|
14
|
+
# Pre-Flight Code
|
15
|
+
#=====================================================================#
|
16
|
+
help_commands = ['-h', '--help', 'help']
|
17
|
+
log_commands = ['-l', '--log-directory']
|
18
|
+
version_commands = ['-v', '--version', 'version']
|
19
|
+
|
20
|
+
#---------------------------------------------------------------------#
|
21
|
+
# Adjustments for non-required version commands
|
22
|
+
#---------------------------------------------------------------------#
|
23
|
+
unless (version_commands & ARGV).empty?
|
24
|
+
puts InspecTools::VERSION
|
25
|
+
exit 0
|
26
|
+
end
|
27
|
+
|
28
|
+
#---------------------------------------------------------------------#
|
29
|
+
# Adjustments for non-required log-directory
|
30
|
+
#---------------------------------------------------------------------#
|
31
|
+
ARGV.push("--log-directory=#{Dir.pwd}/logs") if (log_commands & ARGV).empty? && (help_commands & ARGV).empty?
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'csv'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'word_wrap'
|
4
|
+
require 'yaml'
|
5
|
+
require 'digest'
|
6
|
+
|
7
|
+
require_relative '../utilities/inspec_util'
|
8
|
+
|
9
|
+
# rubocop:disable Metrics/AbcSize
|
10
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
11
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
12
|
+
|
13
|
+
module InspecTools
|
14
|
+
# Methods for converting from CSV to various formats
|
15
|
+
class CSVTool
|
16
|
+
def initialize(csv, mapping, name, verbose = false)
|
17
|
+
@name = name
|
18
|
+
@csv = csv
|
19
|
+
@mapping = mapping
|
20
|
+
@verbose = verbose
|
21
|
+
@csv.shift if @mapping['skip_csv_header']
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_ckl
|
25
|
+
# TODO
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_xccdf
|
29
|
+
# TODO
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_inspec
|
33
|
+
@controls = []
|
34
|
+
@cci_xml = nil
|
35
|
+
@profile = {}
|
36
|
+
read_cci_xml
|
37
|
+
insert_json_metadata
|
38
|
+
parse_controls
|
39
|
+
@profile['controls'] = @controls
|
40
|
+
@profile['sha256'] = Digest::SHA256.hexdigest @profile.to_s
|
41
|
+
@profile
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def insert_json_metadata
|
47
|
+
@profile['name'] = @name
|
48
|
+
@profile['title'] = 'InSpec Profile'
|
49
|
+
@profile['maintainer'] = 'The Authors'
|
50
|
+
@profile['copyright'] = 'The Authors'
|
51
|
+
@profile['copyright_email'] = 'you@example.com'
|
52
|
+
@profile['license'] = 'Apache-2.0'
|
53
|
+
@profile['summary'] = 'An InSpec Compliance Profile'
|
54
|
+
@profile['version'] = '0.1.0'
|
55
|
+
@profile['supports'] = []
|
56
|
+
@profile['attributes'] = []
|
57
|
+
@profile['generator'] = {
|
58
|
+
'name': 'inspec_tools',
|
59
|
+
'version': VERSION
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
def read_cci_xml
|
64
|
+
cci_list_path = File.join(File.dirname(__FILE__), '../data/U_CCI_List.xml')
|
65
|
+
@cci_xml = Nokogiri::XML(File.open(cci_list_path))
|
66
|
+
@cci_xml.remove_namespaces!
|
67
|
+
rescue StandardError => e
|
68
|
+
puts "Exception: #{e.message}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_nist_reference(cci_number)
|
72
|
+
item_node = @cci_xml.xpath("//cci_list/cci_items/cci_item[@id='#{cci_number}']")[0] unless @cci_xml.nil?
|
73
|
+
unless item_node.nil?
|
74
|
+
nist_ref = item_node.xpath('./references/reference[not(@version <= preceding-sibling::reference/@version) and not(@version <=following-sibling::reference/@version)]/@index').text
|
75
|
+
nist_ver = item_node.xpath('./references/reference[not(@version <= preceding-sibling::reference/@version) and not(@version <=following-sibling::reference/@version)]/@version').text
|
76
|
+
end
|
77
|
+
[nist_ref, nist_ver]
|
78
|
+
end
|
79
|
+
|
80
|
+
def parse_controls
|
81
|
+
@csv.each do |row|
|
82
|
+
print '.'
|
83
|
+
control = {}
|
84
|
+
control['id'] = row[@mapping['control.id']] unless @mapping['control.id'].nil? || row[@mapping['control.id']].nil?
|
85
|
+
control['title'] = row[@mapping['control.title']] unless @mapping['control.title'].nil? || row[@mapping['control.title']].nil?
|
86
|
+
control['desc'] = row[@mapping['control.desc']] unless @mapping['control.desc'].nil? || row[@mapping['control.desc']].nil?
|
87
|
+
control['tags'] = {}
|
88
|
+
nist, nist_rev = get_nist_reference(row[@mapping['control.tags']['cci']]) unless @mapping['control.tags']['cci'].nil? || row[@mapping['control.tags']['cci']].nil?
|
89
|
+
control['tags']['nist'] = [nist, 'Rev_' + nist_rev] unless nist.nil? || nist_rev.nil?
|
90
|
+
@mapping['control.tags'].each do |tag|
|
91
|
+
control['tags'][tag.first.to_s] = row[tag.last] unless row[tag.last].nil?
|
92
|
+
end
|
93
|
+
unless @mapping['control.tags']['severity'].nil? || row[@mapping['control.tags']['severity']].nil?
|
94
|
+
control['impact'] = Utils::InspecUtil.get_impact(row[@mapping['control.tags']['severity']])
|
95
|
+
control['tags']['severity'] = Utils::InspecUtil.get_impact_string(control['impact'])
|
96
|
+
end
|
97
|
+
@controls << control
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|