contrast-agent 4.8.0 → 4.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -1
  3. data/.rspec +0 -1
  4. data/.rspec_parallel +6 -0
  5. data/.simplecov +1 -0
  6. data/ext/cs__contrast_patch/cs__contrast_patch.c +0 -1
  7. data/ext/cs__contrast_patch/cs__contrast_patch.h +0 -2
  8. data/lib/contrast/agent/assess/contrast_event.rb +1 -5
  9. data/lib/contrast/agent/assess/contrast_object.rb +0 -3
  10. data/lib/contrast/agent/assess/finalizers/hash.rb +2 -5
  11. data/lib/contrast/agent/assess/policy/patcher.rb +5 -4
  12. data/lib/contrast/agent/assess/policy/policy.rb +1 -1
  13. data/lib/contrast/agent/assess/policy/policy_scanner.rb +2 -6
  14. data/lib/contrast/agent/assess/policy/preshift.rb +16 -12
  15. data/lib/contrast/agent/assess/policy/propagation_method.rb +102 -59
  16. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +2 -7
  17. data/lib/contrast/agent/assess/policy/propagator/match_data.rb +31 -11
  18. data/lib/contrast/agent/assess/policy/propagator/remove.rb +4 -9
  19. data/lib/contrast/agent/assess/policy/propagator/split.rb +10 -6
  20. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +3 -3
  21. data/lib/contrast/agent/assess/policy/rewriter_patch.rb +6 -7
  22. data/lib/contrast/agent/assess/policy/source_method.rb +18 -22
  23. data/lib/contrast/agent/assess/policy/trigger/xpath.rb +0 -4
  24. data/lib/contrast/agent/assess/policy/trigger_method.rb +62 -88
  25. data/lib/contrast/agent/assess/policy/trigger_node.rb +1 -1
  26. data/lib/contrast/agent/assess/property/evented.rb +2 -1
  27. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +3 -4
  28. data/lib/contrast/agent/at_exit_hook.rb +3 -3
  29. data/lib/contrast/agent/class_reopener.rb +6 -5
  30. data/lib/contrast/agent/disable_reaction.rb +4 -5
  31. data/lib/contrast/agent/exclusion_matcher.rb +2 -7
  32. data/lib/contrast/agent/inventory/database_config.rb +117 -0
  33. data/lib/contrast/agent/inventory/dependency_analysis.rb +2 -6
  34. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +9 -10
  35. data/lib/contrast/agent/inventory/policy/datastores.rb +5 -6
  36. data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
  37. data/lib/contrast/agent/middleware.rb +15 -13
  38. data/lib/contrast/agent/patching/policy/after_load_patch.rb +6 -3
  39. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +21 -16
  40. data/lib/contrast/agent/patching/policy/module_policy.rb +2 -4
  41. data/lib/contrast/agent/patching/policy/patch.rb +13 -8
  42. data/lib/contrast/agent/patching/policy/patch_status.rb +3 -7
  43. data/lib/contrast/agent/patching/policy/patcher.rb +14 -14
  44. data/lib/contrast/agent/patching/policy/policy.rb +2 -4
  45. data/lib/contrast/agent/patching/policy/policy_node.rb +2 -3
  46. data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +1 -1
  47. data/lib/contrast/agent/protect/policy/policy.rb +1 -1
  48. data/lib/contrast/agent/protect/policy/rule_applicator.rb +3 -5
  49. data/lib/contrast/agent/protect/rule/base.rb +10 -10
  50. data/lib/contrast/agent/protect/rule/cmd_injection.rb +4 -5
  51. data/lib/contrast/agent/protect/rule/no_sqli.rb +7 -53
  52. data/lib/contrast/agent/protect/rule/path_traversal.rb +1 -5
  53. data/lib/contrast/agent/protect/rule/sql_sample_builder.rb +137 -0
  54. data/lib/contrast/agent/protect/rule/sqli.rb +7 -70
  55. data/lib/contrast/agent/reaction_processor.rb +3 -4
  56. data/lib/contrast/agent/request.rb +13 -7
  57. data/lib/contrast/agent/request_context.rb +36 -34
  58. data/lib/contrast/agent/request_handler.rb +5 -3
  59. data/lib/contrast/agent/response.rb +2 -3
  60. data/lib/contrast/agent/rewriter.rb +4 -3
  61. data/lib/contrast/agent/rule_set.rb +5 -4
  62. data/lib/contrast/agent/scope.rb +32 -20
  63. data/lib/contrast/agent/service_heartbeat.rb +2 -3
  64. data/lib/contrast/agent/static_analysis.rb +7 -6
  65. data/lib/contrast/agent/thread.rb +2 -4
  66. data/lib/contrast/agent/thread_watcher.rb +3 -4
  67. data/lib/contrast/agent/tracepoint_hook.rb +20 -7
  68. data/lib/contrast/agent/version.rb +1 -1
  69. data/lib/contrast/api/communication/messaging_queue.rb +16 -11
  70. data/lib/contrast/api/communication/response_processor.rb +11 -11
  71. data/lib/contrast/api/communication/service_lifecycle.rb +9 -5
  72. data/lib/contrast/api/communication/socket_client.rb +18 -14
  73. data/lib/contrast/api/communication/speedracer.rb +5 -6
  74. data/lib/contrast/api/decorators/address.rb +2 -3
  75. data/lib/contrast/api/decorators/agent_startup.rb +7 -9
  76. data/lib/contrast/api/decorators/application_startup.rb +9 -10
  77. data/lib/contrast/api/decorators/application_update.rb +0 -4
  78. data/lib/contrast/api/decorators/http_request.rb +3 -7
  79. data/lib/contrast/api/decorators/instrumentation_mode.rb +3 -5
  80. data/lib/contrast/api/decorators/message.rb +7 -7
  81. data/lib/contrast/api/decorators/route_coverage.rb +24 -1
  82. data/lib/contrast/api/decorators/trace_event_object.rb +2 -3
  83. data/lib/contrast/components/agent.rb +13 -15
  84. data/lib/contrast/components/app_context.rb +7 -11
  85. data/lib/contrast/components/assess.rb +19 -16
  86. data/lib/contrast/components/base.rb +40 -0
  87. data/lib/contrast/components/config.rb +1 -2
  88. data/lib/contrast/components/contrast_service.rb +8 -11
  89. data/lib/contrast/components/heap_dump.rb +5 -4
  90. data/lib/contrast/components/inventory.rb +2 -7
  91. data/lib/contrast/components/logger.rb +14 -10
  92. data/lib/contrast/components/protect.rb +10 -13
  93. data/lib/contrast/components/sampling.rb +5 -5
  94. data/lib/contrast/components/scope.rb +9 -32
  95. data/lib/contrast/components/settings.rb +1 -5
  96. data/lib/contrast/config/base_configuration.rb +14 -6
  97. data/lib/contrast/configuration.rb +22 -19
  98. data/lib/contrast/extension/assess/array.rb +3 -15
  99. data/lib/contrast/extension/assess/eval_trigger.rb +2 -23
  100. data/lib/contrast/extension/assess/fiber.rb +6 -16
  101. data/lib/contrast/extension/assess/hash.rb +3 -13
  102. data/lib/contrast/extension/assess/kernel.rb +3 -14
  103. data/lib/contrast/extension/assess/marshal.rb +6 -14
  104. data/lib/contrast/extension/assess/regexp.rb +5 -15
  105. data/lib/contrast/extension/assess/string.rb +6 -31
  106. data/lib/contrast/extension/extension.rb +61 -0
  107. data/lib/contrast/extension/kernel.rb +2 -4
  108. data/lib/contrast/extension/protect/kernel.rb +0 -15
  109. data/lib/contrast/framework/grape/support.rb +174 -0
  110. data/lib/contrast/framework/manager.rb +44 -9
  111. data/lib/contrast/framework/rack/patch/session_cookie.rb +6 -6
  112. data/lib/contrast/framework/rack/support.rb +1 -1
  113. data/lib/contrast/framework/rails/patch/assess_configuration.rb +5 -8
  114. data/lib/contrast/framework/rails/patch/support.rb +43 -36
  115. data/lib/contrast/framework/rails/railtie.rb +8 -6
  116. data/lib/contrast/framework/rails/rewrite/active_record_named.rb +4 -4
  117. data/lib/contrast/framework/rails/support.rb +60 -13
  118. data/lib/contrast/framework/sinatra/support.rb +1 -1
  119. data/lib/contrast/funchook/funchook.rb +4 -3
  120. data/lib/contrast/logger/application.rb +1 -6
  121. data/lib/contrast/logger/log.rb +103 -13
  122. data/lib/contrast/logger/request.rb +0 -4
  123. data/lib/contrast/tasks/config.rb +0 -1
  124. data/lib/contrast/tasks/service.rb +1 -6
  125. data/lib/contrast/utils/assess/sampling_util.rb +2 -3
  126. data/lib/contrast/utils/assess/tracking_util.rb +2 -4
  127. data/lib/contrast/utils/class_util.rb +26 -19
  128. data/lib/contrast/utils/heap_dump_util.rb +5 -3
  129. data/lib/contrast/utils/invalid_configuration_util.rb +4 -3
  130. data/lib/contrast/utils/io_util.rb +46 -40
  131. data/lib/contrast/utils/job_servers_running.rb +4 -3
  132. data/lib/contrast/utils/lru_cache.rb +43 -0
  133. data/lib/contrast/utils/os.rb +2 -3
  134. data/lib/contrast/utils/ruby_ast_rewriter.rb +16 -13
  135. data/lib/contrast/utils/string_utils.rb +2 -3
  136. data/lib/contrast/utils/tag_util.rb +26 -19
  137. data/lib/contrast.rb +24 -14
  138. data/resources/assess/policy.json +197 -2
  139. data/resources/deadzone/policy.json +10 -0
  140. data/ruby-agent.gemspec +13 -3
  141. data/service_executables/VERSION +1 -1
  142. data/service_executables/linux/contrast-service +0 -0
  143. data/service_executables/mac/contrast-service +0 -0
  144. metadata +91 -25
  145. data/lib/contrast/components/interface.rb +0 -196
  146. data/lib/contrast/delegators/input_analysis.rb +0 -12
  147. data/lib/contrast/utils/inventory_util.rb +0 -114
