nexpose_ticketing 0.8.3 → 1.0.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.
@@ -1,118 +1,184 @@
1
1
  require 'net/http'
2
2
  require 'nokogiri'
3
3
  require 'dbm'
4
+ require 'nexpose_ticketing/common_helper'
5
+ require 'nexpose_ticketing/nx_logger'
6
+ require 'nexpose_ticketing/version'
4
7
 
5
8
  class ServiceDeskHelper
6
- attr_accessor :servicedesk_data, :options, :log
7
-
8
- def initialize(servicedesk_data, options)
9
- @servicedesk_data = servicedesk_data
10
- @options = options
11
- @log = NexposeTicketing::NXLogger.new
12
-
13
- @rest_uri = servicedesk_data[:rest_uri]
14
- @api_key = servicedesk_data[:api_key]
15
- @ticket_db_path = servicedesk_data[:ticket_db_path]
9
+ attr_accessor :servicedesk_data, :options, :log
10
+
11
+ def initialize(servicedesk_data, options)
12
+ @servicedesk_data = servicedesk_data
13
+ @options = options
14
+ @log = NexposeTicketing::NxLogger.instance
15
+
16
+ @rest_uri = servicedesk_data[:rest_uri]
17
+ @api_key = servicedesk_data[:api_key]
18
+ @ticket_db_path = servicedesk_data[:ticket_db_path]
19
+ @common_helper = NexposeTicketing::CommonHelper.new(@options)
20
+ end
21
+
22
+
23
+ def open_database()
24
+ DBM.open(@ticket_db_path, 0600, DBM::WRCREAT)
25
+ end
26
+
27
+
28
+ def add_ticket_to_database(workorderid, nxid)
29
+ @log.log_message("Adding ticket <#{workorderid}> for NXID <#{nxid}> to local db.")
30
+ db = open_database()
31
+ db[nxid] = workorderid
32
+ db.close()
33
+ end
34
+
35
+
36
+ def find_ticket_in_database(nxid)
37
+ @log.log_message("Finding workorder id for NXID <#{nxid}> from local db.")
38
+ db = open_database()
39
+ begin
40
+ workorderid = db[nxid]
41
+ @log.log_message("Lookup found incident <#{workorderid}> in the db.")
42
+ rescue Exception => e
43
+ @log.log_message("Threw an exception accessing the dbm <#{e.class} #{e} #{e.message}>.")
44
+ raise e
16
45
  end
46
+ db.close()
17
47
 
18
-
19
- def open_database()
20
- DBM.open(@ticket_db_path, 0600, DBM::WRCREAT)
21
- end
48
+ workorderid
49
+ end
22
50
 
23
51
 
24
- def add_ticket_to_database(workorderid, nxid)
25
- @log.log_message("Adding ticket <#{workorderid}> for NXID <#{nxid}> to local db.")
26
- db = open_database()
27
- db[nxid] = workorderid
28
- db.close()
52
+ def remove_tickets_from_database(tickets)
53
+ db = open_database()
54
+ tickets.each do |t|
55
+ nxid = t[:nxid]
56
+ @log.log_message("Removing workorder id from database for NXID <#{nxid}>")
57
+ db.delete(nxid) unless db[nxid].nil?
58
+ end
59
+ db.close()
60
+ end
61
+
62
+
63
+ def prepare_create_tickets(vulnerability_list, nexpose_identifier_id)
64
+ @log.log_message('Preparing ticket creation...')
65
+ case @options[:ticket_mode]
66
+ # 'D' Default IP *-* Vulnerability
67
+ when 'D' then matching_fields = ['ip_address', 'vulnerability_id']
68
+ # 'I' IP address -* Vulnerability
69
+ when 'I' then matching_fields = ['ip_address']
70
+ # 'V' Vulnerability -* Assets
71
+ when 'V' then matching_fields = ['vulnerability_id']
72
+ else
73
+ fail 'Unsupported ticketing mode selected.'
29
74
  end
