sqreen 1.19.1-java → 1.21.0.beta3-java

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 (101) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +34 -0
  3. data/lib/sqreen/actions/block_user.rb +1 -1
  4. data/lib/sqreen/actions/redirect_ip.rb +1 -1
  5. data/lib/sqreen/actions/redirect_user.rb +1 -1
  6. data/lib/sqreen/agent_message.rb +20 -0
  7. data/lib/sqreen/aggregated_metric.rb +25 -0
  8. data/lib/sqreen/attack_detected.html +1 -2
  9. data/lib/sqreen/ca.crt +24 -0
  10. data/lib/sqreen/condition_evaluator.rb +9 -2
  11. data/lib/sqreen/conditionable.rb +24 -6
  12. data/lib/sqreen/configuration.rb +11 -5
  13. data/lib/sqreen/deferred_logger.rb +50 -14
  14. data/lib/sqreen/deliveries/batch.rb +12 -2
  15. data/lib/sqreen/deliveries/simple.rb +4 -0
  16. data/lib/sqreen/deprecation.rb +38 -0
  17. data/lib/sqreen/ecosystem.rb +96 -0
  18. data/lib/sqreen/ecosystem/dispatch_table.rb +43 -0
  19. data/lib/sqreen/ecosystem/exception_reporting.rb +26 -0
  20. data/lib/sqreen/ecosystem/http/net_http.rb +50 -0
  21. data/lib/sqreen/ecosystem/http/rack_request.rb +39 -0
  22. data/lib/sqreen/ecosystem/loggable.rb +13 -0
  23. data/lib/sqreen/ecosystem/module_api.rb +30 -0
  24. data/lib/sqreen/ecosystem/module_api/event_listener.rb +18 -0
  25. data/lib/sqreen/ecosystem/module_api/instrumentation.rb +23 -0
  26. data/lib/sqreen/ecosystem/module_api/message_producer.rb +51 -0
  27. data/lib/sqreen/ecosystem/module_api/signal_producer.rb +24 -0
  28. data/lib/sqreen/ecosystem/module_api/tracing.rb +45 -0
  29. data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +31 -0
  30. data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +27 -0
  31. data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +16 -0
  32. data/lib/sqreen/ecosystem/module_api/transaction_storage.rb +71 -0
  33. data/lib/sqreen/ecosystem/module_registry.rb +44 -0
  34. data/lib/sqreen/ecosystem/redis/redis_connection.rb +43 -0
  35. data/lib/sqreen/ecosystem/tracing/modules/client.rb +31 -0
  36. data/lib/sqreen/ecosystem/tracing/modules/server.rb +30 -0
  37. data/lib/sqreen/ecosystem/tracing/sampler.rb +160 -0
  38. data/lib/sqreen/ecosystem/tracing/sampling_configuration.rb +150 -0
  39. data/lib/sqreen/ecosystem/tracing/signals/tracing_client.rb +53 -0
  40. data/lib/sqreen/ecosystem/tracing/signals/tracing_server.rb +53 -0
  41. data/lib/sqreen/ecosystem/tracing_broker.rb +101 -0
  42. data/lib/sqreen/ecosystem/tracing_id_setup.rb +34 -0
  43. data/lib/sqreen/ecosystem/transaction_storage.rb +64 -0
  44. data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +13 -0
  45. data/lib/sqreen/ecosystem_integration.rb +87 -0
  46. data/lib/sqreen/ecosystem_integration/around_callbacks.rb +99 -0
  47. data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +42 -0
  48. data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +58 -0
  49. data/lib/sqreen/ecosystem_integration/signal_consumption.rb +35 -0
  50. data/lib/sqreen/endpoint_testing.rb +184 -0
  51. data/lib/sqreen/event.rb +7 -5
  52. data/lib/sqreen/events/attack.rb +23 -18
  53. data/lib/sqreen/events/remote_exception.rb +0 -22
  54. data/lib/sqreen/events/request_record.rb +15 -71
  55. data/lib/sqreen/frameworks/generic.rb +24 -1
  56. data/lib/sqreen/frameworks/rails.rb +0 -7
  57. data/lib/sqreen/frameworks/request_recorder.rb +15 -2
  58. data/lib/sqreen/graft/call.rb +106 -19
  59. data/lib/sqreen/graft/callback.rb +1 -1
  60. data/lib/sqreen/graft/hook.rb +212 -100
  61. data/lib/sqreen/graft/hook_point.rb +18 -11
  62. data/lib/sqreen/kit/signals/specialized/aggregated_metric.rb +72 -0
  63. data/lib/sqreen/kit/signals/specialized/attack.rb +57 -0
  64. data/lib/sqreen/kit/signals/specialized/binning_metric.rb +76 -0
  65. data/lib/sqreen/kit/signals/specialized/http_trace.rb +26 -0
  66. data/lib/sqreen/kit/signals/specialized/sdk_track_call.rb +50 -0
  67. data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +57 -0
  68. data/lib/sqreen/legacy/instrumentation.rb +22 -10
  69. data/lib/sqreen/legacy/old_event_submission_strategy.rb +228 -0
  70. data/lib/sqreen/legacy/waf_redactions.rb +49 -0
  71. data/lib/sqreen/log.rb +3 -2
  72. data/lib/sqreen/log/loggable.rb +2 -1
  73. data/lib/sqreen/logger.rb +24 -0
  74. data/lib/sqreen/metrics.rb +1 -0
  75. data/lib/sqreen/metrics/base.rb +3 -0
  76. data/lib/sqreen/metrics/req_detailed.rb +41 -0
  77. data/lib/sqreen/metrics_store.rb +33 -12
  78. data/lib/sqreen/null_logger.rb +22 -0
  79. data/lib/sqreen/performance_notifications/binned_metrics.rb +8 -2
  80. data/lib/sqreen/remote_command.rb +4 -0
  81. data/lib/sqreen/rules.rb +12 -6
  82. data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
  83. data/lib/sqreen/rules/custom_error_cb.rb +3 -3
  84. data/lib/sqreen/rules/not_found_cb.rb +2 -0
  85. data/lib/sqreen/rules/rule_cb.rb +6 -2
  86. data/lib/sqreen/rules/waf_cb.rb +16 -13
  87. data/lib/sqreen/runner.rb +138 -16
  88. data/lib/sqreen/sensitive_data_redactor.rb +19 -31
  89. data/lib/sqreen/session.rb +53 -43
  90. data/lib/sqreen/signals/conversions.rb +288 -0
  91. data/lib/sqreen/signals/http_trace_redaction.rb +111 -0
  92. data/lib/sqreen/signals/signals_submission_strategy.rb +78 -0
  93. data/lib/sqreen/version.rb +1 -1
  94. data/lib/sqreen/weave/budget.rb +35 -0
  95. data/lib/sqreen/weave/legacy/instrumentation.rb +277 -135
  96. data/lib/sqreen/worker.rb +6 -2
  97. metadata +86 -10
  98. data/lib/sqreen/backport.rb +0 -9
  99. data/lib/sqreen/backport/clock_gettime.rb +0 -74
  100. data/lib/sqreen/backport/original_name.rb +0 -88
  101. data/lib/sqreen/encoding_sanitizer.rb +0 -27
