newrelic_security 0.1.0 → 0.3.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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/pr_ci.yml +2 -2
  3. data/CHANGELOG.md +82 -0
  4. data/THIRD_PARTY_NOTICES.md +8 -0
  5. data/lib/newrelic_security/agent/agent.rb +24 -4
  6. data/lib/newrelic_security/agent/configuration/manager.rb +51 -8
  7. data/lib/newrelic_security/agent/control/app_info.rb +2 -0
  8. data/lib/newrelic_security/agent/control/application_runtime_error.rb +95 -0
  9. data/lib/newrelic_security/agent/control/application_url_mappings.rb +2 -0
  10. data/lib/newrelic_security/agent/control/collector.rb +34 -3
  11. data/lib/newrelic_security/agent/control/control_command.rb +2 -3
  12. data/lib/newrelic_security/agent/control/critical_message.rb +2 -0
  13. data/lib/newrelic_security/agent/control/error_reporting.rb +74 -0
  14. data/lib/newrelic_security/agent/control/event.rb +26 -4
  15. data/lib/newrelic_security/agent/control/event_processor.rb +26 -0
  16. data/lib/newrelic_security/agent/control/event_subscriber.rb +2 -8
  17. data/lib/newrelic_security/agent/control/exit_event.rb +2 -0
  18. data/lib/newrelic_security/agent/control/grpc_context.rb +2 -1
  19. data/lib/newrelic_security/agent/control/health_check.rb +5 -0
  20. data/lib/newrelic_security/agent/control/http_context.rb +16 -7
  21. data/lib/newrelic_security/agent/control/iast_client.rb +24 -11
  22. data/lib/newrelic_security/agent/control/iast_data_transfer_request.rb +2 -0
  23. data/lib/newrelic_security/agent/control/scan_scheduler.rb +77 -0
  24. data/lib/newrelic_security/agent/control/websocket_client.rb +23 -0
  25. data/lib/newrelic_security/agent/utils/agent_utils.rb +14 -9
  26. data/lib/newrelic_security/constants.rb +2 -2
  27. data/lib/newrelic_security/instrumentation-security/async-http/instrumentation.rb +2 -13
  28. data/lib/newrelic_security/instrumentation-security/curb/instrumentation.rb +1 -14
  29. data/lib/newrelic_security/instrumentation-security/ethon/chain.rb +0 -6
  30. data/lib/newrelic_security/instrumentation-security/ethon/instrumentation.rb +7 -42
  31. data/lib/newrelic_security/instrumentation-security/ethon/prepend.rb +0 -4
  32. data/lib/newrelic_security/instrumentation-security/excon/instrumentation.rb +3 -13
  33. data/lib/newrelic_security/instrumentation-security/grape/chain.rb +7 -2
  34. data/lib/newrelic_security/instrumentation-security/grape/instrumentation.rb +3 -1
  35. data/lib/newrelic_security/instrumentation-security/grape/prepend.rb +7 -1
  36. data/lib/newrelic_security/instrumentation-security/grpc/server/instrumentation.rb +3 -2
  37. data/lib/newrelic_security/instrumentation-security/httpclient/instrumentation.rb +4 -28
  38. data/lib/newrelic_security/instrumentation-security/httprb/instrumentation.rb +1 -12
  39. data/lib/newrelic_security/instrumentation-security/httpx/instrumentation.rb +1 -15
  40. data/lib/newrelic_security/instrumentation-security/instrumentation_utils.rb +0 -17
  41. data/lib/newrelic_security/instrumentation-security/net_http/instrumentation.rb +6 -23
  42. data/lib/newrelic_security/instrumentation-security/net_ldap/instrumentation.rb +1 -1
  43. data/lib/newrelic_security/instrumentation-security/padrino/chain.rb +17 -0
  44. data/lib/newrelic_security/instrumentation-security/padrino/instrumentation.rb +15 -2
  45. data/lib/newrelic_security/instrumentation-security/padrino/prepend.rb +12 -0
  46. data/lib/newrelic_security/instrumentation-security/patron/instrumentation.rb +2 -15
  47. data/lib/newrelic_security/instrumentation-security/rails/chain.rb +26 -2
  48. data/lib/newrelic_security/instrumentation-security/rails/instrumentation.rb +29 -3
  49. data/lib/newrelic_security/instrumentation-security/rails/prepend.rb +18 -0
  50. data/lib/newrelic_security/instrumentation-security/roda/chain.rb +7 -2
  51. data/lib/newrelic_security/instrumentation-security/roda/instrumentation.rb +3 -1
  52. data/lib/newrelic_security/instrumentation-security/roda/prepend.rb +7 -1
  53. data/lib/newrelic_security/instrumentation-security/sinatra/chain.rb +6 -0
  54. data/lib/newrelic_security/instrumentation-security/sinatra/instrumentation.rb +9 -0
  55. data/lib/newrelic_security/instrumentation-security/sinatra/prepend.rb +4 -0
  56. data/lib/newrelic_security/instrumentation-security/sqlite3/instrumentation.rb +4 -4
  57. data/lib/newrelic_security/newrelic-security-api/api.rb +1 -1
  58. data/lib/newrelic_security/parse-cron/cron_parser.rb +294 -0
  59. data/lib/newrelic_security/version.rb +1 -1
  60. data/newrelic_security.gemspec +1 -1
  61. metadata +8 -4
