inspec_tools 2.0.2.pre13 → 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4dc5b1e3bca7c7388c9fd078810f362b74f79f5713fa5bd84b35837565ba0818
4
- data.tar.gz: ee8cd675fdd5ed0d302f88f9ebb19e83f98e5d346bcce10c435655f297075b98
3
+ metadata.gz: c551987d4bfca9ae4d14630f4beb3f4dd6cbe78314a2f229d5df49b4c72cd0e2
4
+ data.tar.gz: d0553cb380d6103f21b879fdb43d39c502ba94d80cc6b30ae8c69cf246464f4d
5
5
  SHA512:
6
- metadata.gz: ad7185fecbd5c6f122738af832e73f3c2571ba9b871901d17cd5c9fda124baa433bdd1747f77340c65b1da69b83a521d390dff0bd17c20b1ce4621e4cdc95088
7
- data.tar.gz: 1034252e96e4212d31fd8ff28a18189e3707c6cb65e88343573cc24f18da8a33bbbaf90ab812e85034449b655bf1a9736458a31a72d2f92f400578827697d04c
6
+ metadata.gz: ffb7fa2a36d380a08c193fc0b1295c74a9479ef54ac5085cf3f36072509d67d235603c6fb589e81ce6c1d52544793fab3b91d37153e303923e7c99bb843f4510
7
+ data.tar.gz: 8e10eacec2b81f6a7c57198cc817050ee501ede1a390e347be50c80429d3834d506eb1f417b9f659ef0c620240d36e15cd65e118ea59fbbaa5481131cba4eb38
data/README.md CHANGED
@@ -65,7 +65,7 @@ For Docker usage, replace the `inspec_tools` command with the correct Docker com
65
65
 
66
66
  - **On Linux and Mac**: `docker run -it -v$(pwd):/share mitre/inspec_tools`
67
67
  - **On Windows CMD**: `docker run -it -v%cd%:/share mitre/inspec_tools`
68
-
68
+
69
69
  Note that all of the above Docker commands will mount your current directory on the Docker container. Ensure that you have navigated to the directory you intend to convert files in before executing the command.
70
70
 
71
71
  ### generate_map
@@ -98,6 +98,8 @@ USAGE: inspec_tools generate_inspec_metadata
98
98
 
99
99
  If the specified threshold is not met, an error code (1) is returned along with non-compliant elements.
100
100
 
101
+ The compliance score are rounded down to the nearest whole number. For example a score of 77.3 would be displayed as 77.
102
+
101
103
  ```
102
104
  USAGE: inspec_tools compliance [OPTIONS] -j <inspec-json> -i <threshold-inline>
103
105
  inspec_tools compliance [OPTIONS] -j <inspec-json> -f <threshold-file>
@@ -142,22 +144,57 @@ failed.high.max: 1
142
144
 
143
145
  ## summary
144
146
 
145
- `summary` parses an inspec results json to create a summary json
147
+ `summary` parses an inspec results json and displays the information from all of the tests that were run. Running the command with flags but `-j` it will display information like:
148
+
149
+ ```
150
+ Overall compliance: 77%
151
+
152
+ failed
153
+ total : 41
154
+ critical : 0
155
+ high : 3
156
+ medium : 33
157
+ low : 5
158
+ passed
159
+ total : 174
160
+ critical : 0
161
+ high : 21
162
+ medium : 147
163
+ low : 6
164
+ no_impact
165
+ total : 21
166
+ critical : 0
167
+ high : 0
168
+ medium : 0
169
+ low : 0
170
+ skipped
171
+ total : 10
172
+ critical : 0
173
+ high : 2
174
+ medium : 5
175
+ low : 3
176
+ error
177
+ total : 0
178
+ critical : 0
179
+ high : 0
180
+ medium : 0
181
+ low : 0
182
+ ```
183
+
184
+ Using additional flags will override the normal output and only display the output that flag specifies.
185
+
186
+ USAGE: inspec_tools summary [OPTIONS] -j <inspec-json>
146
187
 
147
188
  ```
