sqreen 1.19.3-java → 1.21.0-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 (113) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +38 -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 +8 -2
  11. data/lib/sqreen/configuration.rb +11 -5
  12. data/lib/sqreen/deferred_logger.rb +50 -14
  13. data/lib/sqreen/deliveries/batch.rb +12 -2
  14. data/lib/sqreen/deliveries/simple.rb +4 -0
  15. data/lib/sqreen/deprecation.rb +38 -0
  16. data/lib/sqreen/ecosystem.rb +123 -0
  17. data/lib/sqreen/ecosystem/databases/database_connection_data.rb +23 -0
  18. data/lib/sqreen/ecosystem/databases/mongo.rb +39 -0
  19. data/lib/sqreen/ecosystem/databases/mysql.rb +54 -0
  20. data/lib/sqreen/ecosystem/databases/postgres.rb +51 -0
  21. data/lib/sqreen/ecosystem/databases/redis.rb +36 -0
  22. data/lib/sqreen/ecosystem/dispatch_table.rb +43 -0
  23. data/lib/sqreen/ecosystem/exception_reporting.rb +28 -0
  24. data/lib/sqreen/ecosystem/http/net_http.rb +50 -0
  25. data/lib/sqreen/ecosystem/http/rack_request.rb +39 -0
  26. data/lib/sqreen/ecosystem/loggable.rb +13 -0
  27. data/lib/sqreen/ecosystem/messaging/bunny.rb +61 -0
  28. data/lib/sqreen/ecosystem/messaging/kafka.rb +70 -0
  29. data/lib/sqreen/ecosystem/messaging/kinesis.rb +66 -0
  30. data/lib/sqreen/ecosystem/messaging/sqs.rb +68 -0
  31. data/lib/sqreen/ecosystem/module_api.rb +30 -0
  32. data/lib/sqreen/ecosystem/module_api/event_listener.rb +18 -0
  33. data/lib/sqreen/ecosystem/module_api/instrumentation.rb +23 -0
  34. data/lib/sqreen/ecosystem/module_api/message_producer.rb +57 -0
  35. data/lib/sqreen/ecosystem/module_api/signal_producer.rb +24 -0
  36. data/lib/sqreen/ecosystem/module_api/tracing.rb +45 -0
  37. data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +31 -0
  38. data/lib/sqreen/ecosystem/module_api/tracing/consumer_data.rb +13 -0
  39. data/lib/sqreen/ecosystem/module_api/tracing/messaging_data.rb +35 -0
  40. data/lib/sqreen/ecosystem/module_api/tracing/producer_data.rb +13 -0
  41. data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +27 -0
  42. data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +16 -0
  43. data/lib/sqreen/ecosystem/module_api/transaction_storage.rb +71 -0
  44. data/lib/sqreen/ecosystem/module_registry.rb +48 -0
  45. data/lib/sqreen/ecosystem/tracing/modules/client.rb +35 -0
  46. data/lib/sqreen/ecosystem/tracing/modules/consumer.rb +35 -0
  47. data/lib/sqreen/ecosystem/tracing/modules/determine_ip.rb +28 -0
  48. data/lib/sqreen/ecosystem/tracing/modules/producer.rb +35 -0
  49. data/lib/sqreen/ecosystem/tracing/modules/server.rb +30 -0
  50. data/lib/sqreen/ecosystem/tracing/sampler.rb +160 -0
  51. data/lib/sqreen/ecosystem/tracing/sampling_configuration.rb +150 -0
  52. data/lib/sqreen/ecosystem/tracing/signals/tracing_client.rb +53 -0
  53. data/lib/sqreen/ecosystem/tracing/signals/tracing_consumer.rb +56 -0
  54. data/lib/sqreen/ecosystem/tracing/signals/tracing_producer.rb +56 -0
  55. data/lib/sqreen/ecosystem/tracing/signals/tracing_server.rb +53 -0
  56. data/lib/sqreen/ecosystem/tracing_broker.rb +101 -0
  57. data/lib/sqreen/ecosystem/tracing_id_setup.rb +34 -0
  58. data/lib/sqreen/ecosystem/transaction_storage.rb +64 -0
  59. data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +13 -0
  60. data/lib/sqreen/ecosystem_integration.rb +81 -0
  61. data/lib/sqreen/ecosystem_integration/around_callbacks.rb +89 -0
  62. data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +38 -0
  63. data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +58 -0
  64. data/lib/sqreen/ecosystem_integration/signal_consumption.rb +35 -0
  65. data/lib/sqreen/endpoint_testing.rb +184 -0
  66. data/lib/sqreen/event.rb +7 -5
  67. data/lib/sqreen/events/attack.rb +23 -18
  68. data/lib/sqreen/events/remote_exception.rb +0 -22
  69. data/lib/sqreen/events/request_record.rb +15 -71
  70. data/lib/sqreen/frameworks/generic.rb +24 -1
  71. data/lib/sqreen/frameworks/rails.rb +0 -7
  72. data/lib/sqreen/frameworks/request_recorder.rb +15 -2
  73. data/lib/sqreen/graft/call.rb +85 -18
  74. data/lib/sqreen/graft/callback.rb +1 -1
  75. data/lib/sqreen/graft/hook.rb +192 -88
  76. data/lib/sqreen/graft/hook_point.rb +18 -11
  77. data/lib/sqreen/kit/signals/specialized/aggregated_metric.rb +72 -0
  78. data/lib/sqreen/kit/signals/specialized/attack.rb +57 -0
  79. data/lib/sqreen/kit/signals/specialized/binning_metric.rb +76 -0
  80. data/lib/sqreen/kit/signals/specialized/http_trace.rb +26 -0
  81. data/lib/sqreen/kit/signals/specialized/sdk_track_call.rb +50 -0
  82. data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +59 -0
  83. data/lib/sqreen/legacy/instrumentation.rb +22 -10
  84. data/lib/sqreen/legacy/old_event_submission_strategy.rb +228 -0
  85. data/lib/sqreen/legacy/waf_redactions.rb +49 -0
  86. data/lib/sqreen/log.rb +3 -2
  87. data/lib/sqreen/log/loggable.rb +2 -1
  88. data/lib/sqreen/logger.rb +24 -0
  89. data/lib/sqreen/metrics/base.rb +3 -0
  90. data/lib/sqreen/metrics_store.rb +33 -12
  91. data/lib/sqreen/null_logger.rb +22 -0
  92. data/lib/sqreen/performance_notifications/binned_metrics.rb +8 -2
  93. data/lib/sqreen/remote_command.rb +4 -0
  94. data/lib/sqreen/rules.rb +12 -6
  95. data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
  96. data/lib/sqreen/rules/custom_error_cb.rb +3 -3
  97. data/lib/sqreen/rules/rule_cb.rb +4 -0
  98. data/lib/sqreen/rules/waf_cb.rb +14 -11
  99. data/lib/sqreen/runner.rb +122 -15
  100. data/lib/sqreen/sensitive_data_redactor.rb +19 -31
  101. data/lib/sqreen/session.rb +53 -43
  102. data/lib/sqreen/signals/conversions.rb +288 -0
  103. data/lib/sqreen/signals/http_trace_redaction.rb +111 -0
  104. data/lib/sqreen/signals/signals_submission_strategy.rb +78 -0
  105. data/lib/sqreen/version.rb +1 -1
  106. data/lib/sqreen/weave/budget.rb +46 -0
  107. data/lib/sqreen/weave/legacy/instrumentation.rb +194 -103
  108. data/lib/sqreen/worker.rb +6 -2
  109. metadata +96 -7
  110. data/lib/sqreen/backport.rb +0 -9
  111. data/lib/sqreen/backport/clock_gettime.rb +0 -74
  112. data/lib/sqreen/backport/original_name.rb +0 -88
  113. data/lib/sqreen/encoding_sanitizer.rb +0 -27
