contrast-agent 4.9.1 → 4.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -1
  3. data/.rspec_parallel +6 -0
  4. data/ext/cs__assess_module/cs__assess_module.c +48 -0
  5. data/ext/cs__assess_module/cs__assess_module.h +7 -0
  6. data/ext/cs__common/cs__common.c +24 -7
  7. data/ext/cs__common/cs__common.h +12 -2
  8. data/ext/cs__contrast_patch/cs__contrast_patch.c +48 -12
  9. data/ext/cs__contrast_patch/cs__contrast_patch.h +5 -4
  10. data/ext/cs__os_information/cs__os_information.c +31 -0
  11. data/ext/cs__os_information/cs__os_information.h +7 -0
  12. data/ext/{cs__protect_kernel → cs__os_information}/extconf.rb +0 -0
  13. data/lib/contrast/agent/assess/contrast_event.rb +1 -2
  14. data/lib/contrast/agent/assess/contrast_object.rb +1 -4
  15. data/lib/contrast/agent/assess/finalizers/hash.rb +0 -1
  16. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +2 -0
  17. data/lib/contrast/agent/assess/policy/patcher.rb +0 -1
  18. data/lib/contrast/agent/assess/policy/policy_scanner.rb +0 -2
  19. data/lib/contrast/agent/assess/policy/preshift.rb +29 -12
  20. data/lib/contrast/agent/assess/policy/propagation_method.rb +71 -142
  21. data/lib/contrast/agent/assess/policy/propagation_node.rb +4 -4
  22. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +2 -2
  23. data/lib/contrast/agent/assess/policy/propagator/match_data.rb +31 -11
  24. data/lib/contrast/agent/assess/policy/propagator/remove.rb +4 -9
  25. data/lib/contrast/agent/assess/policy/propagator/split.rb +3 -2
  26. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +1 -0
  27. data/lib/contrast/agent/assess/policy/rewriter_patch.rb +0 -1
  28. data/lib/contrast/agent/assess/policy/source_method.rb +15 -88
  29. data/lib/contrast/agent/assess/policy/trigger/xpath.rb +0 -1
  30. data/lib/contrast/agent/assess/policy/trigger_method.rb +45 -172
  31. data/lib/contrast/agent/assess/policy/trigger_node.rb +52 -19
  32. data/lib/contrast/agent/assess/property/evented.rb +2 -1
  33. data/lib/contrast/agent/assess/property/tagged.rb +15 -132
  34. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +0 -1
  35. data/lib/contrast/agent/deadzone/policy/policy.rb +6 -0
  36. data/lib/contrast/agent/disable_reaction.rb +1 -1
  37. data/lib/contrast/agent/exclusion_matcher.rb +0 -4
  38. data/lib/contrast/agent/inventory/database_config.rb +117 -0
  39. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +7 -5
  40. data/lib/contrast/agent/inventory/policy/datastores.rb +2 -2
  41. data/lib/contrast/agent/metric_telemetry_event.rb +26 -0
  42. data/lib/contrast/agent/middleware.rb +23 -0
  43. data/lib/contrast/agent/patching/policy/after_load_patch.rb +3 -0
  44. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +17 -12
  45. data/lib/contrast/agent/patching/policy/method_policy.rb +54 -9
  46. data/lib/contrast/agent/patching/policy/module_policy.rb +2 -4
  47. data/lib/contrast/agent/patching/policy/patch.rb +42 -238
  48. data/lib/contrast/agent/patching/policy/patch_status.rb +3 -7
  49. data/lib/contrast/agent/patching/policy/patcher.rb +10 -49
  50. data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +1 -1
  51. data/lib/contrast/agent/protect/rule/no_sqli.rb +7 -53
  52. data/lib/contrast/agent/protect/rule/sql_sample_builder.rb +137 -0
  53. data/lib/contrast/agent/protect/rule/sqli.rb +7 -70
  54. data/lib/contrast/agent/reaction_processor.rb +1 -1
  55. data/lib/contrast/agent/request.rb +9 -4
  56. data/lib/contrast/agent/request_context.rb +51 -33
  57. data/lib/contrast/agent/request_handler.rb +7 -3
  58. data/lib/contrast/agent/rule_set.rb +2 -4
  59. data/lib/contrast/agent/scope.rb +32 -20
  60. data/lib/contrast/agent/startup_metrics_telemetry_event.rb +71 -0
  61. data/lib/contrast/agent/static_analysis.rb +5 -3
  62. data/lib/contrast/agent/telemetry.rb +129 -0
  63. data/lib/contrast/agent/telemetry_event.rb +34 -0
  64. data/lib/contrast/agent/thread_watcher.rb +43 -14
  65. data/lib/contrast/agent/tracepoint_hook.rb +16 -3
  66. data/lib/contrast/agent/version.rb +1 -1
  67. data/lib/contrast/agent.rb +6 -1
  68. data/lib/contrast/api/communication/messaging_queue.rb +12 -6
  69. data/lib/contrast/api/communication/service_lifecycle.rb +4 -1
  70. data/lib/contrast/api/communication/socket_client.rb +4 -4
  71. data/lib/contrast/api/decorators/agent_startup.rb +4 -4
  72. data/lib/contrast/api/decorators/application_startup.rb +6 -5
  73. data/lib/contrast/api/decorators/route_coverage.rb +24 -1
  74. data/lib/contrast/components/agent.rb +5 -2
  75. data/lib/contrast/components/api.rb +34 -0
  76. data/lib/contrast/components/app_context.rb +24 -0
  77. data/lib/contrast/components/assess.rb +13 -3
  78. data/lib/contrast/components/base.rb +2 -2
  79. data/lib/contrast/components/config.rb +91 -11
  80. data/lib/contrast/components/contrast_service.rb +10 -2
  81. data/lib/contrast/components/logger.rb +13 -8
  82. data/lib/contrast/components/scope.rb +9 -28
  83. data/lib/contrast/config/api_configuration.rb +22 -0
  84. data/lib/contrast/config/assess_configuration.rb +1 -0
  85. data/lib/contrast/config/base_configuration.rb +14 -6
  86. data/lib/contrast/config/env_variables.rb +25 -0
  87. data/lib/contrast/config/root_configuration.rb +1 -0
  88. data/lib/contrast/config/service_configuration.rb +2 -1
  89. data/lib/contrast/config.rb +1 -0
  90. data/lib/contrast/configuration.rb +22 -15
  91. data/lib/contrast/extension/assess/array.rb +1 -11
  92. data/lib/contrast/extension/assess/eval_trigger.rb +0 -20
  93. data/lib/contrast/extension/assess/fiber.rb +0 -11
  94. data/lib/contrast/extension/assess/hash.rb +0 -10
  95. data/lib/contrast/extension/assess/kernel.rb +1 -10
  96. data/lib/contrast/extension/assess/marshal.rb +3 -11
  97. data/lib/contrast/extension/assess/regexp.rb +0 -11
  98. data/lib/contrast/extension/assess/string.rb +1 -26
  99. data/lib/contrast/extension/extension.rb +61 -0
  100. data/lib/contrast/framework/grape/support.rb +174 -0
  101. data/lib/contrast/framework/manager.rb +56 -18
  102. data/lib/contrast/framework/rack/support.rb +1 -1
  103. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +9 -6
  104. data/lib/contrast/framework/rails/patch/assess_configuration.rb +0 -1
  105. data/lib/contrast/framework/rails/patch/support.rb +35 -30
  106. data/lib/contrast/framework/rails/railtie.rb +1 -1
  107. data/lib/contrast/framework/rails/rewrite/active_record_named.rb +1 -0
  108. data/lib/contrast/framework/rails/support.rb +60 -13
  109. data/lib/contrast/framework/sinatra/support.rb +1 -1
  110. data/lib/contrast/logger/application.rb +4 -0
  111. data/lib/contrast/logger/log.rb +89 -15
  112. data/lib/contrast/utils/assess/propagation_method_utils.rb +129 -0
  113. data/lib/contrast/utils/assess/property/tagged_utils.rb +142 -0
  114. data/lib/contrast/utils/assess/source_method_utils.rb +83 -0
  115. data/lib/contrast/utils/assess/trigger_method_utils.rb +138 -0
  116. data/lib/contrast/utils/class_util.rb +58 -44
  117. data/lib/contrast/utils/exclude_key.rb +20 -0
  118. data/lib/contrast/utils/io_util.rb +43 -35
  119. data/lib/contrast/utils/lru_cache.rb +45 -0
  120. data/lib/contrast/utils/metrics_hash.rb +59 -0
  121. data/lib/contrast/utils/os.rb +23 -0
  122. data/lib/contrast/utils/patching/policy/patch_utils.rb +232 -0
  123. data/lib/contrast/utils/patching/policy/patcher_utils.rb +54 -0
  124. data/lib/contrast/utils/requests_client.rb +150 -0
  125. data/lib/contrast/utils/ruby_ast_rewriter.rb +16 -13
  126. data/lib/contrast/utils/tag_util.rb +2 -1
  127. data/lib/contrast/utils/telemetry.rb +78 -0
  128. data/lib/contrast/utils/telemetry_identifier.rb +137 -0
  129. data/lib/contrast.rb +19 -1
  130. data/resources/assess/policy.json +208 -7
  131. data/resources/deadzone/policy.json +91 -0
  132. data/ruby-agent.gemspec +12 -2
  133. data/service_executables/VERSION +1 -1
  134. data/service_executables/linux/contrast-service +0 -0
  135. data/service_executables/mac/contrast-service +0 -0
  136. metadata +102 -18
  137. data/ext/cs__protect_kernel/cs__protect_kernel.c +0 -47
  138. data/ext/cs__protect_kernel/cs__protect_kernel.h +0 -12
  139. data/lib/contrast/extension/protect/kernel.rb +0 -39
  140. data/lib/contrast/utils/inventory_util.rb +0 -113
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/utils/env_configuration_item'
5
+ require 'ougai'
5
6
  require 'contrast/configuration'
