datadog 2.16.0 → 2.18.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.
Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -1
  3. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +12 -46
  4. data/ext/datadog_profiling_native_extension/collectors_stack.c +227 -49
  5. data/ext/datadog_profiling_native_extension/collectors_stack.h +19 -3
  6. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +63 -12
  7. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
  8. data/ext/datadog_profiling_native_extension/encoded_profile.c +22 -12
  9. data/ext/datadog_profiling_native_extension/encoded_profile.h +1 -0
  10. data/ext/datadog_profiling_native_extension/extconf.rb +7 -0
  11. data/ext/datadog_profiling_native_extension/heap_recorder.c +239 -363
  12. data/ext/datadog_profiling_native_extension/heap_recorder.h +4 -6
  13. data/ext/datadog_profiling_native_extension/http_transport.c +45 -72
  14. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +22 -0
  15. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +8 -5
  16. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +1 -0
  17. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +6 -3
  18. data/ext/datadog_profiling_native_extension/ruby_helpers.c +1 -13
  19. data/ext/datadog_profiling_native_extension/ruby_helpers.h +2 -10
  20. data/ext/datadog_profiling_native_extension/stack_recorder.c +156 -60
  21. data/ext/libdatadog_api/crashtracker.c +10 -3
  22. data/ext/libdatadog_api/extconf.rb +2 -2
  23. data/ext/libdatadog_api/library_config.c +54 -12
  24. data/ext/libdatadog_api/library_config.h +6 -0
  25. data/ext/libdatadog_api/macos_development.md +3 -3
  26. data/ext/libdatadog_api/process_discovery.c +2 -7
  27. data/ext/libdatadog_extconf_helpers.rb +2 -2
  28. data/lib/datadog/appsec/api_security/lru_cache.rb +56 -0
  29. data/lib/datadog/appsec/api_security/route_extractor.rb +65 -0
  30. data/lib/datadog/appsec/api_security/sampler.rb +59 -0
  31. data/lib/datadog/appsec/api_security.rb +23 -0
  32. data/lib/datadog/appsec/assets/waf_rules/recommended.json +257 -85
  33. data/lib/datadog/appsec/assets/waf_rules/strict.json +10 -78
  34. data/lib/datadog/appsec/component.rb +30 -54
  35. data/lib/datadog/appsec/configuration/settings.rb +60 -2
  36. data/lib/datadog/appsec/context.rb +6 -6
  37. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +1 -1
  38. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +27 -16
  39. data/lib/datadog/appsec/processor/rule_loader.rb +5 -6
  40. data/lib/datadog/appsec/remote.rb +15 -55
  41. data/lib/datadog/appsec/security_engine/engine.rb +194 -0
  42. data/lib/datadog/appsec/security_engine/runner.rb +10 -11
  43. data/lib/datadog/appsec.rb +4 -7
  44. data/lib/datadog/core/buffer/random.rb +18 -2
  45. data/lib/datadog/core/configuration/agent_settings.rb +52 -0
  46. data/lib/datadog/core/configuration/agent_settings_resolver.rb +4 -46
  47. data/lib/datadog/core/configuration/components.rb +31 -24
  48. data/lib/datadog/core/configuration/components_state.rb +23 -0
  49. data/lib/datadog/core/configuration/option.rb +27 -27
  50. data/lib/datadog/core/configuration/option_definition.rb +4 -4
  51. data/lib/datadog/core/configuration/options.rb +1 -1
  52. data/lib/datadog/core/configuration/settings.rb +32 -20
  53. data/lib/datadog/core/configuration/stable_config.rb +1 -2
  54. data/lib/datadog/core/configuration.rb +16 -16
  55. data/lib/datadog/core/crashtracking/component.rb +2 -1
  56. data/lib/datadog/core/crashtracking/tag_builder.rb +4 -22
  57. data/lib/datadog/core/encoding.rb +1 -1
  58. data/lib/datadog/core/environment/cgroup.rb +10 -12
  59. data/lib/datadog/core/environment/container.rb +38 -40
  60. data/lib/datadog/core/environment/ext.rb +6 -6
  61. data/lib/datadog/core/environment/identity.rb +3 -3
  62. data/lib/datadog/core/environment/platform.rb +3 -3
  63. data/lib/datadog/core/error.rb +11 -9
  64. data/lib/datadog/core/logger.rb +2 -2
  65. data/lib/datadog/core/metrics/client.rb +12 -14
  66. data/lib/datadog/core/metrics/logging.rb +5 -5
  67. data/lib/datadog/core/process_discovery/tracer_memfd.rb +15 -0
  68. data/lib/datadog/core/process_discovery.rb +5 -1
  69. data/lib/datadog/core/rate_limiter.rb +4 -2
  70. data/lib/datadog/core/remote/client.rb +32 -31
  71. data/lib/datadog/core/remote/component.rb +3 -3
  72. data/lib/datadog/core/remote/configuration/digest.rb +7 -7
  73. data/lib/datadog/core/remote/configuration/path.rb +1 -1
  74. data/lib/datadog/core/remote/configuration/repository.rb +12 -0
  75. data/lib/datadog/core/remote/transport/http/client.rb +1 -1
  76. data/lib/datadog/core/remote/transport/http/config.rb +21 -5
  77. data/lib/datadog/core/remote/transport/http/negotiation.rb +1 -1
  78. data/lib/datadog/core/runtime/metrics.rb +3 -3
  79. data/lib/datadog/core/tag_builder.rb +56 -0
  80. data/lib/datadog/core/telemetry/component.rb +39 -24
  81. data/lib/datadog/core/telemetry/emitter.rb +7 -1
  82. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +66 -0
  83. data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
  84. data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
  85. data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
  86. data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
  87. data/lib/datadog/core/telemetry/event/app_started.rb +269 -0
  88. data/lib/datadog/core/telemetry/event/base.rb +40 -0
  89. data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
  90. data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
  91. data/lib/datadog/core/telemetry/event/log.rb +76 -0
  92. data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
  93. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +43 -0
  94. data/lib/datadog/core/telemetry/event.rb +17 -475
  95. data/lib/datadog/core/telemetry/logger.rb +5 -4
  96. data/lib/datadog/core/telemetry/logging.rb +11 -5
  97. data/lib/datadog/core/telemetry/metric.rb +3 -3
  98. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +2 -2
  99. data/lib/datadog/core/telemetry/transport/telemetry.rb +0 -1
  100. data/lib/datadog/core/telemetry/worker.rb +48 -27
  101. data/lib/datadog/core/transport/http/adapters/net.rb +17 -2
  102. data/lib/datadog/core/transport/http/adapters/test.rb +2 -1
  103. data/lib/datadog/core/transport/http/builder.rb +14 -14
  104. data/lib/datadog/core/transport/http/env.rb +8 -0
  105. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +6 -6
  106. data/lib/datadog/core/utils/duration.rb +32 -32
  107. data/lib/datadog/core/utils/forking.rb +2 -2
  108. data/lib/datadog/core/utils/network.rb +6 -6
  109. data/lib/datadog/core/utils/only_once_successful.rb +16 -5
  110. data/lib/datadog/core/utils/time.rb +10 -2
  111. data/lib/datadog/core/utils/truncation.rb +21 -0
  112. data/lib/datadog/core/utils.rb +7 -0
  113. data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
  114. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
  115. data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
  116. data/lib/datadog/core/worker.rb +1 -1
  117. data/lib/datadog/core/workers/async.rb +9 -10
  118. data/lib/datadog/di/instrumenter.rb +52 -2
  119. data/lib/datadog/di/probe_notification_builder.rb +31 -41
  120. data/lib/datadog/di/probe_notifier_worker.rb +9 -1
  121. data/lib/datadog/di/serializer.rb +6 -2
  122. data/lib/datadog/di/transport/http/input.rb +10 -0
  123. data/lib/datadog/di/transport/input.rb +10 -2
  124. data/lib/datadog/error_tracking/component.rb +2 -2
  125. data/lib/datadog/profiling/collectors/code_provenance.rb +18 -9
  126. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +4 -0
  127. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
  128. data/lib/datadog/profiling/collectors/thread_context.rb +16 -1
  129. data/lib/datadog/profiling/component.rb +7 -9
  130. data/lib/datadog/profiling/ext.rb +0 -13
  131. data/lib/datadog/profiling/flush.rb +1 -1
  132. data/lib/datadog/profiling/http_transport.rb +3 -8
  133. data/lib/datadog/profiling/profiler.rb +2 -0
  134. data/lib/datadog/profiling/scheduler.rb +10 -2
  135. data/lib/datadog/profiling/stack_recorder.rb +5 -5
  136. data/lib/datadog/profiling/tag_builder.rb +5 -41
  137. data/lib/datadog/profiling/tasks/setup.rb +2 -0
  138. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +15 -0
  139. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +19 -12
  140. data/lib/datadog/tracing/contrib/action_pack/ext.rb +2 -0
  141. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +4 -1
  142. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +33 -0
  143. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -0
  144. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +2 -4
  145. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +10 -0
  146. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +5 -1
  147. data/lib/datadog/tracing/contrib/http/instrumentation.rb +1 -5
  148. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +1 -5
  149. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +1 -5
  150. data/lib/datadog/tracing/contrib/lograge/patcher.rb +4 -2
  151. data/lib/datadog/tracing/contrib/patcher.rb +5 -2
  152. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +1 -0
  153. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -2
  154. data/lib/datadog/tracing/contrib/support.rb +28 -0
  155. data/lib/datadog/tracing/metadata/errors.rb +4 -4
  156. data/lib/datadog/tracing/sync_writer.rb +1 -1
  157. data/lib/datadog/tracing/trace_operation.rb +12 -4
  158. data/lib/datadog/tracing/tracer.rb +6 -2
  159. data/lib/datadog/version.rb +1 -1
  160. metadata +31 -12
  161. data/lib/datadog/appsec/assets/waf_rules/processors.json +0 -321
  162. data/lib/datadog/appsec/assets/waf_rules/scanners.json +0 -1023
  163. data/lib/datadog/appsec/processor/rule_merger.rb +0 -171
  164. data/lib/datadog/appsec/processor.rb +0 -107
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "2.2",
3
3
  "metadata": {
4
- "rules_version": "1.13.3"
4
+ "rules_version": "1.14.2"
5
5
  },
