sqreen 1.20.1-java → 1.22.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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -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/attack_detected.html +1 -2
  7. data/lib/sqreen/condition_evaluator.rb +8 -2
  8. data/lib/sqreen/configuration.rb +1 -1
  9. data/lib/sqreen/deferred_logger.rb +50 -14
  10. data/lib/sqreen/deliveries/batch.rb +8 -1
  11. data/lib/sqreen/dependency/detector.rb +11 -3
  12. data/lib/sqreen/dependency/new_relic.rb +10 -1
  13. data/lib/sqreen/deprecation.rb +38 -0
  14. data/lib/sqreen/ecosystem.rb +123 -0
  15. data/lib/sqreen/ecosystem/databases/database_connection_data.rb +23 -0
  16. data/lib/sqreen/ecosystem/databases/mongo.rb +39 -0
  17. data/lib/sqreen/ecosystem/databases/mysql.rb +54 -0
  18. data/lib/sqreen/ecosystem/databases/postgres.rb +51 -0
  19. data/lib/sqreen/ecosystem/databases/redis.rb +36 -0
  20. data/lib/sqreen/ecosystem/dispatch_table.rb +43 -0
  21. data/lib/sqreen/ecosystem/exception_reporting.rb +28 -0
  22. data/lib/sqreen/ecosystem/http/net_http.rb +50 -0
  23. data/lib/sqreen/ecosystem/http/rack_request.rb +39 -0
  24. data/lib/sqreen/ecosystem/loggable.rb +13 -0
  25. data/lib/sqreen/ecosystem/messaging/bunny.rb +61 -0
  26. data/lib/sqreen/ecosystem/messaging/kafka.rb +70 -0
  27. data/lib/sqreen/ecosystem/messaging/kinesis.rb +66 -0
  28. data/lib/sqreen/ecosystem/messaging/sqs.rb +68 -0
  29. data/lib/sqreen/ecosystem/module_api.rb +30 -0
  30. data/lib/sqreen/ecosystem/module_api/event_listener.rb +18 -0
  31. data/lib/sqreen/ecosystem/module_api/instrumentation.rb +23 -0
  32. data/lib/sqreen/ecosystem/module_api/message_producer.rb +57 -0
  33. data/lib/sqreen/ecosystem/module_api/signal_producer.rb +24 -0
  34. data/lib/sqreen/ecosystem/module_api/tracing.rb +45 -0
  35. data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +31 -0
  36. data/lib/sqreen/ecosystem/module_api/tracing/consumer_data.rb +13 -0
  37. data/lib/sqreen/ecosystem/module_api/tracing/messaging_data.rb +35 -0
  38. data/lib/sqreen/ecosystem/module_api/tracing/producer_data.rb +13 -0
  39. data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +27 -0
  40. data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +16 -0
  41. data/lib/sqreen/ecosystem/module_api/transaction_storage.rb +71 -0
  42. data/lib/sqreen/ecosystem/module_registry.rb +48 -0
  43. data/lib/sqreen/ecosystem/tracing/modules/client.rb +35 -0
  44. data/lib/sqreen/ecosystem/tracing/modules/consumer.rb +35 -0
  45. data/lib/sqreen/ecosystem/tracing/modules/determine_ip.rb +28 -0
  46. data/lib/sqreen/ecosystem/tracing/modules/producer.rb +35 -0
  47. data/lib/sqreen/ecosystem/tracing/modules/server.rb +30 -0
  48. data/lib/sqreen/ecosystem/tracing/sampler.rb +160 -0
  49. data/lib/sqreen/ecosystem/tracing/sampling_configuration.rb +150 -0
  50. data/lib/sqreen/ecosystem/tracing/signals/tracing_client.rb +53 -0
  51. data/lib/sqreen/ecosystem/tracing/signals/tracing_consumer.rb +56 -0
  52. data/lib/sqreen/ecosystem/tracing/signals/tracing_producer.rb +56 -0
  53. data/lib/sqreen/ecosystem/tracing/signals/tracing_server.rb +53 -0
  54. data/lib/sqreen/ecosystem/tracing_broker.rb +101 -0
  55. data/lib/sqreen/ecosystem/tracing_id_setup.rb +34 -0
  56. data/lib/sqreen/ecosystem/transaction_storage.rb +64 -0
  57. data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +13 -0
  58. data/lib/sqreen/ecosystem_integration.rb +81 -0
  59. data/lib/sqreen/ecosystem_integration/around_callbacks.rb +89 -0
  60. data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +38 -0
  61. data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +58 -0
  62. data/lib/sqreen/ecosystem_integration/signal_consumption.rb +35 -0
  63. data/lib/sqreen/events/request_record.rb +0 -1
  64. data/lib/sqreen/frameworks/generic.rb +36 -1
  65. data/lib/sqreen/frameworks/rails.rb +0 -7
  66. data/lib/sqreen/frameworks/request_recorder.rb +2 -0
  67. data/lib/sqreen/graft/call.rb +85 -18
  68. data/lib/sqreen/graft/callback.rb +1 -1
  69. data/lib/sqreen/graft/hook.rb +192 -88
  70. data/lib/sqreen/graft/hook_point.rb +18 -11
  71. data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +2 -0
  72. data/lib/sqreen/legacy/instrumentation.rb +22 -10
  73. data/lib/sqreen/legacy/old_event_submission_strategy.rb +9 -2
  74. data/lib/sqreen/log.rb +3 -2
  75. data/lib/sqreen/log/loggable.rb +1 -0
  76. data/lib/sqreen/logger.rb +24 -0
  77. data/lib/sqreen/metrics_store.rb +11 -0
  78. data/lib/sqreen/null_logger.rb +22 -0
  79. data/lib/sqreen/remote_command.rb +4 -0
  80. data/lib/sqreen/rules.rb +8 -4
  81. data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
  82. data/lib/sqreen/rules/custom_error_cb.rb +3 -3
  83. data/lib/sqreen/rules/rule_cb.rb +2 -0
  84. data/lib/sqreen/rules/waf_cb.rb +3 -3
  85. data/lib/sqreen/runner.rb +47 -7
  86. data/lib/sqreen/session.rb +2 -0
  87. data/lib/sqreen/signals/conversions.rb +6 -1
  88. data/lib/sqreen/version.rb +1 -1
  89. data/lib/sqreen/weave/budget.rb +46 -0
  90. data/lib/sqreen/weave/legacy/instrumentation.rb +252 -109
  91. data/lib/sqreen/worker.rb +6 -2
  92. metadata +60 -11
  93. data/lib/sqreen/encoding_sanitizer.rb +0 -27