6
7
 
7
8
  module Contrast
@@ -23,17 +24,33 @@ module Contrast
23
24
  # time than to silently fail to deliver functionality.
24
25
  module Config
25
26
  CONTRAST_ENV_MARKER = 'CONTRAST__'
27
+ CONTRAST_LOG = 'contrast_agent.log'
28
+ CONTRAST_NAME = 'Contrast Agent'
26
29
 
27
30
  class Interface # :nodoc:
28
31
  def initialize
29
32
  build
30
33
  end
31
34
 
32
- def build log: true
35
+ # Basic logger for handling configuration validation logging
36
+ # the file to log is determined by the default one or set
37
+ # by the config file, if that configuration is found
38
+ def proto_logger
39
+ @_proto_logger ||= begin
40
+ @_proto_logger = ::Ougai::Logger.new(logger_path || CONTRAST_LOG)
41
+ @_proto_logger.progname = CONTRAST_NAME
42
+ @_proto_logger.level = ::Ougai::Logging::Severity::WARN
43
+ @_proto_logger.formatter = Contrast::Logger::Format.new
44
+ @_proto_logger.formatter.datetime_format = '%Y-%m-%dT%H:%M:%S.%L%z'
45
+ @_proto_logger
46
+ end
47
+ end
48
+
49
+ def build
33
50
  @_valid = nil
