datadog 2.18.0 → 2.20.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +73 -1
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +51 -10
- data/ext/datadog_profiling_native_extension/collectors_stack.c +58 -49
- data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -1
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +5 -6
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +37 -26
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +0 -1
- data/ext/datadog_profiling_native_extension/ruby_helpers.h +1 -1
- data/ext/libdatadog_api/extconf.rb +3 -1
- data/ext/libdatadog_extconf_helpers.rb +13 -3
- data/lib/datadog/appsec/api_security/route_extractor.rb +7 -1
- data/lib/datadog/appsec/component.rb +3 -13
- data/lib/datadog/appsec/context.rb +23 -0
- data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +2 -1
- data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +2 -1
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +0 -1
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +0 -1
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +14 -22
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +23 -2
- data/lib/datadog/appsec/contrib/rails/patcher.rb +14 -26
- data/lib/datadog/appsec/contrib/rails/patches/process_action_patch.rb +27 -0
- data/lib/datadog/appsec/contrib/rails/patches/render_to_body_patch.rb +33 -0
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +0 -1
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +23 -0
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +8 -18
- data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +31 -0
- data/lib/datadog/appsec/event.rb +3 -18
- data/lib/datadog/appsec/instrumentation/gateway/argument.rb +17 -1
- data/lib/datadog/appsec/metrics/collector.rb +7 -3
- data/lib/datadog/appsec/metrics/telemetry.rb +1 -1
- data/lib/datadog/appsec/metrics/telemetry_exporter.rb +28 -0
- data/lib/datadog/appsec/metrics.rb +1 -0
- data/lib/datadog/appsec/security_engine/engine.rb +14 -32
- data/lib/datadog/appsec/security_engine/result.rb +16 -0
- data/lib/datadog/appsec/security_engine/runner.rb +18 -4
- data/lib/datadog/appsec/thread_safe_ref.rb +61 -0
- data/lib/datadog/appsec/trace_keeper.rb +24 -0
- data/lib/datadog/appsec/utils/hash_coercion.rb +23 -0
- data/lib/datadog/appsec.rb +0 -7
- data/lib/datadog/auto_instrument_base.rb +2 -1
- data/lib/datadog/core/configuration/option.rb +29 -20
- data/lib/datadog/core/configuration/option_definition.rb +2 -2
- data/lib/datadog/core/configuration/options.rb +13 -7
- data/lib/datadog/core/configuration/settings.rb +20 -0
- data/lib/datadog/core/telemetry/component.rb +8 -4
- data/lib/datadog/core/telemetry/event/app_started.rb +21 -3
- data/lib/datadog/di/boot.rb +7 -0
- data/lib/datadog/di/component.rb +7 -0
- data/lib/datadog/di/instrumenter.rb +11 -18
- data/lib/datadog/di/probe_file_loader/railtie.rb +15 -0
- data/lib/datadog/di/probe_file_loader.rb +82 -0
- data/lib/datadog/di/probe_notification_builder.rb +21 -16
- data/lib/datadog/di/remote.rb +3 -5
- data/lib/datadog/di/serializer.rb +6 -2
- data/lib/datadog/di.rb +0 -7
- data/lib/datadog/kit/appsec/events/v2.rb +196 -0
- data/lib/datadog/kit/appsec/events.rb +11 -10
- data/lib/datadog/kit/identity.rb +17 -11
- data/lib/datadog/opentelemetry/api/baggage.rb +2 -2
- data/lib/datadog/opentelemetry/api/context.rb +10 -9
- data/lib/datadog/opentelemetry/sdk/propagator.rb +4 -4
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +8 -8
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +14 -10
- data/lib/datadog/opentelemetry/trace.rb +4 -4
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +2 -0
- data/lib/datadog/profiling/collectors/info.rb +41 -0
- data/lib/datadog/profiling/component.rb +1 -0
- data/lib/datadog/profiling/exporter.rb +9 -3
- data/lib/datadog/profiling/sequence_tracker.rb +44 -0
- data/lib/datadog/profiling/tag_builder.rb +2 -0
- data/lib/datadog/profiling.rb +7 -8
- data/lib/datadog/single_step_instrument.rb +9 -0
- data/lib/datadog/tracing/analytics.rb +1 -1
- data/lib/datadog/tracing/buffer.rb +7 -7
- data/lib/datadog/tracing/configuration/dynamic.rb +4 -6
- data/lib/datadog/tracing/configuration/ext.rb +3 -2
- data/lib/datadog/tracing/configuration/settings.rb +17 -0
- data/lib/datadog/tracing/context.rb +2 -2
- data/lib/datadog/tracing/contrib/action_cable/event.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/action_mailer/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +4 -4
- data/lib/datadog/tracing/contrib/action_pack/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/event.rb +8 -8
- data/lib/datadog/tracing/contrib/active_job/events/discard.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/perform.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +3 -3
- data/lib/datadog/tracing/contrib/active_model_serializers/integration.rb +1 -2
- data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +5 -5
- data/lib/datadog/tracing/contrib/active_record/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/utils.rb +15 -15
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +13 -7
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +13 -0
- data/lib/datadog/tracing/contrib/active_support/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +2 -1
- data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +7 -9
- data/lib/datadog/tracing/contrib/aws/ext.rb +1 -1
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/parsed_context.rb +3 -1
- data/lib/datadog/tracing/contrib/aws/patcher.rb +5 -1
- data/lib/datadog/tracing/contrib/aws/service/base.rb +2 -1
- data/lib/datadog/tracing/contrib/aws/service/dynamodb.rb +1 -1
- data/lib/datadog/tracing/contrib/aws/service/eventbridge.rb +1 -1
- data/lib/datadog/tracing/contrib/aws/service/kinesis.rb +1 -1
- data/lib/datadog/tracing/contrib/aws/service/s3.rb +1 -1
- data/lib/datadog/tracing/contrib/aws/service/sns.rb +1 -1
- data/lib/datadog/tracing/contrib/aws/service/sqs.rb +1 -1
- data/lib/datadog/tracing/contrib/aws/service/states.rb +1 -1
- data/lib/datadog/tracing/contrib/aws/services.rb +7 -7
- data/lib/datadog/tracing/contrib/concurrent_ruby/async_patch.rb +1 -1
- data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +1 -1
- data/lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb +1 -1
- data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/concurrent_ruby/promises_future_patch.rb +1 -1
- data/lib/datadog/tracing/contrib/configurable.rb +6 -6
- data/lib/datadog/tracing/contrib/configuration/resolvers/pattern_resolver.rb +4 -4
- data/lib/datadog/tracing/contrib/dalli/ext.rb +3 -2
- data/lib/datadog/tracing/contrib/dalli/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/delayed_job/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +3 -2
- data/lib/datadog/tracing/contrib/elasticsearch/integration.rb +4 -4
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +51 -53
- data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +5 -5
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +2 -2
- data/lib/datadog/tracing/contrib/ethon/ext.rb +3 -2
- data/lib/datadog/tracing/contrib/ethon/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/excon/ext.rb +3 -2
- data/lib/datadog/tracing/contrib/excon/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/excon/middleware.rb +2 -2
- data/lib/datadog/tracing/contrib/ext.rb +3 -3
- data/lib/datadog/tracing/contrib/extensions.rb +9 -9
- data/lib/datadog/tracing/contrib/faraday/ext.rb +3 -2
- data/lib/datadog/tracing/contrib/faraday/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +4 -2
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +8 -8
- data/lib/datadog/tracing/contrib/grape/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/graphql/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/graphql/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +24 -24
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +8 -8
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +3 -3
- data/lib/datadog/tracing/contrib/grpc/distributed/fetcher.rb +1 -1
- data/lib/datadog/tracing/contrib/grpc/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/hanami/ext.rb +2 -2
- data/lib/datadog/tracing/contrib/hanami/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +1 -1
- data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +9 -11
- data/lib/datadog/tracing/contrib/http/distributed/fetcher.rb +4 -4
- data/lib/datadog/tracing/contrib/http/ext.rb +3 -2
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +5 -5
- data/lib/datadog/tracing/contrib/httpclient/ext.rb +3 -2
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +3 -3
- data/lib/datadog/tracing/contrib/httpclient/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/httprb/ext.rb +3 -2
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +4 -4
- data/lib/datadog/tracing/contrib/httprb/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/event.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/join_group.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/leave_group.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/sync_group.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/karafka/monitor.rb +13 -13
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +4 -4
- data/lib/datadog/tracing/contrib/lograge/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/lograge/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/parsers.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +6 -6
- data/lib/datadog/tracing/contrib/mysql2/ext.rb +1 -1
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +16 -6
- data/lib/datadog/tracing/contrib/mysql2/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/opensearch/ext.rb +3 -2
- data/lib/datadog/tracing/contrib/opensearch/integration.rb +1 -2
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +68 -70
- data/lib/datadog/tracing/contrib/opensearch/quantize.rb +5 -5
- data/lib/datadog/tracing/contrib/patcher.rb +7 -9
- data/lib/datadog/tracing/contrib/pg/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/presto/ext.rb +1 -1
- data/lib/datadog/tracing/contrib/presto/instrumentation.rb +3 -3
- data/lib/datadog/tracing/contrib/presto/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/propagation/sql_comment/comment.rb +1 -1
- data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +1 -1
- data/lib/datadog/tracing/contrib/que/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/racecar/event.rb +1 -1
- data/lib/datadog/tracing/contrib/racecar/events/batch.rb +2 -2
- data/lib/datadog/tracing/contrib/racecar/events/consume.rb +1 -1
- data/lib/datadog/tracing/contrib/racecar/events/message.rb +2 -2
- data/lib/datadog/tracing/contrib/racecar/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/header_collection.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/header_tagging.rb +32 -32
- data/lib/datadog/tracing/contrib/rack/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +21 -17
- data/lib/datadog/tracing/contrib/rack/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/request_queue.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/middlewares.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/patcher.rb +4 -1
- data/lib/datadog/tracing/contrib/rails/runner.rb +62 -40
- data/lib/datadog/tracing/contrib/rake/instrumentation.rb +4 -4
- data/lib/datadog/tracing/contrib/rake/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +2 -2
- data/lib/datadog/tracing/contrib/redis/ext.rb +3 -2
- data/lib/datadog/tracing/contrib/redis/integration.rb +2 -2
- data/lib/datadog/tracing/contrib/redis/patcher.rb +4 -4
- data/lib/datadog/tracing/contrib/redis/quantize.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/tags.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +4 -4
- data/lib/datadog/tracing/contrib/registry.rb +1 -1
- data/lib/datadog/tracing/contrib/resque/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/resque/resque_job.rb +1 -1
- data/lib/datadog/tracing/contrib/rest_client/ext.rb +3 -2
- data/lib/datadog/tracing/contrib/rest_client/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +3 -3
- data/lib/datadog/tracing/contrib/roda/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/roda/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/semantic_logger/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/semantic_logger/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/sequel/database.rb +5 -5
- data/lib/datadog/tracing/contrib/sequel/dataset.rb +1 -1
- data/lib/datadog/tracing/contrib/sequel/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/sequel/utils.rb +1 -1
- data/lib/datadog/tracing/contrib/shoryuken/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/sidekiq/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/sidekiq/utils.rb +1 -1
- data/lib/datadog/tracing/contrib/sinatra/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +38 -40
- data/lib/datadog/tracing/contrib/sneakers/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/stripe/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/stripe/request.rb +1 -1
- data/lib/datadog/tracing/contrib/sucker_punch/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/trilogy/ext.rb +1 -1
- data/lib/datadog/tracing/contrib/trilogy/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/utils/quantization/hash.rb +11 -11
- data/lib/datadog/tracing/contrib/utils/quantization/http.rb +6 -6
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +8 -2
- data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
- data/lib/datadog/tracing/distributed/baggage.rb +73 -8
- data/lib/datadog/tracing/distributed/datadog.rb +4 -5
- data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +11 -13
- data/lib/datadog/tracing/distributed/helpers.rb +1 -1
- data/lib/datadog/tracing/distributed/none.rb +4 -2
- data/lib/datadog/tracing/distributed/propagation.rb +4 -1
- data/lib/datadog/tracing/distributed/propagation_policy.rb +1 -1
- data/lib/datadog/tracing/distributed/trace_context.rb +22 -16
- data/lib/datadog/tracing/event.rb +5 -7
- data/lib/datadog/tracing/flush.rb +1 -1
- data/lib/datadog/tracing/metadata/analytics.rb +1 -1
- data/lib/datadog/tracing/metadata/tagging.rb +4 -4
- data/lib/datadog/tracing/pipeline/span_filter.rb +3 -1
- data/lib/datadog/tracing/pipeline/span_processor.rb +3 -1
- data/lib/datadog/tracing/pipeline.rb +1 -1
- data/lib/datadog/tracing/sampling/ext.rb +0 -2
- data/lib/datadog/tracing/sampling/rule_sampler.rb +30 -30
- data/lib/datadog/tracing/sampling/span/rule_parser.rb +1 -1
- data/lib/datadog/tracing/sampling/span/sampler.rb +0 -7
- data/lib/datadog/tracing/span.rb +1 -1
- data/lib/datadog/tracing/span_event.rb +10 -10
- data/lib/datadog/tracing/span_link.rb +12 -12
- data/lib/datadog/tracing/span_operation.rb +31 -11
- data/lib/datadog/tracing/trace_digest.rb +21 -23
- data/lib/datadog/tracing/trace_operation.rb +84 -88
- data/lib/datadog/tracing/trace_segment.rb +2 -2
- data/lib/datadog/tracing/tracer.rb +36 -38
- data/lib/datadog/tracing/transport/http/client.rb +1 -1
- data/lib/datadog/tracing/transport/http/traces.rb +2 -2
- data/lib/datadog/tracing/transport/io/client.rb +5 -5
- data/lib/datadog/tracing/transport/io/traces.rb +4 -4
- data/lib/datadog/tracing/transport/statistics.rb +1 -1
- data/lib/datadog/tracing/transport/traces.rb +5 -5
- data/lib/datadog/tracing/workers/trace_writer.rb +12 -12
- data/lib/datadog/tracing/workers.rb +2 -2
- data/lib/datadog/tracing.rb +2 -2
- data/lib/datadog/version.rb +1 -1
- data/lib/datadog.rb +7 -0
- metadata +17 -6
@@ -212,21 +212,6 @@ uint64_t native_thread_id_for(VALUE thread) {
|
|
212
212
|
#endif
|
213
213
|
}
|
214
214
|
|
215
|
-
// Returns the stack depth by using the same approach as rb_profile_frames and backtrace_each: get the positions
|
216
|
-
// of the end and current frame pointers and subtracting them.
|
217
|
-
ptrdiff_t stack_depth_for(VALUE thread) {
|
218
|
-
const rb_execution_context_t *ec = thread_struct_from_object(thread)->ec;
|
219
|
-
const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
|
220
|
-
|
221
|
-
if (end_cfp == NULL) return 0;
|
222
|
-
|
223
|
-
// Skip dummy frame, as seen in `backtrace_each` (`vm_backtrace.c`) and our custom rb_profile_frames
|
224
|
-
// ( https://github.com/ruby/ruby/blob/4bd38e8120f2fdfdd47a34211720e048502377f1/vm_backtrace.c#L890-L914 )
|
225
|
-
end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
|
226
|
-
|
227
|
-
return end_cfp <= cfp ? 0 : end_cfp - cfp - 1;
|
228
|
-
}
|
229
|
-
|
230
215
|
// This was renamed in Ruby 3.2
|
231
216
|
#if !defined(ccan_list_for_each) && defined(list_for_each)
|
232
217
|
#define ccan_list_for_each list_for_each
|
@@ -360,11 +345,16 @@ calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id)
|
|
360
345
|
}
|
361
346
|
#endif
|
362
347
|
|
363
|
-
// In PROF-11475 we spotted a crash when calling `rb_iseq_line_no` from this method.
|
364
|
-
//
|
365
|
-
//
|
366
|
-
//
|
367
|
-
|
348
|
+
// In PROF-11475 we spotted a crash when calling `rb_iseq_line_no` from this method.
|
349
|
+
// We were only able to reproduce this issue on Ruby 2.6 and 2.7, not 2.5 or the 3.x series (tried 3.0, 3.2 and 3.4).
|
350
|
+
// Note that going out of bounds doesn't crash every time, as usual with C we may just read garbage or get lucky.
|
351
|
+
//
|
352
|
+
// For those problematic Rubies, we observed that when we try to take a sample in the middle of processing the
|
353
|
+
// VM `LEAVE` instruction, the value of `n` can violate the documented assumptions above and be
|
354
|
+
// `n > ISEQ_BODY(iseq)->iseq_size)`.
|
355
|
+
//
|
356
|
+
// To work around this and any other potential issues, we validate here that the bytecode position is sane.
|
357
|
+
if (RB_UNLIKELY(n < 0 || n > ISEQ_BODY(iseq)->iseq_size)) return 0;
|
368
358
|
|
369
359
|
if (lineno) *lineno = rb_iseq_line_no(iseq, pos);
|
370
360
|
#ifdef USE_ISEQ_NODE_ID
|
@@ -410,6 +400,9 @@ calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
|
|
410
400
|
// * Add frame_flags.same_frame and logic to skip redoing work if the buffer already contains the same data we're collecting
|
411
401
|
// * Skipped use of rb_callable_method_entry_t (cme) for Ruby frames as it doesn't impact us.
|
412
402
|
// * Imported fix from https://github.com/ruby/ruby/pull/8280 to keep us closer to upstream
|
403
|
+
// * Added potential fix for https://github.com/ruby/ruby/pull/13643 (this one is a just-in-case, unclear if it happens
|
404
|
+
// for ddtrace)
|
405
|
+
// * Reversed order of iteration to better enable caching
|
413
406
|
//
|
414
407
|
// What is rb_profile_frames?
|
415
408
|
// `rb_profile_frames` is a Ruby VM debug API added for use by profilers for sampling the stack trace of a Ruby thread.
|
@@ -445,6 +438,16 @@ int ddtrace_rb_profile_frames(VALUE thread, int start, int limit, frame_info *st
|
|
445
438
|
// support sampling any thread (including the current) passed as an argument
|
446
439
|
rb_thread_t *th = thread_struct_from_object(thread);
|
447
440
|
const rb_execution_context_t *ec = th->ec;
|
441
|
+
|
442
|
+
// As of this writing, we don't support profiling with MN enabled, and this only happens in that mode, but as we
|
443
|
+
// probably want to experiment with it in the future, I've decided to import https://github.com/ruby/ruby/pull/9310
|
444
|
+
// here.
|
445
|
+
if (ec == NULL) return 0;
|
446
|
+
|
447
|
+
// I suspect this won't happen for ddtrace, but just-in-case we've imported a potential fix for
|
448
|
+
// https://github.com/ruby/ruby/pull/13643 by assuming that these can be NULL/zero with the cfp being non-NULL yet.
|
449
|
+
if (ec->vm_stack == NULL || ec->vm_stack_size == 0) return 0;
|
450
|
+
|
448
451
|
const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
|
449
452
|
#ifndef NO_JIT_RETURN
|
450
453
|
const rb_control_frame_t *top = cfp;
|
@@ -462,11 +465,6 @@ int ddtrace_rb_profile_frames(VALUE thread, int start, int limit, frame_info *st
|
|
462
465
|
// it from https://github.com/ruby/ruby/pull/7116 in a "just in case" kind of mindset.
|
463
466
|
if (cfp == NULL) return 0;
|
464
467
|
|
465
|
-
// As of this writing, we don't support profiling with MN enabled, and this only happens in that mode, but as we
|
466
|
-
// probably want to experiment with it in the future, I've decided to import https://github.com/ruby/ruby/pull/9310
|
467
|
-
// here.
|
468
|
-
if (ec == NULL) return 0;
|
469
|
-
|
470
468
|
// Fix: Skip dummy frame that shows up in main thread.
|
471
469
|
//
|
472
470
|
// According to a comment in `backtrace_each` (`vm_backtrace.c`), there's two dummy frames that we should ignore
|
@@ -483,7 +481,20 @@ int ddtrace_rb_profile_frames(VALUE thread, int start, int limit, frame_info *st
|
|
483
481
|
// See comment on `record_placeholder_stack_in_native_code` for a full explanation of what this means (and why we don't just return 0)
|
484
482
|
if (end_cfp <= cfp) return PLACEHOLDER_STACK_IN_NATIVE_CODE;
|
485
483
|
|
486
|
-
|
484
|
+
// This is the position just after the top of the stack -- e.g. where a new frame pushed on the stack would end up.
|
485
|
+
const rb_control_frame_t *top_sentinel = RUBY_VM_NEXT_CONTROL_FRAME(cfp);
|
486
|
+
|
487
|
+
// We iterate the stack from bottom (beginning of thread) to the top (currently-active frame). This is different
|
488
|
+
// from upstream rb_profile_frames, but actually matches what `backtrace_each` does (yes, different Ruby VM APIs
|
489
|
+
// iterate in different directions).
|
490
|
+
// We do this to better take advantage of the `same_frame` caching mechanism: By starting from the bottom of the
|
491
|
+
// stack towards the top, we can usually keep most of the stack intact when the code is only going up and down
|
492
|
+
// a few methods at the top. Before this change, the cache was really only useful if between samples the app had
|
493
|
+
// not moved from the current stack, as adding or removing one frame would invalidate the existing cache (because
|
494
|
+
// every position would shift).
|
495
|
+
cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
|
496
|
+
|
497
|
+
for (i=0; i<limit && cfp != top_sentinel; cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
|
487
498
|
if (cfp->iseq && !cfp->pc) {
|
488
499
|
// Fix: Do nothing -- this frame should not be used
|
489
500
|
//
|
@@ -41,7 +41,6 @@ rb_nativethread_id_t pthread_id_for(VALUE thread);
|
|
41
41
|
bool is_current_thread_holding_the_gvl(void);
|
42
42
|
current_gvl_owner gvl_owner(void);
|
43
43
|
uint64_t native_thread_id_for(VALUE thread);
|
44
|
-
ptrdiff_t stack_depth_for(VALUE thread);
|
45
44
|
void ddtrace_thread_list(VALUE result_array);
|
46
45
|
bool is_thread_alive(VALUE thread);
|
47
46
|
VALUE thread_name_for(VALUE thread);
|
@@ -72,7 +72,7 @@ NORETURN(void raise_syserr(
|
|
72
72
|
// reference a valid object (in which case value is not changed).
|
73
73
|
//
|
74
74
|
// Note: GVL can be released and other threads may get to run before this method returns
|
75
|
-
bool ruby_ref_from_id(
|
75
|
+
bool ruby_ref_from_id(VALUE obj_id, VALUE *value);
|
76
76
|
|
77
77
|
// Native wrapper to get the approximate/estimated current size of the passed
|
78
78
|
// object.
|
@@ -26,7 +26,9 @@ if ENV['DD_NO_EXTENSION'].to_s.strip.downcase == 'true'
|
|
26
26
|
end
|
27
27
|
skip_building_extension!('current Ruby VM is not supported') if RUBY_ENGINE != 'ruby'
|
28
28
|
skip_building_extension!('Microsoft Windows is not supported') if Gem.win_platform?
|
29
|
-
|
29
|
+
|
30
|
+
libdatadog_issue = Datadog::LibdatadogExtconfHelpers.load_libdatadog_or_get_issue
|
31
|
+
skip_building_extension!("issue setting up `libdatadog` gem: #{libdatadog_issue}") if libdatadog_issue
|
30
32
|
|
31
33
|
require 'mkmf'
|
32
34
|
|
@@ -5,6 +5,8 @@ require 'pathname'
|
|
5
5
|
|
6
6
|
module Datadog
|
7
7
|
# Contains a bunch of shared helpers that get used during building of extensions that link to libdatadog
|
8
|
+
#
|
9
|
+
# Note: Specs for this file currently live in `spec/datadog/profiling/native_extension_helpers_spec.rb`.
|
8
10
|
module LibdatadogExtconfHelpers
|
9
11
|
# Used to make sure the correct gem version gets loaded, as extconf.rb does not get run with "bundle exec" and thus
|
10
12
|
# may see multiple libdatadog versions. See https://github.com/DataDog/dd-trace-rb/pull/2531 for the horror story.
|
@@ -122,9 +124,17 @@ module Datadog
|
|
122
124
|
end
|
123
125
|
end
|
124
126
|
|
125
|
-
|
126
|
-
|
127
|
-
|
127
|
+
# Note: This helper is currently only used in the `libdatadog_api/extconf.rb` BUT still lives here to enable testing.
|
128
|
+
def self.load_libdatadog_or_get_issue
|
129
|
+
try_loading_libdatadog do |exception|
|
130
|
+
return "There was an error loading `libdatadog`: #{exception.class} #{exception.message}"
|
131
|
+
end
|
132
|
+
|
133
|
+
unless Libdatadog.pkgconfig_folder
|
134
|
+
"The `libdatadog` gem installed on your system is missing binaries for your platform variant. " \
|
135
|
+
"Your platform: " \
|
136
|
+
"`#{Libdatadog.current_platform}`; available binaries: `#{Libdatadog.available_binaries.join("`, `")}`"
|
137
|
+
end
|
128
138
|
end
|
129
139
|
end
|
130
140
|
end
|
@@ -10,6 +10,7 @@ module Datadog
|
|
10
10
|
GRAPE_ROUTE_KEY = 'grape.routing_args'
|
11
11
|
RAILS_ROUTE_KEY = 'action_dispatch.route_uri_pattern'
|
12
12
|
RAILS_ROUTES_KEY = 'action_dispatch.routes'
|
13
|
+
RAILS_PATH_PARAMS_KEY = 'action_dispatch.request.path_parameters'
|
13
14
|
RAILS_FORMAT_SUFFIX = '(.:format)'
|
14
15
|
|
15
16
|
# HACK: We rely on the fact that each contrib will modify `request.env`
|
@@ -36,6 +37,11 @@ module Datadog
|
|
36
37
|
# "/users/:id(.:format)"
|
37
38
|
#
|
38
39
|
# WARNING: This method works only *after* the request has been routed.
|
40
|
+
#
|
41
|
+
# WARNING: In Rails > 7.1 when a route was not found,
|
42
|
+
# action_dispatch.route_uri_pattern will not be set.
|
43
|
+
# In Rails < 7.1 it also will not be set even if a route was found,
|
44
|
+
# but in this case action_dispatch.request.path_parameters won't be empty.
|
39
45
|
def self.route_pattern(request)
|
40
46
|
if request.env.key?(GRAPE_ROUTE_KEY)
|
41
47
|
pattern = request.env[GRAPE_ROUTE_KEY][:route_info]&.pattern&.origin
|
@@ -45,7 +51,7 @@ module Datadog
|
|
45
51
|
"#{request.script_name}#{pattern}"
|
46
52
|
elsif request.env.key?(RAILS_ROUTE_KEY)
|
47
53
|
request.env[RAILS_ROUTE_KEY].delete_suffix(RAILS_FORMAT_SUFFIX)
|
48
|
-
elsif request.env.key?(RAILS_ROUTES_KEY)
|
54
|
+
elsif request.env.key?(RAILS_ROUTES_KEY) && !request.env.fetch(RAILS_PATH_PARAMS_KEY, {}).empty?
|
49
55
|
pattern = request.env[RAILS_ROUTES_KEY].router
|
50
56
|
.recognize(request) { |route, _| break route.path.spec.to_s }
|
51
57
|
|
@@ -4,6 +4,7 @@ require_relative 'security_engine/engine'
|
|
4
4
|
require_relative 'security_engine/runner'
|
5
5
|
require_relative 'processor/rule_loader'
|
6
6
|
require_relative 'actions_handler'
|
7
|
+
require_relative 'thread_safe_ref'
|
7
8
|
|
8
9
|
module Datadog
|
9
10
|
module AppSec
|
@@ -74,25 +75,14 @@ module Datadog
|
|
74
75
|
def initialize(security_engine:, telemetry:)
|
75
76
|
@security_engine = security_engine
|
76
77
|
@telemetry = telemetry
|
77
|
-
|
78
|
-
@mutex = Mutex.new
|
79
78
|
end
|
80
79
|
|
81
80
|
def reconfigure!
|
82
|
-
|
83
|
-
security_engine.reconfigure!
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def reconfigure_lock(&block)
|
88
|
-
@mutex.synchronize(&block)
|
81
|
+
security_engine.reconfigure!
|
89
82
|
end
|
90
83
|
|
91
84
|
def shutdown!
|
92
|
-
|
93
|
-
security_engine.finalize!
|
94
|
-
@security_engine = nil
|
95
|
-
end
|
85
|
+
# no-op
|
96
86
|
end
|
97
87
|
end
|
98
88
|
end
|
@@ -37,6 +37,7 @@ module Datadog
|
|
37
37
|
@events = []
|
38
38
|
@waf_runner = waf_runner
|
39
39
|
@metrics = Metrics::Collector.new
|
40
|
+
@interrupted = false
|
40
41
|
end
|
41
42
|
|
42
43
|
def run_waf(persistent_data, ephemeral_data, timeout = WAF::LibDDWAF::DDWAF_RUN_TIMEOUT)
|
@@ -55,6 +56,22 @@ module Datadog
|
|
55
56
|
result
|
56
57
|
end
|
57
58
|
|
59
|
+
def mark_as_interrupted!
|
60
|
+
@interrupted = true
|
61
|
+
end
|
62
|
+
|
63
|
+
def interrupted?
|
64
|
+
@interrupted
|
65
|
+
end
|
66
|
+
|
67
|
+
def waf_runner_ruleset_version
|
68
|
+
@waf_runner.ruleset_version
|
69
|
+
end
|
70
|
+
|
71
|
+
def waf_runner_known_addresses
|
72
|
+
@waf_runner.waf_addresses
|
73
|
+
end
|
74
|
+
|
58
75
|
def extract_schema
|
59
76
|
@waf_runner.run({'waf.context.processor' => {'extract-schema' => true}}, {})
|
60
77
|
end
|
@@ -66,6 +83,12 @@ module Datadog
|
|
66
83
|
Metrics::Exporter.export_rasp_metrics(@metrics.rasp, @span)
|
67
84
|
end
|
68
85
|
|
86
|
+
def export_request_telemetry
|
87
|
+
return if @trace.nil?
|
88
|
+
|
89
|
+
Metrics::TelemetryExporter.export_waf_request_metrics(@metrics.waf, self)
|
90
|
+
end
|
91
|
+
|
69
92
|
def finalize!
|
70
93
|
@waf_runner.finalize!
|
71
94
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require_relative '../ext'
|
4
4
|
require_relative '../configuration'
|
5
5
|
require_relative '../data_extractor'
|
6
|
+
require_relative '../../../trace_keeper'
|
6
7
|
|
7
8
|
module Datadog
|
8
9
|
module AppSec
|
@@ -25,7 +26,7 @@ module Datadog
|
|
25
26
|
return result
|
26
27
|
end
|
27
28
|
|
28
|
-
context.trace
|
29
|
+
TraceKeeper.keep!(context.trace)
|
29
30
|
|
30
31
|
if result
|
31
32
|
record_successful_signin(context, resource)
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require_relative '../ext'
|
4
4
|
require_relative '../configuration'
|
5
5
|
require_relative '../data_extractor'
|
6
|
+
require_relative '../../../trace_keeper'
|
6
7
|
|
7
8
|
module Datadog
|
8
9
|
module AppSec
|
@@ -26,7 +27,7 @@ module Datadog
|
|
26
27
|
|
27
28
|
next yield(resource) if resource.new_record? && block_given?
|
28
29
|
|
29
|
-
context.trace
|
30
|
+
TraceKeeper.keep!(context.trace)
|
30
31
|
record_successful_signup(context, resource)
|
31
32
|
Instrumentation.gateway.push('appsec.events.user_lifecycle', Ext::EVENT_SIGNUP)
|
32
33
|
|
@@ -46,33 +46,22 @@ module Datadog
|
|
46
46
|
boot = Datadog::Core::Remote::Tie.boot
|
47
47
|
Datadog::Core::Remote::Tie::Tracing.tag(boot, active_span)
|
48
48
|
|
49
|
-
security_engine = nil
|
50
|
-
ready = false
|
51
|
-
ctx = nil
|
52
|
-
|
53
49
|
# For a given request, keep using the first Rack stack scope for
|
54
50
|
# nested apps. Don't set `context` local variable so that on popping
|
55
51
|
# out of this nested stack we don't finalize the parent's context
|
56
52
|
return @app.call(env) if active_context(env)
|
57
53
|
|
58
|
-
Datadog::AppSec.
|
59
|
-
security_engine = Datadog::AppSec.security_engine
|
60
|
-
|
61
|
-
if security_engine
|
62
|
-
ctx = Datadog::AppSec::Context.activate(
|
63
|
-
Datadog::AppSec::Context.new(active_trace, active_span, security_engine.new_runner)
|
64
|
-
)
|
65
|
-
|
66
|
-
env[Datadog::AppSec::Ext::CONTEXT_KEY] = ctx
|
67
|
-
ready = true
|
68
|
-
end
|
69
|
-
end
|
54
|
+
security_engine = Datadog::AppSec.security_engine
|
70
55
|
|
71
56
|
# TODO: handle exceptions, except for @app.call
|
57
|
+
return @app.call(env) unless security_engine
|
72
58
|
|
73
|
-
|
59
|
+
ctx = Datadog::AppSec::Context.activate(
|
60
|
+
Datadog::AppSec::Context.new(active_trace, active_span, security_engine.new_runner)
|
61
|
+
)
|
62
|
+
env[Datadog::AppSec::Ext::CONTEXT_KEY] = ctx
|
74
63
|
|
75
|
-
add_appsec_tags(
|
64
|
+
add_appsec_tags(ctx)
|
76
65
|
add_request_tags(ctx, env)
|
77
66
|
|
78
67
|
http_response = nil
|
@@ -97,6 +86,7 @@ module Datadog
|
|
97
86
|
end
|
98
87
|
|
99
88
|
if interrupt_params
|
89
|
+
ctx.mark_as_interrupted!
|
100
90
|
http_response = AppSec::Response.from_interrupt_params(interrupt_params, env['HTTP_ACCEPT']).to_rack
|
101
91
|
end
|
102
92
|
|
@@ -128,6 +118,8 @@ module Datadog
|
|
128
118
|
ensure
|
129
119
|
if ctx
|
130
120
|
ctx.export_metrics
|
121
|
+
ctx.export_request_telemetry
|
122
|
+
|
131
123
|
Datadog::AppSec::Context.deactivate
|
132
124
|
end
|
133
125
|
end
|
@@ -156,7 +148,7 @@ module Datadog
|
|
156
148
|
end
|
157
149
|
|
158
150
|
# standard:disable Metrics/MethodLength
|
159
|
-
def add_appsec_tags(
|
151
|
+
def add_appsec_tags(context)
|
160
152
|
span = context.span
|
161
153
|
trace = context.trace
|
162
154
|
|
@@ -166,15 +158,15 @@ module Datadog
|
|
166
158
|
span.set_tag('_dd.runtime_family', 'ruby')
|
167
159
|
span.set_tag('_dd.appsec.waf.version', Datadog::AppSec::WAF::VERSION::BASE_STRING)
|
168
160
|
|
169
|
-
if
|
170
|
-
span.set_tag('_dd.appsec.event_rules.version',
|
161
|
+
if context.waf_runner_ruleset_version
|
162
|
+
span.set_tag('_dd.appsec.event_rules.version', context.waf_runner_ruleset_version)
|
171
163
|
|
172
164
|
unless @oneshot_tags_sent
|
173
165
|
# Small race condition, but it's inoccuous: worst case the tags
|
174
166
|
# are sent a couple of times more than expected
|
175
167
|
@oneshot_tags_sent = true
|
176
168
|
|
177
|
-
span.set_tag('_dd.appsec.event_rules.addresses', JSON.dump(
|
169
|
+
span.set_tag('_dd.appsec.event_rules.addresses', JSON.dump(context.waf_runner_known_addresses))
|
178
170
|
|
179
171
|
# Ensure these tags reach the backend
|
180
172
|
trace.keep!
|
@@ -16,6 +16,7 @@ module Datadog
|
|
16
16
|
gateway = Instrumentation.gateway
|
17
17
|
|
18
18
|
watch_request_action(gateway)
|
19
|
+
watch_response_body_json(gateway)
|
19
20
|
end
|
20
21
|
|
21
22
|
def watch_request_action(gateway = Instrumentation.gateway)
|
@@ -29,18 +30,38 @@ module Datadog
|
|
29
30
|
|
30
31
|
result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
|
31
32
|
|
32
|
-
if result.match?
|
33
|
+
if result.match?
|
33
34
|
context.events.push(
|
34
35
|
AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
|
35
36
|
)
|
37
|
+
|
38
|
+
AppSec::Event.tag_and_keep!(context, result)
|
39
|
+
AppSec::ActionsHandler.handle(result.actions)
|
36
40
|
end
|
37
41
|
|
42
|
+
stack.call(gateway_request.request)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def watch_response_body_json(gateway = Instrumentation.gateway)
|
47
|
+
gateway.watch('rails.response.body.json', :appsec) do |stack, container|
|
48
|
+
context = container.context
|
49
|
+
|
50
|
+
persistent_data = {
|
51
|
+
'server.response.body' => container.data
|
52
|
+
}
|
53
|
+
result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
|
54
|
+
|
38
55
|
if result.match?
|
56
|
+
context.events.push(
|
57
|
+
AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
|
58
|
+
)
|
59
|
+
|
39
60
|
AppSec::Event.tag_and_keep!(context, result)
|
40
61
|
AppSec::ActionsHandler.handle(result.actions)
|
41
62
|
end
|
42
63
|
|
43
|
-
stack.call(
|
64
|
+
stack.call(container)
|
44
65
|
end
|
45
66
|
end
|
46
67
|
end
|
@@ -8,6 +8,8 @@ require_relative '../rack/request_middleware'
|
|
8
8
|
require_relative '../rack/request_body_middleware'
|
9
9
|
require_relative 'gateway/watcher'
|
10
10
|
require_relative 'gateway/request'
|
11
|
+
require_relative 'patches/render_to_body_patch'
|
12
|
+
require_relative 'patches/process_action_patch'
|
11
13
|
|
12
14
|
require_relative '../../../tracing/contrib/rack/middlewares'
|
13
15
|
|
@@ -17,6 +19,7 @@ module Datadog
|
|
17
19
|
module Rails
|
18
20
|
# Patcher for AppSec on Rails
|
19
21
|
module Patcher
|
22
|
+
GUARD_ACTION_CONTROLLER_ONCE_PER_APP = Hash.new { |h, key| h[key] = Datadog::Core::Utils::OnlyOnce.new }
|
20
23
|
BEFORE_INITIALIZE_ONLY_ONCE_PER_APP = Hash.new { |h, key| h[key] = Datadog::Core::Utils::OnlyOnce.new }
|
21
24
|
AFTER_INITIALIZE_ONLY_ONCE_PER_APP = Hash.new { |h, key| h[key] = Datadog::Core::Utils::OnlyOnce.new }
|
22
25
|
|
@@ -34,6 +37,7 @@ module Datadog
|
|
34
37
|
Gateway::Watcher.watch
|
35
38
|
patch_before_initialize
|
36
39
|
patch_after_initialize
|
40
|
+
patch_action_controller
|
37
41
|
|
38
42
|
Patcher.instance_variable_set(:@patched, true)
|
39
43
|
end
|
@@ -49,7 +53,8 @@ module Datadog
|
|
49
53
|
# Middleware must be added before the application is initialized.
|
50
54
|
# Otherwise the middleware stack will be frozen.
|
51
55
|
add_middleware(app) if Datadog.configuration.tracing[:rails][:middleware]
|
52
|
-
|
56
|
+
|
57
|
+
::ActionController::Metal.prepend(Patches::ProcessActionPatch)
|
53
58
|
end
|
54
59
|
end
|
55
60
|
|
@@ -65,31 +70,6 @@ module Datadog
|
|
65
70
|
end
|
66
71
|
end
|
67
72
|
|
68
|
-
# Hook into ActionController::Instrumentation#process_action, which encompasses action filters
|
69
|
-
module ProcessActionPatch
|
70
|
-
def process_action(*args)
|
71
|
-
env = request.env
|
72
|
-
|
73
|
-
context = env[Datadog::AppSec::Ext::CONTEXT_KEY]
|
74
|
-
|
75
|
-
return super unless context
|
76
|
-
|
77
|
-
# TODO: handle exceptions, except for super
|
78
|
-
|
79
|
-
gateway_request = Gateway::Request.new(request)
|
80
|
-
|
81
|
-
http_response, _gateway_request = Instrumentation.gateway.push('rails.request.action', gateway_request) do
|
82
|
-
super
|
83
|
-
end
|
84
|
-
|
85
|
-
http_response
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def patch_process_action
|
90
|
-
::ActionController::Metal.prepend(ProcessActionPatch)
|
91
|
-
end
|
92
|
-
|
93
73
|
def include_middleware?(middleware, app)
|
94
74
|
found = false
|
95
75
|
|
@@ -143,6 +123,14 @@ module Datadog
|
|
143
123
|
end
|
144
124
|
end
|
145
125
|
|
126
|
+
def patch_action_controller
|
127
|
+
::ActiveSupport.on_load(:action_controller) do
|
128
|
+
GUARD_ACTION_CONTROLLER_ONCE_PER_APP[self].run do
|
129
|
+
::ActionController::Base.prepend(Patches::RenderToBodyPatch)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
146
134
|
def setup_security
|
147
135
|
Datadog::AppSec::Contrib::Rails::Framework.setup
|
148
136
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module AppSec
|
5
|
+
module Contrib
|
6
|
+
module Rails
|
7
|
+
module Patches
|
8
|
+
# Hook into ActionController::Instrumentation#process_action, which encompasses action filters
|
9
|
+
module ProcessActionPatch
|
10
|
+
def process_action(*args)
|
11
|
+
context = request.env[Datadog::AppSec::Ext::CONTEXT_KEY]
|
12
|
+
return super unless context
|
13
|
+
|
14
|
+
# TODO: handle exceptions, except for super
|
15
|
+
gateway_request = Gateway::Request.new(request)
|
16
|
+
http_response, _gateway_request = Instrumentation.gateway.push('rails.request.action', gateway_request) do
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
http_response
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../utils/hash_coercion'
|
4
|
+
require_relative '../../../instrumentation/gateway/argument'
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module AppSec
|
8
|
+
module Contrib
|
9
|
+
module Rails
|
10
|
+
module Patches
|
11
|
+
# A patch targeting `AbstractController::Rendering#render_to_body`
|
12
|
+
# method to capture JSON response body right before it is serialized.
|
13
|
+
module RenderToBodyPatch
|
14
|
+
def render_to_body(options = {})
|
15
|
+
return super unless options.key?(:json)
|
16
|
+
|
17
|
+
context = request.env[Datadog::AppSec::Ext::CONTEXT_KEY]
|
18
|
+
return super unless context
|
19
|
+
|
20
|
+
data = Utils::HashCoercion.coerce(options[:json])
|
21
|
+
return super unless data
|
22
|
+
|
23
|
+
container = Instrumentation::Gateway::DataContainer.new(data, context: context)
|
24
|
+
Instrumentation.gateway.push('rails.response.body.json', container)
|
25
|
+
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -17,6 +17,7 @@ module Datadog
|
|
17
17
|
|
18
18
|
watch_request_dispatch(gateway)
|
19
19
|
watch_request_routed(gateway)
|
20
|
+
watch_response_body_json(gateway)
|
20
21
|
end
|
21
22
|
|
22
23
|
def watch_request_dispatch(gateway = Instrumentation.gateway)
|
@@ -67,6 +68,28 @@ module Datadog
|
|
67
68
|
stack.call(gateway_request.request)
|
68
69
|
end
|
69
70
|
end
|
71
|
+
|
72
|
+
def watch_response_body_json(gateway = Instrumentation.gateway)
|
73
|
+
gateway.watch('sinatra.response.body.json', :appsec) do |stack, container|
|
74
|
+
context = container.context
|
75
|
+
|
76
|
+
persistent_data = {
|
77
|
+
'server.response.body' => container.data
|
78
|
+
}
|
79
|
+
result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
|
80
|
+
|
81
|
+
if result.match?
|
82
|
+
context.events.push(
|
83
|
+
AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
|
84
|
+
)
|
85
|
+
|
86
|
+
AppSec::Event.tag_and_keep!(context, result)
|
87
|
+
AppSec::ActionsHandler.handle(result.actions)
|
88
|
+
end
|
89
|
+
|
90
|
+
stack.call(container)
|
91
|
+
end
|
92
|
+
end
|
70
93
|
end
|
71
94
|
end
|
72
95
|
end
|