@@ -1,6 +1,10 @@
1
1
  # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'contrast/components/base'
5
+ require 'contrast/components/config'
6
+ require 'contrast/components/settings'
7
+
4
8
  module Contrast
5
9
  module Components
6
10
  module Assess
@@ -10,24 +14,21 @@ module Contrast
10
14
  # Specifically, this allows for querying the state of the Assess product.
11
15
  class Interface
12
16
  include Contrast::Components::ComponentBase
13
- include Contrast::Components::Interface
14
-
15
- access_component :config, :settings
16
17
 
17
18
  def enabled?
18
19
  # config overrides if forcibly set
19
20
  return false if forcibly_disabled?
20
21
  return true if forcibly_enabled?
21
22
 
22
- SETTINGS.assess_state.enabled == true
23
+ ::Contrast::SETTINGS.assess_state.enabled == true
23
24
  end
24
25
 
25
26
  def tainted_columns
26
- SETTINGS.tainted_columns
27
+ ::Contrast::SETTINGS.tainted_columns
27
28
  end
28
29
 
29
30
  def forcibly_disabled?
30
- @_forcibly_disabled = false?(CONFIG.root.assess.enable) if @_forcibly_disabled.nil?
31
+ @_forcibly_disabled = false?(::Contrast::CONFIG.root.assess.enable) if @_forcibly_disabled.nil?
31
32
  @_forcibly_disabled