148
- USAGE: inspec_tools summary [OPTIONS] -j <inspec-json> -o <summary-csv>
149
-
150
189
  FLAGS:
151
- -j --inspec-json <inspec-json> : path to InSpec results JSON
152
- -o --output <output-json> : path to summary JSON
153
- -c --cli, --no-cli : print formatted summary to STDOUT
190
+ -j --inspec-json <inspec-json> : path to InSpec results JSON
154
191
  -V --verbose, --no-verbose : print verbose an debug output
155
192
  -f --json-full, --no-json-full : print the summary STDOUT as JSON
156
193
  -k --json-counts, --no-json_cou : print the reslut status to STDOUT as JSON
157
194
 
158
195
  Examples:
159
196
 
160
- inspec_tools summary -j examples/sample_json/rhel-simp.json -f -o summary.json -c
197
+ inspec_tools summary -j examples/sample_json/rhel-simp.json -f
161
198
  ```
162
199
 
163
200
  ## xccdf2inspec
@@ -174,7 +211,7 @@ FLAGS:
174
211
  -f --format [ruby | hash] : the format you would like (default: ruby) [optional]
175
212
  -s --separate-files [true | false] : output the resulting controls as one or mutiple files (default: true) [optional]
176
213
  -m --metadata <metadata-json> : path to json file with additional metadata for the inspec.yml file [optional]
177
- -r --replace-tags <array> : A case-sensitive, comma separated list to replace tags with a $ if found in a group rules description tag [optional]
214
+ -r --replace-tags <array> : A case-sensitive, space separated list to replace tags with a $ if found in a group rules description tag [optional]
178
215
 
179
216
  example: inspec_tools xccdf2inspec -x xccdf_file.xml -a attributes.yml -o myprofile -f ruby -s false
180
217
  ```
@@ -258,7 +295,7 @@ FLAGS:
258
295
  -s --separate-files [true | false] : output the resulting controls as multiple files (default: true) [optional]
259
296
  -d --debug : debug run [optional]
260
297
 