6
6
  "rules": [
7
7
  {
@@ -1750,24 +1750,7 @@
1750
1750
  {
1751
1751
  "id": "http-endpoint-fingerprint",
1752
1752
  "generator": "http_endpoint_fingerprint",
1753
- "conditions": [
1754
- {
1755
- "operator": "exists",
1756
- "parameters": {
1757
- "inputs": [
1758
- {
1759
- "address": "waf.context.event"
1760
- },
1761
- {
1762
- "address": "server.business_logic.users.login.failure"
1763
- },
1764
- {
1765
- "address": "server.business_logic.users.login.success"
1766
- }
1767
- ]
1768
- }
1769
- }
1770
- ],
1753
+ "conditions": [],
1771
1754
  "parameters": {
1772
1755
  "mappings": [
1773
1756
  {
@@ -1795,7 +1778,7 @@
1795
1778
  }
1796
1779
  ]
1797
1780
  },
1798
- "evaluate": false,
1781
+ "evaluate": true,
1799
1782
  "output": true
1800
1783
  },
1801
1784
  {
@@ -1951,24 +1934,7 @@
1951
1934
  {
1952
1935
  "id": "http-header-fingerprint",
1953
1936
  "generator": "http_header_fingerprint",
1954
- "conditions": [
1955
- {
1956
- "operator": "exists",
1957
- "parameters": {
1958
- "inputs": [
1959
- {
1960
- "address": "waf.context.event"
1961
- },
1962
- {
1963
- "address": "server.business_logic.users.login.failure"
1964
- },
1965
- {
1966
- "address": "server.business_logic.users.login.success"
1967
- }
1968
- ]
1969
- }
1970
- }
1971
- ],
1937
+ "conditions": [],
1972
1938
  "parameters": {
1973
1939
  "mappings": [
1974
1940
  {
@@ -1981,30 +1947,13 @@
1981
1947
  }
1982
1948
  ]
1983
1949
  },
1984
- "evaluate": false,
1950
+ "evaluate": true,
1985
1951
  "output": true
1986
1952
  },
1987
1953
  {
1988
1954
  "id": "http-network-fingerprint",
1989
1955
  "generator": "http_network_fingerprint",
1990
- "conditions": [
1991
- {
1992
- "operator": "exists",
1993
- "parameters": {
1994
- "inputs": [
1995
- {
1996
- "address": "waf.context.event"
1997
- },
1998
- {
1999
- "address": "server.business_logic.users.login.failure"
2000
- },
2001
- {
2002
- "address": "server.business_logic.users.login.success"
2003
- }
2004
- ]
2005
- }
2006
- }
2007
- ],
1956
+ "conditions": [],
2008
1957
  "parameters": {
2009
1958
  "mappings": [
2010
1959
  {
@@ -2017,30 +1966,13 @@
2017
1966
  }
2018
1967
  ]
2019
1968
  },
2020
- "evaluate": false,
1969
+ "evaluate": true,
2021
1970
  "output": true
2022
1971
  },
2023
1972
  {
2024
1973
  "id": "session-fingerprint",
2025
1974
  "generator": "session_fingerprint",
2026
- "conditions": [
2027
- {
2028
- "operator": "exists",
2029
- "parameters": {
2030
- "inputs": [
2031
- {
2032
- "address": "waf.context.event"
2033
- },
2034
- {
2035
- "address": "server.business_logic.users.login.failure"
2036
- },
2037
- {
2038
- "address": "server.business_logic.users.login.success"
2039
- }
2040
- ]
2041
- }
2042
- }
2043
- ],
1975
+ "conditions": [],
2044
1976
  "parameters": {
2045
1977
  "mappings": [
2046
1978
  {
@@ -2063,7 +1995,7 @@
2063
1995
  }
2064
1996
  ]
2065
1997
  },
2066
- "evaluate": false,
1998
+ "evaluate": true,
2067
1999
  "output": true
2068
2000
  }
2069
2001
  ],
@@ -3090,4 +3022,4 @@
3090
3022
  }
3091
3023
  }