30
75
 
76
+ tickets = prepare_tickets(vulnerability_list, nexpose_identifier_id, matching_fields)
31
77
 
32
- def find_ticket_in_database(nxid)
33
- @log.log_message("Finding workorder id for NXID <#{nxid}> from local db.")
34
- db = open_database()
35
- begin
36
- workorderid = db[nxid]
37
- @log.log_message("Lookup found incident <#{workorderid}> in the db.")
38
- rescue Exception => e
39
- @log.log_message("Threw an exception accessing the dbm <#{e.class} #{e} #{e.message}>.")
40
- raise e
41
- end
42
- db.close()
78
+ tickets.each { |ticket| @log.log_message("Prepared ticket: #{ticket}")}
79
+ tickets
80
+ end
43
81
 
44
- return workorderid
45
- end
46
82
 
83
+ def prepare_tickets(vulnerability_list, nexpose_identifier_id, matching_fields)
84
+ @log.log_message("Preparing ticket for #{@options[:ticket_mode]} mode.")
85
+ tickets = []
86
+ host_vulns={}
87
+ previous_row = nil
88
+ description = nil
89
+ nxid = nil
47
90
 
48
- def remove_ticket_from_database(nxid)
49
- @log.log_message("Removing workorder id from database for NXID <#{nxid}>")
50
- db = open_database()
51
- db.delete(nxid)
52
- db.close()
91
+ initial_scan = false
92
+
93
+ CSV.parse( vulnerability_list.chomp, headers: :first_row ) do |row|
94
+ initial_scan = initial_scan || row['comparison'].nil?
95
+
96
+ if previous_row.nil?
97
+ nxid = @common_helper.generate_nxid(nexpose_identifier_id, row)
98
+ previous_row = row.dup
99
+ description = @common_helper.get_description(nexpose_identifier_id, row)
100
+
101
+ host_vulns[nxid] = { :ip => row['ip_address'],
102
+ :description => "",
103
+ :title => @common_helper.get_title(row) }
104
+ elsif matching_fields.any? { |x| previous_row[x].nil? || previous_row[x] != row[x] }
105
+ nxid = @common_helper.generate_nxid(nexpose_identifier_id, previous_row)
106
+ info = @common_helper.get_field_info(matching_fields, previous_row)
107
+ @log.log_message("Generated ticket with #{info}")
108
+
109
+ host_vulns[nxid][:description] = @common_helper.print_description(description)
110
+ previous_row = nil
111
+ description = nil
112
+ redo
113
+ else
114
+ description = @common_helper.update_description(description, row)
115
+ end
53
116
  end
54
117
 
55
- def prepare_create_tickets(vulnerability_list, nexpose_identifier_id)
56
- @log.log_message('Preparing ticket requests...')
57
- case @options[:ticket_mode]
58
- # 'D' Default mode: IP *-* Vulnerability
59
- when 'D'
60
- tickets = create_tickets_by_default(vulnerability_list, nexpose_identifier_id)
61
- # 'I' IP address mode: IP address -* Vulnerability
62
- when 'I'
63
- tickets = create_tickets_by_ip(vulnerability_list, nexpose_identifier_id)
64
- else
65
- fail 'No ticketing mode selected.'
66
- end
67
-
68
- tickets.each { |ticket| @log.log_message("Prepared ticket: #{ticket}")}
69
- return tickets
118
+ unless host_vulns[nxid].nil? || host_vulns[nxid].empty?
119
+ host_vulns[nxid][:description] = @common_helper.print_description(description)
70
120
  end
71
121
 