@@ -8,11 +8,12 @@ module NewRelic::Security
8
8
  def _roda_handle_main_route_on_enter(env)
9
9
  event = nil
10
10
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
11
+ return unless NewRelic::Security::Agent.config[:enabled]
11
12
  NewRelic::Security::Agent.config.update_port = NewRelic::Security::Agent::Utils.app_port(env) unless NewRelic::Security::Agent.config[:listen_port]
12
13
  NewRelic::Security::Agent::Utils.get_app_routes(:roda) if NewRelic::Security::Agent.agent.route_map.empty?
13
14
  NewRelic::Security::Agent::Control::HTTPContext.set_context(env)
14
15
  ctxt = NewRelic::Security::Agent::Control::HTTPContext.get_context
15
- ctxt.route = "#{env[REQUEST_METHOD].to_s}@#{env[PATH_INFO].to_s}" if ctxt
16
+ ctxt.route = "#{env[REQUEST_METHOD]}@#{env[PATH_INFO]}" if ctxt
16
17
  NewRelic::Security::Agent::Utils.parse_fuzz_header(NewRelic::Security::Agent::Control::HTTPContext.get_context)
17
18
  rescue => exception
18
19
  NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
@@ -26,6 +27,7 @@ module NewRelic::Security
26
27
  # NewRelic::Security::Agent.logger.debug "\n\nHTTP Context : #{::NewRelic::Agent::Tracer.current_transaction.instance_variable_get(:@security_context_data).inspect}\n\n"
27
28
  NewRelic::Security::Agent::Control::ReflectedXSS.check_xss(NewRelic::Security::Agent::Control::HTTPContext.get_context, retval) if NewRelic::Security::Agent.config[:'security.detection.rxss.enabled']
28
29
  NewRelic::Security::Agent::Utils.delete_created_files(NewRelic::Security::Agent::Control::HTTPContext.get_context)
30
+ NewRelic::Security::Agent.agent.error_reporting&.report_unhandled_or_5xx_exceptions(NewRelic::Security::Agent::Control::HTTPContext.get_current_transaction, NewRelic::Security::Agent::Control::HTTPContext.get_context, retval[0])
29
31
  NewRelic::Security::Agent::Control::HTTPContext.reset_context
30
32
  NewRelic::Security::Agent.logger.debug "Exit event : #{event}"
31
33
  rescue => exception
@@ -6,7 +6,13 @@ module NewRelic::Security
6
6
 
7
7
  def _roda_handle_main_route(*args)
8
8
  retval = nil
9
- event = _roda_handle_main_route_on_enter(self.env) { retval = super }
9
+ event = _roda_handle_main_route_on_enter(env) do
10
+ begin
11
+ retval = super
12
+ ensure
13
+ NewRelic::Security::Agent.agent.error_reporting&.report_unhandled_or_5xx_exceptions(NewRelic::Security::Agent::Control::HTTPContext.get_current_transaction, NewRelic::Security::Agent::Control::HTTPContext.get_context, nil)
14
+ end
15
+ end
10
16
  _roda_handle_main_route_on_exit(event, retval) { return retval }