32
33
  end
33
34
 
@@ -39,9 +40,9 @@ module Contrast
39
40
  # faster comparisons when we use it. Anything not one of the known values of
40
41
  # 'NONE', 'SOME', or 'ALL' is treated as 'ALL'
41
42
  #
42
- # @return [Symbol] the normalized value of CONFIG.root.assess.stacktraces
43
+ # @return [Symbol] the normalized value of ::Contrast::CONFIG.root.assess.stacktraces
43
44
  def capture_stacktrace_value
44
- @_capture_stacktrace_value ||= case CONFIG.root.assess.stacktraces.upcase
45
+ @_capture_stacktrace_value ||= case ::Contrast::CONFIG.root.assess.stacktraces.upcase
45
46
  when 'NONE'
46
47
  :NONE
47
48
  when 'SOME'
@@ -71,38 +72,40 @@ module Contrast
71
72
  end
72
73
 
73
74
  def scan_response?
74
- @_scan_response = !false?(CONFIG.root.assess.enable_scan_response) if @_scan_response.nil?
75
+ @_scan_response = !false?(::Contrast::CONFIG.root.assess.enable_scan_response) if @_scan_response.nil?
75
76
  @_scan_response
76
77
  end
77
78
 
78
79
  def track_frozen_sources?
79
- @_track_frozen_sources = !false?(CONFIG.root.agent.ruby.track_frozen_sources) if @_track_frozen_sources.nil?
80
+ if @_track_frozen_sources.nil?
81
+ @_track_frozen_sources = !false?(::Contrast::CONFIG.root.agent.ruby.track_frozen_sources)
82
+ end
80
83
  @_track_frozen_sources
