inspec_tools 2.0.4 → 2.2.0

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: 22680d948ef0c9745db5983c3ae8dea966cfa05f2aa2977e2f0409a0d4416a14
4
- data.tar.gz: 60954f2699569649f559a4071c97e70a1b0d77eb0f695207106dd4b06887c8b9
3
+ metadata.gz: 315e07faccf97b313b9493963ef7b9b80ffa7a1459bfa661527c4e827de89676
4
+ data.tar.gz: e31f0bc2c0006bcb96b9ee46f34c59b8ba71358c2293d7c39874b0fc80b5292b
5
5
  SHA512:
6
- metadata.gz: 5eab94b7c0f08fe13b37a2c0483e7991c8b625c2134f502e94f8c194d4ef4aee73001d9ccc52686a924ff6d1b4436511706e4ab5cb274476765ebc6e97d42a45
7
- data.tar.gz: 07d82a9e11bfb00ee867893cbecbe1ce0d9d7bb0a156ec1e81a80f862ede193c1cb9b4abefcd45bb5d068a7719b9c18a1fbd9053b51e68d9854792b4b90674a5
6
+ metadata.gz: 50409617c4e6142916f328e5850a5ef3f2d99b9e71671714ce0475708c435242911b6d4455f47fd1f5e50a7778b80e673d4ec74e3ee5d8f66ab5530c42fa8ad9
7
+ data.tar.gz: e34adf2df0ec1b1bcd5d9224a2621565c5c4efbe79177c2326a3ef8eef6e10922cbc025682c6bade7179add2e59b3b6394419da0cf7c82f1fd8dcfb58efe49f3
data/README.md CHANGED
@@ -65,12 +65,12 @@ 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
72
72
 
73
- This command will generate a `mapping.xml` file that can be passed in to the `csv2inspec` command with the `--m` option.
73
+ This command will generate a `mapping.yml` file that can be passed in to the `csv2inspec` command with the `--m` option.
74
74
 
75
75
  ```
76
76
  USAGE: inspec_tools generate_map
@@ -100,13 +100,15 @@ If the specified threshold is not met, an error code (1) is returned along with
100
100
 
101
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
102
 
103
+ Thresholds provided inline (i.e. `-i`) override thresholds provided by files (i.e. `-f`).
104
+
103
105
  ```
104
106
  USAGE: inspec_tools compliance [OPTIONS] -j <inspec-json> -i <threshold-inline>
105
107
  inspec_tools compliance [OPTIONS] -j <inspec-json> -f <threshold-file>
106
108
  FLAGS:
107
109
  -j --inspec-json <inspec-json> : path to InSpec results Json
108
110
  -i --template-inline <threshold-inline> : inline compliance threshold definition
109
- -f --template-file <threshold-file> : yaml file with compliance threshold definition
111
+ -f --threshold-file <threshold-file> : yaml file with compliance threshold definition
110
112
  Examples:
111
113
 
112
114
  inspec_tools compliance -j examples/sample_json/rhel-simp.json -i '{compliance.min: 80, failed.critical.max: 0, failed.high.max: 0}'
@@ -135,11 +137,11 @@ failed.high.max: 1
135
137
 
136
138
  #### In-Line Examples
137
139
  ```
138
- {compliance: {min: 90}, failed: {critical: {max: 0}, high: {max: 0}}}
140
+ "{compliance: {min: 90}, failed: {critical: {max: 0}, high: {max: 0}}}"
139
141
  ```
140
142
 
141
143
  ```
142
- {compliance.min: 81, failed.critical.max: 0, failed.high.max: 0}
144
+ "{compliance.min: 81, failed.critical.max: 0, failed.high.max: 0}"
143
145
  ```
144
146
 
145
147
  ## summary
@@ -181,16 +183,20 @@ error
181
183
  low : 0
182
184
  ```
183
185
 
184
- Using additional flags will override the normal output and only display the output that flag specifies.
186
+ Using additional flags will override the normal output and only display the output that flag specifies.
187
+
188
+ USAGE: inspec_tools summary [OPTIONS] -j <inspec-json>
189
+
190
+ Thresholds provided inline (i.e. `-i`) override thresholds provided by files (i.e. `-t`).
185
191
 
186
- USAGE: inspec_tools summary [OPTIONS] -j <inspec-json>
187
192
 
188
193
  ```