34
51
  @config = Contrast::Configuration.new
35
52
  env_overrides
36
- validate(log: log)
53
+ validate
37
54
  end
38
55
  alias_method :rebuild, :build
39
56
 
@@ -43,7 +60,8 @@ module Contrast
43
60
  end
44
61
 
45
62
  def valid?
46
- @_valid = validate(log: false) if @_valid.nil?
63
+ @_valid = validate if @_valid.nil?
64
+ @_valid
47
65
  end
48
66
 
49
67
  def invalid?
@@ -58,20 +76,28 @@ module Contrast
58
76
 
59
77
  SESSION_VARIABLES = 'Invalid configuration. '\
60
78
  "Setting both application.session_id and application.session_metadata is not allowed.\n"
61
- def validate log: false
79
+ API_URL = "Invalid configuration. Missing a required connection value 'url' is not set."
80
+ API_KEY = "Invalid configuration. Missing a required connection value 'api_key' is not set."
81
+ API_SERVICE_KEY = "Invalid configuration. Missing a required connection value 'service_tag' is not set."
82
+ API_USERNAME = "Invalid configuration. Missing a required connection value 'user_name' is not set."
83
+ def validate
62
84
  # The config has information about how to construct the logger.
63
85
  # If the config is invalid, and you want to know about it, then
64
86
  # you have a circular dependency if you try to log it,
65
- # hence `log: false`.
87
+ # so we use basic proto_logger to do this job.
66
88
  if !session_id.empty? && !session_metadata.empty?
67
- if log
68
- cs__class.log_error(SESSION_VARIABLES)
69
- else
70
- puts SESSION_VARIABLES
71
- end
89
+ proto_logger.error(SESSION_VARIABLES)
72
90
  return false
73
91
  end
74
-
92
+ if bypass
93
+ msg = []
94
+ msg << API_URL unless api_url
95
+ msg << API_KEY unless api_key
96
+ msg << API_SERVICE_KEY unless api_service_key
97
+ msg << API_USERNAME unless api_username
98
+ msg.any? { |m| proto_logger.error(m) }
99
+ return false unless msg.empty?
100
+ end
75
101
  true
76
102
  end
77
103
 
@@ -107,6 +133,60 @@ module Contrast
107
133
  def session_metadata
108
134
  @config.application.session_metadata