261
- example: inspec_tools pdf2inspec -p benchmark.pdf -o /path/to/myprofile -f ruby -s true
298
+ example: inspec_tools pdf2inspec -p examples/CIS_Ubuntu_Linux_16.04_LTS_Benchmark_v1.0.0.pdf -o /path/to/myprofile -f ruby -s true
262
299
  ```
263
300
 
264
301
  ## xlsx2inspec
data/Rakefile CHANGED
@@ -1,10 +1,9 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
1
+ require 'rake/testtask'
3
2
  require File.expand_path('../lib/inspec_tools/version', __FILE__)
4
3
 
5
4
  Rake::TestTask.new(:test) do |t|
6
- t.libs << "test"
7
- t.libs << "lib"
5
+ t.libs << 'test'
6
+ t.libs << 'lib'
8
7
  t.test_files = FileList['test/**/*_test.rb']
9
8
  end
10
9
 
@@ -22,9 +21,76 @@ namespace :test do
22
21
  end
23
22
  end
24
23
 
25
- desc 'Build and publish the gem'
26
- task publish: :build do
27
- system("gem push pkg/inspec_tools-#{InspecTools::VERSION}.gem")
24
+ desc 'Build for release'
25
+ task :build_release do
26
+
27
+ Rake::Task["generate_mapping_objects"].reenable
28
+ Rake::Task["generate_mapping_objects"].invoke
29
+
30
+ system('gem build inspec_tools.gemspec')
28
31
  end
29
32
 
30
- task :default => :test
33
+ desc 'Generate mapping objects'
34
+ task :generate_mapping_objects do
35
+ require 'roo'
36
+
37
+ nist_mapping_cis_controls = ENV['NIST_MAPPING_CIS_CONTROLS'] || 'NIST_Map_02052020_CIS_Controls_Version_7.1_Implementation_Groups_1.2.xlsx'.freeze
38
+ nist_mapping_cis_critical_controls = ENV['NIST_MAPPING_CIS_CRITICAL_CONTROLS'] || 'NIST_Map_09212017B_CSC-CIS_Critical_Security_Controls_VER_6.1_Excel_9.1.2016.xlsx'.freeze
39
+
40
+ data_root_path = File.join(File.expand_path(__dir__), 'lib', 'data')
41
+ cis_controls_path = File.join(data_root_path, nist_mapping_cis_controls)
42
+ cis_critical_controls_path = File.join(data_root_path, nist_mapping_cis_critical_controls)
43
+
44
+ raise "#{cis_controls_path} does not exist" unless File.exist?(cis_controls_path)
45
+
46
+ raise "#{cis_critical_controls_path} does not exist" unless File.exist?(cis_critical_controls_path)
47
+
48
+ marshal_cis_controls(cis_controls_path, data_root_path)
49
+ marshal_cis_critical_controls(cis_critical_controls_path, data_root_path)
50
+ end
51
+
52
+ def marshal_cis_controls(cis_controls_path, data_root_path)
53
+ cis_to_nist = {}
54
+ Roo::Spreadsheet.open(cis_controls_path).sheet(3).each do |row|
55
+ if row[3].is_a?(Numeric)
56
+ cis_to_nist[row[3].to_s] = row[0]
57
+ else
58
+ cis_to_nist[row[2].to_s] = row[0] unless (row[2] == '') || row[2].to_i.nil?
59
+ end
60
+ end
61
+ output_file = File.new(File.join(data_root_path, 'cis_to_nist_mapping'), 'w')
62
+ Marshal.dump(cis_to_nist, output_file)
63
+ output_file.close
64
+ end
65
+
66
+ def marshal_cis_critical_controls(cis_critical_controls_path, data_root_path)
67
+ controls_spreadsheet = Roo::Spreadsheet.open(cis_critical_controls_path)
68
+ controls_spreadsheet.default_sheet = 'VER 6.1 Controls'
69
+ headings = {}
70
+ controls_spreadsheet.row(3).each_with_index { |header, idx| headings[header] = idx }
71
+
72
+ nist_ver = 4
73
+ cis_ver = controls_spreadsheet.row(2)[4].split(' ')[-1]
74
+ control_count = 1
75
+ mapping = []
76
+ ((controls_spreadsheet.first_row + 3)..controls_spreadsheet.last_row).each do |row_value|
77
+ current_row = {}
78
+ if controls_spreadsheet.row(row_value)[headings['NIST SP 800-53 Control #']].to_s != ''
79
+ current_row[:nist] = controls_spreadsheet.row(row_value)[headings['NIST SP 800-53 Control #']].to_s
80
+ else
81
+ current_row[:nist] = 'Not Mapped'
82
+ end
83
+ current_row[:nist_ver] = nist_ver
84
+ if controls_spreadsheet.row(row_value)[headings['Control']].to_s == ''
85
+ current_row[:cis] = control_count.to_s
86
+ control_count += 1
87
+ else
88
+ current_row[:cis] = controls_spreadsheet.row(row_value)[headings['Control']].to_s
89
+ end
90
+ current_row[:cis_ver] = cis_ver
91
+ mapping << current_row
92
+ end
93
+ output_file = File.new(File.join(data_root_path, 'cis_to_nist_critical_controls'), 'w')
94
+ Marshal.dump(mapping, output_file)
95
+ output_file.close
96
+ end
@@ -0,0 +1,4 @@
1
+ AllCops:
2
+ DisabledByDefault: true
3
+ Style/StringLiterals:
4
+ Enabled: true
@@ -38,6 +38,7 @@ module HappyMapperTools
38
38
  element :documentable, Boolean, tag: 'Documentable'
39
39
  element :mitigations, String, tag: 'Mitigations'
40
40
  element :severity_override_guidance, String, tag: 'SeverityOverrideGuidance'
41
+ element :security_override_guidance, String, tag: 'SecurityOverrideGuidance'
41
42
  element :potential_impacts, String, tag: 'PotentialImpacts'
42
43
  element :third_party_tools, String, tag: 'ThirdPartyTools'
43
44
  element :mitigation_controls, String, tag: 'MitigationControl'
@@ -53,7 +54,8 @@ module HappyMapperTools
53
54
 
54
55
  detail_tags = %i(vuln_discussion false_positives false_negatives documentable
55
56
  mitigations severity_override_guidance potential_impacts
56
- third_party_tools mitigation_controls responsibility ia_controls)
57
+ third_party_tools mitigation_controls responsibility ia_controls
58
+ security_override_guidance)
57
59
 
58
60
  detail_tags.each do |name|
59
61
  define_method name do
@@ -140,57 +142,75 @@ module HappyMapperTools
140
142
  end
141
143
 
142
144
  class DescriptionDetailsType
143
- def self.type
144
- DescriptionDetails
145
- end
145
+ class << self
146
+ def type
147
+ DescriptionDetails
148
+ end
146
149
 
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}"
150
+ def apply(value)
151
+ value = value.gsub('&', 'and')
152
+ DescriptionDetails.parse "<Details>#{value}</Details>"
153
+ rescue Nokogiri::XML::SyntaxError => e
154
+ if e.to_s.include?('StartTag')
155
+ report_invalid_start_tag(value, e)
156
+ else
157
+ report_disallowed_tags(value)
158
+ end
159
+ end
160
+
161
+ def apply?(value, _convert_to_type)
162
+ value.is_a?(String)
167
163
  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
- '`&lt;`,`&gt;`, `<` '.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
164
 
190
- def self.apply?(value, _convert_to_type)
191
- value.is_a?(String)
165
+ private
166
+
167
+ def report_invalid_start_tag(value, error)
168
+ puts error.to_s.colorize(:red)
169
+ column = error.column - '<Details>'.length - 2
170
+ puts "Error around #{value[column-10..column+10].colorize(:light_yellow)}"
171
+ exit(1)
172
+ end
173
+
174
+ def report_disallowed_tags(value)
175
+ allowed_tags = %w{VulnDiscussion FalsePositives FalseNegatives Documentable
176
+ Mitigations SeverityOverrideGuidance PotentialImpacts
177
+ PotentialImpacts ThirdPartyTools MitigationControl
178
+ Responsibility IAControl SecurityOverrideGuidance}
179
+
180
+ tags_found = value.scan(%r{(?<=<)([^\/]*?)((?= \/>)|(?=>))}).to_a
181
+
182
+ tags_found = tags_found.uniq.flatten.reject!(&:empty?)
183
+ offending_tags = tags_found - allowed_tags
184
+
185
+ if offending_tags.count > 1
186
+ puts "\n\nThe non-standard tags: #{offending_tags.to_s.colorize(:red)}" \
187
+ ' were found in: ' + "\n\n#{value}"
188
+ else
189
+ puts "\n\nThe non-standard tag: #{offending_tags.to_s.colorize(:red)}" \
190
+ ' was found in: ' + "\n\n#{value}"
191
+ end
192
+ puts "\n\nPlease:\n "
193
+ option_one = '(1) ' + '(best)'.colorize(:green) + ' Use the ' +
194
+ '`-r --replace-tags array` '.colorize(:light_yellow) +
195
+ '(case sensitive) option to replace the offending tags ' \
196
+ 'during processing of the XCCDF ' \
197
+ 'file to use the ' +
198
+ "`$#{offending_tags[0]}` " .colorize(:light_green) +
199
+ 'syntax in your InSpec profile.'
200
+ option_two = '(2) Update your XCCDF file to *not use* non-standard XCCDF ' \
201
+ 'elements within ' +
202
+ '`&lt;`,`&gt;`, `<` '.colorize(:red) +
203
+ 'or '.colorize(:default) +
204
+ '`>` '.colorize(:red) +
205
+ 'as "placeholders", and use something that doesn\'t confuse ' \
206
+ 'the XML parser, such as : ' +
207
+ "`$#{offending_tags[0]}`" .colorize(:light_green)
208
+ puts option_one
209
+ puts "\n"
210
+ puts option_two
211
+ end
192
212
  end