189
194
  FLAGS:
190
- -j --inspec-json <inspec-json> : path to InSpec results JSON
191
- -V --verbose, --no-verbose : print verbose an debug output
192
- -f --json-full, --no-json-full : print the summary STDOUT as JSON
193
- -k --json-counts, --no-json_cou : print the reslut status to STDOUT as JSON
195
+ -j --inspec-json <inspec-json> : path to InSpec results JSON
196
+ -f --json-full, --no-json-full : print the summary STDOUT as JSON
197
+ -k --json-counts, --no-json-counts : print the result status to STDOUT as JSON
198
+ -t, --threshold-file=THRESHOLD_FILE] : path to threshold YAML file
199
+ -i, --threshold-inline=THRESHOLD_INLINE] : string of text representing threshold YAML inline
194
200
 
195
201
  Examples:
196
202
 
@@ -211,7 +217,7 @@ FLAGS:
211
217
  -f --format [ruby | hash] : the format you would like (default: ruby) [optional]
212
218
  -s --separate-files [true | false] : output the resulting controls as one or mutiple files (default: true) [optional]
213
219
  -m --metadata <metadata-json> : path to json file with additional metadata for the inspec.yml file [optional]
214
- -r --replace-tags <array> : A case-sensitive, comma separated list to replace tags with a $ if found in a group rules description tag [optional]
220
+ -r --replace-tags <array> : A case-sensitive, space separated list to replace tags with a $ if found in a group rules description tag [optional]
215
221
 
216
222
  example: inspec_tools xccdf2inspec -x xccdf_file.xml -a attributes.yml -o myprofile -f ruby -s false
217
223
  ```
@@ -220,16 +226,18 @@ example: inspec_tools xccdf2inspec -x xccdf_file.xml -a attributes.yml -o myprof
220
226
 
221
227
  `inspec2xccdf` converts an InSpec profile in json format to a STIG XCCDF Document
222
228
 
229
+ See [examples documentation](./examples/inspec2xccdf/README.md) for additional guidance on usage including attribute details.
230
+
223
231
  ```
224
232
  USAGE: inspec_tools inspec2xccdf [OPTIONS] -j <inspec-json> -a <xccdf-attr-yml> -o <xccdf-xml>
225
233
 
226
234
  FLAGS:
227
235
  -j --inspec-json <inspec-json> : path to InSpec Json file created using command 'inspec json <profile> > example.json'
228
- -a --attributes <xccdf-attr-yml> : 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
229
- -o --output <xccdf-xml> : name or path to create the xccdf and title to give the xccdf
230
- -V --verbose : verbose run [optional]
236
+ -a --attributes <xccdf-attr-yml> : 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.
237
+ -o --output <xccdf-xml> : name or path to create the XCCDF and title to give the XCCDF
238
+ -m, [--metadata=METADATA] : path to json file with additional host metadata for the XCCDF file
231
239
 
232
- example: inspec_tools inspec2xccdf -j example.json -a attributes.yml -o xccdf.xml
240
+ example: inspec_tools inspec2xccdf -j examples/sample_json/good_nginxresults.json -a lib/data/attributes.yml -o output.xccdf
233
241
  ```
234
242
 
235
243
  ## csv2inspec
@@ -295,7 +303,7 @@ FLAGS:
295
303
  -s --separate-files [true | false] : output the resulting controls as multiple files (default: true) [optional]
296
304
  -d --debug : debug run [optional]
297
305
 
298
- example: inspec_tools pdf2inspec -p benchmark.pdf -o /path/to/myprofile -f ruby -s true
306
+ 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
299
307
  ```
300
308
 
301
309
  ## 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
 
@@ -20,11 +19,86 @@ namespace :test do
20
19
  'test/unit/inspec_tools_test.rb'
21
20
  ])
22
21
  end