72
- ## Uses the configured or default options to set up a ticket creation request
73
- def create_ticket_request(subject, description)
74
- request = Nokogiri::XML::Builder.new do |xml|
75
- xml.Operation {
76
- xml.Details {
77
- xml.parameter {
78
- xml.name {
79
- xml.text 'requester'
80
- }
81
- xml.value {
82
- xml.text @servicedesk_data[:requestor]
83
- }
84
- }
85
- xml.parameter {
86
- xml.name {
87
- xml.text 'Group'
88
- }
89
- xml.value {
90
- xml.text @servicedesk_data[:group]
91
- }
92
- }
93
- xml.parameter {
94
- xml.name {
95
- xml.text 'subject'
96
- }
97
- xml.value {
98
- xml.text subject
99
- }
100
- }
101
- xml.parameter {
102
- xml.name {
103
- xml.text 'description'
104
- }
105
- xml.value {
106
- xml.cdata description
107
- }
108
- }
109
- }
122
+ host_vulns.each do |nxid, vuln_info|
123
+ workorderid = initial_scan ? nil : find_ticket_in_database(nxid)
124
+ if workorderid.nil? || workorderid.empty?
125
+ @log.log_message("Creating new incident for assetid #{nxid}")
126
+ tickets << { :action => :create, :nxid => nxid,
127
+ :description => create_ticket_request(vuln_info[:title], vuln_info[:description]) }
128
+ else
129
+ @log.log_message("Updating incident for assetid #{nxid}")
130
+ tickets << { :action => :modify, :nxid => nxid,
131
+ :workorderid => workorderid,
132
+ :description => modify_ticket_request(vuln_info[:description]) }
133
+ end
134
+ end
135
+ tickets
136
+ end
137
+
138
+ ## Uses the configured or default options to set up a ticket creation request
139
+ def create_ticket_request(subject, description)
140
+ request = Nokogiri::XML::Builder.new do |xml|
141
+ xml.Operation {
142
+ xml.Details {
143
+ xml.parameter {
144
+ xml.name {
145
+ xml.text 'requester'
110
146
  }
111
- end
112
- return request.to_xml
147
+ xml.value {
148
+ xml.text @servicedesk_data[:requester]
149
+ }
150
+ }
151
+ xml.parameter {
152
+ xml.name {
153
+ xml.text 'Group'
154
+ }
155
+ xml.value {
156
+ xml.text @servicedesk_data[:group]
157
+ }
158
+ }
159
+ xml.parameter {
160
+ xml.name {
161
+ xml.text 'subject'
162
+ }
163
+ xml.value {
164
+ xml.text subject
165
+ }
166
+ }
167
+ xml.parameter {
168
+ xml.name {
169
+ xml.text 'description'
170
+ }
171
+ xml.value {
172
+ xml.cdata description
173
+ }
174
+ }
175
+ }
176
+ }
113
177
  end
178
+ request.to_xml
179
+ end
114
180
 
115
- def modify_ticket_request(description)
181
+ def modify_ticket_request(description)
116
182
  # modifyRequest = """
117
183
  # <Operation>
118
184
  # <Details>
@@ -123,224 +189,171 @@ class ServiceDeskHelper
123
189
  # </Details>
124
190
  # </Operation>
125
191
  # """
126
- doc = Nokogiri::XML::Builder.new() do |xml|
127
- xml.Operation {
128
- xml.Details {
129
- xml.parameter {
130
- xml.name {
131
- xml.text 'Description'
132
- }
133
- xml.value {
134
- xml.cdata description
135
- }
136
- }
192
+ doc = Nokogiri::XML::Builder.new() do |xml|
193
+ xml.Operation {
194
+ xml.Details {
195
+ xml.parameter {
196
+ xml.name {
197
+ xml.text 'requester'
137
198
  }
138
-
199
+ xml.value {
200
+ xml.text @servicedesk_data[:requester]
201
+ }
202
+ }
203
+ xml.parameter {
204
+ xml.name {
205
+ xml.text 'description'
206
+ }
207
+ xml.value {
208
+ xml.cdata description
209
+ }
210
+ }
139
211
  }
140
- end
141
-
142
- return doc.to_xml
212
+ }
143
213
  end
214
+ doc.to_xml
215
+ end
216
+
217
+ def submit_ticket(ticket)
218
+ @log.log_message("Connecting to #{@rest_uri}.")
219
+ uri = URI( @rest_uri )
220
+ res = Net::HTTP::post_form(uri,
221
+ 'OPERATION_NAME' => 'ADD_REQUEST',
222
+ 'TECHNICIAN_KEY' => @api_key,
223
+ 'INPUT_DATA' => ticket[:description])
224
+
225
+ response = Nokogiri::XML.parse(res.read_body)
226
+ begin
227
+ status = response.xpath('//statuscode').text
228
+ status_code = status.empty? ? -1 : Integer(status)
229
+
230
+ if status_code != 200
231
+ @log.log_message("Unable to create ticket #{ticket}, got response #{response.to_xml}")
232
+ return
233
+ end
144
234
 
145
- ## Given a bunch of vulnerabilities that passed the filters, make tickets for each one
146
- def create_tickets_by_default(vulnerability_list, nexpose_identifier_id)
147
- @log.log_message('Preparing tickets by vulnerability...')
148
- tickets = []
149
- CSV.parse( vulnerability_list.chomp, headers: :first_row ) do |vuln|
150
- subject = "#{vuln['ip_address']}: #{vuln['summary']}"
151
- description = "Host: #{ip_address}\nSummary: #{vuln['summary']}\nFix: #{vuln['fix']}\nURL: #{vuln['url']}"
152
-
153
- tickets << { :action => :create, :nxid => "#{nexpose_identifier_id}#{vuln['asset_id']}#{vuln['vulnerability_id']}#{vuln['solution_id']}",
154
- :description => create_ticket_request( subject, description ) }
155
- end
156
- return tickets
235
+ workorderid = Integer(response.xpath('//workorderid').text)
236
+ rescue ArgumentError => ae
237
+ @log.log_message("Failed to parse response from servicedesk #{response}")
238
+ raise ae
157
239
  end
158
240
 
159
-
160
- def create_tickets_by_ip(vulnerability_list, nexpose_identifier_id)
161
- @log.log_message('Preparing tickets by ip')
162
- tickets = []
163
- hostVulns = {}
164
- CSV.parse( vulnerability_list.chomp, headers: :first_row ) do |vuln|
165
- hostVulns["#{nexpose_identifier_id}#{vuln['ip_address']}"] = { :ip => vuln['ip_address'], :description => "" } if not hostVulns.has_key?("#{nexpose_identifier_id}#{vuln['ip_address']}")
166
- hostVulns["#{nexpose_identifier_id}#{vuln['ip_address']}"][:description] += "Summary: #{vuln['summary']}\nFix: #{vuln['fix']}\nURL: #{vuln['url']}\n\n"
167
- end
168
-
169
- hostVulns.each do |nxid, vulnInfo|
170
- tickets << { :action => :create, :nxid => nxid,
171
- :description => create_ticket_request( "Vulnerabilities on #{vulnInfo[:ip]}", vulnInfo[:description] ) }
172
- end
173
- return tickets
241
+ @log.log_message( "created ticket #{workorderid}")
242
+ add_ticket_to_database( workorderid, ticket[:nxid] )
243
+ end
244
+
245
+
246
+ def modify_ticket(ticket)
247
+ @log.log_message("Connecting to #{@rest_uri}/#{ticket[:workorderid]}")
248
+ uri = URI( "#{@rest_uri}/#{ticket[:workorderid]}")
249
+ res = Net::HTTP::post_form(uri,
250
+ 'OPERATION_NAME' => 'EDIT_REQUEST',
251
+ 'TECHNICIAN_KEY' => @api_key,
252
+ 'INPUT_DATA' => ticket[:description])
253
+
254
+ response = Nokogiri::XML.parse(res.read_body)
255
+ begin
256
+ status = Integer(response.xpath('//statuscode').text)
257
+ rescue Exception => e
258
+ @log.log_message("XML request was #{ticket[:description]} response is #{response.to_xml}")
259
+ raise e
174
260
  end
175
-
176
-
177
- def submit_ticket(ticket)
178
- @log.log_message("Connecting to #{@rest_uri}.")
179
- uri = URI( @rest_uri )
180
- res = Net::HTTP::post_form( uri,
181
- 'OPERATION_NAME' => 'ADD_REQUEST',
182
- 'TECHNICIAN_KEY' => @api_key,
183
- 'INPUT_DATA' => ticket[:description] )
184
-
185
- response = Nokogiri::XML.parse( res.read_body )
186
- begin
187
- status = response.xpath('//statuscode').text
188
- if status.empty?
189
- status_code = -1
190
- else
191
- status_code = Integer( status )
192
- end
193
-
194
- if status_code != 200
195
- @log.log_message("Unable to create ticket #{ticket}, got response #{response.to_xml}")
196
- return
197
- end
198
-
199
- workorderid = Integer(response.xpath('//workorderid').text)
200
- rescue ArgumentError => ae
201
- @log.log_message("Failed to parse response from servicedesk #{response}")
202
- raise ae
203
- end
204
-
205
- @log.log_message( "created ticket #{workorderid}")
206
- add_ticket_to_database( workorderid, ticket[:nxid] )
261
+
262
+ unless status == 200
263
+ @log.log_message("Unable to modify ticket #{ticket}, got response #{response.to_xml}")
207
264
  end
208
-
209
-
210
- def modify_ticket(ticket)
211
- @log.log_message("Connecting to #{@rest_uri}/#{ticket[:workorderid]}")
212
- uri = URI( "#{@rest_uri}/#{ticket[:workorderid]}" )
213
- res = Net::HTTP::post_form( uri,
214
- 'OPERATION_NAME' => 'EDIT_REQUEST',
215
- 'TECHNICIAN_KEY' => @api_key,
216
- 'INPUT_DATA' => ticket[:description] )
217
-
218
- response = Nokogiri::XML.parse( res.read_body )
219
- begin
220
- status = Integer(response.xpath('//statuscode').text)
221
- rescue Exception => e
222
- @log.log_message("XML request was #{ticket[:description]} response is #{response.to_xml}")
223
- raise e
224
- end
225
-
226
- if status != 200
227
- @log.log_message("Unable to modify ticket #{ticket}, got response #{response.to_xml}")
228
- return
229
- end
265
+ end
266
+
267
+
268
+ def close_ticket(ticket)
269
+ @log.log_message("Connecting to #{@rest_uri}/#{ticket[:workorderid]}")
270
+ uri = URI( "#{@rest_uri}/#{ticket[:workorderid]}" )
271
+ res = Net::HTTP::post_form(uri,
272
+ 'OPERATION_NAME' => 'CLOSE_REQUEST',
273
+ 'TECHNICIAN_KEY' => @api_key)
274
+
275
+ response = Nokogiri::XML.parse(res.read_body)
276
+ begin
277
+ status = Integer(response.xpath('//statuscode').text)
278
+ rescue Exception => e
279
+ @log.log_message("XML request was #{ticket[:description]} response is #{response.to_xml}")
280
+ raise e
230
281
  end
231
282
 
283
+ unless status == 200
284
+ @log.log_message("Unable to close ticket #{ticket}, got response #{response.to_xml}")
285
+ end
286
+ end
232
287
 
233
- def close_ticket(ticket)
234
- @log.log_message("Connecting to #{@rest_uri}/#{ticket[:workorderid]}")
235
- uri = URI( "#{@rest_uri}/#{ticket[:workorderid]}" )
236
- res = Net::HTTP::post_form( uri,
237
- 'OPERATION_NAME' => 'CLOSE_REQUEST',
238
- 'TECHNICIAN_KEY' => @api_key )
239
-
240
- response = Nokogiri::XML.parse( res.read_body )
241
- begin
242
- status = Integer(response.xpath('//statuscode').text)
243
- rescue Exception => e
244
- @log.log_message("XML request was #{ticket[:description]} response is #{response.to_xml}")
245
- raise e
246
- end
247
-
248
- if status != 200
249
- @log.log_message("Unable to close ticket #{ticket}, got response #{response.to_xml}")
250
- return
251
- end
252
288
 
253
- end
289
+ def create_tickets(tickets)
290
+ @log.log_message("Creating tickets on server at #{@rest_uri}")
254
291
 
292
+ tickets.each { |ticket| submit_ticket(ticket) }
293
+ end
255
294
 
256
- def create_tickets(tickets)
257
- @log.log_message("Creating tickets on server at #{@rest_uri}")
258
295
 
259
- tickets.each { |ticket| submit_ticket(ticket) }
296
+ def prepare_update_tickets(vulnerability_list, nexpose_identifier_id)
297
+ @log.log_message('Preparing ticket updates...')
298
+ case @options[:ticket_mode]
299
+ # 'D' Default IP *-* Vulnerability
300
+ when 'D' then fail 'Ticket updates are not supported in Default mode.'
301
+ # 'I' IP address -* Vulnerability
302
+ when 'I' then matching_fields = ['ip_address']
303
+ # 'V' Vulnerability -* Assets
304
+ when 'V' then matching_fields = ['vulnerability_id']
305
+ else
306
+ fail 'Unsupported ticketing mode selected.'
260
307
  end
261
308
 
262
-
263
- def prepare_update_tickets(vulnerability_list, nexpose_identifier_id)
264
- fail 'Ticket updates are only supported in IP-address mode.' if @options[:ticket_mode] != 'I'
265
-
266
- @log.log_message('Preparing ticket updates by IP address.')
267
- tickets = []
268
- hostVulns={}
269
- CSV.parse( vulnerability_list.chomp, headers: :first_row ) do |vuln|
270
- hostVulns["#{nexpose_identifier_id}#{vuln['ip_address']}"] = { :ip => vuln['ip_address'], :description => "" } if not hostVulns.has_key?(vuln['asset_id'])
271
- hostVulns["#{nexpose_identifier_id}#{vuln['ip_address']}"][:description] += "Summary: #{vuln['summary']}\nFix: #{vuln['fix']}\nURL: #{vuln['url']}\n\n"
272
- end
273
-
274
- hostVulns.each do |nxid, vulnInfo|
275
- workorderid = find_ticket_in_database(nxid)
276
- if workorderid.nil? || workorderid.empty?
277
- @log.log_message("No incident found for assetid #{nxid}, using defaults")
278
- tickets << { :action => :create, :nxid => nxid,
279
- :description => create_ticket_request("Vulnerabilities on #{vulnInfo[:ip]}", vulnInfo[:description]) }
280
- else
281
- tickets << { :action => :modifty, :nxid => nxid, :workorderid => workorderid,
282
- :description => modify_ticket_request( vulnInfo[:description] ) }
283
- end
284
- end
285
- return tickets
286
- end
309
+ prepare_tickets(vulnerability_list, nexpose_identifier_id, matching_fields)
310
+ end
287
311
 
288
312
 
289
- def update_tickets(tickets)
290
- @log.log_message('Updating tickets')
291
- tickets.each do |ticket|
292
- if ticket[:action] == :create
293
- @log.log_message('Creating ticket')
294
- submit_ticket(ticket)
295
- else
296
- @log.log_message("Updating ticket #{ticket[:workorderid]}")
297
- modify_ticket(ticket)
298
- end
299
- end
313
+ def update_tickets(tickets)
314
+ @log.log_message('Updating tickets')
315
+ tickets.each do |ticket|
316
+ if ticket[:action] == :create
317
+ @log.log_message('Creating ticket')
318
+ submit_ticket(ticket)
319
+ else
320
+ @log.log_message("Updating ticket #{ticket[:workorderid]}")
321
+ modify_ticket(ticket)
322
+ end
300
323
  end
301
-
302
-
303
- # Prepare ticket closures from the CSV of vulnerabilities exported from Nexpose.
304
- #
305
- # * *Args* :
306
- # - +vulnerability_list+ - CSV of vulnerabilities within Nexpose.
307
- #
308
- # * *Returns* :
309
- # - List of savon-formated (hash) tickets for closing within ServiceDesk.
310
- #
311
- def prepare_close_tickets(vulnerability_list, nexpose_identifier_id)
312
- fail 'Ticket closures are only supported in default mode.' if @options[:ticket_mode] == 'I'
313
- @log.log_message('Preparing ticket closures by default method.')
314
- @nxid = nil
315
- tickets = []
316
- CSV.parse(vulnerability_list.chomp, headers: :first_row) do |row|
317
- case @options[:ticket_mode]
318
- # 'D' Default mode: IP *-* Vulnerability
319
- when 'D'
320
- @nxid = "#{nexpose_identifier_id}#{row['asset_id']}#{row['vulnerability_id']}#{row['solution_id']}"
321
- # 'I' IP address mode: IP address -* Vulnerability
322
- when 'I'
323
- @nxid = "#{nexpose_identifier_id}#{row['current_ip']}"
324
- # 'V' Vulnerability mode: Vulnerability -* IP address
325
- # when 'V'
326
- # @NXID = "#{nexpose_identifier_id}#{row['current_asset_id']}#{row['current_vuln_id']}"
327
- else
328
- fail 'Could not close tickets - do not understand the ticketing mode!'
329
- end
330
- workorderid = find_ticket_in_database(@nxid)
331
- # Query ServiceDesk for the incident by unique id (generated NXID)
332
- if workorderid.nil? || workorderid.empty?
333
- @log.log_message("No workorderid found for NXID #{@nxid}")
334
- else
335
- tickets << { :action => :close, :nxid => @nxid, :workorderid => workorderid,
336
- :description => closeTicketRequest() }
337
- end
324
+ end
325
+
326
+ # Prepare ticket closures from the CSV of vulnerabilities exported from Nexpose.
327
+ #
328
+ # * *Args* :
329
+ # - +vulnerability_list+ - CSV of vulnerabilities within Nexpose.
330
+ #
331
+ # * *Returns* :
332
+ # - List of savon-formated (hash) tickets for closing within ServiceDesk.
333
+ #
334
+ def prepare_close_tickets(vulnerability_list, nexpose_identifier_id)
335
+ @log.log_message("Preparing ticket closures for mode #{@options[:ticket_mode]}.")
336
+ @nxid = nil
337
+ tickets = []
338
+ CSV.parse(vulnerability_list.chomp, headers: :first_row) do |row|
339
+ @nxid = @common_helper.generate_nxid(nexpose_identifier_id, row)
340
+
341
+ workorderid = find_ticket_in_database(@nxid)
342
+ # Query ServiceDesk for the incident by unique id (generated NXID)
343
+ if workorderid.nil? || workorderid.empty?
344
+ @log.log_message("No workorderid found for NXID #{@nxid}")
345
+ else
346
+ tickets << { :action => :close, :nxid => @nxid,
347
+ :workorderid => workorderid,
348
+ :description => 'Automatically closing ticket.' }
338
349
  end
339
- return tickets
340
350
  end
351
+ tickets
352
+ end
341
353
 
342
354
 
343
- def close_tickets( tickets )
344
- tickets.each { |ticket| close_ticket(ticket) if ticket[:action] == close && !ticket[:workorderid].nil?}
345
- end
355
+ def close_tickets( tickets )
356
+ tickets.each { |ticket| close_ticket(ticket) if ticket[:action] == :close && !ticket[:workorderid].nil?}
357
+ remove_tickets_from_database(tickets)
358
+ end
346
359
  end