datadog 2.21.0 → 2.23.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 +106 -2
- data/ext/LIBDATADOG_DEVELOPMENT.md +3 -0
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
- data/ext/datadog_profiling_native_extension/collectors_stack.c +4 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +1 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +6 -4
- data/ext/datadog_profiling_native_extension/heap_recorder.c +1 -1
- data/ext/libdatadog_api/datadog_ruby_common.h +1 -1
- data/ext/libdatadog_api/ddsketch.c +106 -0
- data/ext/libdatadog_api/feature_flags.c +554 -0
- data/ext/libdatadog_api/feature_flags.h +5 -0
- data/ext/libdatadog_api/init.c +5 -0
- data/ext/libdatadog_api/library_config.c +34 -25
- data/ext/libdatadog_api/process_discovery.c +19 -13
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +26 -0
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +59 -0
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +29 -0
- data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +26 -0
- data/lib/datadog/appsec/api_security/endpoint_collection.rb +10 -0
- data/lib/datadog/appsec/api_security/route_extractor.rb +23 -6
- data/lib/datadog/appsec/api_security/sampler.rb +7 -4
- data/lib/datadog/appsec/assets/blocked.html +8 -0
- data/lib/datadog/appsec/assets/blocked.json +1 -1
- data/lib/datadog/appsec/assets/blocked.text +3 -1
- data/lib/datadog/appsec/assets/waf_rules/README.md +30 -36
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +359 -4
- data/lib/datadog/appsec/assets/waf_rules/strict.json +43 -2
- data/lib/datadog/appsec/assets.rb +1 -1
- data/lib/datadog/appsec/compressed_json.rb +1 -1
- data/lib/datadog/appsec/configuration/settings.rb +9 -0
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +3 -1
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +3 -2
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +3 -1
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +3 -1
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +9 -4
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +5 -1
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +7 -2
- data/lib/datadog/appsec/contrib/rails/patcher.rb +30 -0
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +3 -1
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +10 -4
- data/lib/datadog/appsec/event.rb +12 -14
- data/lib/datadog/appsec/metrics/collector.rb +19 -3
- data/lib/datadog/appsec/metrics/telemetry_exporter.rb +2 -1
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +4 -4
- data/lib/datadog/appsec/remote.rb +29 -13
- data/lib/datadog/appsec/response.rb +18 -4
- data/lib/datadog/appsec/security_engine/result.rb +28 -9
- data/lib/datadog/appsec/security_engine/runner.rb +17 -7
- data/lib/datadog/appsec/security_event.rb +5 -7
- data/lib/datadog/core/configuration/components.rb +44 -9
- data/lib/datadog/core/configuration/config_helper.rb +1 -1
- data/lib/datadog/core/configuration/settings.rb +14 -0
- data/lib/datadog/core/configuration/stable_config.rb +10 -0
- data/lib/datadog/core/configuration/supported_configurations.rb +330 -299
- data/lib/datadog/core/configuration.rb +1 -1
- data/lib/datadog/core/ddsketch.rb +19 -0
- data/lib/datadog/core/environment/ext.rb +6 -0
- data/lib/datadog/core/environment/process.rb +79 -0
- data/lib/datadog/core/environment/yjit.rb +2 -1
- data/lib/datadog/core/feature_flags.rb +61 -0
- data/lib/datadog/core/pin.rb +4 -8
- data/lib/datadog/core/process_discovery.rb +4 -2
- data/lib/datadog/core/remote/client/capabilities.rb +7 -0
- data/lib/datadog/core/remote/component.rb +4 -6
- data/lib/datadog/core/remote/transport/config.rb +2 -10
- data/lib/datadog/core/remote/transport/http/config.rb +9 -9
- data/lib/datadog/core/remote/transport/http/negotiation.rb +17 -8
- data/lib/datadog/core/remote/transport/http.rb +2 -0
- data/lib/datadog/core/remote/transport/negotiation.rb +2 -18
- data/lib/datadog/core/remote/worker.rb +25 -37
- data/lib/datadog/core/tag_builder.rb +0 -4
- data/lib/datadog/core/tag_normalizer.rb +84 -0
- data/lib/datadog/core/telemetry/component.rb +18 -3
- data/lib/datadog/core/telemetry/emitter.rb +6 -6
- data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +30 -0
- data/lib/datadog/core/telemetry/event/app_started.rb +52 -49
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +1 -1
- data/lib/datadog/core/telemetry/event.rb +1 -0
- data/lib/datadog/core/telemetry/logger.rb +2 -2
- data/lib/datadog/core/telemetry/logging.rb +2 -8
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +5 -6
- data/lib/datadog/core/telemetry/transport/telemetry.rb +1 -2
- data/lib/datadog/core/transport/http/client.rb +69 -0
- data/lib/datadog/core/transport/response.rb +4 -1
- data/lib/datadog/core/utils/array.rb +29 -0
- data/lib/datadog/{appsec/api_security → core/utils}/lru_cache.rb +10 -21
- data/lib/datadog/core/utils/network.rb +22 -1
- data/lib/datadog/core/utils/only_once_successful.rb +6 -2
- data/lib/datadog/core/utils.rb +2 -0
- data/lib/datadog/data_streams/configuration/settings.rb +49 -0
- data/lib/datadog/data_streams/configuration.rb +11 -0
- data/lib/datadog/data_streams/ext.rb +11 -0
- data/lib/datadog/data_streams/extensions.rb +16 -0
- data/lib/datadog/data_streams/pathway_context.rb +169 -0
- data/lib/datadog/data_streams/processor.rb +509 -0
- data/lib/datadog/data_streams/transport/http/api.rb +33 -0
- data/lib/datadog/data_streams/transport/http/client.rb +21 -0
- data/lib/datadog/data_streams/transport/http/stats.rb +87 -0
- data/lib/datadog/data_streams/transport/http.rb +41 -0
- data/lib/datadog/data_streams/transport/stats.rb +60 -0
- data/lib/datadog/data_streams.rb +100 -0
- data/lib/datadog/di/boot.rb +1 -0
- data/lib/datadog/di/component.rb +14 -16
- data/lib/datadog/di/context.rb +70 -0
- data/lib/datadog/di/el/compiler.rb +164 -0
- data/lib/datadog/di/el/evaluator.rb +159 -0
- data/lib/datadog/di/el/expression.rb +42 -0
- data/lib/datadog/di/el.rb +5 -0
- data/lib/datadog/di/error.rb +29 -0
- data/lib/datadog/di/instrumenter.rb +163 -48
- data/lib/datadog/di/probe.rb +55 -15
- data/lib/datadog/di/probe_builder.rb +39 -1
- data/lib/datadog/di/probe_manager.rb +13 -4
- data/lib/datadog/di/probe_notification_builder.rb +105 -67
- data/lib/datadog/di/proc_responder.rb +32 -0
- data/lib/datadog/di/serializer.rb +151 -7
- data/lib/datadog/di/transport/diagnostics.rb +2 -2
- data/lib/datadog/di/transport/http/diagnostics.rb +2 -4
- data/lib/datadog/di/transport/http/input.rb +2 -4
- data/lib/datadog/di/transport/http.rb +6 -2
- data/lib/datadog/di/transport/input.rb +64 -4
- data/lib/datadog/open_feature/component.rb +60 -0
- data/lib/datadog/open_feature/configuration.rb +27 -0
- data/lib/datadog/open_feature/evaluation_engine.rb +69 -0
- data/lib/datadog/open_feature/exposures/batch_builder.rb +32 -0
- data/lib/datadog/open_feature/exposures/buffer.rb +43 -0
- data/lib/datadog/open_feature/exposures/deduplicator.rb +30 -0
- data/lib/datadog/open_feature/exposures/event.rb +60 -0
- data/lib/datadog/open_feature/exposures/reporter.rb +40 -0
- data/lib/datadog/open_feature/exposures/worker.rb +116 -0
- data/lib/datadog/open_feature/ext.rb +14 -0
- data/lib/datadog/open_feature/native_evaluator.rb +38 -0
- data/lib/datadog/open_feature/noop_evaluator.rb +26 -0
- data/lib/datadog/open_feature/provider.rb +141 -0
- data/lib/datadog/open_feature/remote.rb +74 -0
- data/lib/datadog/open_feature/resolution_details.rb +35 -0
- data/lib/datadog/open_feature/transport.rb +72 -0
- data/lib/datadog/open_feature.rb +19 -0
- data/lib/datadog/opentelemetry/configuration/settings.rb +159 -0
- data/lib/datadog/opentelemetry/metrics.rb +110 -0
- data/lib/datadog/opentelemetry/sdk/configurator.rb +25 -1
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +38 -0
- data/lib/datadog/opentelemetry.rb +3 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +15 -6
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +1 -1
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -1
- data/lib/datadog/profiling/profiler.rb +4 -0
- data/lib/datadog/profiling/tag_builder.rb +36 -3
- data/lib/datadog/profiling.rb +1 -2
- data/lib/datadog/single_step_instrument.rb +1 -1
- data/lib/datadog/tracing/component.rb +6 -17
- data/lib/datadog/tracing/configuration/dynamic.rb +2 -2
- data/lib/datadog/tracing/configuration/ext.rb +9 -0
- data/lib/datadog/tracing/configuration/settings.rb +77 -3
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +4 -4
- data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -2
- data/lib/datadog/tracing/contrib/active_job/log_injection.rb +21 -7
- data/lib/datadog/tracing/contrib/active_job/patcher.rb +5 -1
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +4 -2
- data/lib/datadog/tracing/contrib/component.rb +2 -2
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -1
- data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +11 -7
- data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +7 -3
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +7 -0
- data/lib/datadog/tracing/contrib/graphql/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +74 -44
- data/lib/datadog/tracing/contrib/http/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +66 -0
- data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +66 -0
- data/lib/datadog/tracing/contrib/kafka/patcher.rb +14 -0
- data/lib/datadog/tracing/contrib/karafka/framework.rb +30 -0
- data/lib/datadog/tracing/contrib/karafka/monitor.rb +11 -0
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +32 -0
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +59 -27
- data/lib/datadog/tracing/contrib/rack/route_inference.rb +53 -0
- data/lib/datadog/tracing/contrib/rails/middlewares.rb +2 -2
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +4 -1
- data/lib/datadog/tracing/contrib/roda/instrumentation.rb +3 -1
- data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +3 -1
- data/lib/datadog/tracing/contrib/status_range_matcher.rb +7 -0
- data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +27 -0
- data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +48 -0
- data/lib/datadog/tracing/contrib/waterdrop/ext.rb +17 -0
- data/lib/datadog/tracing/contrib/waterdrop/integration.rb +43 -0
- data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +46 -0
- data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +46 -0
- data/lib/datadog/tracing/contrib/waterdrop/producer.rb +50 -0
- data/lib/datadog/tracing/contrib/waterdrop.rb +37 -0
- data/lib/datadog/tracing/contrib.rb +1 -0
- data/lib/datadog/tracing/metadata/ext.rb +9 -1
- data/lib/datadog/tracing/transport/http/client.rb +12 -26
- data/lib/datadog/tracing/transport/trace_formatter.rb +11 -0
- data/lib/datadog/tracing/transport/traces.rb +3 -5
- data/lib/datadog/version.rb +2 -2
- data/lib/datadog.rb +2 -0
- metadata +92 -16
- data/ext/libdatadog_api/macos_development.md +0 -26
- data/lib/datadog/core/remote/transport/http/client.rb +0 -49
- data/lib/datadog/core/telemetry/transport/http/client.rb +0 -49
- data/lib/datadog/di/transport/http/client.rb +0 -47
|
@@ -11,7 +11,7 @@ static VALUE _native_configurator_get(VALUE self);
|
|
|
11
11
|
static VALUE _native_configurator_with_local_path(DDTRACE_UNUSED VALUE _self, VALUE rb_configurator, VALUE path);
|
|
12
12
|
static VALUE _native_configurator_with_fleet_path(DDTRACE_UNUSED VALUE _self, VALUE rb_configurator, VALUE path);
|
|
13
13
|
|
|
14
|
-
static VALUE
|
|
14
|
+
static VALUE config_logged_result_class = Qnil;
|
|
15
15
|
|
|
16
16
|
// ddog_Configurator memory management
|
|
17
17
|
static void configurator_free(void *configurator_ptr) {
|
|
@@ -29,29 +29,29 @@ static const rb_data_type_t configurator_typed_data = {
|
|
|
29
29
|
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
//
|
|
33
|
-
static void
|
|
34
|
-
|
|
32
|
+
// ddog_LibraryConfigLoggedResult memory management
|
|
33
|
+
static void config_logged_result_free(void *config_logged_result_ptr) {
|
|
34
|
+
ddog_LibraryConfigLoggedResult *config_logged_result = (ddog_LibraryConfigLoggedResult *)config_logged_result_ptr;
|
|
35
35
|
|
|
36
|
-
ddog_library_config_drop(*
|
|
37
|
-
ruby_xfree(
|
|
36
|
+
ddog_library_config_drop(*config_logged_result);
|
|
37
|
+
ruby_xfree(config_logged_result_ptr);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
static const rb_data_type_t
|
|
41
|
-
.wrap_struct_name = "Datadog::Core::Configuration::
|
|
40
|
+
static const rb_data_type_t config_logged_result_typed_data = {
|
|
41
|
+
.wrap_struct_name = "Datadog::Core::Configuration::StableConfigLoggedResult",
|
|
42
42
|
.function = {
|
|
43
|
-
.dfree =
|
|
43
|
+
.dfree = config_logged_result_free,
|
|
44
44
|
.dsize = NULL,
|
|
45
45
|
},
|
|
46
46
|
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
47
47
|
};
|
|
48
48
|
|
|
49
49
|
void library_config_init(VALUE core_module) {
|
|
50
|
-
rb_global_variable(&
|
|
50
|
+
rb_global_variable(&config_logged_result_class);
|
|
51
51
|
VALUE configuration_module = rb_define_module_under(core_module, "Configuration");
|
|
52
52
|
VALUE stable_config_module = rb_define_module_under(configuration_module, "StableConfig");
|
|
53
53
|
VALUE configurator_class = rb_define_class_under(stable_config_module, "Configurator", rb_cObject);
|
|
54
|
-
|
|
54
|
+
config_logged_result_class = rb_define_class_under(configuration_module, "StableConfigLoggedResult", rb_cObject);
|
|
55
55
|
|
|
56
56
|
rb_define_alloc_func(configurator_class, _native_configurator_new);
|
|
57
57
|
rb_define_method(configurator_class, "get", _native_configurator_get, 0);
|
|
@@ -61,11 +61,12 @@ void library_config_init(VALUE core_module) {
|
|
|
61
61
|
rb_define_singleton_method(testing_module, "with_local_path", _native_configurator_with_local_path, 2);
|
|
62
62
|
rb_define_singleton_method(testing_module, "with_fleet_path", _native_configurator_with_fleet_path, 2);
|
|
63
63
|
|
|
64
|
-
rb_undef_alloc_func(
|
|
64
|
+
rb_undef_alloc_func(config_logged_result_class); // It cannot be created from Ruby code and only serves as an intermediate object for the Ruby GC
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
static VALUE _native_configurator_new(VALUE klass) {
|
|
68
|
-
|
|
68
|
+
// We always collect debug logs, so if DD_TRACE_DEBUG is set by stable config, we'll be able to log them.
|
|
69
|
+
ddog_Configurator *configurator = ddog_library_configurator_new(true, DDOG_CHARSLICE_C("ruby"));
|
|
69
70
|
|
|
70
71
|
ddog_library_configurator_with_detect_process_info(configurator);
|
|
71
72
|
|
|
@@ -98,10 +99,11 @@ static VALUE _native_configurator_get(VALUE self) {
|
|
|
98
99
|
ddog_Configurator *configurator;
|
|
99
100
|
TypedData_Get_Struct(self, ddog_Configurator, &configurator_typed_data, configurator);
|
|
100
101
|
|
|
101
|
-
|
|
102
|
+
// We don't allocate memory here so if there is an error, we don't need to manage the memory
|
|
103
|
+
ddog_LibraryConfigLoggedResult before_error_result = ddog_library_configurator_get(configurator);
|
|
102
104
|
|
|
103
|
-
if (
|
|
104
|
-
ddog_Error err =
|
|
105
|
+
if (before_error_result.tag == DDOG_LIBRARY_CONFIG_LOGGED_RESULT_ERR) {
|
|
106
|
+
ddog_Error err = before_error_result.err;
|
|
105
107
|
VALUE message = get_error_details_and_drop(&err);
|
|
106
108
|
if (is_config_loaded()) {
|
|
107
109
|
log_warning(message);
|
|
@@ -111,14 +113,20 @@ static VALUE _native_configurator_get(VALUE self) {
|
|
|
111
113
|
return rb_hash_new();
|
|
112
114
|
}
|
|
113
115
|
|
|
114
|
-
// Wrapping
|
|
115
|
-
// We need to allocate memory for
|
|
116
|
-
// So we cannot reference it with &config_vec
|
|
116
|
+
// Wrapping config_logged_result into a Ruby object enables the Ruby GC to manage its memory
|
|
117
|
+
// We need to allocate memory for config_logged_result because once it is out of scope, it will be freed (at the end of this function)
|
|
117
118
|
// We are doing this in case one of the ruby API raises an exception before the end of this function,
|
|
118
119
|
// so the allocated memory will still be freed
|
|
119
|
-
|
|
120
|
-
*
|
|
121
|
-
VALUE
|
|
120
|
+
ddog_LibraryConfigLoggedResult *configurator_logged_result = ruby_xcalloc(1, sizeof(ddog_LibraryConfigLoggedResult));
|
|
121
|
+
*configurator_logged_result = before_error_result;
|
|
122
|
+
VALUE config_logged_result_rb = TypedData_Wrap_Struct(config_logged_result_class, &config_logged_result_typed_data, configurator_logged_result);
|
|
123
|
+
|
|
124
|
+
VALUE logs = Qnil;
|
|
125
|
+
if (configurator_logged_result->ok.logs.length > 0) {
|
|
126
|
+
logs = rb_utf8_str_new_cstr(configurator_logged_result->ok.logs.ptr);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
ddog_Vec_LibraryConfig config_vec = configurator_logged_result->ok.value;
|
|
122
130
|
|
|
123
131
|
VALUE local_config_hash = rb_hash_new();
|
|
124
132
|
VALUE fleet_config_hash = rb_hash_new();
|
|
@@ -127,8 +135,8 @@ static VALUE _native_configurator_get(VALUE self) {
|
|
|
127
135
|
bool fleet_config_id_set = false;
|
|
128
136
|
VALUE local_hash = rb_hash_new();
|
|
129
137
|
VALUE fleet_hash = rb_hash_new();
|
|
130
|
-
for (uintptr_t i = 0; i < config_vec
|
|
131
|
-
ddog_LibraryConfig config = config_vec
|
|
138
|
+
for (uintptr_t i = 0; i < config_vec.len; i++) {
|
|
139
|
+
ddog_LibraryConfig config = config_vec.ptr[i];
|
|
132
140
|
VALUE selected_hash;
|
|
133
141
|
if (config.source == DDOG_LIBRARY_CONFIG_SOURCE_LOCAL_STABLE_CONFIG) {
|
|
134
142
|
selected_hash = local_config_hash;
|
|
@@ -156,9 +164,10 @@ static VALUE _native_configurator_get(VALUE self) {
|
|
|
156
164
|
rb_hash_aset(fleet_hash, ID2SYM(rb_intern("config")), fleet_config_hash);
|
|
157
165
|
|
|
158
166
|
VALUE result = rb_hash_new();
|
|
167
|
+
rb_hash_aset(result, ID2SYM(rb_intern("logs")), logs);
|
|
159
168
|
rb_hash_aset(result, ID2SYM(rb_intern("local")), local_hash);
|
|
160
169
|
rb_hash_aset(result, ID2SYM(rb_intern("fleet")), fleet_hash);
|
|
161
170
|
|
|
162
|
-
RB_GC_GUARD(
|
|
171
|
+
RB_GC_GUARD(config_logged_result_rb);
|
|
163
172
|
return result;
|
|
164
173
|
}
|
|
@@ -42,7 +42,6 @@ static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, VALUE self) {
|
|
|
42
42
|
rb_scan_args(argc, argv, "1:", &logger, &options);
|
|
43
43
|
if (options == Qnil) options = rb_hash_new();
|
|
44
44
|
|
|
45
|
-
VALUE schema_version = rb_hash_fetch(options, ID2SYM(rb_intern("schema_version")));
|
|
46
45
|
VALUE runtime_id = rb_hash_fetch(options, ID2SYM(rb_intern("runtime_id")));
|
|
47
46
|
VALUE tracer_language = rb_hash_fetch(options, ID2SYM(rb_intern("tracer_language")));
|
|
48
47
|
VALUE tracer_version = rb_hash_fetch(options, ID2SYM(rb_intern("tracer_version")));
|
|
@@ -50,8 +49,9 @@ static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, VALUE self) {
|
|
|
50
49
|
VALUE service_name = rb_hash_fetch(options, ID2SYM(rb_intern("service_name")));
|
|
51
50
|
VALUE service_env = rb_hash_fetch(options, ID2SYM(rb_intern("service_env")));
|
|
52
51
|
VALUE service_version = rb_hash_fetch(options, ID2SYM(rb_intern("service_version")));
|
|
52
|
+
VALUE process_tags = rb_hash_fetch(options, ID2SYM(rb_intern("process_tags")));
|
|
53
|
+
VALUE container_id = rb_hash_fetch(options, ID2SYM(rb_intern("container_id")));
|
|
53
54
|
|
|
54
|
-
ENFORCE_TYPE(schema_version, T_FIXNUM);
|
|
55
55
|
ENFORCE_TYPE(runtime_id, T_STRING);
|
|
56
56
|
ENFORCE_TYPE(tracer_language, T_STRING);
|
|
57
57
|
ENFORCE_TYPE(tracer_version, T_STRING);
|
|
@@ -59,17 +59,23 @@ static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, VALUE self) {
|
|
|
59
59
|
ENFORCE_TYPE(service_name, T_STRING);
|
|
60
60
|
ENFORCE_TYPE(service_env, T_STRING);
|
|
61
61
|
ENFORCE_TYPE(service_version, T_STRING);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
);
|
|
62
|
+
ENFORCE_TYPE(process_tags, T_STRING);
|
|
63
|
+
ENFORCE_TYPE(container_id, T_STRING);
|
|
64
|
+
|
|
65
|
+
void* builder = ddog_tracer_metadata_new();
|
|
66
|
+
|
|
67
|
+
ddog_tracer_metadata_set(builder, DDOG_METADATA_KIND_RUNTIME_ID, StringValueCStr(runtime_id));
|
|
68
|
+
ddog_tracer_metadata_set(builder, DDOG_METADATA_KIND_TRACER_LANGUAGE, StringValueCStr(tracer_language));
|
|
69
|
+
ddog_tracer_metadata_set(builder, DDOG_METADATA_KIND_TRACER_VERSION, StringValueCStr(tracer_version));
|
|
70
|
+
ddog_tracer_metadata_set(builder, DDOG_METADATA_KIND_HOSTNAME, StringValueCStr(hostname));
|
|
71
|
+
ddog_tracer_metadata_set(builder, DDOG_METADATA_KIND_SERVICE_NAME, StringValueCStr(service_name));
|
|
72
|
+
ddog_tracer_metadata_set(builder, DDOG_METADATA_KIND_SERVICE_ENV, StringValueCStr(service_env));
|
|
73
|
+
ddog_tracer_metadata_set(builder, DDOG_METADATA_KIND_SERVICE_VERSION, StringValueCStr(service_version));
|
|
74
|
+
ddog_tracer_metadata_set(builder, DDOG_METADATA_KIND_PROCESS_TAGS, StringValueCStr(process_tags));
|
|
75
|
+
ddog_tracer_metadata_set(builder, DDOG_METADATA_KIND_CONTAINER_ID, StringValueCStr(container_id));
|
|
76
|
+
|
|
77
|
+
ddog_Result_TracerMemfdHandle result = ddog_tracer_metadata_store(builder);
|
|
78
|
+
ddog_tracer_metadata_free(builder);
|
|
73
79
|
|
|
74
80
|
if (result.tag == DDOG_RESULT_TRACER_MEMFD_HANDLE_ERR_TRACER_MEMFD_HANDLE) {
|
|
75
81
|
rb_funcall(logger, rb_intern("debug"), 1, rb_sprintf("Failed to store the tracer configuration in a memory file descriptor: %"PRIsVALUE, get_error_details_and_drop(&result.err)));
|
|
@@ -10,7 +10,7 @@ module Datadog
|
|
|
10
10
|
module LibdatadogExtconfHelpers
|
|
11
11
|
# Used to make sure the correct gem version gets loaded, as extconf.rb does not get run with "bundle exec" and thus
|
|
12
12
|
# may see multiple libdatadog versions. See https://github.com/DataDog/dd-trace-rb/pull/2531 for the horror story.
|
|
13
|
-
LIBDATADOG_VERSION = '~>
|
|
13
|
+
LIBDATADOG_VERSION = '~> 24.0.1.1.0'
|
|
14
14
|
|
|
15
15
|
# Used as an workaround for a limitation with how dynamic linking works in environments where the datadog gem and
|
|
16
16
|
# libdatadog are moved after the extension gets compiled.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module AppSec
|
|
5
|
+
module APISecurity
|
|
6
|
+
module EndpointCollection
|
|
7
|
+
# This module serializes Grape routes.
|
|
8
|
+
module GrapeRouteSerializer
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def serialize(route, path_prefix: '')
|
|
12
|
+
path = path_prefix + route.pattern.origin
|
|
13
|
+
|
|
14
|
+
{
|
|
15
|
+
type: "REST",
|
|
16
|
+
resource_name: "#{route.request_method} #{path}",
|
|
17
|
+
operation_name: "http.request",
|
|
18
|
+
method: route.request_method,
|
|
19
|
+
path: path
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'rails_route_serializer'
|
|
4
|
+
require_relative 'grape_route_serializer'
|
|
5
|
+
require_relative 'sinatra_route_serializer'
|
|
6
|
+
|
|
7
|
+
module Datadog
|
|
8
|
+
module AppSec
|
|
9
|
+
module APISecurity
|
|
10
|
+
module EndpointCollection
|
|
11
|
+
# This class works with a collection of rails routes
|
|
12
|
+
# and produces an Enumerator that yields serialized endpoints.
|
|
13
|
+
class RailsCollector
|
|
14
|
+
def initialize(routes)
|
|
15
|
+
@routes = routes
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_enum
|
|
19
|
+
Enumerator.new do |yielder|
|
|
20
|
+
@routes.each do |route|
|
|
21
|
+
if route.dispatcher?
|
|
22
|
+
yielder.yield RailsRouteSerializer.serialize(route)
|
|
23
|
+
elsif mounted_grape_app?(route.app.rack_app)
|
|
24
|
+
route.app.rack_app.routes.each do |grape_route|
|
|
25
|
+
yielder.yield GrapeRouteSerializer.serialize(grape_route, path_prefix: route.path.spec.to_s)
|
|
26
|
+
end
|
|
27
|
+
elsif mounted_sinatra_app?(route.app.rack_app)
|
|
28
|
+
route.app.rack_app.routes.each do |method, sinatra_routes|
|
|
29
|
+
next if method == 'HEAD'
|
|
30
|
+
|
|
31
|
+
sinatra_routes.each do |sinatra_route, _, _|
|
|
32
|
+
yielder.yield SinatraRouteSerializer.serialize(
|
|
33
|
+
sinatra_route, method: method, path_prefix: route.path.spec.to_s
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def mounted_grape_app?(rack_app)
|
|
45
|
+
return false unless defined?(::Grape::API)
|
|
46
|
+
|
|
47
|
+
rack_app.is_a?(Class) && rack_app < ::Grape::API
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def mounted_sinatra_app?(rack_app)
|
|
51
|
+
return false unless defined?(::Sinatra::Base)
|
|
52
|
+
|
|
53
|
+
rack_app.is_a?(Class) && rack_app < ::Sinatra::Base
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module AppSec
|
|
5
|
+
module APISecurity
|
|
6
|
+
module EndpointCollection
|
|
7
|
+
# This module serializes Rails Journey Router routes.
|
|
8
|
+
module RailsRouteSerializer
|
|
9
|
+
FORMAT_SUFFIX = "(.:format)"
|
|
10
|
+
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def serialize(route)
|
|
14
|
+
method = route.verb.empty? ? "*" : route.verb
|
|
15
|
+
path = route.path.spec.to_s.delete_suffix(FORMAT_SUFFIX)
|
|
16
|
+
|
|
17
|
+
{
|
|
18
|
+
type: "REST",
|
|
19
|
+
resource_name: "#{method} #{path}",
|
|
20
|
+
operation_name: "http.request",
|
|
21
|
+
method: method,
|
|
22
|
+
path: path
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module AppSec
|
|
5
|
+
module APISecurity
|
|
6
|
+
module EndpointCollection
|
|
7
|
+
# This module serializes Sinatra routes.
|
|
8
|
+
module SinatraRouteSerializer
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def serialize(route, method:, path_prefix: '')
|
|
12
|
+
path = path_prefix + route.safe_string
|
|
13
|
+
|
|
14
|
+
{
|
|
15
|
+
type: "REST",
|
|
16
|
+
resource_name: "#{method} #{path}",
|
|
17
|
+
operation_name: "http.request",
|
|
18
|
+
method: method,
|
|
19
|
+
path: path
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../../tracing/contrib/rack/route_inference'
|
|
4
|
+
|
|
3
5
|
module Datadog
|
|
4
6
|
module AppSec
|
|
5
7
|
module APISecurity
|
|
@@ -8,7 +10,8 @@ module Datadog
|
|
|
8
10
|
SINATRA_ROUTE_KEY = 'sinatra.route'
|
|
9
11
|
SINATRA_ROUTE_SEPARATOR = ' '
|
|
10
12
|
GRAPE_ROUTE_KEY = 'grape.routing_args'
|
|
11
|
-
|
|
13
|
+
RAILS_ROUTE_URI_PATTERN_KEY = 'action_dispatch.route_uri_pattern'
|
|
14
|
+
RAILS_ROUTE_KEY = 'action_dispatch.route' # Rails 8.1.1+
|
|
12
15
|
RAILS_ROUTES_KEY = 'action_dispatch.routes'
|
|
13
16
|
RAILS_PATH_PARAMS_KEY = 'action_dispatch.request.path_parameters'
|
|
14
17
|
RAILS_FORMAT_SUFFIX = '(.:format)'
|
|
@@ -35,6 +38,9 @@ module Datadog
|
|
|
35
38
|
# Rails > 7.1 (fast path)
|
|
36
39
|
# uses `action_dispatch.route_uri_pattern` with a string like
|
|
37
40
|
# "/users/:id(.:format)"
|
|
41
|
+
# Rails > 8.1.1 (fast path)
|
|
42
|
+
# uses `action_dispatch.route` to store the ActionDispatch::Journey::Route
|
|
43
|
+
# that matched when the request was routed
|
|
38
44
|
#
|
|
39
45
|
# WARNING: This method works only *after* the request has been routed.
|
|
40
46
|
#
|
|
@@ -50,11 +56,18 @@ module Datadog
|
|
|
50
56
|
pattern = request.env[SINATRA_ROUTE_KEY].split(SINATRA_ROUTE_SEPARATOR, 2)[1]
|
|
51
57
|
"#{request.script_name}#{pattern}"
|
|
52
58
|
elsif request.env.key?(RAILS_ROUTE_KEY)
|
|
53
|
-
request.env[RAILS_ROUTE_KEY].delete_suffix(RAILS_FORMAT_SUFFIX)
|
|
59
|
+
request.env[RAILS_ROUTE_KEY].path.spec.to_s.delete_suffix(RAILS_FORMAT_SUFFIX)
|
|
60
|
+
elsif request.env.key?(RAILS_ROUTE_URI_PATTERN_KEY)
|
|
61
|
+
request.env[RAILS_ROUTE_URI_PATTERN_KEY].delete_suffix(RAILS_FORMAT_SUFFIX)
|
|
54
62
|
elsif request.env.key?(RAILS_ROUTES_KEY) && !request.env.fetch(RAILS_PATH_PARAMS_KEY, {}).empty?
|
|
55
|
-
# NOTE: Rails
|
|
56
|
-
#
|
|
57
|
-
|
|
63
|
+
# NOTE: In Rails < 7.1 this `request` argument will be a Rack::Request,
|
|
64
|
+
# it does not have all the methods that ActionDispatch::Request has.
|
|
65
|
+
# Before trying to use the router to recognize the route, we need to
|
|
66
|
+
# create a new ActionDispatch::Request from the request env
|
|
67
|
+
#
|
|
68
|
+
# NOTE: Rails mutates HEAD request by changing the method to GET
|
|
69
|
+
# and uses it for route recognition to check if the route is defined
|
|
70
|
+
request = request.env[RAILS_ROUTES_KEY].request_class.new(request.env)
|
|
58
71
|
|
|
59
72
|
pattern = request.env[RAILS_ROUTES_KEY].router
|
|
60
73
|
.recognize(request) { |route, _| break route.path.spec.to_s }
|
|
@@ -66,8 +79,12 @@ module Datadog
|
|
|
66
79
|
# to generic request path
|
|
67
80
|
(pattern || request.path).delete_suffix(RAILS_FORMAT_SUFFIX)
|
|
68
81
|
else
|
|
69
|
-
request.
|
|
82
|
+
Tracing::Contrib::Rack::RouteInference.read_or_infer(request.env)
|
|
70
83
|
end
|
|
84
|
+
rescue => e
|
|
85
|
+
AppSec.telemetry&.report(e, description: 'AppSec: Could not extract route pattern')
|
|
86
|
+
|
|
87
|
+
nil
|
|
71
88
|
end
|
|
72
89
|
end
|
|
73
90
|
end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'zlib'
|
|
4
|
-
require_relative 'lru_cache'
|
|
5
4
|
require_relative 'route_extractor'
|
|
6
5
|
require_relative '../../core/utils/time'
|
|
6
|
+
require_relative '../../core/utils/lru_cache'
|
|
7
7
|
|
|
8
8
|
module Datadog
|
|
9
9
|
module AppSec
|
|
@@ -37,20 +37,23 @@ module Datadog
|
|
|
37
37
|
def initialize(sample_delay)
|
|
38
38
|
raise ArgumentError, 'sample_delay must be an Integer' unless sample_delay.is_a?(Integer)
|
|
39
39
|
|
|
40
|
-
@cache = LRUCache.new(MAX_CACHE_SIZE)
|
|
40
|
+
@cache = Core::Utils::LRUCache.new(MAX_CACHE_SIZE)
|
|
41
41
|
@sample_delay_seconds = sample_delay
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def sample?(request, response)
|
|
45
45
|
return true if @sample_delay_seconds.zero?
|
|
46
|
+
return false if response.status == 404
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
route_pattern = RouteExtractor.route_pattern(request).to_s
|
|
49
|
+
|
|
50
|
+
key = Zlib.crc32("#{request.request_method}#{route_pattern}#{response.status}")
|
|
48
51
|
current_timestamp = Core::Utils::Time.now.to_i
|
|
49
52
|
cached_timestamp = @cache[key] || 0
|
|
50
53
|
|
|
51
54
|
return false if current_timestamp - cached_timestamp <= @sample_delay_seconds
|
|
52
55
|
|
|
53
|
-
@cache
|
|
56
|
+
@cache[key] = current_timestamp
|
|
54
57
|
true
|
|
55
58
|
end
|
|
56
59
|
end
|
|
@@ -82,12 +82,20 @@
|
|
|
82
82
|
footer p {
|
|
83
83
|
font-size: 16px
|
|
84
84
|
}
|
|
85
|
+
|
|
86
|
+
.security-response-id {
|
|
87
|
+
font-size:14px;
|
|
88
|
+
color:#999;
|
|
89
|
+
margin-top:20px;
|
|
90
|
+
font-family:monospace
|
|
91
|
+
}
|
|
85
92
|
</style>
|
|
86
93
|
</head>
|
|
87
94
|
|
|
88
95
|
<body>
|
|
89
96
|
<main>
|
|
90
97
|
<p>Sorry, you cannot access this page. Please contact the customer service team.</p>
|
|
98
|
+
<p class="security-response-id">Security Response ID: [security_response_id]</p>
|
|
91
99
|
</main>
|
|
92
100
|
<footer>
|
|
93
101
|
<p>Security provided by <a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"errors":
|
|
1
|
+
{"errors":[{"title":"You've been blocked","detail":"Sorry, you cannot access this page. Please contact the customer service team. Security provided by Datadog."}],"security_response_id":"[security_response_id]"}
|
|
@@ -2,51 +2,45 @@ AppSec WAF rules based on [appsec-event-rules](https://github.com/datadog/appsec
|
|
|
2
2
|
|
|
3
3
|
## How to update
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
> This process is a temporary workaround to maintain compatibility with the existing code structure and will be changed.
|
|
5
|
+
In order to update rules, download `recommended.json` and `strict.json` of the desired version from [appsec-event-rules](https://github.com/datadog/appsec-event-rules) (example: [v1.13.3](https://github.com/DataDog/appsec-event-rules/tree/1.13.3/build))
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
2. Run the script below inside `waf_rules` folder to extract scanners and processors into separate files
|
|
7
|
+
You can store the following code as a `Rakefile` under `lib/datadog/appsec/assets/waf_rules`
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
```ruby
|
|
10
|
+
def download(filename)
|
|
11
|
+
build_path = 'repos/DataDog/appsec-event-rules/contents/build'
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
system("gh api #{build_path}/#{filename} --jq '.content' | base64 -d > #{filename}")
|
|
14
|
+
end
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
strict_processors = strict_rules.delete('processors')
|
|
16
|
+
task default: :update
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
raise 'Processors are not the same, unable to extract them'
|
|
23
|
-
end
|
|
18
|
+
task :verify_dependencies do
|
|
19
|
+
next if system('which gh 1>/dev/null')
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
abort <<~MESSAGE
|
|
22
|
+
\033[0;33mNOTE: To successfully execute that task make sure you have
|
|
23
|
+
GitHub CLI installed and authenticated https://cli.github.com/\033[0m
|
|
24
|
+
MESSAGE
|
|
25
|
+
end
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
desc 'Update recommended.json and strict.json to the latest version'
|
|
28
|
+
task update: :verify_dependencies do
|
|
29
|
+
download('strict.json')
|
|
30
|
+
download('recommended.json')
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
end
|
|
32
|
+
puts "\033[0;32mSuccess!\033[0m"
|
|
33
|
+
end
|
|
34
|
+
```
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
File.open(File.expand_path('scanners.json', __dir__), 'wb') do |file|
|
|
40
|
-
file.write(JSON.pretty_generate(recommended_scanners))
|
|
41
|
-
end
|
|
36
|
+
And run the following command
|
|
42
37
|
|
|
43
|
-
|
|
38
|
+
> [!IMPORTANT]
|
|
39
|
+
> To run that command you will need to install GitHub CLI tool and authenticate it
|
|
40
|
+
> See: https://cli.github.com/ (or ddtool)
|
|
44
41
|
|
|
45
|
-
File.open(File.expand_path('recommended.json', __dir__), 'wb') do |file|
|
|
46
|
-
file.write(JSON.pretty_generate(recommended_rules))
|
|
47
|
-
end
|
|
48
42
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
43
|
+
```console
|
|
44
|
+
$ bundle exec rake update
|
|
45
|
+
Success!
|
|
46
|
+
```
|