datadog 2.12.2 → 2.13.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 +36 -1
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +14 -13
- data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +89 -0
- data/lib/datadog/appsec/actions_handler.rb +22 -1
- data/lib/datadog/appsec/anonymizer.rb +16 -0
- data/lib/datadog/appsec/configuration/settings.rb +62 -10
- data/lib/datadog/appsec/contrib/auto_instrument.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/configuration.rb +7 -31
- data/lib/datadog/appsec/contrib/devise/data_extractor.rb +79 -0
- data/lib/datadog/appsec/contrib/devise/ext.rb +21 -0
- data/lib/datadog/appsec/contrib/devise/integration.rb +0 -1
- data/lib/datadog/appsec/contrib/devise/patcher.rb +36 -23
- data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +102 -0
- data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +69 -0
- data/lib/datadog/appsec/contrib/devise/{patcher/rememberable_patch.rb → patches/skip_signin_tracking_patch.rb} +2 -2
- data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +93 -0
- data/lib/datadog/appsec/contrib/rack/ext.rb +14 -0
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +10 -3
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +0 -2
- data/lib/datadog/appsec/event.rb +1 -1
- data/lib/datadog/appsec/ext.rb +4 -2
- data/lib/datadog/appsec/instrumentation/gateway/argument.rb +4 -2
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +8 -3
- data/lib/datadog/appsec/security_engine/runner.rb +2 -2
- data/lib/datadog/appsec/utils.rb +0 -2
- data/lib/datadog/core/configuration/components.rb +2 -1
- data/lib/datadog/core/configuration/ext.rb +4 -0
- data/lib/datadog/core/configuration/options.rb +2 -2
- data/lib/datadog/core/configuration/settings.rb +53 -30
- data/lib/datadog/core/environment/agent_info.rb +4 -3
- data/lib/datadog/core/remote/component.rb +3 -6
- data/lib/datadog/core/remote/configuration/repository.rb +2 -1
- data/lib/datadog/core/remote/negotiation.rb +9 -9
- data/lib/datadog/core/remote/transport/config.rb +4 -3
- data/lib/datadog/core/remote/transport/http/client.rb +4 -3
- data/lib/datadog/core/remote/transport/http/config.rb +6 -32
- data/lib/datadog/core/remote/transport/http/negotiation.rb +6 -32
- data/lib/datadog/core/remote/transport/http.rb +22 -57
- data/lib/datadog/core/remote/transport/negotiation.rb +4 -3
- data/lib/datadog/core/runtime/metrics.rb +8 -1
- data/lib/datadog/core/telemetry/http/adapters/net.rb +1 -1
- data/lib/datadog/core/transport/http/api/instance.rb +17 -0
- data/lib/datadog/core/transport/http/api/spec.rb +17 -0
- data/lib/datadog/core/transport/http/builder.rb +5 -3
- data/lib/datadog/core/transport/http.rb +39 -2
- data/lib/datadog/di/component.rb +0 -2
- data/lib/datadog/di/probe_notifier_worker.rb +16 -16
- data/lib/datadog/di/transport/diagnostics.rb +4 -3
- data/lib/datadog/di/transport/http/api.rb +2 -12
- data/lib/datadog/di/transport/http/client.rb +4 -3
- data/lib/datadog/di/transport/http/diagnostics.rb +7 -33
- data/lib/datadog/di/transport/http/input.rb +7 -33
- data/lib/datadog/di/transport/http.rb +14 -56
- data/lib/datadog/di/transport/input.rb +4 -3
- data/lib/datadog/di/utils.rb +5 -0
- data/lib/datadog/kit/appsec/events.rb +9 -0
- data/lib/datadog/kit/identity.rb +5 -1
- data/lib/datadog/opentelemetry/api/baggage.rb +90 -0
- data/lib/datadog/opentelemetry/api/baggage.rbs +26 -0
- data/lib/datadog/opentelemetry/api/context.rb +16 -2
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +1 -1
- data/lib/datadog/opentelemetry.rb +2 -1
- data/lib/datadog/profiling/collectors/thread_context.rb +1 -1
- data/lib/datadog/profiling.rb +5 -2
- data/lib/datadog/tracing/component.rb +15 -12
- data/lib/datadog/tracing/configuration/ext.rb +7 -1
- data/lib/datadog/tracing/configuration/settings.rb +18 -2
- data/lib/datadog/tracing/context_provider.rb +1 -1
- data/lib/datadog/tracing/contrib/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -5
- data/lib/datadog/tracing/contrib/excon/middleware.rb +5 -3
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -3
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +7 -1
- data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +3 -0
- data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +0 -15
- data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +4 -1
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +5 -5
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +5 -11
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +6 -10
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +5 -3
- data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +6 -1
- data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +3 -0
- data/lib/datadog/tracing/correlation.rb +9 -2
- data/lib/datadog/tracing/distributed/baggage.rb +131 -0
- data/lib/datadog/tracing/distributed/datadog.rb +2 -0
- data/lib/datadog/tracing/distributed/propagation.rb +25 -4
- data/lib/datadog/tracing/distributed/propagation_policy.rb +42 -0
- data/lib/datadog/tracing/metadata/ext.rb +5 -0
- data/lib/datadog/tracing/sampling/span/rule.rb +0 -1
- data/lib/datadog/tracing/span_operation.rb +2 -1
- data/lib/datadog/tracing/sync_writer.rb +1 -2
- data/lib/datadog/tracing/trace_digest.rb +9 -2
- data/lib/datadog/tracing/trace_operation.rb +29 -17
- data/lib/datadog/tracing/trace_segment.rb +6 -4
- data/lib/datadog/tracing/tracer.rb +38 -2
- data/lib/datadog/tracing/transport/http/api.rb +2 -10
- data/lib/datadog/tracing/transport/http/client.rb +5 -4
- data/lib/datadog/tracing/transport/http/traces.rb +13 -41
- data/lib/datadog/tracing/transport/http.rb +11 -44
- data/lib/datadog/tracing/transport/trace_formatter.rb +7 -0
- data/lib/datadog/tracing/transport/traces.rb +21 -9
- data/lib/datadog/tracing/workers/trace_writer.rb +2 -6
- data/lib/datadog/tracing/writer.rb +2 -6
- data/lib/datadog/tracing.rb +16 -3
- data/lib/datadog/version.rb +2 -2
- metadata +17 -13
- data/lib/datadog/appsec/contrib/devise/event.rb +0 -54
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +0 -72
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +0 -47
- data/lib/datadog/appsec/contrib/devise/resource.rb +0 -35
- data/lib/datadog/appsec/contrib/devise/tracking.rb +0 -57
- data/lib/datadog/appsec/utils/trace_operation.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c826569b30a9e809d44f98b6371650aa38306e325b2f1ceb79ece2d3fb23360
|
4
|
+
data.tar.gz: 6753a8ac457c797fe29e19f1af4d434e33d6f74aa3b7c9a32394a8d3e5d57f33
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14445f04bb88f59798ed30ed28c849556556639720d2086f678058021e23ca64ab4740a3e4df1e53cab34e5f18eb785dfeebfd0716c20a75971acb605cdf6884
|
7
|
+
data.tar.gz: b3d8a318c7571747d80bb474478ab4a4ae92c422ba9a6177b6889fc3231bac4666c13d8c77ebd6bf43bd5045f427d6771e3f69531b23903ebdf4673824268f50
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,28 @@
|
|
2
2
|
|
3
3
|
## [Unreleased]
|
4
4
|
|
5
|
+
## [2.13.0] - 2025-04-02
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
* Core: Add `DD_TRACE_EXPERIMENTAL_RUNTIME_ID_ENABLED` experimental option to enable runtime ID collection for runtime metrics. ([#4473][])
|
10
|
+
* Tracing: Add support for W3C Baggage API along with automatic extraction and injection, and OpenTelemetry support. ([#4493][], [#4505][])
|
11
|
+
* Tracing: Add `DD_APM_TRACING_ENABLED` option to disable APM tracing while keeping other products traces. ([#4498][])
|
12
|
+
* Tracing: Add `DD_TRACE_NATIVE_SPAN_EVENTS` option to override span events serialization for agent-less environments. ([#4507][])
|
13
|
+
* AppSec: Add stack trace reporting for security events. ([#4526][])
|
14
|
+
* AppSec: Improve `devise` instrumentation to support latest Account Takeover (ATO) detection. ([#4433][])
|
15
|
+
|
16
|
+
### Changed
|
17
|
+
|
18
|
+
* Core: Improve `DD_TAGS` configuration handling to be more consistent across Datadog libraries and Agent. ([#4530][])
|
19
|
+
* Tracing: Enable by default 128-bit trace ID logging so that trace IDs are consistent across logs and the Datadog UI. ([#4528][])
|
20
|
+
|
21
|
+
### Fixed
|
22
|
+
|
23
|
+
* Core: Fix initialization when the library is partially loaded. ([#4498][])
|
24
|
+
* Tracing: Fix trace ID propagation by ensuring extraction of 16-character hex values from the `_dd.p.tid` tag in `x-datadog-tags` header. ([#4534][])
|
25
|
+
* Tracing: Profiling: Fix warnings printed by `ruby -w`. ([#4547][], [#4549][])
|
26
|
+
|
5
27
|
## [2.12.2] - 2025-03-17
|
6
28
|
|
7
29
|
### Fixed
|
@@ -3145,7 +3167,8 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
|
|
3145
3167
|
Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
3146
3168
|
|
3147
3169
|
|
3148
|
-
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.
|
3170
|
+
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.13.0...master
|
3171
|
+
[2.13.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.12.2...v2.13.0
|
3149
3172
|
[2.12.2]: https://github.com/DataDog/dd-trace-rb/compare/v2.12.1...v2.12.2
|
3150
3173
|
[2.12.1]: https://github.com/DataDog/dd-trace-rb/compare/v2.12.0...v2.12.1
|
3151
3174
|
[2.12.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.11.0...v2.12.0
|
@@ -4649,8 +4672,20 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
4649
4672
|
[#4424]: https://github.com/DataDog/dd-trace-rb/issues/4424
|
4650
4673
|
[#4425]: https://github.com/DataDog/dd-trace-rb/issues/4425
|
4651
4674
|
[#4426]: https://github.com/DataDog/dd-trace-rb/issues/4426
|
4675
|
+
[#4433]: https://github.com/DataDog/dd-trace-rb/issues/4433
|
4652
4676
|
[#4437]: https://github.com/DataDog/dd-trace-rb/issues/4437
|
4677
|
+
[#4473]: https://github.com/DataDog/dd-trace-rb/issues/4473
|
4678
|
+
[#4493]: https://github.com/DataDog/dd-trace-rb/issues/4493
|
4653
4679
|
[#4497]: https://github.com/DataDog/dd-trace-rb/issues/4497
|
4680
|
+
[#4498]: https://github.com/DataDog/dd-trace-rb/issues/4498
|
4681
|
+
[#4505]: https://github.com/DataDog/dd-trace-rb/issues/4505
|
4682
|
+
[#4507]: https://github.com/DataDog/dd-trace-rb/issues/4507
|
4683
|
+
[#4526]: https://github.com/DataDog/dd-trace-rb/issues/4526
|
4684
|
+
[#4528]: https://github.com/DataDog/dd-trace-rb/issues/4528
|
4685
|
+
[#4530]: https://github.com/DataDog/dd-trace-rb/issues/4530
|
4686
|
+
[#4534]: https://github.com/DataDog/dd-trace-rb/issues/4534
|
4687
|
+
[#4547]: https://github.com/DataDog/dd-trace-rb/issues/4547
|
4688
|
+
[#4549]: https://github.com/DataDog/dd-trace-rb/issues/4549
|
4654
4689
|
[@AdrianLC]: https://github.com/AdrianLC
|
4655
4690
|
[@Azure7111]: https://github.com/Azure7111
|
4656
4691
|
[@BabyGroot]: https://github.com/BabyGroot
|
@@ -212,7 +212,7 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
212
212
|
static VALUE _native_sample(VALUE self, VALUE collector_instance, VALUE profiler_overhead_stack_thread, VALUE allow_exception);
|
213
213
|
static VALUE _native_on_gc_start(VALUE self, VALUE collector_instance);
|
214
214
|
static VALUE _native_on_gc_finish(VALUE self, VALUE collector_instance);
|
215
|
-
static VALUE _native_sample_after_gc(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE
|
215
|
+
static VALUE _native_sample_after_gc(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE allow_exception);
|
216
216
|
static void update_metrics_and_sample(
|
217
217
|
thread_context_collector_state *state,
|
218
218
|
VALUE thread_being_sampled,
|
@@ -297,6 +297,7 @@ static void otel_without_ddtrace_trace_identifiers_for(
|
|
297
297
|
static otel_span otel_span_from(VALUE otel_context, VALUE otel_current_span_key);
|
298
298
|
static uint64_t otel_span_id_to_uint(VALUE otel_span_id);
|
299
299
|
static VALUE safely_lookup_hash_without_going_into_ruby_code(VALUE hash, VALUE key);
|
300
|
+
static VALUE _native_reset_monotonic_to_system_state(DDTRACE_UNUSED VALUE self, VALUE collector_instance);
|
300
301
|
|
301
302
|
void collectors_thread_context_init(VALUE profiling_module) {
|
302
303
|
VALUE collectors_module = rb_define_module_under(profiling_module, "Collectors");
|
@@ -321,13 +322,14 @@ void collectors_thread_context_init(VALUE profiling_module) {
|
|
321
322
|
rb_define_singleton_method(testing_module, "_native_sample_allocation", _native_sample_allocation, 3);
|
322
323
|
rb_define_singleton_method(testing_module, "_native_on_gc_start", _native_on_gc_start, 1);
|
323
324
|
rb_define_singleton_method(testing_module, "_native_on_gc_finish", _native_on_gc_finish, 1);
|
324
|
-
rb_define_singleton_method(testing_module, "_native_sample_after_gc", _native_sample_after_gc,
|
325
|
+
rb_define_singleton_method(testing_module, "_native_sample_after_gc", _native_sample_after_gc, 2);
|
325
326
|
rb_define_singleton_method(testing_module, "_native_thread_list", _native_thread_list, 0);
|
326
327
|
rb_define_singleton_method(testing_module, "_native_per_thread_context", _native_per_thread_context, 1);
|
327
328
|
rb_define_singleton_method(testing_module, "_native_stats", _native_stats, 1);
|
328
329
|
rb_define_singleton_method(testing_module, "_native_gc_tracking", _native_gc_tracking, 1);
|
329
330
|
rb_define_singleton_method(testing_module, "_native_new_empty_thread", _native_new_empty_thread, 0);
|
330
331
|
rb_define_singleton_method(testing_module, "_native_sample_skipped_allocation_samples", _native_sample_skipped_allocation_samples, 2);
|
332
|
+
rb_define_singleton_method(testing_module, "_native_reset_monotonic_to_system_state", _native_reset_monotonic_to_system_state, 1);
|
331
333
|
#ifndef NO_GVL_INSTRUMENTATION
|
332
334
|
rb_define_singleton_method(testing_module, "_native_on_gvl_waiting", _native_on_gvl_waiting, 1);
|
333
335
|
rb_define_singleton_method(testing_module, "_native_gvl_waiting_at_for", _native_gvl_waiting_at_for, 1);
|
@@ -551,19 +553,9 @@ static VALUE _native_on_gc_finish(DDTRACE_UNUSED VALUE self, VALUE collector_ins
|
|
551
553
|
return Qtrue;
|
552
554
|
}
|
553
555
|
|
554
|
-
|
555
|
-
// It SHOULD NOT be used for other purposes.
|
556
|
-
static VALUE _native_sample_after_gc(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE reset_monotonic_to_system_state, VALUE allow_exception) {
|
557
|
-
ENFORCE_BOOLEAN(reset_monotonic_to_system_state);
|
556
|
+
static VALUE _native_sample_after_gc(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE allow_exception) {
|
558
557
|
ENFORCE_BOOLEAN(allow_exception);
|
559
558
|
|
560
|
-
thread_context_collector_state *state;
|
561
|
-
TypedData_Get_Struct(collector_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
562
|
-
|
563
|
-
if (reset_monotonic_to_system_state == Qtrue) {
|
564
|
-
state->time_converter_state = (monotonic_to_system_epoch_state) MONOTONIC_TO_SYSTEM_EPOCH_INITIALIZER;
|
565
|
-
}
|
566
|
-
|
567
559
|
if (allow_exception == Qfalse) debug_enter_unsafe_context();
|
568
560
|
|
569
561
|
thread_context_collector_sample_after_gc(collector_instance);
|
@@ -2167,3 +2159,12 @@ static VALUE safely_lookup_hash_without_going_into_ruby_code(VALUE hash, VALUE k
|
|
2167
2159
|
|
2168
2160
|
return state.result;
|
2169
2161
|
}
|
2162
|
+
|
2163
|
+
static VALUE _native_reset_monotonic_to_system_state(DDTRACE_UNUSED VALUE self, VALUE collector_instance) {
|
2164
|
+
thread_context_collector_state *state;
|
2165
|
+
TypedData_Get_Struct(collector_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
2166
|
+
|
2167
|
+
state->time_converter_state = (monotonic_to_system_epoch_state) MONOTONIC_TO_SYSTEM_EPOCH_INITIALIZER;
|
2168
|
+
|
2169
|
+
return Qtrue;
|
2170
|
+
}
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module AppSec
|
5
|
+
module ActionsHandler
|
6
|
+
# This module serves encapsulates MessagePack serialization for caller locations.
|
7
|
+
#
|
8
|
+
# It serializes part of the stack:
|
9
|
+
# up to 32 frames (configurable)
|
10
|
+
# keeping frames from top and bottom of the stack (75% to 25%, configurable).
|
11
|
+
#
|
12
|
+
# It represents the stack trace that is added to span metastruct field.
|
13
|
+
class SerializableBacktrace
|
14
|
+
CLASS_AND_FUNCTION_NAME_REGEX = /\b((?:\w+::)*\w+)?[#.]?\b(\w+)\z/.freeze
|
15
|
+
|
16
|
+
def initialize(locations:, stack_id:)
|
17
|
+
@stack_id = stack_id
|
18
|
+
@locations = locations
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_msgpack(packer = nil)
|
22
|
+
# JRuby doesn't pass the packer
|
23
|
+
packer ||= MessagePack::Packer.new
|
24
|
+
|
25
|
+
packer.write_map_header(3)
|
26
|
+
|
27
|
+
packer.write('id')
|
28
|
+
packer.write(@stack_id.encode('UTF-8'))
|
29
|
+
|
30
|
+
packer.write('language')
|
31
|
+
packer.write('ruby'.encode('UTF-8'))
|
32
|
+
|
33
|
+
serializable_locations_map = build_serializable_locations_map
|
34
|
+
|
35
|
+
packer.write('frames')
|
36
|
+
packer.write_array_header(serializable_locations_map.size)
|
37
|
+
|
38
|
+
serializable_locations_map.each do |frame_id, location|
|
39
|
+
packer.write_map_header(6)
|
40
|
+
|
41
|
+
packer.write('id')
|
42
|
+
packer.write(frame_id)
|
43
|
+
|
44
|
+
packer.write('text')
|
45
|
+
packer.write(location.to_s.encode('UTF-8'))
|
46
|
+
|
47
|
+
packer.write('file')
|
48
|
+
packer.write(location.path&.encode('UTF-8'))
|
49
|
+
|
50
|
+
packer.write('line')
|
51
|
+
packer.write(location.lineno)
|
52
|
+
|
53
|
+
class_name, function_name = location.label&.match(CLASS_AND_FUNCTION_NAME_REGEX)&.captures
|
54
|
+
|
55
|
+
packer.write('class_name')
|
56
|
+
packer.write(class_name&.encode('UTF-8'))
|
57
|
+
|
58
|
+
packer.write('function')
|
59
|
+
packer.write(function_name&.encode('UTF-8'))
|
60
|
+
end
|
61
|
+
|
62
|
+
packer
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def build_serializable_locations_map
|
68
|
+
max_depth = Datadog.configuration.appsec.stack_trace.max_depth
|
69
|
+
top_percent = Datadog.configuration.appsec.stack_trace.top_percentage
|
70
|
+
|
71
|
+
drop_from_idx = max_depth * top_percent / 100
|
72
|
+
drop_until_idx = @locations.size - (max_depth - drop_from_idx)
|
73
|
+
|
74
|
+
frame_idx = -1
|
75
|
+
@locations.each_with_object({}) do |location, map|
|
76
|
+
# we are dropping frames from library code without increasing frame index
|
77
|
+
next if location.path&.include?('lib/datadog')
|
78
|
+
|
79
|
+
frame_idx += 1
|
80
|
+
|
81
|
+
next if max_depth != 0 && frame_idx >= drop_from_idx && frame_idx < drop_until_idx
|
82
|
+
|
83
|
+
map[frame_idx] = location
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'actions_handler/serializable_backtrace'
|
4
|
+
|
3
5
|
module Datadog
|
4
6
|
module AppSec
|
5
7
|
# this module encapsulates functions for handling actions that libddawf returns
|
@@ -19,7 +21,26 @@ module Datadog
|
|
19
21
|
throw(Datadog::AppSec::Ext::INTERRUPT, action_params)
|
20
22
|
end
|
21
23
|
|
22
|
-
def generate_stack(
|
24
|
+
def generate_stack(action_params)
|
25
|
+
return unless Datadog.configuration.appsec.stack_trace.enabled
|
26
|
+
|
27
|
+
stack_id = action_params['stack_id']
|
28
|
+
return unless stack_id
|
29
|
+
|
30
|
+
active_span = AppSec.active_context&.span
|
31
|
+
return unless active_span
|
32
|
+
|
33
|
+
event_category = Ext::EXPLOIT_PREVENTION_EVENT_CATEGORY
|
34
|
+
tag_key = Ext::TAG_METASTRUCT_STACK_TRACE
|
35
|
+
|
36
|
+
existing_stack_data = active_span.get_metastruct_tag(tag_key).dup || { event_category => [] }
|
37
|
+
max_stack_traces = Datadog.configuration.appsec.stack_trace.max_stack_traces
|
38
|
+
return if max_stack_traces != 0 && existing_stack_data[event_category].count >= max_stack_traces
|
39
|
+
|
40
|
+
backtrace = SerializableBacktrace.new(locations: Array(caller_locations), stack_id: stack_id)
|
41
|
+
existing_stack_data[event_category] << backtrace
|
42
|
+
active_span.set_metastruct_tag(tag_key, existing_stack_data)
|
43
|
+
end
|
23
44
|
|
24
45
|
def generate_schema(_action_params); end
|
25
46
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'digest/sha2'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module AppSec
|
7
|
+
# Manual anonymization of the potential PII data
|
8
|
+
module Anonymizer
|
9
|
+
def self.anonymize(payload)
|
10
|
+
raise ArgumentError, "expected String, received #{payload.class}" unless payload.is_a?(String)
|
11
|
+
|
12
|
+
"anon_#{Digest::SHA256.hexdigest(payload)[0, 32]}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -164,6 +164,66 @@ module Datadog
|
|
164
164
|
end
|
165
165
|
end
|
166
166
|
|
167
|
+
settings :stack_trace do
|
168
|
+
option :enabled do |o|
|
169
|
+
o.type :bool
|
170
|
+
o.env 'DD_APPSEC_STACK_TRACE_ENABLED'
|
171
|
+
o.default true
|
172
|
+
end
|
173
|
+
|
174
|
+
# The maximum number of stack trace frames to collect for each stack trace.
|
175
|
+
#
|
176
|
+
# If the stack trace exceeds this limit, the frames are dropped from the middle of the stack trace:
|
177
|
+
# 75% of the frames are kept from the top of the stack trace and 25% from the bottom
|
178
|
+
# (this percentage is also configurable).
|
179
|
+
#
|
180
|
+
# Minimum value is 10.
|
181
|
+
# Set to zero if you don't want any frames to be dropped.
|
182
|
+
#
|
183
|
+
# Default value is 32
|
184
|
+
option :max_depth do |o|
|
185
|
+
o.type :int
|
186
|
+
o.env 'DD_APPSEC_MAX_STACK_TRACE_DEPTH'
|
187
|
+
o.default 32
|
188
|
+
|
189
|
+
o.setter do |value|
|
190
|
+
value = 0 if value < 0
|
191
|
+
value
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# The percentage of frames to keep from the top of the stack trace.
|
196
|
+
#
|
197
|
+
# Default value is 75
|
198
|
+
option :top_percentage do |o|
|
199
|
+
o.type :int
|
200
|
+
o.env 'DD_APPSEC_MAX_STACK_TRACE_DEPTH_TOP_PERCENT'
|
201
|
+
o.default 75
|
202
|
+
|
203
|
+
o.setter do |value|
|
204
|
+
value = 100 if value > 100
|
205
|
+
value = 0 if value.negative?
|
206
|
+
value
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# Maximum number of stack traces to collect per span.
|
211
|
+
#
|
212
|
+
# Set to zero if you want to collect all stack traces.
|
213
|
+
#
|
214
|
+
# Default value is 2
|
215
|
+
option :max_stack_traces do |o|
|
216
|
+
o.type :int
|
217
|
+
o.env 'DD_APPSEC_MAX_STACK_TRACES'
|
218
|
+
o.default 2
|
219
|
+
|
220
|
+
o.setter do |value|
|
221
|
+
value = 0 if value < 0
|
222
|
+
value
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
167
227
|
settings :auto_user_instrumentation do
|
168
228
|
define_method(:enabled?) { get_option(:mode) != DISABLED_AUTO_USER_INSTRUMENTATION_MODE }
|
169
229
|
|
@@ -178,10 +238,10 @@ module Datadog
|
|
178
238
|
Datadog.logger.warn(
|
179
239
|
'The appsec.auto_user_instrumentation.mode value provided is not supported. ' \
|
180
240
|
"Supported values are: #{AUTO_USER_INSTRUMENTATION_MODES.join(' | ')}. " \
|
181
|
-
"Using
|
241
|
+
"Using value: #{DISABLED_AUTO_USER_INSTRUMENTATION_MODE}."
|
182
242
|
)
|
183
243
|
|
184
|
-
|
244
|
+
DISABLED_AUTO_USER_INSTRUMENTATION_MODE
|
185
245
|
end
|
186
246
|
end
|
187
247
|
end
|
@@ -259,14 +319,6 @@ module Datadog
|
|
259
319
|
o.type :bool, nilable: true
|
260
320
|
o.env 'DD_APPSEC_SCA_ENABLED'
|
261
321
|
end
|
262
|
-
|
263
|
-
settings :standalone do
|
264
|
-
option :enabled do |o|
|
265
|
-
o.type :bool
|
266
|
-
o.env 'DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED'
|
267
|
-
o.default false
|
268
|
-
end
|
269
|
-
end
|
270
322
|
end
|
271
323
|
end
|
272
324
|
end
|
@@ -9,7 +9,7 @@ module Datadog
|
|
9
9
|
def self.patch_all
|
10
10
|
integrations = []
|
11
11
|
|
12
|
-
Datadog::AppSec::Contrib::Integration.registry.
|
12
|
+
Datadog::AppSec::Contrib::Integration.registry.each_value do |integration|
|
13
13
|
next unless integration.klass.auto_instrument?
|
14
14
|
|
15
15
|
integrations << integration.name
|
@@ -7,19 +7,11 @@ module Datadog
|
|
7
7
|
# A temporary configuration module to accomodate new RFC changes.
|
8
8
|
# NOTE: DEV-3 Remove module
|
9
9
|
module Configuration
|
10
|
-
|
11
|
-
|
12
|
-
AppSec::Configuration::Settings::SAFE_TRACK_USER_EVENTS_MODE =>
|
10
|
+
TRACK_USER_EVENTS_CONVERSION_RULES = {
|
11
|
+
AppSec::Configuration::Settings::SAFE_TRACK_USER_EVENTS_MODE =>
|
13
12
|
AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE,
|
14
|
-
|
13
|
+
AppSec::Configuration::Settings::EXTENDED_TRACK_USER_EVENTS_MODE =>
|
15
14
|
AppSec::Configuration::Settings::IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE
|
16
|
-
}.freeze,
|
17
|
-
auto_instrumentation_to_track_user: {
|
18
|
-
AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE =>
|
19
|
-
AppSec::Configuration::Settings::SAFE_TRACK_USER_EVENTS_MODE,
|
20
|
-
AppSec::Configuration::Settings::IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE =>
|
21
|
-
AppSec::Configuration::Settings::EXTENDED_TRACK_USER_EVENTS_MODE
|
22
|
-
}.freeze
|
23
15
|
}.freeze
|
24
16
|
|
25
17
|
module_function
|
@@ -44,30 +36,14 @@ module Datadog
|
|
44
36
|
appsec.auto_user_instrumentation.mode
|
45
37
|
appsec.track_user_events.mode
|
46
38
|
|
47
|
-
if !appsec.
|
48
|
-
appsec.
|
49
|
-
return
|
50
|
-
end
|
51
|
-
|
52
|
-
if appsec.auto_user_instrumentation.options[:mode].default_precedence?
|
53
|
-
return MODES_CONVERSION_RULES[:track_user_to_auto_instrumentation].fetch(
|
39
|
+
if !appsec.track_user_events.options[:mode].default_precedence? &&
|
40
|
+
appsec.auto_user_instrumentation.options[:mode].default_precedence?
|
41
|
+
return TRACK_USER_EVENTS_CONVERSION_RULES.fetch(
|
54
42
|
appsec.track_user_events.mode, appsec.auto_user_instrumentation.mode
|
55
43
|
)
|
56
44
|
end
|
57
45
|
|
58
|
-
|
59
|
-
if appsec.auto_user_instrumentation.mode == identification_mode ||
|
60
|
-
appsec.track_user_events.mode == AppSec::Configuration::Settings::EXTENDED_TRACK_USER_EVENTS_MODE
|
61
|
-
return identification_mode
|
62
|
-
end
|
63
|
-
|
64
|
-
AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE
|
65
|
-
end
|
66
|
-
|
67
|
-
# NOTE: Remove in next version of tracking
|
68
|
-
def track_user_events_mode
|
69
|
-
MODES_CONVERSION_RULES[:auto_instrumentation_to_track_user]
|
70
|
-
.fetch(auto_user_instrumentation_mode, Datadog.configuration.appsec.track_user_events.mode)
|
46
|
+
appsec.auto_user_instrumentation.mode
|
71
47
|
end
|
72
48
|
end
|
73
49
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../anonymizer'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module AppSec
|
7
|
+
module Contrib
|
8
|
+
module Devise
|
9
|
+
# Extracts user identification data from Devise resources.
|
10
|
+
# Supports both regular and anonymized data extraction modes.
|
11
|
+
class DataExtractor
|
12
|
+
PRIORITY_ORDERED_ID_KEYS = [:id, 'id', :uuid, 'uuid'].freeze
|
13
|
+
PRIORITY_ORDERED_LOGIN_KEYS = [:email, 'email', :username, 'username', :login, 'login'].freeze
|
14
|
+
|
15
|
+
def initialize(mode:)
|
16
|
+
@mode = mode
|
17
|
+
@devise_scopes = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def extract_id(object)
|
21
|
+
return if object.nil?
|
22
|
+
|
23
|
+
if object.respond_to?(:[])
|
24
|
+
id = object[PRIORITY_ORDERED_ID_KEYS.find { |key| object[key] }]
|
25
|
+
scope = find_devise_scope(object)
|
26
|
+
|
27
|
+
id = "#{scope}:#{id}" if id && scope
|
28
|
+
return transform(id)
|
29
|
+
end
|
30
|
+
|
31
|
+
id = object.id if object.respond_to?(:id)
|
32
|
+
id ||= object.uuid if object.respond_to?(:uuid)
|
33
|
+
|
34
|
+
scope = find_devise_scope(object)
|
35
|
+
id = "#{scope}:#{id}" if id && scope
|
36
|
+
|
37
|
+
transform(id)
|
38
|
+
end
|
39
|
+
|
40
|
+
def extract_login(object)
|
41
|
+
return if object.nil?
|
42
|
+
|
43
|
+
if object.respond_to?(:[])
|
44
|
+
login = object[PRIORITY_ORDERED_LOGIN_KEYS.find { |key| object[key] }]
|
45
|
+
return transform(login)
|
46
|
+
end
|
47
|
+
|
48
|
+
login = object.email if object.respond_to?(:email)
|
49
|
+
login ||= object.username if object.respond_to?(:username)
|
50
|
+
login ||= object.login if object.respond_to?(:login)
|
51
|
+
|
52
|
+
transform(login)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def find_devise_scope(object)
|
58
|
+
return if ::Devise.mappings.count == 1
|
59
|
+
|
60
|
+
@devise_scopes[object.class.name] ||= begin
|
61
|
+
::Devise.mappings.each_value.find { |mapping| mapping.class_name == object.class.name }&.name
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def transform(value)
|
66
|
+
return if value.nil?
|
67
|
+
return value.to_s unless anonymize?
|
68
|
+
|
69
|
+
Anonymizer.anonymize(value.to_s)
|
70
|
+
end
|
71
|
+
|
72
|
+
def anonymize?
|
73
|
+
@mode == AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -6,6 +6,27 @@ module Datadog
|
|
6
6
|
module Devise
|
7
7
|
# Devise integration constants
|
8
8
|
module Ext
|
9
|
+
EVENT_LOGIN_SUCCESS = 'users.login.success'
|
10
|
+
EVENT_LOGIN_FAILURE = 'users.login.failure'
|
11
|
+
EVENT_SIGNUP = 'users.signup'
|
12
|
+
|
13
|
+
TAG_DD_USR_ID = '_dd.appsec.usr.id'
|
14
|
+
TAG_DD_USR_LOGIN = '_dd.appsec.usr.login'
|
15
|
+
TAG_DD_SIGNUP_MODE = '_dd.appsec.events.users.signup.auto.mode'
|
16
|
+
TAG_DD_COLLECTION_MODE = '_dd.appsec.user.collection_mode'
|
17
|
+
TAG_DD_LOGIN_SUCCESS_MODE = '_dd.appsec.events.users.login.success.auto.mode'
|
18
|
+
TAG_DD_LOGIN_FAILURE_MODE = '_dd.appsec.events.users.login.failure.auto.mode'
|
19
|
+
|
20
|
+
TAG_USR_ID = 'usr.id'
|
21
|
+
TAG_SIGNUP_TRACK = 'appsec.events.users.signup.track'
|
22
|
+
TAG_SIGNUP_USR_ID = 'appsec.events.users.signup.usr.id'
|
23
|
+
TAG_SIGNUP_USR_LOGIN = 'appsec.events.users.signup.usr.login'
|
24
|
+
TAG_LOGIN_FAILURE_TRACK = 'appsec.events.users.login.failure.track'
|
25
|
+
TAG_LOGIN_FAILURE_USR_ID = 'appsec.events.users.login.failure.usr.id'
|
26
|
+
TAG_LOGIN_FAILURE_USR_LOGIN = 'appsec.events.users.login.failure.usr.login'
|
27
|
+
TAG_LOGIN_FAILURE_USR_EXISTS = 'appsec.events.users.login.failure.usr.exists'
|
28
|
+
TAG_LOGIN_SUCCESS_TRACK = 'appsec.events.users.login.success.track'
|
29
|
+
TAG_LOGIN_SUCCESS_USR_LOGIN = 'appsec.events.users.login.success.usr.login'
|
9
30
|
end
|
10
31
|
end
|
11
32
|
end
|
@@ -1,15 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
|
5
|
-
require_relative '
|
3
|
+
require_relative '../../../core/utils/only_once'
|
4
|
+
|
5
|
+
require_relative 'tracking_middleware'
|
6
|
+
require_relative 'patches/signup_tracking_patch'
|
7
|
+
require_relative 'patches/signin_tracking_patch'
|
8
|
+
require_relative 'patches/skip_signin_tracking_patch'
|
6
9
|
|
7
10
|
module Datadog
|
8
11
|
module AppSec
|
9
12
|
module Contrib
|
10
13
|
module Devise
|
11
|
-
#
|
14
|
+
# Devise patcher
|
12
15
|
module Patcher
|
16
|
+
GUARD_ONCE_PER_APP = Hash.new do |hash, key|
|
17
|
+
hash[key] = Datadog::Core::Utils::OnlyOnce.new
|
18
|
+
end
|
19
|
+
|
13
20
|
module_function
|
14
21
|
|
15
22
|
def patched?
|
@@ -21,29 +28,35 @@ module Datadog
|
|
21
28
|
end
|
22
29
|
|
23
30
|
def patch
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
31
|
+
::ActiveSupport.on_load(:before_initialize) do |app|
|
32
|
+
GUARD_ONCE_PER_APP[app].run do
|
33
|
+
begin
|
34
|
+
app.middleware.insert_after(Warden::Manager, TrackingMiddleware)
|
35
|
+
rescue RuntimeError
|
36
|
+
AppSec.telemetry.error('AppSec: unable to insert Devise TrackingMiddleware')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
34
40
|
|
35
|
-
|
36
|
-
|
41
|
+
::ActiveSupport.on_load(:after_initialize) do
|
42
|
+
if ::Devise::RegistrationsController.descendants.empty?
|
43
|
+
::Devise::RegistrationsController.prepend(Patches::SignupTrackingPatch)
|
44
|
+
else
|
45
|
+
::Devise::RegistrationsController.descendants.each do |controller|
|
46
|
+
controller.prepend(Patches::SignupTrackingPatch)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
37
50
|
|
38
|
-
|
39
|
-
::Devise::Models::Rememberable # rubocop:disable Lint/Void
|
40
|
-
::Devise::Strategies::Rememberable.prepend(RememberablePatch)
|
41
|
-
end
|
51
|
+
::Devise::Strategies::Authenticatable.prepend(Patches::SigninTrackingPatch)
|
42
52
|
|
43
|
-
|
44
|
-
|
45
|
-
|
53
|
+
if ::Devise::STRATEGIES.include?(:rememberable)
|
54
|
+
# Rememberable strategy is required in autoloaded Rememberable model
|
55
|
+
require 'devise/models/rememberable'
|
56
|
+
::Devise::Strategies::Rememberable.prepend(Patches::SkipSigninTrackingPatch)
|
46
57
|
end
|
58
|
+
|
59
|
+
Patcher.instance_variable_set(:@patched, true)
|
47
60
|
end
|
48
61
|
end
|
49
62
|
end
|