81
84
  end
82
85
 
83
86
  def require_scan?
84
- @_require_scan = !false?(CONFIG.root.agent.ruby.require_scan) if @_require_scan.nil?
87
+ @_require_scan = !false?(::Contrast::CONFIG.root.agent.ruby.require_scan) if @_require_scan.nil?
85
88
  @_require_scan
86
89
  end
87
90
 
88
91
  def tags
89
- CONFIG.root.assess&.tags
92
+ ::Contrast::CONFIG.root.assess&.tags
90
93
  end
91
94
 
92
95
  def disabled_rules
93
96
  # TODO: RUBY-903
94
- CONFIG.root.assess&.rules&.disabled_rules || SETTINGS.assess_state.disabled_assess_rules || []
97
+ ::Contrast::CONFIG.root.assess&.rules&.disabled_rules ||
98
+ ::Contrast::SETTINGS.assess_state.disabled_assess_rules ||
99
+ []
95
100
  end
96
101
 
97
102
  private
98
103
 
99
104
  def forcibly_enabled?
100
- @_forcibly_enabled = true?(CONFIG.root.assess.enable) if @_forcibly_enabled.nil?
105
+ @_forcibly_enabled = true?(::Contrast::CONFIG.root.assess.enable) if @_forcibly_enabled.nil?
101
106
  @_forcibly_enabled
102
107
  end
103
108
  end
104
-
105
- COMPONENT_INTERFACE = Interface.new
106
109
  end
107
110
  end
108
111
  end
@@ -0,0 +1,40 @@
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 Components
6
+ # All components should inherit from this,
7
+ # whether Interfaces, InstanceMethods or ClassMethods.
8
+ module ComponentBase
9
+ # use this to determine if the configuration value is literally boolean
10
+ # false or some form of the word `false`, regardless of case. It should
11
+ # be used for those values which default to `true` as they should only
12
+ # treat a value explicitly set to `false` as such.
13
+ #
14
+ # @param config_param [Boolean,String] the value to check
15
+ # @return [Boolean] should the value be treated as `false`
16
+ def false? config_param
17
+ return false if config_param == true
18
+ return true if config_param == false
19
+ return false unless config_param.cs__is_a?(String)
20
+
21
+ config_param.downcase == Contrast::Utils::ObjectShare::FALSE
22
+ end
23
+
24
+ # use this to determine if the configuration value is literally boolean
25
+ # true or some form of the word `true`, regardless of case. It should
26
+ # be used for those values which default to `false` as they should only
27
+ # treat a value explicitly set to `true` as such.
28
+ #
29
+ # @param config_param [Boolean,String] the value to check
30
+ # @return [Boolean] should the value be treated as `true`
31
+ def true? config_param
32
+ return false if config_param == false
33
+ return true if config_param == true
34
+ return false unless config_param.cs__is_a?(String)
35
+
36
+ config_param.downcase == Contrast::Utils::ObjectShare::TRUE
37
+ end
38
+ end
39
+ end
40
+ end
@@ -44,6 +44,7 @@ module Contrast
44
44
 
45
45
  def valid?
46
46
  @_valid = validate(log: false) if @_valid.nil?
47
+ @_valid
47
48
  end
48
49
 
49
50
  def invalid?
@@ -108,8 +109,6 @@ module Contrast
108
109
  @config.application.session_metadata
109
110
  end
110
111
  end
111
-
112
- COMPONENT_INTERFACE = Interface.new
113
112
  end
114
113
  end
115
114
  end
@@ -13,37 +13,36 @@ module Contrast
13
13
  # the Service, as well as sending a message to the Service.