3092
3024
  ]
3093
- }
3025
+ }
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'processor'
4
- require_relative 'processor/rule_merger'
3
+ require_relative 'security_engine/engine'
4
+ require_relative 'security_engine/runner'
5
5
  require_relative 'processor/rule_loader'
6
6
  require_relative 'actions_handler'
7
7
 
@@ -32,7 +32,8 @@ module Datadog
32
32
  return
33
33
  end
34
34
 
35
- processor = create_processor(settings, telemetry)
35
+ require_libddwaf(telemetry: telemetry)
36
+ Datadog::AppSec::WAF.logger = Datadog.logger if Datadog.logger.debug? && settings.appsec.waf_debug
36
37
 
37
38
  # We want to always instrument user events when AppSec is enabled.
38
39
  # There could be cases in which users use the DD_APPSEC_ENABLED Env variable to
@@ -42,67 +43,44 @@ module Datadog
42
43
  devise_integration = Datadog::AppSec::Contrib::Devise::Integration.new
43
44
  settings.appsec.instrument(:devise) unless devise_integration.patcher.patched?
44
45
 
45
- new(processor, telemetry)
46
+ security_engine = SecurityEngine::Engine.new(appsec_settings: settings.appsec, telemetry: telemetry)
47
+ new(security_engine: security_engine, telemetry: telemetry)
48
+ rescue
49
+ Datadog.logger.warn('AppSec is disabled, see logged errors above')
50
+
51
+ nil
46
52
  end