@@ -9,6 +9,26 @@ module Sqreen
9
9
  class NullLogger
10
10
  include Singleton
11
11
 
12
+ def debug?
13
+ false
14
+ end
15
+
16
+ def info?
17
+ false
18
+ end
19
+
20
+ def warn?
21
+ false
22
+ end
23
+
24
+ def error?
25
+ false
26
+ end
27
+
28
+ def fatal?
29
+ false
30
+ end
31
+
12
32
  def debug(_msg = nil); end
13
33
 
14
34
  def info(_msg = nil); end
@@ -19,6 +39,8 @@ module Sqreen
19
39
 
20
40
  def fatal(_msg = nil); end
21
41
 
42
+ def unknown(_msg = nil); end
43
+
22
44
  def add(_severity, _msg = nil); end
23
45
 
24
46
  def formatter=(_); end
@@ -122,10 +122,16 @@ module Sqreen
122
122
  attr_reader :metrics_store
123
123
  attr_reader :period
124
124
 
125
- def ensure_metric(metric_name)
125
+ def ensure_metric(metric_name, rule = nil)
126
126
  return if metrics_store.metric?(metric_name)
127
127
  metrics_store.create_metric(
128
- 'name' => metric_name, 'period' => period, 'kind' => 'Binning', 'options' => @perf_metric_opts
128
+ {
129
+ 'name' => metric_name,
130
+ 'period' => period,
131
+ 'kind' => 'Binning',
132
+ 'options' => @perf_metric_opts,
133
+ },
134
+ rule
129
135
  )