14
14
  class Interface
15
15
  include Contrast::Components::ComponentBase
16
- include Contrast::Components::Interface
17
16
 
18
17
  DEFAULT_SERVICE_LOG = 'contrast_service.log'
19
18
  # The Rails ActionDispatch regexp for localhost IP + literal localhost
20
19
  # https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/request.rb#L32
21
20
  LOCALHOST = Regexp.union [/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/, /^localhost$/]
22
21
 
23
- access_component :agent, :config
24
-
25
22
  def use_bundled_service?
26
23
  # Validates the config to decide if it's suitable for starting
27
24
  # the bundled service
28
25
 
29
26
  # Requirement says "must be true" but that
30
27
  # should be "must not be false" -- oops.
31
- @_use_bundled_service ||= !false?(CONFIG.root.agent.start_bundled_service) &&
28
+ @_use_bundled_service ||= !false?(::Contrast::CONFIG.root.agent.start_bundled_service) &&
32
29
  # Either a valid host or a valid socket
33
30
  # Path validity is the service's problem
34
31
  (LOCALHOST.match?(host) || !!socket_path)
35
32
  end
36
33
 
37
34
  def host
38
- @_host ||= (CONFIG.root.agent.service.host || Contrast::Config::ServiceConfiguration::DEFAULT_HOST).to_s
35
+ @_host ||=
36
+ (::Contrast::CONFIG.root.agent.service.host || Contrast::Config::ServiceConfiguration::DEFAULT_HOST).to_s
39
37
  end
40
38
 
41
39
  def port
42
- @_port ||= (CONFIG.root.agent.service.port || Contrast::Config::ServiceConfiguration::DEFAULT_PORT).to_i
40
+ @_port ||=
41
+ (::Contrast::CONFIG.root.agent.service.port || Contrast::Config::ServiceConfiguration::DEFAULT_PORT).to_i
43
42
  end
44
43
 
45
44
  def socket_path
46
- @_socket_path ||= CONFIG.root.agent.service.socket
45
+ @_socket_path ||= ::Contrast::CONFIG.root.agent.service.socket
47
46
  end
48
47
 
49
48
  def use_tcp?
@@ -51,18 +50,16 @@ module Contrast
51
50
  end
52
51
 
53
52
  def logger_path
54
- @_logger_path ||= CONFIG.root.agent.service.logger.path || DEFAULT_SERVICE_LOG
53
+ @_logger_path ||= ::Contrast::CONFIG.root.agent.service.logger.path || DEFAULT_SERVICE_LOG
55
54
  end
56
55
 
57
56
  private
58
57
 
59
58
  def disabled?
60
- @_disabled = false?(CONFIG.root.agent.start_bundled_service) if @_disabled.nil?
59
+ @_disabled = false?(::Contrast::CONFIG.root.agent.start_bundled_service) if @_disabled.nil?
61
60
  @_disabled
62
61
  end
63
62
  end
64
-
65
- COMPONENT_INTERFACE = Interface.new
66
63
  end
67
64
  end
68
65
  end
@@ -1,6 +1,9 @@
1
1
  # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'contrast/components/base'
5
+ require 'contrast/components/heap_dump'
6
+
4
7
  module Contrast
5
8
  module Components
6
9
  module HeapDump
@@ -11,9 +14,6 @@ module Contrast
11
14
  # utility.
12
15
  module ClassMethods
13
16
  include Contrast::Components::ComponentBase
14
- include Contrast::Components::Interface
15
-
16
- access_component :config
17
17
 
18
18
  def heap_dump_enabled?
19
19
  heap_dump_control[:enabled]
@@ -21,7 +21,7 @@ module Contrast
21
21
 
22
22
  def heap_dump_control
23
23
  @_heap_dump_control ||= begin
