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.
@@ -64,8 +64,13 @@ module NexposeTicketing
64
64
  # |url| |summary| |fix|
65
65
  #
66
66
  def self.all_new_vulns(options = {})
67
- "SELECT DISTINCT on (da.ip_address, davs.solution_id) subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, davs.solution_id, ds.nexpose_id,
68
- ds.url,proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, fa.riskscore, dv.cvss_score, dvr.source, dvr.reference,
67
+ "SELECT DISTINCT on (da.ip_address, subs.vulnerability_id) subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
68
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
69
+ '|Nexpose ID: ' || ds.nexpose_id ||
70
+ '|Fix: ' || coalesce(proofAsText(ds.fix), 'None') ||
71
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
72
+ fa.riskscore, dv.cvss_score,
73
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references,
69
74
  fasva.first_discovered, fasva.most_recently_discovered
70
75
  FROM (SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan
71
76
  FROM fact_asset_scan_vulnerability_finding fasv
@@ -77,15 +82,17 @@ module NexposeTicketing
77
82
  GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan, fasv.scan_id
78
83
  HAVING NOT baselineComparison(fasv.scan_id, current_scan) = 'Old'
79
84
  ) subs
80
- JOIN dim_vulnerability dv USING (vulnerability_id)
81
- JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
82
- JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
83
- JOIN fact_asset_vulnerability_age fasva ON subs.vulnerability_id = fasva.vulnerability_id AND subs.asset_id = fasva.asset_id
84
- JOIN dim_solution ds USING (solution_id)
85
- JOIN dim_asset da ON subs.asset_id = da.asset_id
86
- JOIN fact_asset fa ON fa.asset_id = da.asset_id
87
- #{createRiskString( options[:riskScore])}
88
- ORDER BY da.ip_address, davs.solution_id"
85
+ JOIN dim_vulnerability dv USING (vulnerability_id)
86
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
87
+ JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
88
+ JOIN fact_asset_vulnerability_age fasva ON subs.vulnerability_id = fasva.vulnerability_id AND subs.asset_id = fasva.asset_id
89
+ JOIN dim_solution ds USING (solution_id)
90
+ JOIN dim_asset da ON subs.asset_id = da.asset_id
91
+ JOIN fact_asset fa ON fa.asset_id = da.asset_id
92
+ #{createRiskString( options[:riskScore])}
93
+ GROUP BY subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
94
+ fa.riskscore, dv.cvss_score, fasva.first_discovered, fasva.most_recently_discovered
95
+ ORDER BY da.ip_address, subs.vulnerability_id"
89
96
  end
90
97
 
91
98
  # Gets all delta vulns for all sites sorted by vuln ID.
@@ -95,25 +102,38 @@ module NexposeTicketing
95
102
  # |url| |summary| |fix|
96
103
  #
97
104
  def self.all_new_vulns_by_vuln_id(options = {})