22
+
23
+ Rake::TestTask.new(:exclude_slow) do |t|
24
+ t.description = 'Excluding all tests that take more than 3 seconds to complete'
25
+ t.libs << 'test'
26
+ t.libs << "lib"
27
+ t.verbose = true
28
+ t.test_files = FileList['test/**/*_test.rb'].reject{|file| file.include? 'pdf_test.rb'}.reverse
29
+ end
30
+ end
31
+
32
+ desc 'Build for release'
33
+ task :build_release do
34
+
35
+ Rake::Task["generate_mapping_objects"].reenable
36
+ Rake::Task["generate_mapping_objects"].invoke
37
+
38
+ system('gem build inspec_tools.gemspec')
39
+ end
40
+
41
+ desc 'Generate mapping objects'
42
+ task :generate_mapping_objects do
43
+ require 'roo'
44
+
45
+ nist_mapping_cis_controls = ENV['NIST_MAPPING_CIS_CONTROLS'] || 'NIST_Map_02052020_CIS_Controls_Version_7.1_Implementation_Groups_1.2.xlsx'.freeze
46
+ 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
47
+
48
+ data_root_path = File.join(File.expand_path(__dir__), 'lib', 'data')
49
+ cis_controls_path = File.join(data_root_path, nist_mapping_cis_controls)
50
+ cis_critical_controls_path = File.join(data_root_path, nist_mapping_cis_critical_controls)
51
+
52
+ raise "#{cis_controls_path} does not exist" unless File.exist?(cis_controls_path)
53
+
54
+ raise "#{cis_critical_controls_path} does not exist" unless File.exist?(cis_critical_controls_path)
55
+
56
+ marshal_cis_controls(cis_controls_path, data_root_path)
57
+ marshal_cis_critical_controls(cis_critical_controls_path, data_root_path)
23
58
  end
24
59
 
25
- desc 'Build and publish the gem'
26
- task publish: :build do
27
- system("gem push pkg/inspec_tools-#{InspecTools::VERSION}.gem")
60
+ def marshal_cis_controls(cis_controls_path, data_root_path)
61
+ cis_to_nist = {}
62
+ Roo::Spreadsheet.open(cis_controls_path).sheet(3).each do |row|
63
+ if row[3].is_a?(Numeric)
64
+ cis_to_nist[row[3].to_s] = row[0]
65
+ else
66
+ cis_to_nist[row[2].to_s] = row[0] unless (row[2] == '') || row[2].to_i.nil?
67
+ end
68
+ end
69
+ output_file = File.new(File.join(data_root_path, 'cis_to_nist_mapping'), 'w')
70
+ Marshal.dump(cis_to_nist, output_file)
71
+ output_file.close
28
72
  end
29
73
 
30
- task :default => :test
74
+ def marshal_cis_critical_controls(cis_critical_controls_path, data_root_path)
75
+ controls_spreadsheet = Roo::Spreadsheet.open(cis_critical_controls_path)
76
+ controls_spreadsheet.default_sheet = 'VER 6.1 Controls'
77
+ headings = {}
78
+ controls_spreadsheet.row(3).each_with_index { |header, idx| headings[header] = idx }
79
+
80
+ nist_ver = 4
81
+ cis_ver = controls_spreadsheet.row(2)[4].split(' ')[-1]
82
+ control_count = 1
83
+ mapping = []
84
+ ((controls_spreadsheet.first_row + 3)..controls_spreadsheet.last_row).each do |row_value|
85
+ current_row = {}
86
+ if controls_spreadsheet.row(row_value)[headings['NIST SP 800-53 Control #']].to_s != ''
87
+ current_row[:nist] = controls_spreadsheet.row(row_value)[headings['NIST SP 800-53 Control #']].to_s
88
+ else
89
+ current_row[:nist] = 'Not Mapped'
90
+ end
91
+ current_row[:nist_ver] = nist_ver
92
+ if controls_spreadsheet.row(row_value)[headings['Control']].to_s == ''
93
+ current_row[:cis] = control_count.to_s
94
+ control_count += 1
95
+ else
96
+ current_row[:cis] = controls_spreadsheet.row(row_value)[headings['Control']].to_s
97
+ end
98
+ current_row[:cis_ver] = cis_ver
99
+ mapping << current_row
100
+ end
101
+ output_file = File.new(File.join(data_root_path, 'cis_to_nist_critical_controls'), 'w')
102
+ Marshal.dump(mapping, output_file)
103
+ output_file.close
104
+ end
@@ -99,6 +99,88 @@ module HappyMapperTools
99
99
  element :content, String, tag: 'check-content'