109
135
  end
136
+
137
+ # Typically, the following values would be accessed through Contrast::Components::AppContext
138
+ # and Contrast::Components::API, but we're too early in the initialization of the Agent to use
139
+ # that mechanism, so we look it up directly for ourselves.
140
+ #
141
+ # @return [String, nil]
142
+ def api_url
143
+ @config.api.url
144
+ end
145
+
146
+ # Typically, the following values would be accessed through Contrast::Components::AppContext
147
+ # and Contrast::Components::API, but we're too early in the initialization of the Agent to use
148
+ # that mechanism, so we look it up directly for ourselves.
149
+ #
150
+ # @return [String, nil]
151
+ def api_key
152
+ @config.api.api_key
153
+ end
154
+
155
+ # Typically, the following values would be accessed through Contrast::Components::AppContext
156
+ # and Contrast::Components::API, but we're too early in the initialization of the Agent to use
157
+ # that mechanism, so we look it up directly for ourselves.
158
+ #
159
+ # @return [String, nil]
160
+ def api_service_key
161
+ @config.api.service_key
162
+ end
163
+
164
+ # Typically, the following values would be accessed through Contrast::Components::AppContext
165
+ # and Contrast::Components::API, but we're too early in the initialization of the Agent to use
166
+ # that mechanism, so we look it up directly for ourselves.
167
+ #
168
+ # @return [String, nil]
169
+ def api_username
170
+ @config.api.user_name
171
+ end
172
+
173
+ # Typically, the following values would be accessed through Contrast::Components::AppContext
174
+ # and Contrast::Components::API, but we're too early in the initialization of the Agent to use
175
+ # that mechanism, so we look it up directly for ourselves.
176
+ #
177
+ # @return [String, nil]
178
+ def bypass
179
+ @config.root.agent.service.bypass
180
+ end
181
+
182
+ # Typically, the following values would be accessed through Contrast::Components::AppContext
183
+ # and Contrast::Components::Logger, but we're too early in the initialization of the Agent to use
184
+ # that mechanism, so we look it up directly for ourselves.
185
+ #
186
+ # @return [String, nil]
187
+ def logger_path
188
+ @config.root.agent.logger.path
189
+ end
110
190
  end
111
191
  end
112
192
  end
@@ -31,12 +31,20 @@ module Contrast
31
31
  (LOCALHOST.match?(host) || !!socket_path)
32
32
  end
33
33
 
34
+ def use_agent_communication?
35
+ return @_use_agent_communication unless @_use_agent_communication.nil?
36
+
37
+ @_use_agent_communication = true?(::Contrast::CONFIG.root.agent.service.bypass)
38
+ end
39
+
34
40
  def host
35
- @_host ||= (::Contrast::CONFIG.root.agent.service.host || Contrast::Config::ServiceConfiguration::DEFAULT_HOST).to_s
41
+ @_host ||=
42
+ (::Contrast::CONFIG.root.agent.service.host || Contrast::Config::ServiceConfiguration::DEFAULT_HOST).to_s
36
43
  end
37
44
 
38
45
  def port
39
- @_port ||= (::Contrast::CONFIG.root.agent.service.port || Contrast::Config::ServiceConfiguration::DEFAULT_PORT).to_i
46
+ @_port ||=
47
+ (::Contrast::CONFIG.root.agent.service.port || Contrast::Config::ServiceConfiguration::DEFAULT_PORT).to_i
40
48
  end
41
49
 
42
50
  def socket_path
@@ -6,20 +6,25 @@ require 'contrast/components/base'
6
6
 
7
7
  module Contrast
8
8
  module Components
9
- module Logger
10
- module InstanceMethods #:nodoc:
9
+ module Logger # :nodoc:
10
+ module InstanceMethods # :nodoc:
11
11
  def logger
12
12
  Contrast::Logger::Log.instance.logger
13
13
  end
14
+
15
+ def add_trace_perf_logging_for sym, custom_message = nil
16
+ logger.add_trace_perf_logging(self, sym, custom_message)
17
+ end
18
+ end
19
+
20
+ class << self
21
+ def add_trace_log_timing_for clazz, method_name, custom_message = nil
22
+ Contrast::Logger::Log.instance.add_method_to_trace_timing(clazz, method_name, custom_message)
23
+ end
14
24
  end
15
- ClassMethods = InstanceMethods
16
25
 
17
- # A wrapper build around the Common Agent Configuration project to allow
18
- # for access of the values contained in its
19
- # parent_configuration_spec.yaml.
20
- # Specifically, this allows for querying the state of the Agent Logger.
21
26
  class Interface