47
53
 
48
54
  private
49
55
 
50
- def create_processor(settings, telemetry)
51
- rules = AppSec::Processor::RuleLoader.load_rules(
52
- telemetry: telemetry,
53
- ruleset: settings.appsec.ruleset
54
- )
55
- return nil unless rules
56
-
57
- data = AppSec::Processor::RuleLoader.load_data(
58
- ip_denylist: settings.appsec.ip_denylist,
59
- user_id_denylist: settings.appsec.user_id_denylist,
60
- )
61
-
62
- exclusions = AppSec::Processor::RuleLoader.load_exclusions(ip_passlist: settings.appsec.ip_passlist)
63
-
64
- # NOTE: This is a temporary solution before the RuleMerger refactoring
65
- # with new RemoteConfig setup
66
- processors = rules['processors']
67
- scanners = rules['scanners']
68
-
69
- ruleset = AppSec::Processor::RuleMerger.merge(
70
- rules: [rules],
71
- data: data,
72
- scanners: scanners,
73
- processors: processors,
74
- exclusions: exclusions,
75
- telemetry: telemetry
76
- )
77
-
78
- processor = Processor.new(ruleset: ruleset, telemetry: telemetry)
79
- return nil unless processor.ready?
80
-
81
- processor
56
+ def require_libddwaf(telemetry:)
57
+ require('libddwaf')
58
+ rescue LoadError => e
59
+ libddwaf_platform = Gem.loaded_specs['libddwaf']&.platform || 'unknown'
60
+ ruby_platforms = Gem.platforms.map(&:to_s)
61
+
62
+ error_message = "libddwaf failed to load - installed platform: #{libddwaf_platform}, " \
63
+ "ruby platforms: #{ruby_platforms}"
64
+
65
+ Datadog.logger.error("#{error_message}, error #{e.inspect}")
66
+ telemetry.report(e, description: error_message)
67
+
68
+ raise e
82
69
  end