100
100
  end
101
101
 
102
+ class MessageType
103
+ include HappyMapper
104
+ attribute :severity, String, tag: 'severity'
105
+ content :message, String
106
+ end
107
+
108
+ class RuleResultType
109
+ include HappyMapper
110
+ attribute :idref, String, tag: 'idref'
111
+ attribute :severity, String, tag: 'severity'
112
+ attribute :time, String, tag: 'time'
113
+ attribute :weight, String, tag: 'weight'
114
+ element :result, String, tag: 'result'
115
+ # element override - Not implemented. Does not apply to Inspec execution
116
+ has_many :ident, Ident, tag: 'ident'
117
+ # Note: element metadata not implemented at this time
118
+ has_many :message, MessageType, tag: 'message'
119
+ has_many :instance, String, tag: 'instance'
120
+ element :fix, Fix, tag: 'fix'
121
+ element :check, Check, tag: 'check'
122
+ end
123
+
124
+ class ScoreType
125
+ include HappyMapper
126
+
127
+ def initialize(system, maximum, score)
128
+ @system = system
129
+ @maximum = maximum
130
+ @score = score
131
+ end
132
+
133
+ attribute :system, String, tag: 'system'
134
+ attribute :maximum, String, tag: 'maximum' # optional attribute
135
+ content :score, String
136
+ end
137
+
138
+ class CPE2idrefType
139
+ include HappyMapper
140
+ attribute :idref, String, tag: 'idref'
141
+ end
142
+
143
+ class IdentityType
144
+ include HappyMapper
145
+ attribute :authenticated, Boolean, tag: 'authenticated'
146
+ attribute :privileged, Boolean, tag: 'privileged'
147
+ content :identity, String
148
+ end
149
+
150
+ class Fact
151
+ include HappyMapper
152
+ attribute :name, String, tag: 'name'
153
+ attribute :type, String, tag: 'type'
154
+ content :fact, String
155
+ end
156
+
157
+ class TargetFact
158
+ include HappyMapper
159
+ has_many :fact, Fact, tag: 'fact'
160
+ end
161
+
162
+ class TestResult
163
+ include HappyMapper
164
+ # Note: element benchmark not implemented at this time since this is same file
165
+ # Note: element title not implemented due to no mapping from Chef Inspec
166
+ element :remark, String, tag: 'remark'
167
+ has_many :organization, String, tag: 'organization'
168
+ element :identity, IdentityType, tag: 'identity'
169
+ element :target, String, tag: 'target'
170
+ has_many :target_address, String, tag: 'target-address'
171
+ element :target_facts, TargetFact, tag: 'target-facts'
172
+ element :platform, CPE2idrefType, tag: 'platform'
173
+ # Note: element profile not implemented since Benchmark profile is also not implemented
174
+ has_many :rule_result, RuleResultType, tag: 'rule-result'
175
+ has_many :score, ScoreType, tag: 'score' # One minimum
176
+ # Note: element signature not implemented due to no mapping from Chef Inspec
177
+ attribute :id, String, tag: 'id'
178
+ attribute :starttime, String, tag: 'start-time'
179
+ attribute :endtime, String, tag: 'end-time'
180
+ # Note: attribute test-system not implemented at this time due to unknown CPE value for Chef Inspec
181
+ attribute :version, String, tag: 'version'
182
+ end
183
+
102
184
  # Class Profile maps from the 'Profile' from Benchmark XML file using HappyMapper
103
185
  class Profile
104
186
  include HappyMapper
@@ -156,6 +238,7 @@ module HappyMapperTools
156
238
  element :version, String, tag: 'version'
157
239
  has_many :profile, Profile, tag: 'Profile'
158
240
  has_many :group, Group, tag: 'Group'
241
+ element :testresult, TestResult, tag: 'TestResult'
159
242
  end
160
243
  end
161
244
  end
@@ -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