213
+ HappyMapper::SupportedTypes.register DescriptionDetailsType
193
214
  end
194
- HappyMapper::SupportedTypes.register DescriptionDetailsType
195
215
  end
196
216
  end
@@ -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 = nil
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
@@ -200,8 +200,6 @@ module InspecPlugins
200
200
  desc 'summary', 'summary parses an inspec results json to create a summary json'
201
201
  long_desc InspecTools::Help.text(:summary)
202
202
  option :inspec_json, required: true, aliases: '-j'
203
- option :output, required: false, aliases: '-o'
204
- option :cli, type: :boolean, required: false, aliases: '-c'
205
203
  option :verbose, type: :boolean, aliases: '-V'
206
204
  option :json_full, type: :boolean, required: false, aliases: '-f'
207
205
  option :json_counts, type: :boolean, required: false, aliases: '-k'
@@ -209,7 +207,7 @@ module InspecPlugins
209
207
  def summary
210
208
  summary = InspecTools::Summary.new(File.read(options[:inspec_json])).to_summary
211
209
 
212
- if options[:cli]
210
+ unless options.include?('json_full') || options.include?('json_counts')
213
211
  puts "\nOverall compliance: #{summary[:compliance]}%\n\n"
214
212
  summary[:status].keys.each do |category|