83
70
  end
84
71
 
85
- attr_reader :processor, :telemetry
72
+ attr_reader :security_engine, :telemetry
86
73
 
87
- def initialize(processor, telemetry)
88
- @processor = processor
74
+ def initialize(security_engine:, telemetry:)
75
+ @security_engine = security_engine
89
76
  @telemetry = telemetry
90
77
 
91
78
  @mutex = Mutex.new
92
79
  end
93
80
 
94
- def reconfigure(ruleset:, telemetry:)
81
+ def reconfigure!
95
82
  @mutex.synchronize do
96
- new_processor = Processor.new(ruleset: ruleset, telemetry: telemetry)
97
-
98
- if new_processor&.ready?
99
- old_processor = @processor
100
-
101
- @telemetry = telemetry
102
- @processor = new_processor
103
-
104
- old_processor&.finalize
105
- end
83
+ security_engine.reconfigure!
106
84
  end
107
85
  end
108
86
 
@@ -112,10 +90,8 @@ module Datadog
112
90
 
113
91
  def shutdown!
114
92
  @mutex.synchronize do
115
- if processor&.ready?
116
- processor.finalize
117
- @processor = nil
118
- end
93
+ security_engine.finalize!
94
+ @security_engine = nil
119
95
  end
120
96
  end
121
97
  end
@@ -80,16 +80,49 @@ module Datadog
80
80
 
81
81
  option :ip_passlist do |o|
82
82
  o.default []
83
+
84
+ o.setter do |value|
85
+ next value if value.nil? || value.empty?
86
+
87
+ Datadog::Core.log_deprecation(disallowed_next_major: false) do
88
+ 'The ip_passlist setting is deprecated and will be removed in the next release. ' \
89
+ 'Please migrate this configuration to your service settings via the Datadog UI'
90
+ end
91
+
92
+ value
93
+ end
83
94
  end
84
95
 
85
96
  option :ip_denylist do |o|
86
97
  o.type :array
87
98
  o.default []
99
+
100
+ o.setter do |value|
101
+ next value if value.nil? || value.empty?
102
+
103
+ Datadog::Core.log_deprecation(disallowed_next_major: false) do
104
+ 'The ip_denylist setting is deprecated and will be removed in the next release. ' \
105
+ 'Please migrate this configuration to your service settings via the Datadog UI'
106
+ end
107
+
108
+ value
109
+ end
88
110
  end
89
111
 
90
112
  option :user_id_denylist do |o|
91
113
  o.type :array
92
114
  o.default []
115
+
116
+ o.setter do |value|
117
+ next value if value.nil? || value.empty?
118
+
119
+ Datadog::Core.log_deprecation(disallowed_next_major: false) do
120
+ 'The user_id_denylist setting is deprecated and will be removed in the next release. ' \
121
+ 'Please migrate this configuration to your service settings via the Datadog UI'
122
+ end
123
+
124
+ value
125
+ end
93
126
  end
94
127
 
95
128
  option :waf_timeout do |o|
@@ -311,12 +344,28 @@ module Datadog
311
344
  end
312
345
 
313
346
  settings :api_security do
347
+ define_method(:enabled?) { get_option(:enabled) }
348
+
314
349
  option :enabled do |o|
315
350
  o.type :bool
316
- o.env 'DD_EXPERIMENTAL_API_SECURITY_ENABLED'
317
- o.default false
351
+ o.env 'DD_API_SECURITY_ENABLED'
352
+ o.default true
318
353
  end
319
354
 