@@ -0,0 +1,70 @@
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/consumer_data'
5
+ require 'sqreen/ecosystem/module_api/tracing/producer_data'
6
+
7
+ module Sqreen
8
+ module Ecosystem
9
+ module Messaging
10
+ class Kafka
11
+ include ModuleApi::Loggable
12
+ include ModuleApi::Instrumentation
13
+ include ModuleApi::MessageProducer
14
+
15
+ def setup
16
+ advice_send = wrap_for_interest(ModuleApi::Tracing::ProducerData, &method(:after_send))
17
+ advice_receive = wrap_for_interest(ModuleApi::Tracing::ConsumerData, &method(:after_receive))
18
+ instrument 'Kafka::Broker#produce', after: advice_send
19
+ instrument 'Kafka::Broker#fetch_messages', after: advice_receive
20
+ end
21
+
22
+ private
23
+
24
+ # @param [Sqreen::Graft::CallbackCall] call
25
+ def after_send(call, _ball)
26
+ return if call.raised
27
+ if call.args.length != 1
28
+ logger.info "Expected 1 arguments to Kafka::Broker#produce"
29
+ return
30
+ end
31
+ options = call.args.first
32
+ topics = options[:messages_for_topics].keys
33
+
34
+ create_signal_data(ModuleApi::Tracing::ProducerData,
35
+ call.instance,
36
+ topics)
37
+ end
38
+
39
+ # @param [Sqreen::Graft::CallbackCall] call
40
+ def after_receive(call, _ball)
41
+ return if call.raised
42
+ if call.args.length != 1
43
+ logger.info "Expected 1 arguments to Kafka::Broker#fetch_messages"
44
+ return
45
+ end
46
+ options = call.args.first
47
+ topics = options[:topics].keys
48
+
49
+ create_signal_data(ModuleApi::Tracing::ConsumerData,
50
+ call.instance,
51
+ topics)
52
+ end
53
+
54
+ # @param [Class] clazz
55
+ # @param [Kafka::Broker] broker
56
+ # @param [Array<String>] topics
57
+ def create_signal_data(clazz, broker, topics)
58
+ host = broker.instance_variable_get :@host
59
+ topics.map do |top|
60
+ clazz.new(
61
+ message_type: :kafka,
62
+ host: host,
63
+ topic: top,
64
+ )
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,66 @@
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/consumer_data'
5
+ require 'sqreen/ecosystem/module_api/tracing/producer_data'
6
+
7
+ # see https://aws.amazon.com/blogs/developer/announcing-amazon-kinesis-subscribetoshard-api-support-in-the-aws-sdk-for-ruby/
8
+ module Sqreen
9
+ module Ecosystem
10
+ module Messaging
11
+ class Kinesis
12
+ include ModuleApi::Loggable
13
+ include ModuleApi::Instrumentation
14
+ include ModuleApi::MessageProducer
15
+
16
+ def setup
17
+ advice_send = wrap_for_interest(ModuleApi::Tracing::ProducerData, &method(:after_send_advice))
18
+ advice_receive = wrap_for_interest(ModuleApi::Tracing::ConsumerData, &method(:after_receive_advice))
19
+ instrument 'Aws::Kinesis::Client#put_record', after: advice_send
20
+ instrument 'Aws::Kinesis::Client#put_records', after: advice_send
21
+ # more sophisticated usages (register_stream_consumer, possibly with AsyncClient)
22
+ # are not supported. They are more difficult to test, as kinesalite doesn't support them
23
+ instrument 'Aws::Kinesis::Client#get_shard_iterator', after: advice_receive
24
+ end
25
+
26
+ private
27
+
28
+ # @param [Sqreen::Graft::CallbackCall] call
29
+ def after_send_advice(call, _ball)
30
+ return if call.raised
31
+ unless call.args.length > 0 && call.args[0].is_a?(Hash)
32
+ logger.info "Unexpected arguments to put_record(s)"
33
+ return
34
+ end
35
+
36
+ create_signal(call.instance, call.args, ModuleApi::Tracing::ProducerData)
37
+ end
38
+
39
+ # @param [Sqreen::Graft::CallbackCall] call
40
+ def after_receive_advice(call, _ball)
41
+ return if call.raised
42
+ unless call.args.length > 0 && call.args[0].is_a?(Hash)
43
+ logger.info "Unexpected arguments to get_shared_iterator"
44
+ return
45
+ end
46
+
47
+ create_signal(call.instance, call.args, ModuleApi::Tracing::ConsumerData)
48
+ end
49
+
50
+ def create_signal(client, args, clazz)
51
+ hash = args[0]
52
+ stream_name = hash[:stream_name] || hash['stream_name']
53
+ return unless stream_name
54
+
55
+ endpoint = client.instance_variable_get(:@config).endpoint
56
+
57
+ clazz.new(
58
+ message_type: :'aws-kinesis',
59
+ host: endpoint.host,
60
+ topic: stream_name,
61
+ )
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,68 @@
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/consumer_data'
5
+ require 'sqreen/ecosystem/module_api/tracing/producer_data'
6
+
7
+ module Sqreen
8
+ module Ecosystem
9
+ module Messaging
10
+ class Sqs
11
+ include ModuleApi::Loggable
12
+ include ModuleApi::Instrumentation
13
+ include ModuleApi::MessageProducer
14
+
15
+ def setup
16
+ advice_send = wrap_for_interest(ModuleApi::Tracing::ProducerData, &method(:after_send_advice))
17
+ advice_receive = wrap_for_interest(ModuleApi::Tracing::ConsumerData, &method(:after_receive_advice))
18
+ instrument 'Aws::SQS::Client#send_message', after: advice_send
19
+ instrument 'Aws::SQS::Client#send_message_batch', after: advice_send
20
+ instrument 'Aws::SQS::Client#receive_message', after: advice_receive
21
+ end
22
+
23
+ private
24
+
25
+ # @param [Sqreen::Graft::CallbackCall] call
26
+ def after_send_advice(call, _ball)
27
+ return if call.raised
28
+ unless call.args.length > 0 && call.args[0].is_a?(Hash)
29
+ logger.info "Unexpected arguments to send_message(_batch)"
30
+ return
31
+ end
32
+
33
+ create_signal(call.args, ModuleApi::Tracing::ProducerData)
34
+ end
35
+
36
+ # @param [Sqreen::Graft::CallbackCall] call
37
+ def after_receive_advice(call, _ball)
38
+ return if call.raised
39
+ unless call.args.length > 0 && call.args[0].is_a?(Hash)
40
+ logger.info "Unexpected arguments to receive_message"
41
+ return
42
+ end
43
+
44
+ create_signal(call.args, ModuleApi::Tracing::ConsumerData)
45
+ end
46
+
47
+ def create_signal(args, clazz)
48
+ hash = args[0]
49
+ queue_url = hash[:queue_url] || hash['queue_url']
50
+ return unless queue_url
51
+
52
+ begin
53
+ uri = URI.parse(queue_url)
54
+ rescue URI::InvalidURIError
55
+ logger.info { "Invalid URI: #{uri}" }
56
+ return
57
+ end
58
+
59
+ clazz.new(
60
+ message_type: :'aws-sqs',
61
+ host: uri.host,
62
+ topic: ($1 if uri.path =~ /\A\/queue\/(?:[^\/]+\/)?([^\/]+)\z/),
63
+ )
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,30 @@
1
+ require 'sqreen/ecosystem/loggable'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ # The API that the transport/tracing modules are written against
6
+ module ModuleApi
7
+ TRACE_ID_HEADER = 'X-Sqreen-Trace-Identifier'.freeze
8
+ TRACE_ID_ENV_KEY = 'HTTP_X_SQREEN_TRACE_IDENTIFIER'.freeze
9
+
10
+ Loggable = Sqreen::Ecosystem::Loggable
11
+
12
+ module ClassMethods
13
+ attr_writer :module_name
14
+
15
+ def module_name
16
+ if instance_variable_defined?(:@module_name)
17
+ @module_name
18
+ else
19
+ # to snake case
20
+ @module_name = to_s.sub(/.*::/, '').gsub(/([a-z])([A-Z])/, '\1_\2').downcase
21
+ end
22
+ end
23
+ end
24
+
25
+ def self.included(mod)
26
+ mod.extend(ClassMethods)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ require 'sqreen/ecosystem/dispatch_table'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module EventListener
7
+ private
8
+
9
+ # XXX: callbacks need to be wrapped in order ot handle
10
+ # perfcap, exceptions, and maybe other concerns applying
11
+ # across the board
12
+ def on_request_start(&cb)
13
+ DispatchTable.add_request_start_listener.call(cb)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ require 'sqreen/ecosystem/module_api'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module Instrumentation
7
+ def self.included(mod)
8
+ mod.send :include, ModuleApi unless mod.ancestors.include?(ModuleApi)
9
+ end
10
+
11
+ private
12
+
13
+ # Just forwards the call to the instrumentation service
14
+ # @param [String] method
15
+ # @param [Hash{Symbol=>Proc}] advice keys are one of: :before, :after,
16
+ # :raised,
17
+ def instrument(method, advice)
18
+ DispatchTable.instrument.call(self.class.module_name, method, advice)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,57 @@
1
+ require 'sqreen/ecosystem/loggable'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module MessageProducer
7
+ include Loggable
8
+
9
+ # method for ecosystem to inject the config
10
+ # @param [Sqreen::Ecosystem::TracingBroker]
11
+ attr_writer :tracing_broker
12
+
13
+ private
14
+
15
+ def determine_interest(type, hints = {})
16
+ @tracing_broker.interested_consumers(type, hints)
17
+ end
18
+
19
+ def publish(data, interested)
20
+ @tracing_broker.publish(data, interested)
21
+ end
22
+
23
+ # Convenience wrapper.
24
+ # Wraps a callback, skipping it if there is no interest in the type
25
+ # produced and submitting the return value as a message to the
26
+ # tracing broker
27
+ def wrap_for_interest(type, gen_hints = nil, &block)
28
+ raise ArgumentError, 'no block passed' if block.nil?
29
+
30
+ proc do |*args|
31
+ hints = gen_hints[*args] if gen_hints
32
+ interested = determine_interest(type, hints || {})
33
+
34
+ unless interested
35
+ logger.debug { "No interested consumers in #{type}" }
36
+ next
37
+ end
38
+
39
+ res = block[*args]
40
+
41
+ next if res.nil?
42
+
43
+ if res.is_a?(Array)
44
+ res.each do |d|
45
+ raise "unexpected return type: #{d.class}" unless d.is_a?(type)
46
+ @tracing_broker.publish(d, interested)
47
+ end
48
+ else
49
+ raise "unexpected return type: #{res.class}" unless res.is_a?(type)
50
+ @tracing_broker.publish(res, interested)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,24 @@
1
+ require 'sqreen/ecosystem/dispatch_table'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module SignalProducer
7
+ # for injection
8
+ # callable taking no arguments and generating a tracing id
9
+ attr_writer :tracing_id_producer
10
+
11
+ private
12
+
13
+ def create_tracing_id
14
+ @tracing_id_producer.call
15
+ end
16
+
17
+ # @param [Sqreen::Kit::Signals::Signal] signal
18
+ def submit_signal(signal)
19
+ DispatchTable.consume_signal.call(signal)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,45 @@
1
+ require 'sqreen/ecosystem/module_api/signal_producer'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module Tracing
7
+ include SignalProducer
8
+
9
+ def self.included(mod)
10
+ mod.extend(ClassMethods)
11
+ end
12
+
13
+ module ClassMethods
14
+ private
15
+
16
+ # @param [Module] type The type the including module is interested in
17
+ def consumes(type)
18
+ @consumes = type
19
+ end
20
+
21
+ # A fixed (non-virtual) scope for this tracing module
22
+ # @param [String] scope
23
+ def fixed_scope(scope)
24
+ @fixed_scope = scope
25
+ end
26
+ end
27
+
28
+ def consumed_type
29
+ self.class.instance_variable_get(:@consumes) \
30
+ || raise('@consumes not specified')
31
+ end
32
+
33
+ def scope(_hints = {})
34
+ self.class.instance_variable_get(:@fixed_scope) \
35
+ || raise('@fixed_scope not set')
36
+ end
37
+
38
+ # including class must implement it
39
+ def receive(_data)
40
+ raise NotImplementedError
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,31 @@
1
+ require 'sqreen/ecosystem/util/call_writers_from_init'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module Tracing
7
+ # The data the tracing module needs in order to populate
8
+ # +Sqreen::Ecosystem::Tracing::Signals::TracingClient::Payload+
9
+ #
10
+ # Signals are not produced by the data producers (transport)
11
+ # because of superior orders, as the only current use of this
12
+ # data is to generate signals.
13
+ module ClientData
14
+ include Util::CallWritersFromInit
15
+
16
+ # @return [Symbol]
17
+ attr_accessor :transport
18
+
19
+ # @return [String]
20
+ attr_accessor :host
21
+
22
+ # @return [String]
23
+ attr_accessor :ip
24
+
25
+ # @return [String]
26
+ attr_accessor :tracing_identifier
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ require 'sqreen/ecosystem/module_api/tracing/messaging_data'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module Tracing
7
+ class ConsumerData
8
+ include MessagingData
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end