24
- config = CONFIG.root&.agent&.heap_dump
24
+ config = ::Contrast::CONFIG.root&.agent&.heap_dump
25
25
  {
26
26
  enabled: true?(config&.enable),
27
27
  path: File.absolute_path(config&.path),
@@ -33,6 +33,7 @@ module Contrast
33
33
  end
34
34
  end
35
35
  end
36
+ InstanceMethods = ClassMethods
36
37
  end
37
38
  end
38
39
  end
@@ -11,22 +11,17 @@ module Contrast
11
11
  # product.
12
12
  class Interface
13
13
  include Contrast::Components::ComponentBase
14
- include Contrast::Components::Interface
15
-
16
- access_component :config, :settings
17
14
 
18
15
  def enabled?
19
- @_enabled = !false?(CONFIG.root.inventory.enable) if @_enabled.nil?
16
+ @_enabled = !false?(::Contrast::CONFIG.root.inventory.enable) if @_enabled.nil?
20
17
  @_enabled
21
18
  end
22
19
 
23
20
  def analyze_libraries?
24
- @_analyze_libraries = !false?(CONFIG.root.inventory.analyze_libraries) if @_analyze_libraries.nil?
21
+ @_analyze_libraries = !false?(::Contrast::CONFIG.root.inventory.analyze_libraries) if @_analyze_libraries.nil?
25
22
  @_analyze_libraries
26
23
  end
27
24
  end
28
-
29
- COMPONENT_INTERFACE = Interface.new
30
25
  end
31
26
  end
32
27
  end
@@ -2,26 +2,30 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/logger/log'
5
+ require 'contrast/components/base'
5
6
 
6
7
  module Contrast
7
8
  module Components
8
- module Logger
9
- module InstanceMethods #:nodoc:
9
+ module Logger # :nodoc:
10
+ module InstanceMethods # :nodoc:
10
11
  def logger
11
12
  Contrast::Logger::Log.instance.logger
12
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
13
18
  end
14
- ClassMethods = InstanceMethods
15
19
 
16
- # A wrapper build around the Common Agent Configuration project to allow
17
- # for access of the values contained in its
18
- # parent_configuration_spec.yaml.
19
- # Specifically, this allows for querying the state of the Agent Logger.
20
- class Interface
21
- include Contrast::Components::ComponentBase
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
22
24
  end
23
25
 
24
- COMPONENT_INTERFACE = Interface.new
26
+ class Interface
27
+ include InstanceMethods
28
+ end
25
29
  end
26
30
  end
27
31
  end
@@ -1,6 +1,8 @@
1
1
  # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'contrast/components/base'
5
+
4
6
  module Contrast
5
7
  module Components
6
8
  module Protect
@@ -8,34 +10,31 @@ module Contrast
8
10
  # its parent_configuration_spec.yaml. Specifically, this allows for querying the state of the Protect product.
9
11
  class Interface
10
12
  include Contrast::Components::ComponentBase
11
- include Contrast::Components::Interface
12
-
13
- access_component :config, :settings
14
13
 
15
14
  def enabled?
16
15
  # config overrides if forcibly set
17
16
  return false if forcibly_disabled?
18
17
  return true if forcibly_enabled?
19
18
 
20
- SETTINGS.protect_state.enabled == true
19
+ ::Contrast::SETTINGS.protect_state.enabled == true
21
20
  end
22
21
 
23
22
  def rule_config
24
- CONFIG.root.protect.rules
23
+ ::Contrast::CONFIG.root.protect.rules
25
24
  end
26
25
 
27
26
  def rules
28
- SETTINGS.protect_state.rules
27
+ ::Contrast::SETTINGS.protect_state.rules
29
28
  end
30
29
 
31
30
  def rule_mode rule_id
32
- CONFIG.root.protect.rules[rule_id]&.applicable_mode ||
33
- SETTINGS.application_state.modes_by_id[rule_id] ||
31
+ ::Contrast::CONFIG.root.protect.rules[rule_id]&.applicable_mode ||
32
+ ::Contrast::SETTINGS.application_state.modes_by_id[rule_id] ||
34
33
  Contrast::Api::Settings::ProtectionRule::Mode::NO_ACTION
35
34
  end
36
35
 
37
36
  def rule name
38
- SETTINGS.protect_state.rules[name]
37
+ ::Contrast::SETTINGS.protect_state.rules[name]
39
38
  end
40
39
 
41
40
  def report_any_command_execution?
@@ -55,17 +54,15 @@ module Contrast
55
54
  end
56
55
 
57
56
  def forcibly_disabled?
58
- @_forcibly_disabled ||= false?(CONFIG.root.protect.enable)
57
+ @_forcibly_disabled ||= false?(::Contrast::CONFIG.root.protect.enable)
59
58
  end
60
59
 
61
60
  private
62
61
 
63
62
  def forcibly_enabled?
64
- @_forcibly_enabled ||= true?(CONFIG.root.protect.enable)
63
+ @_forcibly_enabled ||= true?(::Contrast::CONFIG.root.protect.enable)
65
64
  end
66
65
  end
67
-
68
- COMPONENT_INTERFACE = Interface.new
69
66
  end
70
67
  end
71
68
  end
@@ -1,6 +1,8 @@
1
1
  # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'contrast/components/base'
5
+
4
6
  module Contrast
5
7
  module Components
6
8
  module Sampling
@@ -15,9 +17,6 @@ module Contrast
15
17
  module ClassMethods #:nodoc:
16
18
  include Contrast::Components::ComponentBase
17
19
  include Constants
18
- include Contrast::Components::Interface
19
-
20
- access_component :config, :settings
21
20
 
22
21
  def sampling_enabled?
23
22
  sampling_control[:enabled]
@@ -25,8 +24,8 @@ module Contrast
25
24
 
26
25
  def sampling_control
27
26
  @_sampling_control ||= begin
28
- config_settings = CONFIG.root.assess&.sampling
29
- settings = SETTINGS&.assess_state&.[](:sampling_settings)
27
+ config_settings = ::Contrast::CONFIG.root.assess&.sampling
28
+ settings = ::Contrast::SETTINGS&.assess_state&.[](:sampling_settings)
30
29
  {
31
30
  enabled: enabled?(config_settings, settings),
32
31
  baseline: baseline(config_settings, settings),
@@ -94,6 +93,7 @@ module Contrast
94
93
  module InstanceMethods #:nodoc:
95
94
  include Contrast::Components::ComponentBase
96
95
  include Constants
96
+ include ClassMethods
97
97
  end
98
98
  end
99
99
  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:
@@ -20,17 +17,13 @@ module Contrast
20
17
  EXECUTION_CONTEXT = {} # rubocop:disable Style/MutableConstant
21
18
 
22
19
  class Interface # :nodoc:
23
- include Contrast::Components::ComponentBase
24
-
25
20
  def initialize
26
21
  # This is probably redundant with #scope_for_current_ec's nil check.
27
22
  EXECUTION_CONTEXT[Fiber.current] = Contrast::Agent::Scope.new
28
23
  end
29
24
 
30
- # This returns the scope governing the current execution context.
31
- # Use this sparingly, preferring the instance & class methods to
32
- # access and query scope, rather than interacting with the scope
33
- # 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.
34
27
  def scope_for_current_ec
35
28
  MONITOR.synchronize do
36
29
  return EXECUTION_CONTEXT[Fiber.current] ||= Contrast::Agent::Scope.new
@@ -39,9 +32,7 @@ module Contrast
39
32
  end
40
33
 
41
34
  module InstanceMethods # :nodoc:
42
- # For each instance method on a scope, define a forwarder
43
- # to the scope on the current execution context's scope.
44
-
35
+ # For each instance method on a scope, define a forwarder to the scope on the current execution context's scope.
45
36
  def scope_for_current_ec
46
37
  MONITOR.synchronize do
47
38
  return EXECUTION_CONTEXT[Fiber.current] ||= Contrast::Agent::Scope.new
@@ -120,24 +111,12 @@ module Contrast
120
111
  ensure
121
112
  scope_for_current_ec.exit_split_scope!
122
113
  end
123
-
124
- # TODO: RUBY-572
125
- #
126
- # Current behavior is to no-op if we're not "in a request context".
127
- # Our C functions were previously checking to see if we had a scope, because
128
- # scope was tacked on to a request context -- so "we have a scope, therefore,
129
- # we have a request context." We've decoupled scopes from request contexts,
130
- # so now it checks "do we have a request context."
131
- # RUBY-290 should remove all of that, including this method.
132
- def in_request_context?
133
- !!Contrast::Agent::REQUEST_TRACKER.current
134
- end
135
114
  end
136
115
 
137
116
  def self.sweep_dead_ecs
138
- # TODO: RUBY-571, #sweep_dead_ecs compensates for a lack of weak tables
139
- # 'ec' for execution context. in this case, it's a Fiber.
140
- # 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
141
120
  MONITOR.synchronize do
142
121
  EXECUTION_CONTEXT.delete_if do |ec, _scope|
143
122
  !ec.alive?
@@ -146,8 +125,6 @@ module Contrast
146
125
  end
147
126
 
148
127
  ClassMethods = InstanceMethods
149
-
150
- COMPONENT_INTERFACE = Interface.new
151
128
  end
152
129
  end
153
130
  end
@@ -22,9 +22,7 @@ module Contrast
22
22
 
23
23
  # This is a class.
24
24
  class Interface
25
- include Contrast::Components::ComponentBase
26
- include Contrast::Components::Interface
27
- access_component :config
25
+ extend Contrast::Components::Config
28
26
 
29
27
  # tainted_columns are database columns that receive unsanitized input.
30
28
  attr_reader :tainted_columns # This can probably go into assess_state?
@@ -76,8 +74,6 @@ module Contrast
76
74
  Contrast::Agent::Protect::Rule::Xxe.new
77
75
  end
78
76
  end
79
-
80
- COMPONENT_INTERFACE = Interface.new
81
77
  end
82
78
  end
83
79
  end
@@ -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
@@ -6,7 +6,7 @@ require 'fileutils'
6
6
 
7
7
  require 'contrast/config'
8
8
  require 'contrast/utils/object_share'
9
- require 'contrast/components/interface'
9
+ require 'contrast/components/scope'
10
10
 
11
11
  module Contrast
12
12
  # This is how we read in the local settings for the Agent, both ENV/ CMD line
@@ -15,9 +15,8 @@ module Contrast
15
15
  class Configuration
16
16
  extend Forwardable
17
17
 
18
- include Contrast::Components::Interface
19
-
20
- access_component :scope
18
+ include Contrast::Components::Scope::InstanceMethods
19
+ extend Contrast::Components::Scope::InstanceMethods
21
20
 
22
21
  def_delegator :root, :assign_value_to_path_array
23
22
 
@@ -49,9 +48,7 @@ module Contrast
49
48
  # in an infinite loop on the to_sym method used later.
50
49
  def method_missing symbol, *args
51
50
  with_contrast_scope do
52
- root.public_send(symbol, *args)
53
- rescue NoMethodError => _e
54
- super
51
+ root.public_send(symbol, *args) if root.cs__respond_to?(symbol)
55
52
  end
56
53
  end
57
54
 
@@ -102,8 +99,7 @@ module Contrast
102
99
  {}
103
100
  end
104
101
 
105
- # We're updating properties loaded from the configuration
106
- # files to match the new agreed upon standard configuration
102
+ # We're updating properties loaded from the configuration files to match the new agreed upon standard configuration
107
103
  # names, so that one file works for all agents
108
104
  def update_prop_keys config
109
105
  CONVERSION.each_pair do |old_method, new_method|
@@ -121,16 +117,7 @@ module Contrast
121
117
  # We changed the seconds values into ms values. Multiply them accordingly
122
118
  old_value = old_value.to_i * 1000 if new_method.end_with?(MILLISECOND_MARKER)
123
119
  new_value = config
124
- end_idx = new_keys.length - 1
125
- new_keys.each_with_index do |new_key, index|
126
- if index == end_idx
127
- new_value[new_key] = old_value if new_value[new_key].nil?
128
- else
129
- new_value = {} if new_value.nil?
130
- new_value[new_key] = {} if new_value[new_key].nil?
131
- new_value = new_value[new_key]
132
- end
133
- end
120
+ replace_props(new_keys, new_value, old_value)
134
121
  end
135
122
 
136
123
  config
@@ -238,5 +225,21 @@ module Contrast
238
225
  convert
239
226
  end
240
227
  end
228
+
229
+ def replace_props new_keys, new_value, old_value
230
+ idx = 0
231
+ end_idx = new_keys.length - 1
232
+ while idx < new_keys.length
233
+ new_key = new_keys[idx]
234
+ if idx == end_idx
235
+ new_value[new_key] = old_value if new_value[new_key].nil?
236
+ else
237
+ new_value = {} if new_value.nil?
238
+ new_value[new_key] = {} if new_value[new_key].nil?
239
+ new_value = new_value[new_key]
240
+ end
241
+ idx += 1
242
+ end
243
+ end
241
244
  end
242
245
  end