nexpose_ticketing 0.0.1 → 0.2.1
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 +8 -8
- data/{README.markdown → README.md} +43 -38
- data/bin/nexpose_jira +2 -3
- data/bin/nexpose_remedy +17 -0
- data/bin/nexpose_servicenow +17 -0
- data/lib/nexpose_ticketing.rb +3 -1
- data/lib/nexpose_ticketing/config/remedy.config +26 -0
- data/lib/nexpose_ticketing/config/remedy_wsdl/HPD_IncidentInterface_Create_WS.xml +296 -0
- data/lib/nexpose_ticketing/config/remedy_wsdl/HPD_IncidentInterface_WS.xml +675 -0
- data/lib/nexpose_ticketing/config/servicenow.config +18 -0
- data/lib/nexpose_ticketing/config/ticket_service.config +2 -2
- data/lib/nexpose_ticketing/helpers/jira_helper.rb +6 -6
- data/lib/nexpose_ticketing/helpers/remedy_helper.rb +448 -0
- data/lib/nexpose_ticketing/helpers/servicenow_helper.rb +315 -0
- data/lib/nexpose_ticketing/nx_logger.rb +35 -0
- data/lib/nexpose_ticketing/queries.rb +105 -14
- data/lib/nexpose_ticketing/ticket_repository.rb +57 -12
- data/lib/nexpose_ticketing/ticket_service.rb +56 -19
- data/nexpose_ticketing.gemspec +5 -4
- metadata +29 -4
@@ -5,7 +5,7 @@ module NexposeTicketing
|
|
5
5
|
require 'nexpose'
|
6
6
|
require 'nexpose_ticketing/queries'
|
7
7
|
|
8
|
-
def nexpose_login
|
8
|
+
def nexpose_login(nexpose_data)
|
9
9
|
@nsc = Nexpose::Connection.new(nexpose_data[:nxconsole], nexpose_data[:nxuser], nexpose_data[:nxpasswd])
|
10
10
|
@nsc.login
|
11
11
|
end
|
@@ -32,10 +32,10 @@ module NexposeTicketing
|
|
32
32
|
# - +csv_file_name+ - CSV File name.
|
33
33
|
#
|
34
34
|
def save_last_scans(csv_file_name, saved_file = nil, report_config = Nexpose::AdhocReportConfig.new(nil, 'sql'))
|
35
|
-
report_config.add_filter('version', '1.
|
35
|
+
report_config.add_filter('version', '1.2.0')
|
36
36
|
report_config.add_filter('query', Queries.last_scans)
|
37
37
|
report_output = report_config.generate(@nsc)
|
38
|
-
csv_output = CSV.parse(report_output.chomp, headers: :first_row
|
38
|
+
csv_output = CSV.parse(report_output.chomp, headers: :first_row)
|
39
39
|
saved_file.open(csv_file_name, 'w') { |file| file.puts(csv_output) } unless saved_file.nil?
|
40
40
|
if saved_file.nil?
|
41
41
|
File.open(csv_file_name, 'w') { |file| file.puts(csv_output) }
|
@@ -48,7 +48,7 @@ module NexposeTicketing
|
|
48
48
|
# - A hash with site_ids => last_scan_id
|
49
49
|
#
|
50
50
|
def last_scans(report_config = Nexpose::AdhocReportConfig.new(nil, 'sql'))
|
51
|
-
report_config.add_filter('version', '1.
|
51
|
+
report_config.add_filter('version', '1.2.0')
|
52
52
|
report_config.add_filter('query', Queries.last_scans)
|
53
53
|
report_output = report_config.generate(@nsc).chomp
|
54
54
|
nexpose_sites = Hash.new(-1)
|
@@ -64,13 +64,14 @@ module NexposeTicketing
|
|
64
64
|
# - +site_options+ - A Hash with site(s) and severity level.
|
65
65
|
#
|
66
66
|
# * *Returns* :
|
67
|
-
# - Returns CSV |asset_id| |ip_address| |current_scan| |vulnerability_id| |solution_id| |nexpose_id|
|
67
|
+
# - Returns CSV |asset_id| |ip_address| |current_scan| |vulnerability_id| |solution_id| |nexpose_id|
|
68
|
+
# |url| |summary| |fix|
|
68
69
|
#
|
69
70
|
def all_vulns(site_options = {}, report_config = Nexpose::AdhocReportConfig.new(nil, 'sql'))
|
70
71
|
sites = Array(site_options[:sites])
|
71
72
|
severity = site_options[:severity].nil? ? 0 : site_options[:severity]
|
72
|
-
report_config.add_filter('version', '1.
|
73
|
-
report_config.add_filter('query', Queries.
|
73
|
+
report_config.add_filter('version', '1.2.0')
|
74
|
+
report_config.add_filter('query', Queries.all_new_vulns)
|
74
75
|
unless sites.empty?
|
75
76
|
sites.each do |site_id|
|
76
77
|
report_config.add_filter('site', site_id)
|
@@ -80,21 +81,65 @@ module NexposeTicketing
|
|
80
81
|
report_config.generate(@nsc)
|
81
82
|
end
|
82
83
|
|
83
|
-
# Gets the
|
84
|
+
# Gets the new vulns from base scan reported_scan_id and the newest / latest scan from a site.
|
84
85
|
#
|
85
86
|
# * *Args* :
|
86
87
|
# - +site_options+ - A Hash with site(s), reported_scan_id and severity level.
|
87
88
|
#
|
88
89
|
# * *Returns* :
|
89
|
-
# - Returns CSV |asset_id| |ip_address| |current_scan| |vulnerability_id| |solution_id| |nexpose_id|
|
90
|
+
# - Returns CSV |asset_id| |ip_address| |current_scan| |vulnerability_id| |solution_id| |nexpose_id|
|
91
|
+
# |url| |summary| |fix|
|
90
92
|
#
|
91
|
-
def
|
93
|
+
def new_vulns_sites(site_options = {}, report_config = Nexpose::AdhocReportConfig.new(nil, 'sql'))
|
92
94
|
site = site_options[:site_id]
|
93
95
|
reported_scan_id = site_options[:scan_id]
|
94
96
|
fail 'Site cannot be null or empty' if site.nil? || reported_scan_id.nil?
|
95
97
|
severity = site_options[:severity].nil? ? 0 : site_options[:severity]
|
96
|
-
report_config.add_filter('version', '1.
|
97
|
-
report_config.add_filter('query', Queries.
|
98
|
+
report_config.add_filter('version', '1.2.0')
|
99
|
+
report_config.add_filter('query', Queries.new_vulns_since_scan(reported_scan_id))
|
100
|
+
report_config.add_filter('site', site)
|
101
|
+
report_config.add_filter('vuln-severity', severity)
|
102
|
+
report_config.generate(@nsc)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Gets the old vulns from base scan reported_scan_id and the newest / latest scan from a site.
|
106
|
+
#
|
107
|
+
# * *Args* :
|
108
|
+
# - +site_options+ - A Hash with site(s), reported_scan_id and severity level.
|
109
|
+
#
|
110
|
+
# * *Returns* :
|
111
|
+
# - Returns CSV |asset_id| |ip_address| |current_scan| |vulnerability_id| |solution_id| |nexpose_id|
|
112
|
+
# |url| |summary| |fix|
|
113
|
+
#
|
114
|
+
def old_vulns_sites(site_options = {}, report_config = Nexpose::AdhocReportConfig.new(nil, 'sql'))
|
115
|
+
site = site_options[:site_id]
|
116
|
+
reported_scan_id = site_options[:scan_id]
|
117
|
+
fail 'Site cannot be null or empty' if site.nil? || reported_scan_id.nil?
|
118
|
+
severity = site_options[:severity].nil? ? 0 : site_options[:severity]
|
119
|
+
report_config.add_filter('version', '1.2.0')
|
120
|
+
report_config.add_filter('query', Queries.old_vulns_since_scan(reported_scan_id))
|
121
|
+
report_config.add_filter('site', site)
|
122
|
+
report_config.add_filter('vuln-severity', severity)
|
123
|
+
report_config.generate(@nsc)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Gets all vulns from base scan reported_scan_id and the newest / latest scan from a site. This is
|
127
|
+
# used for IP-based issue updating. Includes the baseline comparision value ('Old','New', or 'Same').
|
128
|
+
#
|
129
|
+
# * *Args* :
|
130
|
+
# - +site_options+ - A Hash with site(s), reported_scan_id and severity level.
|
131
|
+
#
|
132
|
+
# * *Returns* :
|
133
|
+
# - Returns CSV |asset_id| |ip_address| |current_scan| |vulnerability_id| |solution_id| |nexpose_id|
|
134
|
+
# |url| |summary| |fix| |comparison|
|
135
|
+
#
|
136
|
+
def all_vulns_sites(site_options = {}, report_config = Nexpose::AdhocReportConfig.new(nil, 'sql'))
|
137
|
+
site = site_options[:site_id]
|
138
|
+
reported_scan_id = site_options[:scan_id]
|
139
|
+
fail 'Site cannot be null or empty' if site.nil? || reported_scan_id.nil?
|
140
|
+
severity = site_options[:severity].nil? ? 0 : site_options[:severity]
|
141
|
+
report_config.add_filter('version', '1.2.0')
|
142
|
+
report_config.add_filter('query', Queries.all_vulns_since_scan(reported_scan_id))
|
98
143
|
report_config.add_filter('site', site)
|
99
144
|
report_config.add_filter('vuln-severity', severity)
|
100
145
|
report_config.generate(@nsc)
|
@@ -53,8 +53,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
53
53
|
require 'fileutils'
|
54
54
|
require 'nexpose_ticketing/ticket_repository'
|
55
55
|
|
56
|
-
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')
|
56
|
+
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')
|
58
58
|
|
59
59
|
attr_accessor :helper_data, :nexpose_data, :options, :ticket_repository, :first_time, :nexpose_site_histories
|
60
60
|
|
@@ -75,7 +75,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
75
75
|
|
76
76
|
# Loads all the helpers.
|
77
77
|
log_message('Loading helpers.')
|
78
|
-
Dir[File.join(File.dirname(__FILE__),'/helpers/*.rb')].each do |file|
|
78
|
+
Dir[File.join(File.dirname(__FILE__), '/helpers/*.rb')].each do |file|
|
79
79
|
log_message("Loading helper: #{file}")
|
80
80
|
require_relative file
|
81
81
|
end
|
@@ -103,7 +103,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
103
103
|
end
|
104
104
|
|
105
105
|
# Prepares all the local and nexpose historical data.
|
106
|
-
def prepare_historical_data(ticket_repository, options,
|
106
|
+
def prepare_historical_data(ticket_repository, options,
|
107
|
+
historical_scan_file = File.join(File.dirname(__FILE__), "#{options[:file_name]}"))
|
107
108
|
if File.exists?(historical_scan_file)
|
108
109
|
log_message("Reading historical CSV file: #{historical_scan_file}.")
|
109
110
|
file_site_histories = ticket_repository.read_last_scans(historical_scan_file)
|
@@ -118,20 +119,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
118
119
|
end
|
119
120
|
|
120
121
|
# Generates a full site(s) report ticket(s).
|
121
|
-
def all_site_report(ticket_repository, options, helper,
|
122
|
+
def all_site_report(ticket_repository, options, helper,
|
123
|
+
historical_scan_file = File.join(File.dirname(__FILE__), "#{options[:file_name]}"))
|
122
124
|
log_message('First time run, generating full vulnerability report.') if @first_time
|
123
125
|
log_message('No site(s) specified, generating full vulnerability report.') if options[:sites].empty?
|
124
126
|
all_delta_vulns = ticket_repository.all_vulns(severity: options[:severity])
|
125
127
|
log_message('Preparing tickets.')
|
126
|
-
tickets = helper.
|
127
|
-
helper.
|
128
|
+
tickets = helper.prepare_create_tickets(all_delta_vulns)
|
129
|
+
helper.create_tickets(tickets)
|
128
130
|
log_message("Done processing, updating historical CSV file #{historical_scan_file}.")
|
129
131
|
ticket_repository.save_last_scans(historical_scan_file)
|
130
132
|
log_message('Done updating historical CSV file, service shutting down.')
|
131
133
|
end
|
132
134
|
|
133
135
|
# There's possibly a new scan with new data.
|
134
|
-
def delta_site_report(ticket_repository, options, helper, file_site_histories,
|
136
|
+
def delta_site_report(ticket_repository, options, helper, file_site_histories,
|
137
|
+
historical_scan_file = File.join(File.dirname(__FILE__), "#{options[:file_name]}"))
|
135
138
|
# Compares the Scan information from the File && Nexpose.
|
136
139
|
no_processing = true
|
137
140
|
@nexpose_site_histories.each do |site_id, scan_id|
|
@@ -158,22 +161,56 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
158
161
|
log_message("New site id: #{site_id} detected. Generating report.")
|
159
162
|
new_site_vuln = ticket_repository.all_vulns(sites: [site_id], severity: options[:severity])
|
160
163
|
log_message('Report generated, preparing tickets.')
|
161
|
-
ticket = helper.
|
162
|
-
helper.
|
164
|
+
ticket = helper.prepare_create_tickets(new_site_vuln)
|
165
|
+
helper.create_tickets(ticket)
|
163
166
|
end
|
164
167
|
|
165
168
|
# There's a new scan with possibly new vulnerabilities.
|
166
169
|
def delta_site_new_scan(ticket_repository, site_id, options, helper, file_site_histories)
|
167
170
|
log_message("New scan detected for site: #{site_id}. Generating report.")
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
171
|
+
|
172
|
+
if options[:ticket_mode] == 'I'
|
173
|
+
# I-mode tickets require updating the tickets in the target system.
|
174
|
+
log_message("Scan id for new scan: #{file_site_histories[site_id]}.")
|
175
|
+
all_scan_vuln = ticket_repository.all_vulns_sites(scan_id: file_site_histories[site_id],
|
176
|
+
site_id: site_id,
|
177
|
+
severity: options[:severity])
|
178
|
+
if helper.respond_to?("prepare_update_tickets") && helper.respond_to?("update_tickets")
|
179
|
+
tickets = helper.prepare_update_tickets(all_scan_vuln)
|
180
|
+
helper.update_tickets(tickets)
|
181
|
+
else
|
182
|
+
log_message("Helper does not implement update methods")
|
183
|
+
fail "Helper using 'I' mode must implement prepare_updates and update_tickets"
|
184
|
+
end
|
185
|
+
else
|
186
|
+
# D-mode tickets require creating new tickets and closing old tickets.
|
187
|
+
new_scan_vuln = ticket_repository.new_vulns_sites(scan_id: file_site_histories[site_id], site_id: site_id,
|
188
|
+
severity: options[:severity])
|
189
|
+
preparse = CSV.new(new_scan_vuln.chomp, headers: :first_row)
|
190
|
+
empty_report = preparse.shift.nil?
|
191
|
+
log_message("No new vulnerabilities found in new scan for site: #{site_id}.") if empty_report
|
192
|
+
log_message("New vulnerabilities found in new scan for site #{site_id}, preparing tickets.") unless empty_report
|
193
|
+
unless empty_report
|
194
|
+
tickets = helper.prepare_create_tickets(new_scan_vuln)
|
195
|
+
helper.create_tickets(tickets)
|
196
|
+
end
|
197
|
+
|
198
|
+
if helper.respond_to?("prepare_close_tickets") && helper.respond_to?("close_tickets")
|
199
|
+
old_scan_vuln = ticket_repository.old_vulns_sites(scan_id: file_site_histories[site_id], site_id: site_id,
|
200
|
+
severity: options[:severity])
|
201
|
+
preparse = CSV.new(old_scan_vuln.chomp, headers: :first_row)
|
202
|
+
empty_report = preparse.shift.nil?
|
203
|
+
log_message("No old (closed) vulnerabilities found in new scan for site: #{site_id}.") if empty_report
|
204
|
+
log_message("Old vulnerabilities found in new scan for site #{site_id}, preparing closures.") unless empty_report
|
205
|
+
unless empty_report
|
206
|
+
tickets = helper.prepare_close_tickets(old_scan_vuln)
|
207
|
+
helper.close_tickets(tickets)
|
208
|
+
end
|
209
|
+
else
|
210
|
+
# Create a log message but do not halt execution of the helper if ticket closeing is not
|
211
|
+
# supported to allow legacy code to execute normally.
|
212
|
+
log_message("Helper does not impelment close methods.")
|
213
|
+
end
|
177
214
|
end
|
178
215
|
end
|
179
216
|
|
data/nexpose_ticketing.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'nexpose_ticketing'
|
5
|
-
s.version = '0.
|
5
|
+
s.version = '0.2.1'
|
6
6
|
s.homepage = 'https://github.com/rapid7/nexpose_ticketing'
|
7
7
|
s.summary = 'Ruby Nexpose Ticketing Engine.'
|
8
8
|
s.description = 'This gem provides a Ruby implementation of different integrations with ticketing services for Nexpose.'
|
@@ -11,9 +11,10 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.email = ['damian_finol@rapid7.com']
|
12
12
|
s.files = Dir['[A-Z]*'] + Dir['lib/**/*']
|
13
13
|
s.require_paths = ['lib']
|
14
|
-
s.extra_rdoc_files = ['README.
|
14
|
+
s.extra_rdoc_files = ['README.md']
|
15
15
|
s.required_ruby_version = '>= 1.9'
|
16
16
|
s.platform = 'ruby'
|
17
|
-
s.executables
|
17
|
+
s.executables = ['nexpose_jira','nexpose_servicenow','nexpose_remedy']
|
18
18
|
s.add_dependency('nexpose', '>= 0.6.0')
|
19
|
-
|
19
|
+
s.add_dependency('savon', '~> 2.1')
|
20
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nexpose_ticketing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Damian Finol
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02
|
11
|
+
date: 2014-07-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nexpose
|
@@ -24,22 +24,47 @@ dependencies:
|
|
24
24
|
- - ! '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.6.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: savon
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.1'
|
27
41
|
description: This gem provides a Ruby implementation of different integrations with
|
28
42
|
ticketing services for Nexpose.
|
29
43
|
email:
|
30
44
|
- damian_finol@rapid7.com
|
31
45
|
executables:
|
32
46
|
- nexpose_jira
|
47
|
+
- nexpose_servicenow
|
48
|
+
- nexpose_remedy
|
33
49
|
extensions: []
|
34
50
|
extra_rdoc_files:
|
35
|
-
- README.
|
51
|
+
- README.md
|
36
52
|
files:
|
37
|
-
- README.
|
53
|
+
- README.md
|
38
54
|
- bin/nexpose_jira
|
55
|
+
- bin/nexpose_remedy
|
56
|
+
- bin/nexpose_servicenow
|
39
57
|
- lib/nexpose_ticketing.rb
|
40
58
|
- lib/nexpose_ticketing/config/jira.config
|
59
|
+
- lib/nexpose_ticketing/config/remedy.config
|
60
|
+
- lib/nexpose_ticketing/config/remedy_wsdl/HPD_IncidentInterface_Create_WS.xml
|
61
|
+
- lib/nexpose_ticketing/config/remedy_wsdl/HPD_IncidentInterface_WS.xml
|
62
|
+
- lib/nexpose_ticketing/config/servicenow.config
|
41
63
|
- lib/nexpose_ticketing/config/ticket_service.config
|
42
64
|
- lib/nexpose_ticketing/helpers/jira_helper.rb
|
65
|
+
- lib/nexpose_ticketing/helpers/remedy_helper.rb
|
66
|
+
- lib/nexpose_ticketing/helpers/servicenow_helper.rb
|
67
|
+
- lib/nexpose_ticketing/nx_logger.rb
|
43
68
|
- lib/nexpose_ticketing/queries.rb
|
44
69
|
- lib/nexpose_ticketing/ticket_repository.rb
|
45
70
|
- lib/nexpose_ticketing/ticket_service.rb
|