22
- include Contrast::Components::ComponentBase
27
+ include InstanceMethods
23
28
  end
24
29
  end
25
30
  end
@@ -7,12 +7,9 @@ require 'contrast/agent/scope'
7
7
 
8
8
  # This is the Scope component.
9
9
  #
10
- # It tracks /Contrast/ scope. That is, "are we currently doing assess
11
- # or protect stuff within a patched method?" -- this is how we avoid doing
12
- # Contrast stuff on Contrast code.
13
- #
14
- # Separately from this component, there is also require scope, which is an
15
- # optimization on how we implement patching to `require`.
10
+ # It tracks /Contrast/ scope. That is, "are we currently doing assess or protect stuff within a patched method?" --
11
+ # this is how we avoid doing Contrast stuff on Contrast code or creating infinite loops -- or "are we in some other
12
+ # execution context for which we need to special case?".
16
13
  module Contrast
17
14
  module Components
18
15
  module Scope # :nodoc:
@@ -25,10 +22,8 @@ module Contrast
25
22
  EXECUTION_CONTEXT[Fiber.current] = Contrast::Agent::Scope.new
26
23
  end
27
24
 
28
- # This returns the scope governing the current execution context.
29
- # Use this sparingly, preferring the instance & class methods to
30
- # access and query scope, rather than interacting with the scope
31
- # object directly.
25
+ # This returns the scope governing the current execution context. Use this sparingly, preferring the instance
26
+ # & class methods to access and query scope, rather than interacting with the scope object directly.
32
27
  def scope_for_current_ec
33
28
  MONITOR.synchronize do
34
29
  return EXECUTION_CONTEXT[Fiber.current] ||= Contrast::Agent::Scope.new
@@ -37,9 +32,7 @@ module Contrast
37
32
  end
38
33
 
39
34
  module InstanceMethods # :nodoc:
40
- # For each instance method on a scope, define a forwarder
41
- # to the scope on the current execution context's scope.
42
-
35
+ # For each instance method on a scope, define a forwarder to the scope on the current execution context's scope.
43
36
  def scope_for_current_ec
44
37
  MONITOR.synchronize do
45
38
  return EXECUTION_CONTEXT[Fiber.current] ||= Contrast::Agent::Scope.new
@@ -118,24 +111,12 @@ module Contrast
118
111
  ensure
119
112
  scope_for_current_ec.exit_split_scope!
120
113
  end
121
-
122
- # TODO: RUBY-572
123
- #
124
- # Current behavior is to no-op if we're not "in a request context".
125
- # Our C functions were previously checking to see if we had a scope, because
126
- # scope was tacked on to a request context -- so "we have a scope, therefore,
127
- # we have a request context." We've decoupled scopes from request contexts,
128
- # so now it checks "do we have a request context."
129
- # RUBY-290 should remove all of that, including this method.
130
- def in_request_context?
131
- !!Contrast::Agent::REQUEST_TRACKER.current
132
- end
133
114
  end
134
115
 
135
116
  def self.sweep_dead_ecs
136
- # TODO: RUBY-571, #sweep_dead_ecs compensates for a lack of weak tables
137
- # 'ec' for execution context. in this case, it's a Fiber.
138
- # Threads rely on Fibers, so two birds, one stone.
117
+ # TODO: RUBY-534, #sweep_dead_ecs compensates for a lack of weak tables. when we can use WeakRef, we should
118
+ # investigate removing this call and instead use the WeakRef for the Execution Context's Keys or using our
119
+ # Finalizers Hash for Fibers
139
120
  MONITOR.synchronize do
140
121
  EXECUTION_CONTEXT.delete_if do |ec, _scope|
141
122
  !ec.alive?
@@ -0,0 +1,22 @@
1
+ # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ require 'contrast/config/default_value'
5
+
6
+ module Contrast
7
+ module Config
8
+ # Api keys configuration
9
+ class ApiConfiguration < BaseConfiguration
10
+ URL = 'https://app.contrastsecurity.com/Contrast'
11
+ KEYS = {
12
+ api_key: EMPTY_VALUE,
13
+ url: Contrast::Config::DefaultValue.new(URL),
14
+ user_name: EMPTY_VALUE,
15
+ service_key: EMPTY_VALUE
16
+ }.cs__freeze
17
+ def initialize hsh
18
+ super(hsh, KEYS)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -10,6 +10,7 @@ module Contrast
10
10
  tags: EMPTY_VALUE,
11
11
  enable: EMPTY_VALUE,
12
12
  enable_scan_response: Contrast::Config::DefaultValue.new('true'),