130
136
  end
131
137
 
@@ -18,10 +18,12 @@ module Sqreen
18
18
  :features_get => :features,
19
19
  :features_change => :change_features,
20
20
  :force_logout => :shutdown,
21
+ :force_restart => :restart,
21
22
  :paths_whitelist => :change_whitelisted_paths,
22
23
  :ips_whitelist => :change_whitelisted_ips,
23
24
  :get_bundle => :upload_bundle,
24
25
  :performance_budget => :change_performance_budget,
26
+ :tracing_enable => :tracing_enable,
25
27
  }.freeze
26
28
 
27
29
  attr_reader :uuid
@@ -39,6 +41,8 @@ module Sqreen
39
41
  begin
40
42
  output = runner.send(KNOWN_COMMANDS[@name], *@params, context_infos)
41
43
  rescue => e
44
+ Sqreen.log.warn { "Command failed with #{e}" }
45
+ Sqreen.log.debug { e.backtrace.map { |x| " #{x}" }.join("\n") }
42
46
  Sqreen::RemoteException.record(e)
43
47
  return { :status => false, :reason => "error: #{e.inspect}" }
44
48
  end
@@ -114,15 +114,19 @@ module Sqreen
114
114
  Sqreen.log.warn('No JavaScript engine is available. ' \
115
115
  'JavaScript callbacks will be ignored')
116
116
  end
117
- Sqreen.log.info("Ignoring JS callback #{rule_name}")
117
+ Sqreen.log.debug("Ignoring JS callback #{rule_name}")
118
118
  return nil
119
119
  end
120
120
 
121
121
  cb_class = ExecJSCB if js
122
122
 
123
- if cbname && Rules.const_defined?(cbname)
124
- # Only load callbacks from sqreen
125
- cb_class = Rules.const_get(cbname)
123
+ if cbname
124
+ cb_class = if cbname.include?('::')
125
+ # Only load callbacks from sqreen
126
+ Rules.walk_const_get(cbname) if cbname.start_with?('::Sqreen::', 'Sqreen::')
127
+ else
128
+ Rules.const_get(cbname) if Rules.const_defined?(cbname) # rubocop:disable Style/IfInsideElse
129
+ end
126
130
  end
127
131
 
128
132
  if cb_class.nil?
@@ -135,13 +139,15 @@ module Sqreen
135
139
  return nil
136
140
  end
137
141
 
142
+ rule_cb = cb_class.new(instr_class, instr_method, hash_rule)
143
+
138
144
  if metrics_store
139
145
  (hash_rule[Attrs::METRICS] || []).each do |metric|
140
- metrics_store.create_metric(metric)
146
+ metrics_store.create_metric(metric, rule_cb)
141
147
  end
142
148
  end
143
149
 
144
- cb_class.new(instr_class, instr_method, hash_rule)
150
+ rule_cb
145
151
  rescue => e
146
152
  rule_name = nil
147
153
  rulespack_id = nil
@@ -33,7 +33,7 @@ module Sqreen
33
33
  private
34
34
 
35
35
  def insert_values(ranges)
36
- Sqreen.log.info 'no ips given for IP blacklisting' if ranges.empty?
36
+ Sqreen.log.debug 'no ips given for IP blacklisting' if ranges.empty?
37
37
 
38
38
  ranges.map { |r| Prefix.from_str(r, r) }.each do |prefix|
39
39
  trie_for(prefix).insert prefix