11
17
  end
12
18
 
@@ -20,6 +20,12 @@ module NewRelic::Security
20
20
  def route_eval(&block)
21
21
  route_eval_on_enter { route_eval_without_security(&block) }
22
22
  end
23
+
24
+ alias_method :dispatch_without_security, :dispatch!
25
+
26
+ def dispatch!
27
+ dispatch_on_enter { dispatch_without_security }
28
+ end
23
29
  end
24
30
  end
25
31
  end
@@ -8,6 +8,7 @@ module NewRelic::Security
8
8
  def call_on_enter(env)
9
9
  event = nil
10
10
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
11
+ return unless NewRelic::Security::Agent.config[:enabled]
11
12
  NewRelic::Security::Agent.config.update_port = NewRelic::Security::Agent::Utils.app_port(env) unless NewRelic::Security::Agent.config[:listen_port]
12
13
  NewRelic::Security::Agent::Utils.get_app_routes(:sinatra) if NewRelic::Security::Agent.agent.route_map.empty?
13
14
  NewRelic::Security::Agent::Control::HTTPContext.set_context(env)
@@ -24,6 +25,7 @@ module NewRelic::Security
24
25
  # NewRelic::Security::Agent.logger.debug "\n\nHTTP Context : #{::NewRelic::Agent::Tracer.current_transaction.instance_variable_get(:@security_context_data).inspect}\n\n"
25
26
  NewRelic::Security::Agent::Control::ReflectedXSS.check_xss(NewRelic::Security::Agent::Control::HTTPContext.get_context, retval) if NewRelic::Security::Agent.config[:'security.detection.rxss.enabled']
26
27
  NewRelic::Security::Agent::Utils.delete_created_files(NewRelic::Security::Agent::Control::HTTPContext.get_context)
28
+ NewRelic::Security::Agent.agent.error_reporting&.report_unhandled_or_5xx_exceptions(NewRelic::Security::Agent::Control::HTTPContext.get_current_transaction, NewRelic::Security::Agent::Control::HTTPContext.get_context, retval[0])
27
29
  NewRelic::Security::Agent::Control::HTTPContext.reset_context
28
30
  NewRelic::Security::Agent.logger.debug "Exit event : #{event}"
29
31
  rescue => exception
@@ -41,6 +43,13 @@ module NewRelic::Security
41
43
  ensure
42
44
  yield
43
45
  end
46
+
47
+ def dispatch_on_enter
48
+ NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
49
+ yield
50
+ ensure
51
+ NewRelic::Security::Agent.agent.error_reporting&.report_unhandled_or_5xx_exceptions(NewRelic::Security::Agent::Control::HTTPContext.get_current_transaction, NewRelic::Security::Agent::Control::HTTPContext.get_context)
52
+ end
44
53
 
45
54
  end
46
55
  end
@@ -14,6 +14,10 @@ module NewRelic::Security
14
14
  def route_eval
15
15
  route_eval_on_enter { super }
16
16
  end
17
+
18
+ def dispatch!
19
+ dispatch_on_enter { super }
20
+ end
17
21
  end
18
22
  end
19
23
  end
@@ -10,7 +10,7 @@ module NewRelic::Security
10
10
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
11
11
  hash = {}
12
12
  hash[:sql] = sql
13
- hash[:parameters] = bind_vars.is_a?(String) ? [bind_vars] : bind_vars.map(&:to_s)
13
+ hash[:parameters] = bind_vars.is_a?(String) ? [bind_vars] : bind_vars.flatten
14
14
  hash[:parameters] = hash[:parameters] + args.map(&:to_s) unless args.empty?
15
15
  event = NewRelic::Security::Agent::Control::Collector.collect(SQL_DB_COMMAND, [hash], SQLITE) unless NewRelic::Security::Instrumentation::InstrumentationUtils.sql_filter_events?(hash[:sql])
