nexpose_servicenow 0.6.2 → 0.7.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 +4 -4
- data/README.md +1 -1
- data/lib/nexpose_servicenow.rb +58 -91
- data/lib/nexpose_servicenow/arg_parser.rb +80 -75
- data/lib/nexpose_servicenow/chunker.rb +0 -1
- data/lib/nexpose_servicenow/csv_compare.rb +17 -0
- data/lib/nexpose_servicenow/helpers/connection_helper.rb +79 -0
- data/lib/nexpose_servicenow/helpers/data_warehouse_helper.rb +134 -0
- data/lib/nexpose_servicenow/{nexpose_helper.rb → helpers/nexpose_console_helper.rb} +32 -85
- data/lib/nexpose_servicenow/historical_data.rb +46 -355
- data/lib/nexpose_servicenow/{queries.rb → queries/nexpose_queries.rb} +61 -90
- data/lib/nexpose_servicenow/queries/queries_base.rb +25 -0
- data/lib/nexpose_servicenow/queries/warehouse_queries.rb +330 -0
- data/lib/nexpose_servicenow/version.rb +1 -1
- data/nexpose_servicenow.gemspec +14 -11
- metadata +27 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba87a2439d290abbf57e7eb2d6792d691166f312
|
4
|
+
data.tar.gz: 0dcb0dc8fc8373431a3ccba7b6879903562a0fee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df8bcf8ccf412d0fe87aa41282233fc6e9739ccac94ec7398c42bd73842ec5de92ef7045ae300ad0e47999c808e5c327caf8fe974997066f349dfef54c45de63
|
7
|
+
data.tar.gz: 2f8dfbd40ea34d981d75da8b0bad547de128b4e3cd118c9bf3dec4883aeab01a61664f29d37a4b1156d60326864874fd3aa0e6a7d929510e356660cb425a2b76
|
data/README.md
CHANGED
@@ -14,7 +14,7 @@ Alternatively, it is also possible to call the following to see a list of parame
|
|
14
14
|
|
15
15
|
## Support
|
16
16
|
Please contact the following address for support queries:
|
17
|
-
[
|
17
|
+
[Rapid7 Support Portal](https://rapid7support.force.com/customers/login)
|
18
18
|
|
19
19
|
Please attach both the gem logs and relevant snippets from the agent logs.
|
20
20
|
|
data/lib/nexpose_servicenow.rb
CHANGED
@@ -2,8 +2,9 @@ require 'csv'
|
|
2
2
|
require 'optparse'
|
3
3
|
require 'nexpose'
|
4
4
|
require 'uri'
|
5
|
-
|
6
|
-
|
5
|
+
require_relative './nexpose_servicenow/helpers/connection_helper'
|
6
|
+
require_relative './nexpose_servicenow/helpers/nexpose_console_helper'
|
7
|
+
require_relative './nexpose_servicenow/helpers/data_warehouse_helper'
|
7
8
|
require 'nexpose_servicenow/arg_parser'
|
8
9
|
require 'nexpose_servicenow/chunker'
|
9
10
|
require 'nexpose_servicenow/nx_logger'
|
@@ -18,49 +19,54 @@ module NexposeServiceNow
|
|
18
19
|
@log = setup_logging(options)
|
19
20
|
|
20
21
|
censored_options = options.dup
|
21
|
-
censored_options[:
|
22
|
-
censored_options[:
|
22
|
+
censored_options[:username] = '*****'
|
23
|
+
censored_options[:password] = '*****'
|
23
24
|
@log.log_message("Options: #{censored_options}")
|
24
25
|
|
25
|
-
options[:
|
26
|
-
options[:
|
26
|
+
query = options[:query]
|
27
|
+
site_ids = options[:nexpose_ids]
|
28
|
+
|
29
|
+
# Filter out irrelevant sites
|
30
|
+
if query == :vulnerable_old_items
|
31
|
+
site_ids = get_historical_data(options).filter_ids(site_ids)
|
32
|
+
if site_ids.count == 0
|
33
|
+
puts 'No sites remaining for vulnerable old items query. Exiting.'
|
34
|
+
exit 0
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
report_details = ConnectionHelper.get_report_names(query, site_ids)
|
27
39
|
|
28
|
-
report_details = NexposeHelper.get_report_names(options[:query],
|
29
|
-
options[:nexpose_ids])
|
30
40
|
report_details.each do |r|
|
31
|
-
r[:report_name] =
|
32
|
-
|
41
|
+
r[:report_name] = ConnectionHelper.get_filepath(r[:report_name],
|
42
|
+
options[:output_dir])
|
33
43
|
end
|
34
44
|
|
35
|
-
|
45
|
+
report_results = create_report(report_details, options)
|
36
46
|
|
37
|
-
|
47
|
+
# If data was returned, we can short circuit here
|
48
|
+
if !report_results.nil? and options[:mode] == 'chunk_info'
|
49
|
+
puts report_results
|
50
|
+
exit 0
|
51
|
+
end
|
38
52
|
|
39
53
|
@log.log_message("Initialising #{options[:mode]} mode")
|
40
54
|
self.send("#{options[:mode]}_mode", report_details, options)
|
41
55
|
end
|
42
56
|
|
43
57
|
def self.get_historical_data(options)
|
44
|
-
HistoricalData.new(options[:output_dir]
|
45
|
-
options[:nexpose_ids],
|
46
|
-
options[:id_type],
|
47
|
-
options[:start_time])
|
48
|
-
end
|
49
|
-
|
50
|
-
def self.get_nexpose_helper(options)
|
51
|
-
NexposeHelper.new(options[:nexpose_url],
|
52
|
-
options[:nexpose_port],
|
53
|
-
options[:nexpose_username],
|
54
|
-
options[:nexpose_password])
|
58
|
+
HistoricalData.new(options[:output_dir])
|
55
59
|
end
|
56
60
|
|
57
|
-
|
58
|
-
|
59
|
-
return options[:nexpose_ids] if options[:nexpose_ids].first.to_s != '0'
|
61
|
+
def self.get_helper(options)
|
62
|
+
name = options[:conn_type].to_s.split('_').map(&:capitalize).join('')
|
60
63
|
|
61
|
-
|
62
|
-
helper
|
63
|
-
|
64
|
+
helper = eval("#{name}Helper")
|
65
|
+
helper.new(options[:url],
|
66
|
+
options[:port],
|
67
|
+
options[:username],
|
68
|
+
options[:password],
|
69
|
+
options[:database_name])
|
64
70
|
end
|
65
71
|
|
66
72
|
def self.setup_logging(options)
|
@@ -74,13 +80,6 @@ module NexposeServiceNow
|
|
74
80
|
log
|
75
81
|
end
|
76
82
|
|
77
|
-
# Merges in the details from the last time the integration ran reports.
|
78
|
-
def self.update_delta_files(options)
|
79
|
-
historical_data = get_historical_data(options)
|
80
|
-
historical_data.update_delta_file
|
81
|
-
historical_data.save_vuln_timestamp(filter_sites(options))
|
82
|
-
end
|
83
|
-
|
84
83
|
# Create a report if explicitly required or else an existing
|
85
84
|
# report file isn't found
|
86
85
|
def self.create_report(report_details, options)
|
@@ -89,76 +88,45 @@ module NexposeServiceNow
|
|
89
88
|
return
|
90
89
|
end
|
91
90
|
|
91
|
+
# Perform all queries if a file is missing, regardless of other settings
|
92
92
|
unless options[:gen_report]
|
93
|
-
# If any file is missing, perform all queries
|
94
93
|
return if report_details.all? { |f| File.exists? f[:report_name] }
|
95
94
|
end
|
96
95
|
|
97
|
-
credentials = %i{
|
96
|
+
credentials = %i{username password}
|
98
97
|
if credentials.any? { |cred| options[cred].to_s == '' }
|
99
98
|
@log.log_error_message 'Nexpose credentials necessary but not supplied.'
|
100
99
|
exit -1
|
101
100
|
end
|
102
101
|
|
103
|
-
#Filter it down to sites which actively need queried
|
104
|
-
sites_to_scan =
|
105
|
-
nexpose_helper = get_nexpose_helper(options)
|
106
|
-
hist_data = get_historical_data(options)
|
107
|
-
vuln_query = options[:query].to_s.start_with? 'vulnerabili'
|
102
|
+
# Filter it down to sites which actively need queried
|
103
|
+
sites_to_scan = options[:nexpose_ids].keys
|
108
104
|
|
109
|
-
|
110
|
-
query_options =
|
111
|
-
query_options[:vuln_query_date] = hist_data.last_vuln_run if vuln_query
|
105
|
+
query_options = { delta_values: options[:nexpose_ids] }
|
106
|
+
query_options[:vuln_query_date] = options[:vuln_query_date]
|
112
107
|
query_options[:filters] = options[:filters]
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
filename.map! { |f| File.expand_path(options[:output_dir], f) }
|
123
|
-
return filename.join("\n")
|
124
|
-
end
|
125
|
-
|
126
|
-
File.expand_path(options[:output_dir], filename)
|
127
|
-
end
|
128
|
-
|
129
|
-
def self.filter_sites(options)
|
130
|
-
# These queries always run to make sure certain data is up to date
|
131
|
-
exceptions = %w(vulnerabili asset_groups sites tags)
|
132
|
-
if exceptions.any? { |e| options[:query].to_s.start_with? e }
|
133
|
-
return options[:nexpose_ids]
|
134
|
-
end
|
135
|
-
|
136
|
-
#Always run the query for latest scans or vulnerabilities
|
137
|
-
if options[:mode] == 'latest_scans' ||
|
138
|
-
options[:mode] == 'get_chunk'
|
139
|
-
return options[:nexpose_ids]
|
140
|
-
end
|
141
|
-
|
142
|
-
historical_data = get_historical_data(options)
|
143
|
-
imported_sites_only = options[:query].to_s.eql? 'vulnerable_old_items'
|
144
|
-
sites_to_scan = historical_data.collections_to_import(imported_sites_only)
|
145
|
-
|
146
|
-
return sites_to_scan unless (sites_to_scan.nil? || sites_to_scan.empty?)
|
147
|
-
|
148
|
-
@log.log_message "Sites #{options[:nexpose_ids]} are up to date."
|
149
|
-
@log.log_message "Query requested was: #{options[:query]}."
|
150
|
-
exit 0
|
108
|
+
query_options[:page_size] = options[:row_limit]
|
109
|
+
query_options[:row_limit] = options[:row_limit]
|
110
|
+
report_helper = get_helper(options)
|
111
|
+
@log.log_message("Querying using the #{report_helper.class}.")
|
112
|
+
report_helper.generate_report(options[:query],
|
113
|
+
sites_to_scan,
|
114
|
+
options[:id_type],
|
115
|
+
options[:output_dir],
|
116
|
+
query_options)
|
151
117
|
end
|
152
118
|
|
153
119
|
# Print the chunk info
|
154
120
|
def self.chunk_info_mode(report_details, options)
|
155
|
-
|
121
|
+
site_ids = options[:nexpose_ids].keys
|
122
|
+
|
123
|
+
# Assign -1 to reports without site IDs
|
156
124
|
report_details = report_details.select do |d|
|
157
|
-
d[:id] == -1 or
|
125
|
+
d[:id] == -1 or site_ids.include? d[:id]
|
158
126
|
end
|
127
|
+
|
159
128
|
chunker = Chunker.new(report_details, options[:row_limit])
|
160
129
|
|
161
|
-
# TODO: Check why filtered_sites are passed in here
|
162
130
|
puts chunker.preprocess
|
163
131
|
end
|
164
132
|
|
@@ -166,16 +134,15 @@ module NexposeServiceNow
|
|
166
134
|
def self.get_chunk_mode(report_details, options)
|
167
135
|
#Get the byte offset and length
|
168
136
|
chunker = Chunker.new(report_details, options[:row_limit])
|
169
|
-
filtered_sites = filter_sites(options)
|
170
137
|
|
171
138
|
puts chunker.read_chunk(options[:chunk_start],
|
172
139
|
options[:chunk_length],
|
173
|
-
|
140
|
+
options[:nexpose_ids].keys.first)
|
174
141
|
end
|
175
142
|
|
176
143
|
def self.latest_scans_mode(report_details, options)
|
177
144
|
historical_data = get_historical_data(options)
|
178
|
-
puts historical_data.filter_report
|
145
|
+
puts historical_data.filter_report options[:nexpose_ids].keys
|
179
146
|
end
|
180
147
|
|
181
148
|
def self.remove_last_scan_mode(report_details, options)
|
@@ -202,7 +169,7 @@ module NexposeServiceNow
|
|
202
169
|
|
203
170
|
def self.remove_diff_comparison_mode(report_details, options)
|
204
171
|
historical_data = get_historical_data(options)
|
205
|
-
historical_data.
|
172
|
+
historical_data.remove_diff_files options[:output_dir]
|
206
173
|
end
|
207
174
|
end
|
208
175
|
end
|
@@ -1,17 +1,17 @@
|
|
1
1
|
require 'optparse'
|
2
2
|
require 'json'
|
3
3
|
require 'time'
|
4
|
-
require_relative './queries'
|
4
|
+
require_relative './queries/nexpose_queries'
|
5
5
|
require_relative './nx_logger'
|
6
6
|
|
7
7
|
module NexposeServiceNow
|
8
8
|
class ArgParser
|
9
9
|
NX_ID_TYPES = %i[site asset_group]
|
10
|
+
NX_CONNECTION_TYPES = %i[nexpose_console data_warehouse]
|
10
11
|
MODES = %i[chunk_info get_chunk latest_scans
|
11
|
-
remove_last_scan
|
12
|
-
|
13
|
-
|
14
|
-
QUERY_NAMES = Queries.methods(false)
|
12
|
+
remove_last_scan remove_last_vuln]
|
13
|
+
REQUIRED_OPTIONS = %i[url port username password]
|
14
|
+
QUERY_NAMES = NexposeQueries.methods(false)
|
15
15
|
|
16
16
|
def self.parse(args)
|
17
17
|
options = Hash.new
|
@@ -46,44 +46,71 @@ module NexposeServiceNow
|
|
46
46
|
options[:query] = query
|
47
47
|
end
|
48
48
|
|
49
|
-
opts.on('-t', '--type
|
50
|
-
"
|
51
|
-
|
49
|
+
opts.on('-t', '--type ID~CONNECTION', 'Select ID type ' \
|
50
|
+
"(#{NX_ID_TYPES.join(', ')}) and connection type " \
|
51
|
+
"(#{NX_CONNECTION_TYPES.join(', ')})") do |types|
|
52
|
+
type = types.split('~')
|
53
|
+
options[:id_type] = type[0].intern
|
54
|
+
options[:conn_type] = type[1].intern
|
55
|
+
|
56
|
+
if options[:conn_type].equal? :data_warehouse
|
57
|
+
REQUIRED_OPTIONS << :database_name
|
58
|
+
end
|
52
59
|
end
|
53
60
|
|
54
|
-
opts.on('-i', '--items x,y,z', Array,
|
55
|
-
'IDs of the nexpose items to
|
56
|
-
|
61
|
+
opts.on('-i', '--items x~x,y~y,z~z', Array,
|
62
|
+
'IDs of the nexpose items to ' \
|
63
|
+
'scan, provided with their previous scan IDs or timestamp ' \
|
64
|
+
'of last scan') do |items|
|
65
|
+
options[:nexpose_ids] = {}
|
66
|
+
|
67
|
+
# Split the string up into site and scan pairs
|
68
|
+
items = items.map { |s| s.split('~') }
|
69
|
+
|
70
|
+
# Store the information in site:scan_id dict
|
71
|
+
items.each { |site, scan| options[:nexpose_ids][site] = scan }
|
72
|
+
end
|
73
|
+
|
74
|
+
opts.on('-a', '--abs-vulntime TIMESTAMP',
|
75
|
+
'Timestamp of last vulnerability definition import') do |vulnt|
|
76
|
+
# TODO: Does the date need formatted?
|
77
|
+
options[:vuln_query_date] = vulnt
|
57
78
|
end
|
58
79
|
|
59
80
|
opts.separator ''
|
60
|
-
opts.separator '
|
81
|
+
opts.separator 'Connection options:'
|
61
82
|
|
62
|
-
opts.on('-n', '--nexpose-
|
63
|
-
'URL of the Nexpose server') do |url|
|
83
|
+
opts.on('-n', '--nexpose-datastore URL',
|
84
|
+
'URL of the Nexpose/Data Warehouse server') do |url|
|
64
85
|
port = url.slice!(/:(\d+)$/)
|
65
86
|
port.slice! ':' unless port.nil?
|
66
87
|
|
67
88
|
url.slice! 'https://'
|
68
|
-
options[:
|
69
|
-
options[:
|
89
|
+
options[:url] = url
|
90
|
+
options[:port] = port
|
70
91
|
end
|
71
92
|
|
72
93
|
opts.on('-u', '--user USER',
|
73
|
-
'Username for Nexpose
|
74
|
-
options[:
|
94
|
+
'Username for Nexpose/Data Warehouse') do |username|
|
95
|
+
options[:username] = username
|
75
96
|
end
|
76
97
|
|
77
98
|
opts.on('-p', '--password PASSWORD',
|
78
|
-
'Password for the Nexpose user') do |password|
|
79
|
-
options[:
|
99
|
+
'Password for the Nexpose/Data Warehouse user') do |password|
|
100
|
+
options[:password] = password
|
101
|
+
end
|
102
|
+
|
103
|
+
opts.on('-b', '--database DATABASE_NAME',
|
104
|
+
'The name of the Postgres Database '\
|
105
|
+
'(DataWarehouse Only)') do |database|
|
106
|
+
options[:database_name] = database
|
80
107
|
end
|
81
108
|
|
82
109
|
opts.separator ''
|
83
110
|
opts.separator 'Chunk info mode options:'
|
84
111
|
|
85
112
|
opts.on('-r', '--row-limit LIMIT',
|
86
|
-
'Maximum number of rows per chunk (
|
113
|
+
'Maximum number of rows per chunk (inc. header).') do |limit|
|
87
114
|
options[:row_limit] = limit.to_i
|
88
115
|
options[:row_limit] = 9_999_999 if options[:row_limit] <= 0
|
89
116
|
end
|
@@ -104,37 +131,7 @@ module NexposeServiceNow
|
|
104
131
|
opts.separator ''
|
105
132
|
opts.separator 'Filter options:'
|
106
133
|
|
107
|
-
=begin
|
108
|
-
# CVE filter is not currently supported.
|
109
|
-
opts.on('-v', '--vuln-identifier CVE',
|
110
|
-
'The CVE values for which to filter.') do |data|
|
111
|
-
# A value of 'none' means the user has left field blank
|
112
|
-
if data.to_s.downcase != 'none'
|
113
|
-
data = data.to_s.sub(' ', '').split(',')
|
114
|
-
|
115
|
-
invalid_cve = data.select { |f| (f =~ /(CVE-)?\d{4}-\d+/) == nil }
|
116
|
-
unless invalid_cve.empty?
|
117
|
-
error = "Invalid CVEs applied: #{invalid_cve}"
|
118
|
-
puts error
|
119
|
-
log.log_message error
|
120
|
-
exit -1
|
121
|
-
end
|
122
|
-
|
123
|
-
data = data.map do |c|
|
124
|
-
if c.start_with? 'CVE-'
|
125
|
-
c
|
126
|
-
else
|
127
|
-
"CVE-#{c}"
|
128
|
-
end
|
129
|
-
end
|
130
|
-
else
|
131
|
-
data = nil
|
132
|
-
end
|
133
134
|
|
134
|
-
options[:filters] ||= {}
|
135
|
-
options[:filters][:cve] = data
|
136
|
-
end
|
137
|
-
=end
|
138
135
|
opts.on('-c', '--cvss-score CVSS',
|
139
136
|
'The minimum CVSS score to import') do |data|
|
140
137
|
|
@@ -175,6 +172,10 @@ module NexposeServiceNow
|
|
175
172
|
dates[0] = dates[0] + ' 00:00:00'
|
176
173
|
dates[1] = dates[1] + ' 23:59:59'
|
177
174
|
|
175
|
+
# Remove rogue '' in datetime format
|
176
|
+
dates[0] = dates[0].gsub("'","")
|
177
|
+
dates[1] = dates[1].gsub("'","")
|
178
|
+
|
178
179
|
# Check for valid dates and placeholders
|
179
180
|
dates.map! do |d|
|
180
181
|
if d =~ /Y{4}-M{1,2}-D{1,2}/i
|
@@ -193,15 +194,6 @@ module NexposeServiceNow
|
|
193
194
|
options[:filters][:date] = dates
|
194
195
|
end
|
195
196
|
|
196
|
-
|
197
|
-
opts.separator ''
|
198
|
-
opts.separator 'Last scan file modification options:'
|
199
|
-
|
200
|
-
opts.on('-e', '--errata DATA',
|
201
|
-
'Date or scan ID to be inserted in last scan file.') do |data|
|
202
|
-
options[:last_scan_data] = data
|
203
|
-
end
|
204
|
-
|
205
197
|
opts.separator ''
|
206
198
|
opts.separator 'Common options:'
|
207
199
|
|
@@ -212,8 +204,8 @@ module NexposeServiceNow
|
|
212
204
|
end
|
213
205
|
|
214
206
|
opt_parser.parse!(args)
|
215
|
-
options = self.validate_input(options)
|
216
207
|
options = self.get_env_settings(options)
|
208
|
+
options = self.validate_input(options)
|
217
209
|
options
|
218
210
|
end
|
219
211
|
|
@@ -221,8 +213,10 @@ module NexposeServiceNow
|
|
221
213
|
#Insert defaults. Some are mode-specific.
|
222
214
|
options[:output_dir] ||= '.'
|
223
215
|
options[:row_limit] ||= 9_999_999
|
216
|
+
options[:vuln_query_date] ||= '1985-01-01 00:00:00'
|
224
217
|
options[:id_type] ||= 'site'
|
225
|
-
options[:
|
218
|
+
options[:conn_type] ||= :nexpose_console
|
219
|
+
options[:nexpose_ids] ||= {}
|
226
220
|
options[:filters] ||= {}
|
227
221
|
|
228
222
|
options[:query] = 'latest_scans' if options[:mode] == 'latest_scans'
|
@@ -233,36 +227,47 @@ module NexposeServiceNow
|
|
233
227
|
options[:mode] == 'latest_scans'
|
234
228
|
end
|
235
229
|
|
230
|
+
options[:port] ||= if options[:conn_type].equal? :nexpose_console
|
231
|
+
'3780'
|
232
|
+
else
|
233
|
+
'5432'
|
234
|
+
end
|
235
|
+
|
236
|
+
log = NexposeServiceNow::NxLogger.instance
|
237
|
+
|
236
238
|
if options[:mode].to_s == ''
|
237
|
-
log = NexposeServiceNow::NxLogger.instance
|
238
239
|
log.log_message('Script was called without mode.')
|
239
240
|
puts 'No mode selected. Use -h to see command line options.'
|
240
241
|
exit -1
|
241
242
|
end
|
242
243
|
|
244
|
+
#Only need to check these if a query is being performed
|
245
|
+
return options unless options[:gen_report]
|
246
|
+
|
247
|
+
REQUIRED_OPTIONS.each do |setting|
|
248
|
+
if options[setting].nil?
|
249
|
+
error = "Option #{setting} wasn't supplied."
|
250
|
+
log.log_error_message error
|
251
|
+
$stderr.puts "ERROR: #{error}"
|
252
|
+
exit -1
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
243
256
|
options
|
244
257
|
end
|
245
258
|
|
246
259
|
def self.get_env_settings(options)
|
247
260
|
#Only need these if a query is being performed
|
248
|
-
return options
|
261
|
+
return options unless options[:gen_report]
|
249
262
|
|
250
263
|
log = NexposeServiceNow::NxLogger.instance
|
251
264
|
log.log_message 'Retrieving environment variables.'
|
252
265
|
|
253
266
|
# Retrieve environment variable settings
|
254
|
-
|
267
|
+
REQUIRED_OPTIONS.each do |setting|
|
255
268
|
option = "nexpose_#{setting}"
|
256
|
-
|
257
|
-
|
258
|
-
options[sym] ||= setting
|
259
|
-
|
260
|
-
if options[sym].nil?
|
261
|
-
error = "Option #{sym} wasn't supplied."
|
262
|
-
log.log_error_message error
|
263
|
-
$stderr.puts "ERROR: #{error}"
|
264
|
-
exit -1
|
265
|
-
end
|
269
|
+
env_setting = ENV[option.upcase]
|
270
|
+
options[setting] ||= env_setting
|
266
271
|
end
|
267
272
|
|
268
273
|
options
|