355
+ # NOTE: Unfortunately, we have to go with Float due to other libs
356
+ # setup, even tho we don't plan to support sub-second delays.
357
+ #
358
+ # WARNING: The value will be converted to Integer.
359
+ option :sample_delay do |o|
360
+ o.type :float
361
+ o.env 'DD_API_SECURITY_SAMPLE_DELAY'
362
+ o.default 30
363
+ o.setter do |value|
364
+ value.to_i
365
+ end
366
+ end
367
+
368
+ # DEV-3.0: Remove `api_security.sample_rate` option
320
369
  option :sample_rate do |o|
321
370
  o.type :float
322
371
  o.env 'DD_API_SECURITY_REQUEST_SAMPLE_RATE'
@@ -325,6 +374,15 @@ module Datadog
325
374
  value = 1 if value > 1
326
375
  SampleRate.new(value)
327
376
  end
377
+ o.after_set do |_, _, precedence|
378
+ next if precedence == Datadog::Core::Configuration::Option::Precedence::DEFAULT
379
+
380
+ Core.log_deprecation(key: :appsec_api_security_sample_rate) do
381
+ 'The appsec.api_security.sample_rate setting is deprecated. ' \
382
+ 'Please remove it from your Datadog.configure block and use ' \
383
+ 'appsec.api_security.sample_delay instead.'
384
+ end
385
+ end
328
386
  end
329
387
  end
330
388
 
@@ -9,6 +9,7 @@ module Datadog
9
9
  class Context
10
10
  ActiveContextError = Class.new(StandardError)
11
11
 
12
+ # TODO: add delegators for active trace span
12
13
  attr_reader :trace, :span, :events
13
14
 
14
15
  class << self
@@ -20,7 +21,7 @@ module Datadog
20
21
  end
21
22
 
22
23
  def deactivate
23
- active&.finalize
24
+ active&.finalize!
24
25
  ensure
25
26
  Thread.current[Ext::ACTIVE_CONTEXT_KEY] = nil
26
27
  end
@@ -30,12 +31,11 @@ module Datadog
30
31
  end
31
32
  end
32
33
 
33
- def initialize(trace, span, security_engine)
34
+ def initialize(trace, span, waf_runner)
34
35
  @trace = trace
35
36
  @span = span
36
37
  @events = []
37
- @security_engine = security_engine
38
- @waf_runner = security_engine.new_runner
38
+ @waf_runner = waf_runner
39
39
  @metrics = Metrics::Collector.new
40
40
  end
41
41
 
@@ -66,8 +66,8 @@ module Datadog
66
66
  Metrics::Exporter.export_rasp_metrics(@metrics.rasp, @span)
67
67
  end
68
68
 
69
- def finalize
70
- @waf_runner.finalize
69
+ def finalize!
70
+ @waf_runner.finalize!
71
71
  end
72
72
  end
73
73
  end
@@ -92,7 +92,7 @@ module Datadog
92
92
  return if value.nil?
93
93
  return value.to_s unless anonymize?
94
94
 
95
- Anonymizer.anonimyze(value.to_s)
95
+ Anonymizer.anonymize(value.to_s)
96
96
  end
97
97
 
98
98
  def anonymize?
@@ -7,7 +7,7 @@ require_relative 'gateway/response'
7
7
 
8
8
  require_relative '../../event'
9
9
  require_relative '../../response'
10
- require_relative '../../processor'
10
+ require_relative '../../api_security'
11
11
  require_relative '../../security_event'
12
12
  require_relative '../../instrumentation/gateway'
13
13
 
@@ -46,7 +46,7 @@ module Datadog
46
46
  boot = Datadog::Core::Remote::Tie.boot
47
47
  Datadog::Core::Remote::Tie::Tracing.tag(boot, active_span)
48
48
 
49
- processor = nil
49
+ security_engine = nil
50
50
  ready = false
51
51
  ctx = nil
52
52
 
@@ -56,11 +56,11 @@ module Datadog
56
56
  return @app.call(env) if active_context(env)
57
57
 
58
58
  Datadog::AppSec.reconfigure_lock do
59
- processor = Datadog::AppSec.processor
59
+ security_engine = Datadog::AppSec.security_engine
60
60
 
61
- if !processor.nil? && processor.ready?
61
+ if security_engine
62
62
  ctx = Datadog::AppSec::Context.activate(
63
- Datadog::AppSec::Context.new(active_trace, active_span, processor)
63
+ Datadog::AppSec::Context.new(active_trace, active_span, security_engine.new_runner)
64
64
  )