@@ -0,0 +1,123 @@
1
+ require 'securerandom'
2
+ require 'sqreen/ecosystem/module_registry'
3
+ require 'sqreen/ecosystem/tracing/sampling_configuration'
4
+ require 'sqreen/ecosystem/transaction_storage'
5
+ require 'sqreen/ecosystem/tracing_broker'
6
+ require 'sqreen/ecosystem/tracing_id_setup'
7
+ require 'sqreen/ecosystem/module_api/message_producer'
8
+ require 'sqreen/ecosystem/module_api/tracing_id_generation'
9
+ require 'sqreen/ecosystem/module_api/tracing'
10
+
11
+ module Sqreen
12
+ # The API for the ecosystem client (together with the dispatch table)
13
+ module Ecosystem
14
+ class << self
15
+ def init(opts = {})
16
+ @registry = ModuleRegistry.new
17
+ register_modules(opts[:modules])
18
+ @registry.init_all
19
+
20
+ # setup tracing generation
21
+ tracing_id_mods = @registry.module_subset(ModuleApi::TracingIdGeneration)
22
+ @tracing_id_setup = TracingIdSetup.new(tracing_id_mods)
23
+ @tracing_id_setup.setup_modules
24
+
25
+ # configure tracing broker with the consumers (tracing modules)
26
+ tracing_modules = @registry.module_subset(ModuleApi::Tracing)
27
+ @tracing_broker = TracingBroker.new(tracing_modules)
28
+
29
+ # inject tracing broker in message producers
30
+ @registry.each_module(ModuleApi::MessageProducer) do |mod|
31
+ mod.tracing_broker = @tracing_broker
32
+ end
33
+ rescue ::Exception # rubocop:disable Lint/RescueException
34
+ # TODO: modules must be disabled at this point
35
+ raise
36
+ end
37
+
38
+ def reset
39
+ instance_variables.each do |ia|
40
+ instance_variable_set(ia, nil)
41
+ end
42
+ end
43
+
44
+ # To be called by the Ecosystem client when a new transaction
45
+ # (generally: request) is started
46
+ # In the future, it's intended that request end/start detection be handled
47
+ # by the Ecosystem itself, so control will flow in the other direction,
48
+ # from the ecosystem to its client
49
+ def start_transaction
50
+ TransactionStorage.create_thread_local
51
+ end
52
+
53
+ def end_transaction
54
+ TransactionStorage.destroy_thread_local
55
+ end
56
+
57
+ # @param [String] tracing_id_prefix
58
+ # @param [Array<Hash{String=>Object}>] sampling_config
59
+ def configure_sampling(tracing_id_prefix, sampling_config)
60
+ @tracing_id_setup.tracing_id_prefix = tracing_id_prefix
61
+ built_samp_cfg = Tracing::SamplingConfiguration.new(sampling_config)
62
+ @tracing_broker.sampling_configuration = built_samp_cfg
63
+ end
64
+
65
+ private
66
+
67
+ def register_modules(modules)
68
+ return register_all_modules unless modules
69
+
70
+ modules.each { |mod| register mod }
71
+ end
72
+
73
+ def register_all_modules
74
+ # replace with something more magical?
75
+ require_relative 'ecosystem/http/rack_request'
76
+ register Http::RackRequest.new
77
+
78
+ require_relative 'ecosystem/http/net_http'
79
+ register Http::NetHttp.new
80
+
81
+ require_relative 'ecosystem/databases/postgres'
82
+ register Databases::Postgres.new
83
+
84
+ require_relative 'ecosystem/databases/mysql'
85
+ register Databases::Mysql.new
86
+
87
+ require_relative 'ecosystem/databases/mongo'
88
+ register Databases::Mongo.new
89
+
90
+ require_relative 'ecosystem/databases/redis'
91
+ register Databases::Redis.new
92
+
93
+ require_relative 'ecosystem/messaging/sqs'
94
+ register Messaging::Sqs.new
95
+
96
+ require_relative 'ecosystem/messaging/kinesis'
97
+ register Messaging::Kinesis.new
98
+
99
+ require_relative 'ecosystem/messaging/bunny'
100
+ register Messaging::Bunny.new
101
+
102
+ require_relative 'ecosystem/messaging/kafka'
103
+ register Messaging::Kafka.new
104
+
105
+ require_relative 'ecosystem/tracing/modules/client'
106
+ register Tracing::Modules::Client.new
107
+
108
+ require_relative 'ecosystem/tracing/modules/server'
109
+ register Tracing::Modules::Server.new
110
+
111
+ require_relative 'ecosystem/tracing/modules/producer'
112
+ register Tracing::Modules::Producer.new
113
+
114
+ require_relative 'ecosystem/tracing/modules/consumer'
115
+ register Tracing::Modules::Consumer.new
116
+ end
117
+
118
+ def register(mod)
119
+ @registry.register mod
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,23 @@
1
+ require 'sqreen/ecosystem/module_api/tracing/client_data'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module Databases
6
+ class DatabaseConnectionData
7
+ include ModuleApi::Tracing::ClientData
8
+
9
+ # @return [Integer]
10
+ attr_accessor :port
11
+
12
+ # @return [String]
13
+ attr_accessor :unix_socket
14
+
15
+ # @return [String]
16
+ attr_accessor :username
17
+
18
+ # @return [String]
19
+ attr_accessor :db
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,39 @@
1
+ require 'sqreen/ecosystem/module_api'
2
+ require 'sqreen/ecosystem/module_api/instrumentation'
3
+ require 'sqreen/ecosystem/module_api/message_producer'
4
+ require 'sqreen/ecosystem/databases/database_connection_data'
5
+
6
+ module Sqreen
7
+ module Ecosystem
8
+ module Databases
9
+ class Mongo
10
+ include ModuleApi::Instrumentation
11
+ include ModuleApi::MessageProducer
12
+
13
+ def setup
14
+ advice = wrap_for_interest(DatabaseConnectionData, &method(:after_advice))
15
+ instrument 'Mongo::Client#initialize', after: advice
16
+ end
17
+
18
+ private
19
+
20
+ # @param [Sqreen::Graft::CallbackCall] call
21
+ def after_advice(call, _ball)
22
+ return if call.raised
23
+
24
+ client = call.instance
25
+ server_addrs = client.cluster.servers.map(&:address)
26
+
27
+ server_addrs.map do |addr|
28
+ DatabaseConnectionData.new(
29
+ transport: :mongo,
30
+ host: addr.host,
31
+ port: addr.port,
32
+ db: client.database.name,
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,54 @@
1
+ require 'sqreen/ecosystem/module_api'
2
+ require 'sqreen/ecosystem/module_api/instrumentation'
3
+ require 'sqreen/ecosystem/module_api/message_producer'
4
+ require 'sqreen/ecosystem/module_api/tracing_id_generation'
5
+ require 'sqreen/ecosystem/module_api/tracing/client_data'
6
+
7
+ module Sqreen
8
+ module Ecosystem
9
+ module Databases
10
+ class Mysql
11
+ include ModuleApi::Instrumentation
12
+ include ModuleApi::MessageProducer
13
+
14
+ def setup
15
+ advice = wrap_for_interest(DatabaseConnectionData, &method(:after_advice))
16
+ instrument 'Mysql2::Client#connect', after: advice
17
+ end
18
+
19
+ private
20
+
21
+ # instance is of type +Mysql2::Client+
22
+ # VALUE rb_mysql_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database,
23
+ # VALUE socket, VALUE flags, VALUE conn_attrs) {
24
+ # @param [Sqreen::Graft::CallbackCall]
25
+ def after_advice(call, _ball)
26
+ args = call.args
27
+
28
+ # build & submit signal
29
+ signal = DatabaseConnectionData.new(transport: :mysql)
30
+
31
+ user = args[0]
32
+ host = args[2]
33
+ port = args[3]
34
+ db = args[4]
35
+ socket = args[5]
36
+
37
+ if socket && !socket.empty?
38
+ signal.unix_socket = socket
39
+ signal.host = 'localhost'
40
+ signal.ip = '::1'
41
+ else
42
+ signal.host = host
43
+ end
44
+
45
+ signal.port = port if port != 0
46
+ signal.username = user
47
+ signal.db = db
48
+
49
+ signal
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,51 @@
1
+ require 'sqreen/ecosystem/module_api'
2
+ require 'sqreen/ecosystem/module_api/instrumentation'
3
+ require 'sqreen/ecosystem/module_api/message_producer'
4
+ require 'sqreen/ecosystem/databases/database_connection_data'
5
+
6
+ module Sqreen
7
+ module Ecosystem
8
+ module Databases
9
+ class Postgres
10
+ include ModuleApi::Instrumentation
11
+ include ModuleApi::MessageProducer
12
+
13
+ def setup
14
+ advice = wrap_for_interest(DatabaseConnectionData, &method(:after_advice))
15
+ instrument 'PG::Connection#initialize', after: advice
16
+ end
17
+
18
+ private
19
+
20
+ # instance is of type +PG::Connection+
21
+ # > c = PG::Connection.new(host: '172.17.0.2', password: 'mysecretpassword', user: 'postgres')
22
+ # => #<PG::Connection:0x000055b44d077d10>
23
+ # > %i{host port user db}.map { |m| c.send m }
24
+ # => ["172.17.0.2", 5432, "postgres", "postgres"]
25
+ def after_advice(call, _ball)
26
+ conn = call.instance
27
+
28
+ # build & submit signal
29
+ signal = DatabaseConnectionData.new(transport: :postgres)
30
+
31
+ host = conn.host
32
+ if host
33
+ if host.include?('/')
34
+ signal.unix_socket = host
35
+ signal.host = 'localhost'
36
+ signal.ip = '::1'
37
+ else
38
+ signal.host = host
39
+ end
40
+ end
41
+
42
+ signal.port = conn.port
43
+ signal.username = conn.user
44
+ signal.db = conn.db
45
+
46
+ signal
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,36 @@
1
+ require 'sqreen/ecosystem/module_api'
2
+ require 'sqreen/ecosystem/module_api/instrumentation'
3
+ require 'sqreen/ecosystem/module_api/message_producer'
4
+ require 'sqreen/ecosystem/databases/database_connection_data'
5
+
6
+ module Sqreen
7
+ module Ecosystem
8
+ module Databases
9
+ class Redis
10
+ include ModuleApi::Instrumentation
11
+ include ModuleApi::MessageProducer
12
+
13
+ def setup
14
+ advice = wrap_for_interest(DatabaseConnectionData, &method(:after_advice))
15
+ instrument 'Redis#initialize', after: advice
16
+ end
17
+
18
+ private
19
+
20
+ # @param [Sqreen::Graft::CallbackCall] call
21
+ def after_advice(call, _ball)
22
+ return if call.raised
23
+
24
+ conn = call.instance.connection
25
+
26
+ DatabaseConnectionData.new(
27
+ transport: :redis,
28
+ host: conn[:host],
29
+ port: conn[:port],
30
+ db: conn[:db].to_s,
31
+ )
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,43 @@
1
+ require 'logger'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ # Configured by the ecosystem client
6
+ module DispatchTable
7
+ class << self
8
+ # data consumption
9
+ # argument: +Sqreen::Kit::Signals::Signal+
10
+ # see +Sqreen::EcosystemIntegration::SignalConsumption#consume_signal+
11
+ attr_accessor :consume_signal
12
+
13
+ # argument: block taking a Rack::Request
14
+ # see +Sqreen::EcosystemIntegration::RequestLifecycleTracking#add_start_observer+
15
+ attr_accessor :add_request_start_listener
16
+
17
+ attr_accessor :fetch_logger
18
+
19
+ # argument: callback taking:
20
+ # * the method to instrument
21
+ # * A Hash{Symbol=>Proc} with the advice. The proc takes the
22
+ # arguments and the ball, so these details of the instrumentation
23
+ # implementation leak through the abstraction
24
+ # see +Sqreen::EcosystemIntegration::InstrumentationService+
25
+ attr_accessor :instrument
26
+
27
+ def reset
28
+ instance_variables.each do |ia|
29
+ instance_variable_set(ia, nil)
30
+ end
31
+
32
+ # set default logger
33
+ logger = ::Logger.new(STDERR)
34
+ logger.level = ::Logger::WARN
35
+ logger.progname = 'sqreen-ecosystem'
36
+ self.fetch_logger = proc { logger }
37
+ end
38
+ end
39
+
40
+ reset
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,28 @@
1
+ require 'sqreen/ecosystem/dispatch_table'
2
+ require 'sqreen/ecosystem/loggable'
3
+ require 'sqreen/kit/configuration'
4
+ require 'sqreen/kit/signals/specialized/sqreen_exception'
5
+
6
+ module Sqreen
7
+ module Ecosystem
8
+ module ExceptionReporting
9
+ include Loggable
10
+
11
+ private
12
+
13
+ # @param [String] message
14
+ # @param [Exception] e
15
+ def report_exception(message, e)
16
+ logger.warn { "#{message}: #{e.message}" }
17
+ logger.debug { e.backtrace.map { |x| " #{x}" }.join("\n") }
18
+
19
+ signal = Sqreen::Kit::Signals::Specialized::SqreenException.new(
20
+ ruby_exception: e,
21
+ source: Sqreen::Kit::Configuration.default_source
22
+ )
23
+
24
+ DispatchTable.consume_signal[signal]
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,50 @@
1
+ require 'sqreen/ecosystem/module_api'
2
+ require 'sqreen/ecosystem/module_api/instrumentation'
3
+ require 'sqreen/ecosystem/module_api/message_producer'
4
+ require 'sqreen/ecosystem/module_api/tracing_id_generation'
5
+ require 'sqreen/ecosystem/module_api/tracing/client_data'
6
+
7
+ module Sqreen
8
+ module Ecosystem
9
+ module Http
10
+ class NetHttp
11
+ class HttpConnectionData
12
+ include ModuleApi::Tracing::ClientData
13
+ end
14
+
15
+ include ModuleApi::Instrumentation
16
+ include ModuleApi::MessageProducer
17
+ include ModuleApi::TracingIdGeneration
18
+
19
+ def setup
20
+ advice = wrap_for_interest(HttpConnectionData, &method(:before_advice))
21
+ instrument 'Net::HTTP#request', before: advice
22
+ end
23
+
24
+ private
25
+
26
+ # instr. def request(req, body = nil, &block) # :yield: +response+
27
+ # req is of type +Net::HTTPGenericRequest+
28
+ def before_advice(call, _ball)
29
+ tracing_id = create_tracing_id
30
+
31
+ # build & submit signal
32
+ host = call.instance.address
33
+ port = call.instance.port
34
+
35
+ # add tracing header
36
+ req = call.args[0]
37
+ req[ModuleApi::TRACE_ID_HEADER] = tracing_id
38
+
39
+ host += ':' + port.to_s if port != 80 && port != 443
40
+
41
+ HttpConnectionData.new(
42
+ transport: 'http',
43
+ host: host,
44
+ tracing_identifier: tracing_id
45
+ )
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end