@@ -50,7 +50,7 @@ module Sqreen
50
50
  begin
51
51
  ipa = IPAddr.new(rip)
52
52
  rescue StandardError
53
- Sqreen.log.info "invalid IP address given by framework: #{rip}"
53
+ Sqreen.log.debug "invalid IP address given by framework: #{rip}"
54
54
  return nil
55
55
  end
56
56
 
@@ -55,12 +55,12 @@ module Sqreen
55
55
  end
56
56
 
57
57
  def respond_page
58
- page = open(File.join(File.dirname(__FILE__), '../attack_detected.html'))
58
+ @page ||= File.read(File.join(File.dirname(__FILE__), '../attack_detected.html'))
59
59
  headers = {
60
60
  'Content-Type' => 'text/html',
61
- 'Content-Length' => page.size.to_s,
61
+ 'Content-Length' => @page.size.to_s,
62
62
  }
63
- [@status_code, headers, page]
63
+ [@status_code, headers, [@page]]
64
64
  end
65
65
  end
66
66
  end
@@ -24,6 +24,8 @@ module Sqreen
24
24
  exception = env['action_dispatch.exception']
25
25
 
26
26
  record_from_env(ua, script_name, path_info, verb, override, host, exception)
27
+
28
+ nil
27
29
  end
28
30
 
29
31
  def record_from_env(ua, script_name, path_info, verb, override, host, exception)
@@ -3,6 +3,7 @@
3
3
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
5
 
6
+ require 'sqreen/deprecation'
6
7
  require 'sqreen/framework_cb'
7
8
  require 'sqreen/context'
8
9
  require 'sqreen/conditionable'
@@ -61,7 +62,9 @@ module Sqreen
61
62
  :infos => infos,
62
63
  :rulespack_id => rulespack_id,
63
64
  :rule_name => rule_name,
65
+ :attack_type => @rule['attack_type'], # for signal
64
66
  :test => test,
67
+ :block => @rule['block'], # for signal
65
68
  :time => at,
66
69
  }
67
70
  if payload_tpl.include?('context')
@@ -87,9 +90,9 @@ module Sqreen
87
90
  framework.observe(:sqreen_exceptions, payload)
88
91
  end
89
92
 
90
- # Recommend taking an action (optionnally adding more data/context)
93
+ # Recommend taking an action (optionally adding more data/context)
91
94
  #
92
- # This will format the requested action and optionnally
95
+ # This will format the requested action and optionally
93
96
  # override it if it should not be taken (should not block for example)
94
97
  def advise_action(action, additional_data = {})
95
98
  return if action.nil? && additional_data.empty?
@@ -107,6 +110,7 @@ module Sqreen
107
110
  )
108
111
  true
109
112
  end
113
+ Sqreen::Deprecation.deprecate(instance_method(:overtime!))
110
114
  end
111
115
  end
112
116
  end
@@ -11,7 +11,7 @@ require 'sqreen/safe_json'
11
11
  require 'sqreen/exception'
12
12
  require 'sqreen/util/capper'
13
13
  require 'sqreen/dependency/libsqreen'
14
- require 'sqreen/encoding_sanitizer'
14
+ require 'sqreen/kit/string_sanitizer'
15
15
 
16
16
  module Sqreen
17
17
  module Rules
@@ -60,7 +60,7 @@ module Sqreen
60
60
  end
61
61
 
62
62
  # 0 for using defaults (PW_RUN_TIMEOUT)
63
- @max_run_budget_us = (@data['values'].fetch('budget_in_ms', 0) * 1000).to_i
63
+ @max_run_budget_us = (@data['values'].fetch('max_budget_ms', 0) * 1000).to_i
64
64
  @max_run_budget_us = INFINITE_BUDGET_US if @max_run_budget_us >= INFINITE_BUDGET_US
65
65
 
66
66
  Sqreen.log.debug { "Max WAF run budget for #{@waf_rule_name} set to #{@max_run_budget_us} us" }
@@ -82,7 +82,7 @@ module Sqreen
82
82
  waf_args = binding_accessors.each_with_object({}) do |(e, b), h|