65
65
 
66
66
  env[Datadog::AppSec::Ext::CONTEXT_KEY] = ctx
@@ -72,7 +72,7 @@ module Datadog
72
72
 
73
73
  return @app.call(env) unless ready
74
74
 
75
- add_appsec_tags(processor, ctx)
75
+ add_appsec_tags(security_engine, ctx)
76
76
  add_request_tags(ctx, env)
77
77
 
78
78
  http_response = nil
@@ -100,7 +100,23 @@ module Datadog
100
100
  http_response = AppSec::Response.from_interrupt_params(interrupt_params, env['HTTP_ACCEPT']).to_rack
101
101
  end
102
102
 
103
- if AppSec.perform_api_security_check?
103
+ # NOTE: This is not optimal, but in the current implementation
104
+ # `gateway_response` is a container to dispatch response event
105
+ # and in case of interruption it suppose to be `nil`.
106
+ #
107
+ # `http_response` is a real response object in both cases, but
108
+ # to save us some computations, we will use already pre-computed
109
+ # `gateway_response` instead of re-creating it.
110
+ #
111
+ # WARNING: This part will be refactored.
112
+ tmp_response = if interrupt_params
113
+ Gateway::Response.new(http_response[2], http_response[0], http_response[1], context: ctx)
114
+ else
115
+ gateway_response
116
+ end
117
+
118
+ if AppSec::APISecurity.enabled? && AppSec::APISecurity.sample_trace?(ctx.trace) &&
119
+ AppSec::APISecurity.sample?(gateway_request.request, tmp_response.response)
104
120
  ctx.events.push(
105
121
  AppSec::SecurityEvent.new(ctx.extract_schema, trace: ctx.trace, span: ctx.span)
106
122
  )
@@ -140,7 +156,7 @@ module Datadog
140
156
  end
141
157
 
142
158
  # standard:disable Metrics/MethodLength
143
- def add_appsec_tags(processor, context)
159
+ def add_appsec_tags(security_engine, context)
144
160
  span = context.span
145
161
  trace = context.trace
146
162
 
@@ -150,20 +166,15 @@ module Datadog
150
166
  span.set_tag('_dd.runtime_family', 'ruby')
151
167
  span.set_tag('_dd.appsec.waf.version', Datadog::AppSec::WAF::VERSION::BASE_STRING)
152
168
 
153
- if processor.diagnostics
154
- diagnostics = processor.diagnostics
155
-
156
- span.set_tag('_dd.appsec.event_rules.version', diagnostics['ruleset_version'])
169
+ if security_engine.ruleset_version
170
+ span.set_tag('_dd.appsec.event_rules.version', security_engine.ruleset_version)
157
171
 
158
172
  unless @oneshot_tags_sent
159
173
  # Small race condition, but it's inoccuous: worst case the tags
160
174
  # are sent a couple of times more than expected
161
175
  @oneshot_tags_sent = true
162
176
 
163
- span.set_tag('_dd.appsec.event_rules.loaded', diagnostics['rules']['loaded'].size.to_f)
164
- span.set_tag('_dd.appsec.event_rules.error_count', diagnostics['rules']['failed'].size.to_f)
165
- span.set_tag('_dd.appsec.event_rules.errors', JSON.dump(diagnostics['rules']['errors']))
166
- span.set_tag('_dd.appsec.event_rules.addresses', JSON.dump(processor.addresses))
177
+ span.set_tag('_dd.appsec.event_rules.addresses', JSON.dump(security_engine.waf_addresses))
167
178
 
168
179
  # Ensure these tags reach the backend
169
180
  trace.keep!
@@ -36,22 +36,21 @@ module Datadog
36
36
 
37
37
  telemetry.report(e, description: 'libddwaf ruleset failed to load')
38
38
 
39
- nil
39
+ raise e
40
40
  end
41
41
 
42
42
  def load_data(ip_denylist: [], user_id_denylist: [])
43
43
  data = []
44
- data << [denylist_data('blocked_ips', ip_denylist)] if ip_denylist.any?
45
- data << [denylist_data('blocked_users', user_id_denylist)] if user_id_denylist.any?
44
+ data << denylist_data('blocked_ips', ip_denylist) if ip_denylist.any?
45
+ data << denylist_data('blocked_users', user_id_denylist) if user_id_denylist.any?
46
46
 