215
213
  puts category
@@ -220,7 +218,6 @@ module InspecPlugins
220
218
  end
221
219
 
222
220
  json_summary = summary.to_json
223
- File.write(options[:output], json_summary) if options[:output]
224
221
  puts json_summary if options[:json_full]
225
222
  puts summary[:status].to_json if options[:json_counts]
226
223
  end
@@ -10,8 +10,8 @@ HIGH = 0.7
10
10
  MEDIUM = 0.5
11
11
  LOW = 0.3
12
12
 
13
- BUCKETS = %w{failed passed no_impact skipped error}.freeze
14
- TALLYS = %w{total critical high medium low}.freeze
13
+ BUCKETS = %i(failed passed no_impact skipped error).freeze
14
+ TALLYS = %i(total critical high medium low).freeze
15
15
 
16
16
  THRESHOLD_TEMPLATE = File.expand_path('../data/threshold.yaml', File.dirname(__FILE__))
17
17
 
@@ -83,7 +83,7 @@ module InspecTools
83
83
  (@summary[:status][:passed][:total]+
84
84
  @summary[:status][:failed][:total]+
85
85
  @summary[:status][:skipped][:total]+
86
- @summary[:status][:error][:total])).round(1)
86
+ @summary[:status][:error][:total])).floor
87
87
  end
88
88
 
89
89
  def threshold_compliance
@@ -104,13 +104,13 @@ module InspecTools
104
104
  TALLYS.each do |tally|
105
105
  max = @threshold["#{bucket}.#{tally}.max"]
106
106
  min = @threshold["#{bucket}.#{tally}.min"]
107
- if max != -1 and status[bucket.to_sym][tally.to_sym] > max
107
+ if max != -1 and status[bucket][tally] > max
108
108
  compliance = false
109
- failure << "Expected #{bucket}.#{tally}.max:#{max} got:#{status[bucket.to_sym][tally.to_sym]}"
109
+ failure << "Expected #{bucket}.#{tally}.max:#{max} got:#{status[bucket][tally]}"
110
110
  end
111
- if min != -1 and status[bucket.to_sym][tally.to_sym] < min
111
+ if min != -1 and status[bucket][tally] < min
112
112
  compliance = false
113
- failure << "Expected #{bucket}.#{tally}.min:#{min} got:#{status[bucket.to_sym][tally.to_sym]}"
113
+ failure << "Expected #{bucket}.#{tally}.min:#{min} got:#{status[bucket][tally]}"
114
114
  end
115
115
  end
116
116
  end