83
83
  h[e] = capper.call(b.resolve(*env))
84
84
  end
85
- waf_args = Sqreen::EncodingSanitizer.sanitize(waf_args)
85
+ waf_args = Sqreen::Kit::StringSanitizer.sanitize(waf_args)
86
86
 
87
87
  if budget
88
88
  rem_budget_s = budget - (Sqreen.time - start)
@@ -98,10 +98,10 @@ module Sqreen
98
98
 
99
99
  case action
100
100
  when :monitor
101
- record_event({ 'waf_data' => data })
101
+ record_event({ waf_data: data })
102
102
  advise_action(nil)
103
103
  when :block
104
- record_event({ 'waf_data' => data })
104
+ record_event({ waf_data: data })
105
105
  advise_action(:raise)
106
106
  when :good
107
107
  advise_action(nil)
@@ -132,20 +132,23 @@ module Sqreen
132
132
  end
133
133
 
134
134
  def record_exception(exception, infos = {}, at = Time.now.utc)
135
- infos.merge!(exception_to_infos(exception)) if exception.is_a?(Sqreen::WAFError)
135
+ infos.merge!(waf_infos(exception)) if exception.is_a?(Sqreen::WAFError)
136
136
  super(exception, infos, at)
137
137
  end
138
138
 
139
139
  private
140
140
 
141
- def exception_to_infos(e)
141
+ # see https://github.com/sqreen/TechDoc/blob/master/content/specs/spec000016-waf-integration.md#error-management
142
+ def waf_infos(e)
142
143
  {
143
- waf_rule: e.rule_name,
144
- error_code: ERROR_CODES[e.error],
145
- }.tap do |r|
146
- r[:error_data] = e.data if e.data
147
- r[:args] = e.args if e.args
148
- end
144
+ waf: {
145
+ waf_rule: e.rule_name,
146
+ error_code: ERROR_CODES[e.error],
147
+ }.tap do |r|
148
+ r[:error_data] = e.data if e.data
149
+ r[:args] = e.args if e.arg
150
+ end,
151
+ }
149
152
  end
150
153
 