13
+ enable_dynamic_sources: Contrast::Config::DefaultValue.new('true'),
13
14
  sampling: Contrast::Config::SamplingConfiguration,
14
15
  rules: Contrast::Config::AssessRulesConfiguration,
15
16
  stacktraces: Contrast::Config::DefaultValue.new('ALL')
@@ -12,7 +12,7 @@ module Contrast
12
12
  class BaseConfiguration
13
13
  extend Forwardable
14
14
 
15
- BOOLEANS = [true, false].cs__freeze
15
+ STRING_BOOLEANS = %w[false true].cs__freeze
16
16
 
17
17
  attr_reader :map
18
18
 
@@ -73,8 +73,18 @@ module Contrast
73
73
  spec_value.new(user_provided_value)
74
74
  elsif spec_value.is_a?(Contrast::Config::DefaultValue) && user_provided_value == EMPTY_VALUE
75
75
  spec_value.value
76
- elsif BOOLEANS.include?(user_provided_value)
77
- user_provided_value.to_s
76
+ elsif user_provided_value.cs__is_a?(String)
77
+ value = user_provided_value.downcase
78
+ # converts string values to 'true' => true or 'false' => false
79
+ case value
80
+ when STRING_BOOLEANS[1]
81
+ true
82
+ when STRING_BOOLEANS[0]
83
+ false
84
+ else
85
+ # returns non boolean string values
86
+ user_provided_value
87
+ end
78
88
  else
79
89
  user_provided_value
80
90
  end
@@ -95,9 +105,7 @@ module Contrast
95
105
 
96
106
  def define_setter str_key
97
107
  define_singleton_method "#{ str_key }=".to_sym do |new_value|
98
- boolean_value = new_value == true
99
- boolean_value ||= new_value == false
100
- @map[str_key] = boolean_value ? new_value.to_s : new_value
108
+ @map[str_key] = new_value
101
109
  end
102
110
  end
103
111
  end
@@ -0,0 +1,25 @@
1
+ # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ module Contrast
5
+ module Config
6
+ # This module is holding all the Env Variables that we could use through the agent lifecycle
7
+ module EnvVariables
8
+ ENV_VARIABLES = {
9
+ telemetry_opt_outs: ENV['CONTRAST_AGENT_TELEMETRY_OPTOUT'].to_s || Contrast::Config::DefaultValue.new('false')
10
+ }.cs__freeze
11
+
12
+ def return_value key
13
+ return unless ENV_VARIABLES.key?(key.to_sym)
14
+
15
+ sym_key = key.downcase.to_sym
16
+ return_val = ENV_VARIABLES[sym_key]
17
+ if return_val.is_a?(Contrast::Config::DefaultValue)
18
+ return_val.value
19
+ else
20
+ return_val
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -6,6 +6,7 @@ module Contrast
6
6
  # The base of the Common Configuration settings.
7
7
  class RootConfiguration < BaseConfiguration
8
8
  KEYS = {
9
+ api: Contrast::Config::ApiConfiguration,
9
10
  enable: BaseConfiguration::EMPTY_VALUE,
10
11
  agent: Contrast::Config::AgentConfiguration,
11
12
  application: Contrast::Config::ApplicationConfiguration,
@@ -19,7 +19,8 @@ module Contrast
19
19
  host: EMPTY_VALUE,
20
20
  port: EMPTY_VALUE,
21
21
  socket: EMPTY_VALUE,
22
- logger: Contrast::Config::LoggerConfiguration
22
+ logger: Contrast::Config::LoggerConfiguration,
23
+ bypass: Contrast::Config::DefaultValue.new(false)
23
24
  }.cs__freeze
24
25
 
25
26
  def initialize hsh
@@ -24,6 +24,7 @@ require 'contrast/config/protect_rules_configuration'
24
24
  require 'contrast/config/sampling_configuration'
25
25
 
26
26
  require 'contrast/config/ruby_configuration'
27
+ require 'contrast/config/api_configuration'
27
28
  require 'contrast/config/agent_configuration'
28
29
  require 'contrast/config/application_configuration'
29
30
  require 'contrast/config/server_configuration'
@@ -7,6 +7,7 @@ require 'fileutils'
7
7
  require 'contrast/config'
8
8
  require 'contrast/utils/object_share'
9
9
  require 'contrast/components/scope'
10
+ require 'contrast/utils/exclude_key'
10
11
 
11
12
  module Contrast
12
13
  # This is how we read in the local settings for the Agent, both ENV/ CMD line
@@ -48,9 +49,7 @@ module Contrast
48
49
  # in an infinite loop on the to_sym method used later.