16
16
  rescue => exception
@@ -34,7 +34,7 @@ module NewRelic::Security
34
34
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
35
35
  hash = {}
36
36
  hash[:sql] = sql
37
- hash[:parameters] = bind_vars.is_a?(String) ? [bind_vars] : bind_vars.map(&:to_s)
37
+ hash[:parameters] = bind_vars.is_a?(String) ? [bind_vars] : bind_vars.flatten
38
38
  hash[:parameters] = hash[:parameters] + args unless args.empty?
39
39
  event = NewRelic::Security::Agent::Control::Collector.collect(SQL_DB_COMMAND, [hash], SQLITE) unless NewRelic::Security::Instrumentation::InstrumentationUtils.sql_filter_events?(hash[:sql])
40
40
  rescue => exception
@@ -102,7 +102,7 @@ module NewRelic::Security
102
102
  def bind_params_on_enter(*bind_vars)
103
103
  event = nil
104
104
  NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
105
- NewRelic::Security::Agent::Control::HTTPContext.get_context.cache[self.object_id][:parameters] = bind_vars.map(&:to_s) if NewRelic::Security::Agent::Control::HTTPContext.get_context && NewRelic::Security::Agent::Control::HTTPContext.get_context.cache.key?(self.object_id)
105
+ NewRelic::Security::Agent::Control::HTTPContext.get_context.cache[self.object_id][:parameters] = bind_vars.flatten if NewRelic::Security::Agent::Control::HTTPContext.get_context && NewRelic::Security::Agent::Control::HTTPContext.get_context.cache.key?(self.object_id)
106
106
  rescue => exception
107
107
  NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
108
108
  ensure
@@ -129,7 +129,7 @@ module NewRelic::Security
129
129
  else
130
130
  hash = {}
131
131
  hash[:sql] = NewRelic::Security::Agent::Control::HTTPContext.get_context.cache[key][:sql]
132
- hash[:parameters] = bind_vars.map(&:to_s)
132
+ hash[:parameters] = bind_vars.flatten
133
133
  ic_args.push(hash)
134
134
  end
135
135
  end
@@ -14,7 +14,7 @@ module NewRelic::Security
14
14
  # @api public
15
15
  #
16
16
  def is_security_active?
17
- NewRelic::Security::Agent.config[:'agent.enabled'] && NewRelic::Security::Agent.config[:enabled]
17
+ NewRelic::Security::Agent.config[:'agent.enabled'] && NewRelic::Security::Agent.config[:'security.enabled'] && NewRelic::Security::Agent.config[:enabled]
18
18
  end
19
19
 
20
20
  #