98
- "SELECT DISTINCT on (subs.vulnerability_id, subs.asset_id, davs.solution_id) subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, dv.title, davs.solution_id, ds.nexpose_id,
99
- ds.url,proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, fa.riskscore
100
- FROM (SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan
101
- FROM fact_asset_scan_vulnerability_finding fasv
102
- JOIN
103
- (
104
- SELECT asset_id, previousScan(asset_id) AS baseline_scan, lastScan(asset_id) AS current_scan
105
- FROM dim_asset #{createAssetString(options)}) s
106
- ON s.asset_id = fasv.asset_id AND (fasv.scan_id = s.baseline_scan OR fasv.scan_id = s.current_scan)
107
- GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan, fasv.scan_id
108
- HAVING NOT baselineComparison(fasv.scan_id, current_scan) = 'Old'
109
- ) subs
110
- JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
111
- JOIN dim_solution ds USING (solution_id)
112
- JOIN dim_asset da ON subs.asset_id = da.asset_id
113
- JOIN dim_vulnerability dv ON subs.vulnerability_id = dv.vulnerability_id
114
- JOIN fact_asset fa ON fa.asset_id = da.asset_id
115
- #{createRiskString(options[:riskScore])}
116
- ORDER BY subs.vulnerability_id, subs.asset_id, davs.solution_id"
105
+ "SELECT DISTINCT on (subs.vulnerability_id) subs.vulnerability_id, dv.title, MAX(dv.cvss_score) as cvss_score,
106
+ string_agg(DISTINCT subs.asset_id ||
107
+ '|' || da.ip_address ||
108
+ '|' || coalesce(da.host_name, '') ||
109
+ '|' || fa.riskscore, '~') as assets,
110
+
111
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
112
+ '|Nexpose ID: ' || ds.nexpose_id ||
113
+ '|Fix: ' || coalesce(proofAsText(ds.fix)) ||
114
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
115
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references
116
+ FROM (SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan
117
+ FROM fact_asset_scan_vulnerability_finding fasv
118
+ JOIN
119
+ (
120
+ SELECT asset_id, previousScan(asset_id) AS baseline_scan, lastScan(asset_id) AS current_scan
121
+ FROM dim_asset #{createAssetString(options)}) s
122
+ ON s.asset_id = fasv.asset_id AND (fasv.scan_id = s.baseline_scan OR fasv.scan_id = s.current_scan)
123
+ GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan, fasv.scan_id
124
+ HAVING NOT baselineComparison(fasv.scan_id, current_scan) = 'Old'
125
+ ) subs
126
+ JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
127
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
128
+ JOIN dim_solution ds USING (solution_id)
129
+ JOIN dim_asset da ON subs.asset_id = da.asset_id
130
+ JOIN dim_vulnerability dv ON subs.vulnerability_id = dv.vulnerability_id
131
+ JOIN fact_asset fa ON fa.asset_id = da.asset_id
132
+ JOIN fact_asset_vulnerability_age fasva ON subs.vulnerability_id = fasva.vulnerability_id AND subs.asset_id = fasva.asset_id
133
+ #{createRiskString(options[:riskScore])}
134
+
135
+ GROUP BY subs.vulnerability_id, dv.title
136
+ ORDER BY subs.vulnerability_id"
117
137
  end
118
138
 
119
139
  # Gets all new vulnerabilities happening after a reported scan id.
@@ -126,25 +146,36 @@ module NexposeTicketing
126
146
  # |url| |summary| |fix|
127
147
  #
128
148
  def self.new_vulns_since_scan(options = {})
129
- "SELECT subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, davs.solution_id, ds.nexpose_id,
130
- ds.url, proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, fa.riskscore
149
+ "SELECT DISTINCT on (da.ip_address, subs.vulnerability_id) subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
150
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
151
+ '|Nexpose ID: ' || ds.nexpose_id ||
152
+ '|Fix: ' || coalesce(proofAsText(ds.fix), 'None') ||
153
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
154
+ fa.riskscore, dv.cvss_score,
155
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references,
156
+ fasva.first_discovered, fasva.most_recently_discovered
131
157
  FROM (SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan
132
158
  FROM fact_asset_scan_vulnerability_finding fasv
133
159
  JOIN
134
160
  (
135
161
  SELECT asset_id, previousScan(asset_id) AS baseline_scan, lastScan(asset_id) AS current_scan
136
162
  FROM dim_asset #{createAssetString(options)}) s
137
- ON s.asset_id = fasv.asset_id AND (fasv.scan_id >= #{options[:scan_id]} OR fasv.scan_id = s.current_scan)
163
+ ON s.asset_id = fasv.asset_id AND (fasv.scan_id >= #{options[:scan_id]} OR fasv.scan_id = s.current_scan)
138
164
  GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan
139
165
  HAVING baselineComparison(fasv.scan_id, current_scan) = 'New'
140
166
  ) subs
167
+ JOIN dim_vulnerability dv USING (vulnerability_id)
168
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
141
169
  JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
170
+ JOIN fact_asset_vulnerability_age fasva ON subs.vulnerability_id = fasva.vulnerability_id AND subs.asset_id = fasva.asset_id
142
171
  JOIN dim_solution ds USING (solution_id)
143
172
  JOIN dim_asset da ON subs.asset_id = da.asset_id
144
173
  AND subs.current_scan > #{options[:scan_id]}
145
174
  JOIN fact_asset fa ON fa.asset_id = da.asset_id
146
175
  #{createRiskString(options[:riskScore])}
147
- ORDER BY da.ip_address"
176
+ GROUP BY subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
177
+ fa.riskscore, dv.cvss_score, fasva.first_discovered, fasva.most_recently_discovered
178
+ ORDER BY da.ip_address, subs.vulnerability_id"
148
179
  end
149
180
 
150
181
 
@@ -158,8 +189,17 @@ module NexposeTicketing
158
189
  # |url| |summary| |fix|
159
190
  #
160
191
  def self.new_vulns_by_vuln_id_since_scan(options = {})
161
- "SELECT DISTINCT on (subs.vulnerability_id, subs.asset_id, davs.solution_id) subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, davs.solution_id, ds.nexpose_id,
162
- ds.url, proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, fa.riskscore
192
+ "SELECT DISTINCT on (subs.vulnerability_id) subs.vulnerability_id, dv.title, MAX(dv.cvss_score) as cvss_score,
193
+ string_agg(DISTINCT subs.asset_id ||
194
+ '|' || da.ip_address ||
195
+ '|' || coalesce(da.host_name, '') ||
196
+ '|' || fa.riskscore, '~') as assets,
197
+
198
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
199
+ '|Nexpose ID: ' || ds.nexpose_id ||
200
+ '|Fix: ' || coalesce(proofAsText(ds.fix)) ||
201
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
202
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references
163
203
  FROM (SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan
164
204
  FROM fact_asset_scan_vulnerability_finding fasv
165
205
  JOIN
@@ -170,13 +210,17 @@ module NexposeTicketing
170
210
  GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan
171
211
  HAVING baselineComparison(fasv.scan_id, current_scan) = 'New'
172
212
  ) subs
213
+ JOIN dim_vulnerability dv USING (vulnerability_id)
214
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
173
215
  JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
216
+ JOIN fact_asset_vulnerability_age fasva ON subs.vulnerability_id = fasva.vulnerability_id AND subs.asset_id = fasva.asset_id
174
217
  JOIN dim_solution ds USING (solution_id)
175
218
  JOIN dim_asset da ON subs.asset_id = da.asset_id
176
219
  AND subs.current_scan > #{options[:scan_id]}
177
220
  JOIN fact_asset fa ON fa.asset_id = da.asset_id
178
221
  #{createRiskString(options[:riskScore])}
179
- ORDER BY subs.vulnerability_id, subs.asset_id, davs.solution_id"
222
+ GROUP BY subs.vulnerability_id, dv.title
223
+ ORDER BY vulnerability_id"
180
224
  end
181
225
 
182
226
 
@@ -190,7 +234,7 @@ module NexposeTicketing
190
234
  # |url| |summary| |fix|
191
235
  #
192
236
  def self.old_vulns_since_scan(options = {})
193
- "SELECT subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, dvs.solution_id, ds.nexpose_id, ds.url,
237
+ "SELECT DISTINCT on (da.ip_address, subs.vulnerability_id) subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id, dvs.solution_id, ds.nexpose_id, ds.url,
194
238
  proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, subs.comparison, fa.riskscore
195
239
  FROM (
196
240
  SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan, baselineComparison(fasv.scan_id, s.current_scan) as comparison
@@ -223,8 +267,14 @@ module NexposeTicketing
223
267
  # |url| |summary| |fix| |comparison|
224
268
  #
225
269
  def self.all_vulns_since_scan(options = {})
226
- "SELECT subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, dvs.solution_id, ds.nexpose_id, ds.url,
227
- proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, subs.comparison, fa.riskscore
270
+ "SELECT DISTINCT on (da.ip_address, subs.vulnerability_id) subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
271
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
272
+ '|Nexpose ID: ' || ds.nexpose_id ||
273
+ '|Fix: ' || coalesce(proofAsText(ds.fix), 'None') ||
274
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
275
+ subs.comparison, fa.riskscore, dv.cvss_score,
276
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references,
277
+ null as first_discovered, null as most_recently_discovered
228
278
  FROM (
229
279
  SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan, baselineComparison(fasv.scan_id, s.current_scan) as comparison
230
280
  FROM fact_asset_scan_vulnerability_finding fasv
@@ -235,17 +285,27 @@ module NexposeTicketing
235
285
  GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan
236
286
  HAVING baselineComparison(fasv.scan_id, current_scan) = 'Old'
237
287
  ) subs
288
+ JOIN dim_vulnerability dv USING (vulnerability_id)
289
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
238
290
  JOIN dim_vulnerability_solution dvs USING (vulnerability_id)
239
291
  JOIN dim_solution ds USING (solution_id)
240
292
  JOIN dim_asset da ON subs.asset_id = da.asset_id
241
- JOIN fact_asset fa ON fa.asset_id = subs.asset_id
242
- #{createRiskString(options[:riskScore])}
293
+ JOIN fact_asset fa ON fa.asset_id = subs.asset_id
294
+ #{createRiskString(options[:riskScore])}
243
295
  AND subs.current_scan > #{options[:scan_id]}
296
+ GROUP BY subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
297
+ fa.riskscore, dv.cvss_score, subs.comparison
244
298
 
245
299
  UNION
246
300
 
247
- SELECT subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, davs.solution_id, ds.nexpose_id, ds.url,
248
- proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, subs.comparison, fa.riskscore
301
+ SELECT DISTINCT on (da.ip_address, subs.vulnerability_id) subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
302
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
303
+ '|Nexpose ID: ' || ds.nexpose_id ||
304
+ '|Fix: ' || coalesce(proofAsText(ds.fix), 'None') ||
305
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
306
+ subs.comparison, fa.riskscore, dv.cvss_score,
307
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references,
308
+ fasva.first_discovered, fasva.most_recently_discovered
249
309
  FROM
250
310
  (
251
311
  SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan, baselineComparison(fasv.scan_id, s.current_scan) as comparison
@@ -258,18 +318,23 @@ module NexposeTicketing
258
318
  GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan
259
319
  HAVING baselineComparison(fasv.scan_id, current_scan) IN ('Same','New')
260
320
  ) subs
321
+ JOIN dim_vulnerability dv USING (vulnerability_id)
322
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
261
323
  JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
324
+ JOIN fact_asset_vulnerability_age fasva ON subs.vulnerability_id = fasva.vulnerability_id AND subs.asset_id = fasva.asset_id
262
325
  JOIN dim_solution ds USING (solution_id)
263
326
  JOIN dim_asset da ON subs.asset_id = da.asset_id
264
327
  JOIN fact_asset fa ON fa.asset_id = subs.asset_id
265
- #{createRiskString(options[:riskScore])}
328
+ #{createRiskString(options[:riskScore])}
266
329
  AND subs.current_scan > #{options[:scan_id]}
330
+ GROUP BY subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
331
+ fa.riskscore, dv.cvss_score, fasva.first_discovered, fasva.most_recently_discovered, subs.comparison
267
332
 
268
333
  ORDER BY ip_address, comparison"
269
334
  end
270
335
 
271
336
  # Gets all vulnerabilities happening after a reported scan id. Sorted by vuln ID. This result set also includes the
272
- # baseline comparision ("Old", "New", or "Same") allowing for IP-based ticket updating.
337
+ # baseline comparision ("Old", "New", or "Same") allowing for vulnerability-based ticket updating.
273
338
  #
274
339
  # * *Args* :
275
340
  # - +reported_scan+ - Last reported scan id.
@@ -279,8 +344,18 @@ module NexposeTicketing
279
344
  # |url| |summary| |fix| |comparison|
280
345
  #
281
346
  def self.all_vulns_by_vuln_id_since_scan(options = {})
282
- "SELECT subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, dv.title, dvs.solution_id, ds.nexpose_id, ds.url,
283
- proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, subs.comparison, fa.riskscore
347
+ "SELECT DISTINCT on (subs.vulnerability_id, subs.comparison) subs.vulnerability_id, dv.title, MAX(dv.cvss_score) as cvss_score,
348
+ string_agg(DISTINCT subs.asset_id ||
349
+ '|' || da.ip_address ||
350
+ '|' || coalesce(da.host_name, '') ||
351
+ '|' || fa.riskscore, '~') as assets,
352
+
353
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
354
+ '|Nexpose ID: ' || ds.nexpose_id ||
355
+ '|Fix: ' || coalesce(proofAsText(ds.fix)) ||
356
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
357
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references,
358
+ subs.comparison
284
359
  FROM (
285
360
  SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan, baselineComparison(fasv.scan_id, s.current_scan) as comparison
286
361
  FROM fact_asset_scan_vulnerability_finding fasv
@@ -291,19 +366,31 @@ module NexposeTicketing
291
366
  GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan
292
367
  HAVING baselineComparison(fasv.scan_id, current_scan) = 'Old'
293
368
  ) subs
369
+ JOIN dim_vulnerability dv USING (vulnerability_id)
370
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
294
371
  JOIN dim_vulnerability_solution dvs USING (vulnerability_id)
295
372
  JOIN dim_solution ds USING (solution_id)
296
373
  JOIN dim_asset da ON subs.asset_id = da.asset_id
297
- JOIN dim_vulnerability dv ON subs.vulnerability_id = dv.vulnerability_id
298
- JOIN fact_asset fa ON fa.asset_id = subs.asset_id
299
- #{createRiskString(options[:riskScore])}
374
+ JOIN fact_asset fa ON fa.asset_id = subs.asset_id
375
+ #{createRiskString(options[:riskScore])}
300
376
  AND subs.current_scan > #{options[:scan_id]}
377
+ GROUP BY subs.vulnerability_id, dv.title, subs.comparison
301
378
 
302
379
  UNION
303
380
 
304
- SELECT subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, dv.title, davs.solution_id, ds.nexpose_id, ds.url,
305
- proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, subs.comparison, fa.riskscore
306
- FROM
381
+ SELECT DISTINCT on (subs.vulnerability_id, subs.comparison) subs.vulnerability_id, dv.title, MAX(dv.cvss_score) as cvss_score,
382
+ string_agg(DISTINCT subs.asset_id ||
383
+ '|' || da.ip_address ||
384
+ '|' || coalesce(da.host_name, '') ||
385
+ '|' || fa.riskscore, '~') as assets,
386
+
387
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
388
+ '|Nexpose ID: ' || ds.nexpose_id ||
389
+ '|Fix: ' || coalesce(proofAsText(ds.fix)) ||
390
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
391
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references,
392
+ subs.comparison
393
+ FROM
307
394
  (
308
395
  SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan, baselineComparison(fasv.scan_id, s.current_scan) as comparison
309
396
  FROM fact_asset_scan_vulnerability_finding fasv
@@ -315,15 +402,17 @@ module NexposeTicketing
315
402
  GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan
316
403
  HAVING baselineComparison(fasv.scan_id, current_scan) IN ('Same','New')
317
404
  ) subs
405
+ JOIN dim_vulnerability dv USING (vulnerability_id)
406
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
318
407
  JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
319
408
  JOIN dim_solution ds USING (solution_id)
320
409
  JOIN dim_asset da ON subs.asset_id = da.asset_id
321
- JOIN dim_vulnerability dv ON subs.vulnerability_id = dv.vulnerability_id
322
- JOIN fact_asset fa ON fa.asset_id = subs.asset_id
323
- #{createRiskString(options[:riskScore])}
410
+ JOIN fact_asset fa ON fa.asset_id = subs.asset_id
411
+ #{createRiskString(options[:riskScore])}
324
412
  AND subs.current_scan > #{options[:scan_id]}
413
+ GROUP BY subs.vulnerability_id, dv.title, subs.comparison
325
414
 
326
- ORDER BY vulnerability_id, comparison, asset_id, solution_id"
415
+ ORDER BY vulnerability_id, comparison"
327
416
  end
328
417
 
329
418
 
@@ -336,7 +425,7 @@ module NexposeTicketing
336
425
  # - Returns |asset_id| |ip_address| |current_scan| |vulnerability_id| |comparison|
337
426
  #
338
427
  def self.old_tickets_by_ip(options = {})
339
- "SELECT subs.asset_id, subs.ip_address, subs.current_scan, subs.vulnerability_id, subs.comparison
428
+ "SELECT DISTINCT on(subs.ip_address) subs.asset_id, subs.ip_address, subs.current_scan, subs.vulnerability_id, subs.comparison
340
429
  FROM (
341
430
  SELECT fasv.asset_id, s.ip_address, fasv.vulnerability_id, s.current_scan, baselineComparison(fasv.scan_id, s.current_scan) as comparison
342
431
  FROM fact_asset_scan_vulnerability_finding fasv
@@ -5,6 +5,8 @@ module NexposeTicketing
5
5
  require 'nexpose'
6
6
  require 'nexpose_ticketing/queries'
7
7
  require 'nexpose_ticketing/report_helper'
8
+ require 'nexpose_ticketing/nx_logger'
9
+ require 'nexpose_ticketing/version'
8
10
 
9
11
  @timeout = 10800
10
12
 
@@ -13,8 +15,12 @@ module NexposeTicketing
13
15
  end
14
16
 
15
17
  def nexpose_login(nexpose_data)
18
+
16
19
  @nsc = Nexpose::Connection.new(nexpose_data[:nxconsole], nexpose_data[:nxuser], nexpose_data[:nxpasswd])
17
20
  @nsc.login
21
+ @log = NexposeTicketing::NxLogger.instance
22
+ @log.on_connect(nexpose_data[:nxconsole], 3780, @nsc.session_id, "{}")
23
+
18
24
  #After login, create the report helper
19
25
  @report_helper = NexposeReportHelper::ReportOps.new(@nsc, @timeout)
20
26
  end
@@ -52,9 +52,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52
52
  require 'yaml'
53
53
  require 'fileutils'
54
54
  require 'nexpose_ticketing/ticket_repository'
55
+ require 'nexpose_ticketing'
56
+ require 'nexpose_ticketing/nx_logger'
57
+ require 'nexpose_ticketing/version'
55
58
 
56
59
  TICKET_SERVICE_CONFIG_PATH = File.join(File.dirname(__FILE__), '/config/ticket_service.config')
57
- LOGGER_FILE = File.join(File.dirname(__FILE__), '/log/ticket_service.log')
60
+ LOGGER_FILE = File.join(File.dirname(__FILE__), '/logs/ticket_service.log')
58
61
 
59
62
  attr_accessor :helper_data, :nexpose_data, :options, :ticket_repository, :first_time, :nexpose_item_histories
60
63
 
@@ -90,14 +93,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
90
93
  end
91
94
 
92
95
  def setup_logging(enabled = false)
93
- if enabled
94
- require 'logger'
95
- directory = File.dirname(LOGGER_FILE)
96
- FileUtils.mkdir_p(directory) unless File.directory?(directory)
97
- @log = Logger.new(LOGGER_FILE, 'monthly')
98
- @log.level = Logger::INFO
99
- log_message('Logging enabled, starting service.')
100
- end
96
+ helper_log = NexposeTicketing::NxLogger.instance
97
+ helper_log.setup_logging(@options[:logging_enabled],
98
+ @options[:log_level])
99
+
100
+ return unless enabled
101
+ require 'logger'
102
+ directory = File.dirname(LOGGER_FILE)
103
+ FileUtils.mkdir_p(directory) unless File.directory?(directory)
104
+ @log = Logger.new(LOGGER_FILE, 'monthly')
105
+ @log.level = Logger::INFO
106
+ log_message('Logging enabled, starting service.')
101
107
  end
102
108
 
103
109
  # Logs a message if logging is enabled.
@@ -222,6 +228,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
222
228
  # There's a new scan with possibly new vulnerabilities.
223
229
  def delta_site_new_scan(ticket_repository, nexpose_item, options, helper, file_site_histories, tag_id=nil)
224
230
  log_message("New scan detected for nexpose id: #{nexpose_item}. Generating report.")
231
+ item = options[:tag_run] ? 'asset' : 'site'
225
232
 
226
233
  if options[:ticket_mode] == 'I' || options[:ticket_mode] == 'V'
227
234
  # I-mode and V-mode tickets require updating the tickets in the target system.
@@ -270,16 +277,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
270
277
  tag_run: options[:tag_run],
271
278
  tag: tag_id)
272
279
 
273
- preparse = CSV.new(new_scan_vuln_file.path, headers: :first_row)
280
+ preparse = CSV.open(new_scan_vuln_file.path, headers: :first_row)
274
281
  empty_report = preparse.shift.nil?
275
- log_message("No new vulnerabilities found in new scan for site: #{nexpose_item}.") if empty_report
276
- log_message("New vulnerabilities found in new scan for site #{nexpose_item}, preparing tickets.") unless empty_report
282
+ preparse.close
283
+
284
+
285
+ log_message("No new vulnerabilities found in new scan for #{item}: #{nexpose_item}.") if empty_report
286
+ log_message("New vulnerabilities found in new scan for #{item} #{nexpose_item}, preparing tickets.") unless empty_report
277
287
  unless empty_report
278
288
  ticket_rate_limiter(options, new_scan_vuln_file, Proc.new {|ticket_batch| helper.prepare_create_tickets(ticket_batch, tag_id.nil? ? nexpose_item : "T#{tag_id}")}, Proc.new {|tickets| helper.create_tickets(tickets)})
279
289
  end
280
290
 
281
291
  if helper.respond_to?('prepare_close_tickets') && helper.respond_to?('close_tickets')
282
292
  old_scan_vuln_file = ticket_repository.old_vulns(scan_id: file_site_histories[nexpose_item],
293
+ nexpose_item: nexpose_item,
283
294
  site_id: nexpose_item,
284
295
  severity: options[:severity],
285
296
  riskScore: options[:riskScore],
@@ -287,10 +298,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
287
298
  tag_run: options[:tag_run],
288
299
  tag: tag_id)
289
300
 
290
- preparse = CSV.new(old_scan_vuln_file.path, headers: :first_row, :skip_blanks => true)
301
+ preparse = CSV.open(old_scan_vuln_file.path, headers: :first_row, :skip_blanks => true)
291
302
  empty_report = preparse.shift.nil?
292
- log_message("No old (closed) vulnerabilities found in new scan for site: #{nexpose_item}.") if empty_report
293
- log_message("Old vulnerabilities found in new scan for site #{nexpose_item}, preparing closures.") unless empty_report
303
+ preparse.close
304
+ log_message("No old (closed) vulnerabilities found in new scan for #{item}: #{nexpose_item}.") if empty_report
305
+ log_message("Old vulnerabilities found in new scan for #{item} #{nexpose_item}, preparing closures.") unless empty_report
294
306
  unless empty_report
295
307
  ticket_rate_limiter(options, old_scan_vuln_file, Proc.new {|ticket_batch| helper.prepare_close_tickets(ticket_batch, tag_id.nil? ? nexpose_item : "T#{tag_id}")}, Proc.new {|tickets| helper.close_tickets(tickets)})
296
308
  end
@@ -366,7 +378,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
366
378
  # Prep the batch of tickets
367
379
  log_message('Creating tickets.')
368
380
  tickets = ticket_prepare_method.call(ticket_batch.join(''))
369
- log_message("Generated tickets: #{ticket_batch.size}")
381
+ log_message("Parsed rows: #{ticket_batch.size}")
370
382
  # Sent them off
371
383
  log_message('Sending tickets.')
372
384
  ticket_send_method.call(tickets)