49
50
  def method_missing symbol, *args
50
51
  with_contrast_scope do
51
- root.public_send(symbol, *args)
52
- rescue NoMethodError => _e
53
- super
52
+ root.public_send(symbol, *args) if root.cs__respond_to?(symbol)
54
53
  end
55
54
  end
56
55
 
@@ -101,8 +100,7 @@ module Contrast
101
100
  {}
102
101
  end
103
102
 
104
- # We're updating properties loaded from the configuration
105
- # files to match the new agreed upon standard configuration
103
+ # We're updating properties loaded from the configuration files to match the new agreed upon standard configuration
106
104
  # names, so that one file works for all agents
107
105
  def update_prop_keys config
108
106
  CONVERSION.each_pair do |old_method, new_method|
@@ -120,16 +118,7 @@ module Contrast
120
118
  # We changed the seconds values into ms values. Multiply them accordingly
121
119
  old_value = old_value.to_i * 1000 if new_method.end_with?(MILLISECOND_MARKER)
122
120
  new_value = config
123
- end_idx = new_keys.length - 1
124
- new_keys.each_with_index do |new_key, index|
125
- if index == end_idx
126
- new_value[new_key] = old_value if new_value[new_key].nil?
127
- else
128
- new_value = {} if new_value.nil?
129
- new_value[new_key] = {} if new_value[new_key].nil?
130
- new_value = new_value[new_key]
131
- end
132
- end
121
+ replace_props(new_keys, new_value, old_value)
133
122
  end
134
123
 
135
124
  config
@@ -230,6 +219,8 @@ module Contrast
230
219
  case convert
231
220
  when Contrast::Config::BaseConfiguration
232
221
  convert.cs__class::KEYS.each_key do |key|
222
+ next if Contrast::Utils::ExcludeKey.excludable? key.to_s
223
+
233
224
  hash[key] = convert_to_hash(convert.send(key), {})
234
225
  end
235
226
  hash
@@ -237,5 +228,21 @@ module Contrast
237
228
  convert
238
229
  end
239
230
  end
231
+
232
+ def replace_props new_keys, new_value, old_value
233
+ idx = 0
234
+ end_idx = new_keys.length - 1
235
+ while idx < new_keys.length
236
+ new_key = new_keys[idx]
237
+ if idx == end_idx
238
+ new_value[new_key] = old_value if new_value[new_key].nil?
239
+ else
240
+ new_value = {} if new_value.nil?
241
+ new_value[new_key] = {} if new_value[new_key].nil?
242
+ new_value = new_value[new_key]
243
+ end
244
+ idx += 1
245
+ end
246
+ end
240
247
  end
241
248
  end
@@ -11,7 +11,7 @@ module Contrast
11
11
  # This is our patch of the Array class required to handle propagation
12
12
  # Disclaimer: there may be a better way, but we're in a 'get it work' state.
13
13
  # Hopefully, we'll be in a 'get it right' state soon.
14
- class ArrayPropagator
14
+ class ArrayPropagator # rubocop:disable Style/StaticClass
15
15
  extend Contrast::Components::Scope::InstanceMethods
16
16
 
17
17
  ARRAY_JOIN_HASH = {
@@ -59,16 +59,6 @@ module Contrast
59
59
  ret
60
60
  end
61
61
  end
62
-
63
- def instrument_array_track
64
- @_instrument_array_track ||= begin
65
- require 'cs__assess_array/cs__assess_array'
66
- true
67
- end
68
- rescue StandardError, LoadError => e
69
- logger.error('Error loading assess track patch', e)
70
- false
71
- end
72
62
  end
73
63
  end
74
64
  end
@@ -34,26 +34,6 @@ module Contrast
34
34
  ret, source)
35
35
  end
36
36
 
37
- def instrument_basic_object_track
38
- @_instrument_basic_object_track ||= begin
39
- require 'cs__assess_basic_object/cs__assess_basic_object'
40
- true
41
- end
42
- rescue StandardError, LoadError => e
43
- logger.error('Error loading basic object track patch', e)
44
- false
45
- end
46
-
47
- def instrument_module_track
48
- @_instrument_module_track ||= begin
49
- require 'cs__assess_module/cs__assess_module'
50
- true
51
- end
52
- rescue StandardError, LoadError => e
53
- logger.error('Error loading module track patch', e)
54
- false
55
- end
56
-
57
37
  private
58
38
 
59
39
  def trigger_node clazz, method
@@ -20,7 +20,6 @@ module Contrast
20
20
  extend Contrast::Components::Logger::InstanceMethods