@@ -0,0 +1,294 @@
1
+ require 'set'
2
+ require 'date'
3
+
4
+ module NewRelic::Security
5
+ module ParseCron
6
+
7
+ # Parses cron expressions and computes the next occurence of the "job"
8
+ class CronParser
9
+ # internal "mutable" time representation
10
+ class InternalTime
11
+ attr_accessor :year, :month, :day, :hour, :min, :time_source
12
+
13
+ def initialize(time, time_source = Time)
14
+ @year = time.year
15
+ @month = time.month
16
+ @day = time.day
17
+ @hour = time.hour
18
+ @min = time.min
19
+
20
+ @time_source = time_source
21
+ end
22
+
23
+ def to_time
24
+ time_source.local(@year, @month, @day, @hour, @min, 0)
25
+ end
26
+
27
+ def inspect
28
+ [year, month, day, hour, min].inspect
29
+ end
30
+ end
31
+
32
+ SYMBOLS = {
33
+ "jan" => "1",
34
+ "feb" => "2",
35
+ "mar" => "3",
36
+ "apr" => "4",
37
+ "may" => "5",
38
+ "jun" => "6",
39
+ "jul" => "7",
40
+ "aug" => "8",
41
+ "sep" => "9",
42
+ "oct" => "10",
43
+ "nov" => "11",
44
+ "dec" => "12",
45
+
46
+ "sun" => "0",
47
+ "mon" => "1",
48
+ "tue" => "2",
49
+ "wed" => "3",
50
+ "thu" => "4",
51
+ "fri" => "5",
52
+ "sat" => "6"
53
+ }
54
+
55
+ def initialize(source, time_source = Time)
56
+ @source = interpret_vixieisms(source)
57
+ @time_source = time_source
58
+ validate_source
59
+ end
60
+
61
+ def interpret_vixieisms(spec)
62
+ case spec
63
+ when '@reboot'
64
+ raise ArgumentError, "Can't predict last/next run of @reboot"
65
+ when '@yearly', '@annually'
66
+ '0 0 1 1 *'
67
+ when '@monthly'
68
+ '0 0 1 * *'
69
+ when '@weekly'
70
+ '0 0 * * 0'
71
+ when '@daily', '@midnight'
72
+ '0 0 * * *'
73
+ when '@hourly'
74
+ '0 * * * *'
75
+ else
76
+ spec
77
+ end
78
+ end
79
+
80
+ # returns the next occurence after the given date
81
+ def next(now = @time_source.now, num = 1)
82
+ t = InternalTime.new(now, @time_source)
83
+
84
+ unless time_specs[:month][0].include?(t.month)
85
+ nudge_month(t)
86
+ t.day = 0
87
+ end
88
+
89
+ unless interpolate_weekdays(t.year, t.month)[0].include?(t.day)
90
+ nudge_date(t)
91
+ t.hour = -1
92
+ end
93
+
94
+ unless time_specs[:hour][0].include?(t.hour)
95
+ nudge_hour(t)
96
+ t.min = -1
97
+ end
98
+
99
+ # always nudge the minute
100
+ nudge_minute(t)
101
+ t = t.to_time
102
+ if num > 1
103
+ recursive_calculate(:next, t, num)
104
+ else
105
+ t
106
+ end
107
+ end
108
+
109
+ # returns the last occurence before the given date
110
+ def last(now = @time_source.now, num = 1)
111
+ t = InternalTime.new(now, @time_source)
112
+
113
+ unless time_specs[:month][0].include?(t.month)
114
+ nudge_month(t, :last)
115
+ t.day = 32
116
+ end
117
+
118
+ if t.day == 32 || !interpolate_weekdays(t.year, t.month)[0].include?(t.day)
119
+ nudge_date(t, :last)
120
+ t.hour = 24
121
+ end
122
+
123
+ unless time_specs[:hour][0].include?(t.hour)
124
+ nudge_hour(t, :last)
125
+ t.min = 60
126
+ end
127
+
128
+ # always nudge the minute
129
+ nudge_minute(t, :last)
130
+ t = t.to_time
131
+ if num > 1
132
+ recursive_calculate(:last, t, num)
133
+ else
134
+ t
135
+ end
136
+ end
137
+
138
+ SUBELEMENT_REGEX = %r{^(\d+)(-(\d+)(/(\d+))?)?$}
139
+ def parse_element(elem, allowed_range)
140
+ values = elem.split(',').map do |subel|
141
+ if subel =~ /^\*/
142
+ step = subel.length > 1 ? subel[2..-1].to_i : 1
143
+ stepped_range(allowed_range, step)
144
+ else
145
+ raise ArgumentError, "Bad Vixie-style specification #{subel}" unless SUBELEMENT_REGEX === subel
146
+ if ::Regexp.last_match(5) # with range
147
+ stepped_range(::Regexp.last_match(1).to_i..::Regexp.last_match(3).to_i, ::Regexp.last_match(5).to_i)
148
+ elsif ::Regexp.last_match(3) # range without step
149
+ stepped_range(::Regexp.last_match(1).to_i..::Regexp.last_match(3).to_i, 1)
150
+ else # just a numeric
151
+ [::Regexp.last_match(1).to_i]
152
+ end
153
+
154
+
155
+
156
+ end
157
+ end.flatten.sort
158
+
159
+ [Set.new(values), values, elem]
160
+ end
161
+
162
+ protected
163
+
164
+ def recursive_calculate(meth, time, num)
165
+ array = [time]
166
+ num.-(1).times do |_num|
167
+ array << send(meth, array.last)
168
+ end
169
+ array
170
+ end
171
+
172
+ # returns a list of days which do both match time_spec[:dom] or time_spec[:dow]
173
+ def interpolate_weekdays(year, month)
174
+ @_interpolate_weekdays_cache ||= {}
175
+ @_interpolate_weekdays_cache["#{year}-#{month}"] ||= interpolate_weekdays_without_cache(year, month)
176
+ end
177
+
178
+ def interpolate_weekdays_without_cache(year, month)
179
+ t = Date.new(year, month, 1)
180
+ valid_mday, _, mday_field = time_specs[:dom]
181
+ valid_wday, _, wday_field = time_specs[:dow]
182
+
183
+ # Careful, if both DOW and DOM fields are non-wildcard,
184
+ # then we only need to match *one* for cron to run the job:
185
+ unless mday_field == '*' and wday_field == '*'
186
+ valid_mday = [] if mday_field == '*'
187
+ valid_wday = [] if wday_field == '*'
188
+ end
189
+ # Careful: crontabs may use either 0 or 7 for Sunday:
190
+ valid_wday << 0 if valid_wday.include?(7)
191
+
192
+ result = []
193
+ while t.month == month
194
+ result << t.mday if valid_mday.include?(t.mday) || valid_wday.include?(t.wday)
195
+ t = t.succ
196
+ end
197
+
198
+ [Set.new(result), result]
199
+ end
200
+
201
+ def nudge_year(t, dir = :next)
202
+ t.year = t.year + (dir == :next ? 1 : -1)
203
+ end
204
+
205
+ def nudge_month(t, dir = :next)
206
+ spec = time_specs[:month][1]
207
+ next_value = find_best_next(t.month, spec, dir)
208
+ t.month = next_value || (dir == :next ? spec.first : spec.last)
209
+
210
+ nudge_year(t, dir) if next_value.nil?
211
+
212
+ # we changed the month, so its likely that the date is incorrect now
213
+ valid_days = interpolate_weekdays(t.year, t.month)[1]
214
+ t.day = dir == :next ? valid_days.first : valid_days.last
215
+ end
216
+
217
+ def date_valid?(t, _dir = :next)
218
+ interpolate_weekdays(t.year, t.month)[0].include?(t.day)
219
+ end
220
+
221
+ def nudge_date(t, dir = :next, can_nudge_month = true)
222
+ spec = interpolate_weekdays(t.year, t.month)[1]
223
+ next_value = find_best_next(t.day, spec, dir)
224
+ t.day = next_value || (dir == :next ? spec.first : spec.last)
225
+
226
+ nudge_month(t, dir) if next_value.nil? && can_nudge_month
227
+ end
228
+
229
+ def nudge_hour(t, dir = :next)
230
+ spec = time_specs[:hour][1]
231
+ next_value = find_best_next(t.hour, spec, dir)
232
+ t.hour = next_value || (dir == :next ? spec.first : spec.last)
233
+
234
+ nudge_date(t, dir) if next_value.nil?
235
+ end
236
+
237
+ def nudge_minute(t, dir = :next)
238
+ spec = time_specs[:minute][1]
239
+ next_value = find_best_next(t.min, spec, dir)
240
+ t.min = next_value || (dir == :next ? spec.first : spec.last)
241
+
242
+ nudge_hour(t, dir) if next_value.nil?
243
+ end
244
+
245
+ def time_specs
246
+ @time_specs ||= begin
247
+ # tokens now contains the 5 fields
248
+ tokens = substitute_parse_symbols(@source).split(/\s+/)
249
+ {
250
+ :minute => parse_element(tokens[0], 0..59), #minute
251
+ :hour => parse_element(tokens[1], 0..23), #hour
252
+ :dom => parse_element(tokens[2], 1..31), #DOM
253
+ :month => parse_element(tokens[3], 1..12), #mon
254
+ :dow => parse_element(tokens[4], 0..6) #DOW
255
+ }
256
+ end
257
+ end
258
+
259
+ def substitute_parse_symbols(str)
260
+ SYMBOLS.inject(str.downcase) do |s, (symbol, replacement)|
261
+ s.gsub(symbol, replacement)
262
+ end
263
+ end
264
+
265
+ def stepped_range(rng, step = 1)
266
+ len = rng.last - rng.first
267
+
268
+ num = len.div(step)
269
+ result = (0..num).map { |i| rng.first + (step * i) }
270
+
271
+ result.pop if result[-1] == rng.last and rng.exclude_end?
272
+ result
273
+ end
274
+
275
+ # returns the smallest element from allowed which is greater than current
276
+ # returns nil if no matching value was found
277
+ def find_best_next(current, allowed, dir)
278
+ if dir == :next
279
+ allowed.sort.find { |val| val > current }
280
+ else
281
+ allowed.sort.reverse.find { |val| val < current }
282
+ end
283
+ end
284
+
285
+ def validate_source
286
+ raise ArgumentError, 'not a valid cronline' unless @source.respond_to?(:split)
287
+ source_length = @source.split(/\s+/).length
288
+ return if source_length >= 5 && source_length <= 6
289
+ raise ArgumentError, 'not a valid cronline'
290
+
291
+ end
292
+ end
293
+ end
294
+ end
@@ -1,5 +1,5 @@
1
1
  module NewRelic