151
154
  ERROR_CODES = {
@@ -11,18 +11,23 @@ require 'sqreen/events/attack'
11
11
 
12
12
  require 'sqreen/log'
13
13
 
14
+ require 'sqreen/agent_message'
14
15
  require 'sqreen/rules'
15
16
  require 'sqreen/session'
17
+ require 'sqreen/version'
16
18
  require 'sqreen/remote_command'
17
19
  require 'sqreen/capped_queue'
18
20
  require 'sqreen/metrics_store'
19
21
  require 'sqreen/deliveries/simple'
20
22
  require 'sqreen/deliveries/batch'
23
+ require 'sqreen/endpoint_testing'
21
24
  require 'sqreen/performance_notifications/metrics'
22
25
  require 'sqreen/performance_notifications/binned_metrics'
23
26
  require 'sqreen/legacy/instrumentation'
24
27
  require 'sqreen/call_countable'
25
28
  require 'sqreen/weave/legacy/instrumentation'
29
+ require 'sqreen/kit/configuration'
30
+ require 'sqreen/ecosystem_integration'
26
31
 
27
32
  module Sqreen
28
33
  @features = {}
@@ -37,6 +42,8 @@ module Sqreen
37
42
  PERF_METRICS_PERIOD = 60 # 1 min
38
43
  DEFAULT_PERF_LEVEL = 0 # disabled
39
44
 
45
+ DEFAULT_USE_SIGNALS = false
46
+
40
47
  class << self
41
48
  attr_reader :features
42
49
  def update_features(features)
@@ -47,10 +54,6 @@ module Sqreen
47
54
  @queue ||= CappedQueue.new(MAX_QUEUE_LENGTH)
48
55
  end
49
56
 
50
- def update_queue(queue)
51
- @queue = queue
52
- end
53
-
54
57
  def observations_queue
55
58
  @observations_queue ||= CappedQueue.new(MAX_OBS_QUEUE_LENGTH)
56
59
  end
@@ -87,7 +90,9 @@ module Sqreen
87
90
 
88
91
  attr_accessor :heartbeat_delay
89
92
  attr_accessor :metrics_engine
93
+ # @return [Sqreen::Deliveries::Simple]
90
94
  attr_reader :deliverer
95
+ # @return [Sqreen::Session]
91
96
  attr_reader :session
92
97
  attr_reader :instrumenter
93
98
  attr_accessor :running
@@ -97,8 +102,8 @@ module Sqreen
97
102
  # we may want to do that in a thread in order to prevent delaying app
98
103
  # startup
99
104
  # set_at_exit do not place a global at_exit (used for testing)
105
+ # @param [Sqreen::Frameworks::GenericFramework] framework
100
106
  def initialize(configuration, framework, set_at_exit = true, session_class = Sqreen::Session)
101
- Sqreen.update_queue(CappedQueue.new(MAX_QUEUE_LENGTH))
102
107
  @logged_out_tried = false
103
108
  @configuration = configuration
104
109
  @framework = framework
@@ -108,15 +113,25 @@ module Sqreen
108
113
  @next_metrics = []
109
114
  @running = true
110
115
 
116
+ @proxy_url = @configuration.get(:proxy_url)
117
+ chosen_endpoints = determine_endpoints
118
+
111
119
  @token = @configuration.get(:token)
112
120
  @app_name = @configuration.get(:app_name)
113
- @url = @configuration.get(:url)
121
+ @url = chosen_endpoints.control.url
122
+ @cert_store = chosen_endpoints.control.ca_store
123
+
114
124
  Sqreen.update_whitelisted_paths([])
115
125
  Sqreen.update_whitelisted_ips({})
116
126
  Sqreen.update_performance_budget(nil)
117
- raise(Sqreen::Exception, 'no url found') unless @url
118
127
  raise(Sqreen::TokenNotFoundException, 'no token found') unless @token
119
128
 
129
+ Sqreen::Kit::Configuration.logger = Sqreen.log
130
+ Sqreen::Kit::Configuration.ingestion_url = chosen_endpoints.ingestion.url
131
+ Sqreen::Kit::Configuration.certificate_store = chosen_endpoints.ingestion.ca_store
132
+ Sqreen::Kit::Configuration.proxy_url = @proxy_url
133
+ Sqreen::Kit::Configuration.default_source = "sqreen:agent:ruby:#{Sqreen::VERSION}"
134
+
120
135
  register_exit_cb if set_at_exit
121
136
 
122
137
  self.metrics_engine = MetricsStore.new
@@ -126,13 +141,19 @@ module Sqreen
126
141
  end
127
142
 
128
143
  if @configuration.get(:weave) || needs_weave.call
129
- @instrumenter = Sqreen::Weave::Legacy::Instrumentation.new(metrics_engine)
144
+ # XXX: don't get updated
145
+ opts = {
146
+ perf_req_metrics_max_reqs: Sqreen.features['perf_req_metrics_max_reqs'],
147
+ perf_req_metrics_period: Sqreen.features['perf_req_metrics_period'],
148
+ }
149
+ @instrumenter = Sqreen::Weave::Legacy::Instrumentation.new(metrics_engine, opts)
130
150
  else
131
151
  @instrumenter = Sqreen::Legacy::Instrumentation.new(metrics_engine)
132
152
  end
133
153
 
134
154
  Sqreen.log.debug "Using token #{@token}"
135
155
  response = create_session(session_class)
156
+ post_endpoint_testing_msgs(chosen_endpoints)
136
157
  wanted_features = response.fetch('features', {})
137
158
  conf_initial_features = configuration.get(:initial_features)
138
159
  unless conf_initial_features.nil?
@@ -142,15 +163,21 @@ module Sqreen
142
163
  Sqreen.log.debug do
143
164
  "Override initial features with #{conf_features.inspect}"
144
165
  end
145
- wanted_features = conf_features
166
+ wanted_features = wanted_features.merge(conf_features)
146
167
  rescue
147
168
  Sqreen.log.warn do
148
- "NOT using invalid inital features #{conf_initial_features}"
169
+ "NOT using invalid initial features #{conf_initial_features}"
149
170
  end
150
171
  end
151
172
  end
152
173
  self.features = wanted_features
153
174
 
175
+ @ecosystem_integration = EcosystemIntegration.new(framework,
176
+ Sqreen.queue,
177
+ create_binning_metric_proc)
178
+ framework.req_start_cb = @ecosystem_integration.method(:request_start)
179
+ framework.req_end_cb = @ecosystem_integration.method(:request_end)
180
+
154
181
  # Ensure a deliverer is there unless features have set it first
155
182
  self.deliverer ||= Deliveries::Simple.new(session)
156
183
  context_infos = {}
@@ -161,7 +188,7 @@ module Sqreen
161
188
  end
162
189
 
163
190
  def create_session(session_class)
164
- @session = session_class.new(@url, @token, @app_name)
191
+ @session = session_class.new(@url, @cert_store, @token, @app_name, @proxy_url)
165
192
  session.login(@framework)
166
193
  end
167
194
 
@@ -170,8 +197,18 @@ module Sqreen
170
197
  @deliverer = new_deliverer
171
198
  end
172
199
 
173
- def batch_events(batch_size, max_staleness = nil)
200
+ def batch_events(batch_size, max_staleness = nil, use_signals = false)
174
201
  size = batch_size.to_i
202
+
203
+ if size <= 1 && use_signals
204
+ Sqreen.log.warn do
205
+ "Using signals with no delivery batching is unsupported. " \
206
+ "Using instead batching with batch size = 30, max_staleness = 60"
207
+ end
208
+ size = 30
209
+ max_staleness = 60
210
+ end
211
+
175
212
  self.deliverer = if size < 1
176
213
  Deliveries::Simple.new(session)
177
214
  else
@@ -241,6 +278,10 @@ module Sqreen
241
278
  rulespack_id, rules = load_rules(context_infos)
242
279
  @framework.instrument_when_ready!(instrumenter, rules)
243
280
  Sqreen.log.info 'Instrumentation set up'
281
+
282
+ # XXX: ecosystem instrumentation should likely be deferred
283
+ # the same way the rest might be
284
+ @ecosystem_integration.init unless Sqreen.features['disable_ecosystem']
244
285
  rulespack_id.to_s
245
286
  end
246
287
 
@@ -301,19 +342,37 @@ module Sqreen
301
342
  def do_heartbeat
302
343
  @last_heartbeat_request = Time.now
303
344
  @next_metrics.concat(metrics_engine.publish(false)) if metrics_engine
304
- res = session.heartbeat(next_command_results, next_metrics)
345
+ metrics_in_hb = use_signals? ? nil : next_metrics
346
+
347
+ res = session.heartbeat(next_command_results, metrics_in_hb)
305
348
  next_command_results.clear
349
+
350
+ deliver_metrics_as_event if use_signals?
306
351
  next_metrics.clear
352
+
307
353
  process_commands(res['commands'])
308
354
  end
309
355
 
356
+ def deliver_metrics_as_event
357
+ # this is disastrous withe simple delivery strategy,
358
+ # as each aggregated metric would trigger an http request
359
+ # Sending of metrics is therefore not supported with simple delivery strategy
360
+ # TODO: Confirm that only batch is used in production
361
+ next_metrics.each { |x| deliverer.post_event(x) }
362
+ end
363
+
310
364
  def features(_context_infos = {})
311
365
  Sqreen.features
312
366
  end
313
367
 
368
+ def use_signals?
369
+ features.fetch('use_signals', DEFAULT_USE_SIGNALS)
370
+ end
371
+
314
372
  def features=(features)
315
373
  Sqreen.update_features(features)
316
374
  session.request_compression = features['request_compression'] if session
375
+ session.use_signals = use_signals?
317
376
  self.performance_metrics_period = features['performance_metrics_period']
318
377
 
319
378
  unless @configuration.get(:weave)
@@ -331,7 +390,7 @@ module Sqreen
331
390
  hd = features['heartbeat_delay'].to_i
332
391
  self.heartbeat_delay = hd if hd > 0
333
392
  return if features['batch_size'].nil?
334
- batch_events(features['batch_size'], features['max_staleness'])
393
+ batch_events(features['batch_size'], features['max_staleness'], use_signals?)
335
394
  end
336
395
 
337
396
  def change_whitelisted_paths(paths, _context_infos = {})
@@ -342,11 +401,28 @@ module Sqreen
342
401
 
343
402
  def change_performance_budget(budget, _context_infos = {})
344
403
  return false unless budget.nil? || budget.to_f > 0
345
- prev = Sqreen.performance_budget
346
- Sqreen.update_performance_budget(budget)
404
+
405
+ if @configuration.get(:weave)
406
+ prev = Sqreen::Weave::Budget.current
407
+ prev = prev.to_h if prev
408
+
409
+ budget_s = budget.to_f / 1000.0 if budget
410
+ Sqreen::Weave::Budget.update(threshold: budget_s)
411
+ else
412
+ prev = Sqreen.performance_budget
413
+ Sqreen.update_performance_budget(budget)
414
+ end
415
+
347
416
  { :was => prev }
348
417
  end
349
418
 
419
+ # @param [String] tracing_id_prefix
420
+ # @param [Array<Hash{String=>Object}>] sampling_config
421
+ def tracing_enable(tracing_id_prefix, sampling_config, _context_infos = {})
422
+ @ecosystem_integration.handle_tracing_command(tracing_id_prefix, sampling_config)
423
+ { status: true }
424
+ end
425
+
350
426
  def upload_bundle(_context_infos = {})
351
427
  t = Time.now
352
428
  session.post_bundle(RuntimeInfos.dependencies_signature, RuntimeInfos.dependencies)
@@ -433,6 +509,15 @@ module Sqreen
433
509
  logout
434
510
  end
435
511
 
512
+ def restart(_context_infos = {})
513
+ shutdown
514
+ heartbeat_delay = @heartbeat_delay
515
+ Thread.new do
516
+ sleep(2 * heartbeat_delay)
517
+ Sqreen::Worker.start(Sqreen.framework)
518
+ end
519
+ end
520
+
436
521
  def logout(retrying = true)
437
522
  return unless session
438
523
  Sqreen.log.debug("Logging out")
@@ -470,6 +555,43 @@ module Sqreen
470
555
 
471
556
  private
472
557
 
558
+ def create_binning_metric_proc
559
+ lambda do |metric_name|
560
+ return if @metrics_engine.metric?(metric_name)
561
+ metrics_engine.create_metric(
562
+ 'name' => metric_name,
563
+ 'kind' => 'Binning',
564
+ 'period' => Sqreen.features['performance_metrics_period'] || 60,
565
+ 'options' => {
566
+ 'base' => Sqreen.features['perf_base'] || PerformanceNotifications::BinnedMetrics::DEFAULT_PERF_BASE,
567
+ 'factor' => Sqreen.features['perf_unit'] || PerformanceNotifications::BinnedMetrics::DEFAULT_PERF_UNIT,
568
+ },
569
+ )
570
+ end
571
+ end
572
+
573
+ def post_endpoint_testing_msgs(chosen_endpoints)
574
+ chosen_endpoints.messages.each do |msg|
575
+ session.post_agent_message(@framework, msg)
576
+ end
577
+ rescue => e
578
+ Sqreen.log.warn "Error submitting agent message: #{e}"
579
+ RemoteException.record(e)
580
+ end
581
+
582
+ def determine_endpoints
583
+ # there's no sniffing going on; just a misnamed config setting
584
+ if @configuration.get(:no_sniff_domains)
585
+ # reproduces behaviour before endpoint testing was introduced
586
+ EndpointTesting.no_test_endpoints(@configuration.get(:url),
587
+ @configuration.get(:ingestion_url))
588
+ else
589
+ EndpointTesting.test_endpoints(@proxy_url,
590
+ @configuration.get(:url),
591
+ @configuration.get(:ingestion_url))
592
+ end
593
+ end
594
+
473
595
  def load_actions(hashes)
474
596
  unsupported = Set.new
475
597