21
21
  extend Contrast::Components::Scope::InstanceMethods
22
22
 
23
-
24
23
  # we use funchook to patch rb_fiber_new the initialize method is not exposed by Ruby core
25
24
  FIBER_NEW_NODE_HASH = {
26
25
  'class_name' => 'Fiber',
@@ -86,16 +85,6 @@ module Contrast
86
85
  rescue Exception => e # rubocop:disable Lint/RescueException
87
86
  logger.error('Unable to propagate during Fiber.new', e)
88
87
  end
89
-
90
- def instrument_fiber_track
91
- @_instrument_fiber_variables ||= begin
92
- require 'cs__assess_fiber_track/cs__assess_fiber_track' if Funchook.available?
93
- true
94
- end
95
- rescue StandardError, LoadError => e
96
- logger.error('Error loading fiber track patch', e)
97
- false
98
- end
99
88
  end
100
89
  end
101
90
  end
@@ -25,16 +25,6 @@ module Contrast
25
25
  # result in a seg fault
26
26
  object
27
27
  end
28
-
29
- def instrument_hash_track
30
- @_instrument_hash_track ||= begin
31
- require 'cs__assess_hash/cs__assess_hash'
32
- true
33
- end
34
- rescue StandardError, LoadError => e
35
- logger.error('Error loading hash track patch', e)
36
- false
37
- end
38
28
  end
39
29
  end
40
30
  end
@@ -14,6 +14,7 @@ module Contrast
14
14
  module KernelPropagator
15
15
  class << self
16
16
  extend Contrast::Components::Logger::InstanceMethods
17
+ include Contrast::Components::Logger::InstanceMethods
17
18
  include Contrast::Extension::Assess::ExecTrigger
18
19
 
19
20
  # We're 'tracking' sprintf now, meaning if anything is tracked on the way
@@ -65,16 +66,6 @@ module Contrast
65
66
  logger.error('Unable to track dataflow through sprintf', e)
66
67
  end
67
68
 
68
- def instrument_kernel_track
69
- @_instrument_fiber_variables ||= begin
70
- require 'cs__assess_kernel/cs__assess_kernel'
71
- true
72
- end
73
- rescue StandardError, LoadError => e
74
- logger.error('Error loading kernel track patch', e)
75
- false
76
- end
77
-
78
69
  private
79
70
 
80
71
  def handle_sprintf_value value, result, parent_events
@@ -12,10 +12,12 @@ module Contrast
12
12
  # Hopefully, we'll be in a 'get it right' state soon.
13
13
  # This module is used for our Marshal.load patches
14
14
  class MarshalPropagator
15
- extend Contrast::Components::Logger::InstanceMethods
16
15
  extend Contrast::Components::Scope::InstanceMethods
17
16
 
18
17
  class << self
18
+ extend Contrast::Components::Logger::InstanceMethods
19
+ include Contrast::Components::Logger::InstanceMethods
20
+
19
21
  def cs__load_protect arg
20
22
  return if in_contrast_scope?
21
23
 
@@ -44,16 +46,6 @@ module Contrast
44
46
  end
45
47
  end
46
48
 
47
- def instrument_marshal_load
48
- @_instrument_marshal_load ||= begin
49
- require 'cs__assess_marshal_module/cs__assess_marshal_module'
50
- true
51
- end
52
- rescue StandardError, LoadError => e
53
- logger.error('Error loading marshal load patch', e)
54
- false
55
- end
56
-
57
49
  def trigger_node clazz, method
58
50
  triggers = Contrast::Agent::Assess::Policy::Policy.instance.triggers
59
51
  return unless triggers
@@ -16,7 +16,6 @@ module Contrast
16
16
  extend Contrast::Components::Logger::InstanceMethods
17
17
  extend Contrast::Components::Scope::InstanceMethods
18
18
 
19
-
20
19
  REGEXP_EQUAL_SQUIGGLE_HASH = {
21
20
  'id' => 'regexp_100',
22
21
  'class_name' => 'Regexp',
@@ -59,16 +58,6 @@ module Contrast
59
58
  rescue Exception => e # rubocop:disable Lint/RescueException
60
59
  logger.error('Unable to propagate during Regexp#=~', e)
61
60
  end
62
-
63
- def instrument_regexp_track
64
- @_instrument_regexp_track ||= begin
65
- require 'cs__assess_regexp/cs__assess_regexp'
66
- true
67
- end
68
- rescue StandardError, LoadError => e
69
- logger.error('Error loading regexp track patch', e)
70
- false
71
- end
72
61
  end
73
62
  end
74
63
  end