2
2
  module Security
3
- VERSION = "0.1.0"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
@@ -39,7 +39,7 @@ Gem::Specification.new do |spec|
39
39
  ]
40
40
  spec.require_paths = ['lib']
41
41
 
42
- spec.add_dependency 'newrelic_rpm', '>= 9.12.0'
42
+ spec.add_dependency 'newrelic_rpm', '>= 9.16.0'
43
43
 
44
44
  spec.add_development_dependency 'minitest', "#{RUBY_VERSION >= '2.7.0' ? '~> 5.18' : '4.7.5'}"
45
45
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: newrelic_security
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Prateek Sen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-07-29 00:00:00.000000000 Z
11
+ date: 2024-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: newrelic_rpm
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 9.12.0
19
+ version: 9.16.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 9.12.0
26
+ version: 9.16.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: minitest
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -151,10 +151,12 @@ files:
151
151
  - lib/newrelic_security/agent/configuration/server_source.rb
152
152
  - lib/newrelic_security/agent/configuration/yaml_source.rb
153
153
  - lib/newrelic_security/agent/control/app_info.rb
154
+ - lib/newrelic_security/agent/control/application_runtime_error.rb
154
155
  - lib/newrelic_security/agent/control/application_url_mappings.rb
155
156
  - lib/newrelic_security/agent/control/collector.rb