47
47
  data
48
48
  end
49
49
 
50
50
  def load_exclusions(ip_passlist: [])
51
- exclusions = []
52
- exclusions << [passlist_exclusions(ip_passlist)] if ip_passlist.any?
51
+ return [] if ip_passlist.empty?
53
52
 
54
- exclusions
53
+ passlist_exclusions(ip_passlist)
55
54
  end
56
55
 
57
56
  private
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../core/remote/dispatcher'
4
- require_relative 'processor/rule_merger'
5
4
  require_relative 'processor/rule_loader'
6
5
 
7
6
  module Datadog
@@ -57,74 +56,35 @@ module Datadog
57
56
  remote_features_enabled? ? ASM_PRODUCTS : []
58
57
  end
59
58
 
60
- # rubocop:disable Metrics/MethodLength
61
- # rubocop:disable Metrics/CyclomaticComplexity
62
59
  def receivers(telemetry)
63
60
  return [] unless remote_features_enabled?
64
61
 
65
62
  matcher = Core::Remote::Dispatcher::Matcher::Product.new(ASM_PRODUCTS)
66
- # rubocop:disable Metrics/BlockLength
67
63
  receiver = Core::Remote::Dispatcher::Receiver.new(matcher) do |repository, changes|
68
- changes.each do |change|
69
- Datadog.logger.debug { "remote config change: '#{change.path}'" }
70
- end
71
-
72
- rules = []
73
- custom_rules = []
74
- data = []
75
- overrides = []
76
- exclusions = []
77
- actions = []
78
-
79
- repository.contents.each do |content|
80
- parsed_content = parse_content(content)
81
-
82
- case content.path.product
83
- when 'ASM_DD'
84
- rules << parsed_content
85
- when 'ASM_DATA'
86
- data << parsed_content['rules_data'] if parsed_content['rules_data']
87
- when 'ASM'
88
- overrides << parsed_content['rules_override'] if parsed_content['rules_override']
89
- exclusions << parsed_content['exclusions'] if parsed_content['exclusions']
90
- custom_rules << parsed_content['custom_rules'] if parsed_content['custom_rules']
91
- actions.concat(parsed_content['actions']) if parsed_content['actions']
92
- end
93
- end
64
+ next unless AppSec.security_engine
94
65
 
95
- if rules.empty?
96
- settings_rules = AppSec::Processor::RuleLoader.load_rules(
97
- telemetry: telemetry,
98
- ruleset: Datadog.configuration.appsec.ruleset
99
- )
66
+ changes.each do |change|
67
+ content = repository[change.path]
68
+ next unless content || change.type == :delete
100
69
 
101
- raise NoRulesError, 'no default rules available' unless settings_rules
70
+ case change.type
71
+ when :insert, :update
72
+ AppSec.security_engine.add_or_update_config(parse_content(content), path: change.path.to_s) # steep:ignore
102
73
 
103
- rules = [settings_rules]
74
+ content.applied # steep:ignore
75
+ when :delete
76
+ AppSec.security_engine.remove_config_at_path(change.path.to_s) # steep:ignore
77
+ end
104
78
  end
105
79
 
106
- ruleset = AppSec::Processor::RuleMerger.merge(
107
- rules: rules,
108
- data: data,
109
- actions: actions,
110
- overrides: overrides,
111
- exclusions: exclusions,
112
- custom_rules: custom_rules,
113
- telemetry: telemetry
114
- )
115
-
116
- Datadog::AppSec.reconfigure(ruleset: ruleset, telemetry: telemetry)
117
-
118
- repository.contents.each do |content|
119
- content.applied if ASM_PRODUCTS.include?(content.path.product)
120
- end
80
+ # This is subject to change - we need to remove the reconfiguration mutex
81
+ # and track usages of each WAF handle instead, so that we know when an old
82
+ # WAF handle can be finalized.
83
+ AppSec.reconfigure!
121
84
  end
122
- # rubocop:enable Metrics/BlockLength
123
85
 
124
86
  [receiver]
125
87
  end
126
- # rubocop:enable Metrics/MethodLength
127
- # rubocop:enable Metrics/CyclomaticComplexity
128
88
 
129
89
  private
130
90