156
157
  - lib/newrelic_security/agent/control/control_command.rb
157
158
  - lib/newrelic_security/agent/control/critical_message.rb
159
+ - lib/newrelic_security/agent/control/error_reporting.rb
158
160
  - lib/newrelic_security/agent/control/event.rb
159
161
  - lib/newrelic_security/agent/control/event_counter.rb
160
162
  - lib/newrelic_security/agent/control/event_processor.rb
@@ -168,6 +170,7 @@ files:
168
170
  - lib/newrelic_security/agent/control/iast_client.rb
169
171
  - lib/newrelic_security/agent/control/iast_data_transfer_request.rb
170
172
  - lib/newrelic_security/agent/control/reflected_xss.rb
173
+ - lib/newrelic_security/agent/control/scan_scheduler.rb
171
174
  - lib/newrelic_security/agent/control/websocket_client.rb
172
175
  - lib/newrelic_security/agent/logging/init_logger.rb
173
176
  - lib/newrelic_security/agent/logging/logger.rb
@@ -268,6 +271,7 @@ files:
268
271
  - lib/newrelic_security/instrumentation-security/sqlite3/instrumentation.rb
269
272
  - lib/newrelic_security/instrumentation-security/sqlite3/prepend.rb
270
273
  - lib/newrelic_security/newrelic-security-api/api.rb
274
+ - lib/newrelic_security/parse-cron/cron_parser.rb
271
275
  - lib/newrelic_security/version.rb
272
276
  - lib/newrelic_security/websocket-client-simple/client.rb
273
277
  - lib/newrelic_security/websocket-client-simple/event_emitter.rb