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
@@ -0,0 +1,129 @@
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/env_variables'
5
+ require 'contrast/components/logger'
6
+ require 'contrast/utils/requests_client'
7
+ require 'contrast/agent/worker_thread'
8
+ require 'contrast/utils/telemetry'
9
+
10
+ module Contrast
11
+ module Agent
12
+ # This class will initialize and hold everything needed for the telemetry
13
+ class Telemetry < WorkerThread
14
+ include Contrast::Utils::RequestsClient
15
+ include Contrast::Components::Logger::InstanceMethods
16
+ # this is where we will send the data from the agents
17
+ URL = 'https://telemetry.ruby.contrastsecurity.com/'
18
+ # Suggested timeout after each send is to be 3 hours (10800 seconds)
19
+ SUGGESTED_TIMEOUT = 10_800
20
+
21
+ class << self
22
+ include Contrast::Components::Logger::InstanceMethods
23
+ include Contrast::Config::EnvVariables
24
+
25
+ def application_id
26
+ @_application_id ||= begin
27
+ id = nil
28
+ mac = Contrast::Utils::Telemetry::Identifier.mac
29
+ app_name = Contrast::Utils::Telemetry::Identifier.app_name
30
+ id = mac + app_name if mac && app_name
31
+ Digest::SHA2.new(256).hexdigest(id || '_' + SecureRandom.uuid)
32
+ end
33
+ end
34
+
35
+ def instance_id
36
+ @_instance_id ||= Digest::SHA2.new(256).hexdigest(Contrast::Utils::Telemetry::Identifier.mac ||
37
+ '_' + SecureRandom.uuid)
38
+ end
39
+
40
+ def enabled?
41
+ @_enabled = telemetry_enabled? if @_enabled.nil?
42
+ @_enabled
43
+ end
44
+
45
+ private
46
+
47
+ def telemetry_enabled?
48
+ opt_out_telemetry = return_value(:telemetry_opt_outs)
49
+ return false if opt_out_telemetry.to_s.casecmp('true').zero?
50
+ return false if opt_out_telemetry.to_s.casecmp('1').zero?
51
+
52
+ # In case of connection error, do not create the background thread or queue,
53
+ # as if the opt-out env var was set
54
+ ip_opt_out_telemetry = Contrast::Utils::RequestsClient.initialize_connection(URL)
55
+ if ip_opt_out_telemetry.nil?
56
+ logger.warn('Connection was not established properly!!!')
57
+ logger.warn('THE SERVICE IS GOING TO BE TERMINATED!!')
58
+ return false
59
+ end
60
+
61
+ true
62
+ end
63
+ end
64
+
65
+ def attempt_to_start?
66
+ unless cs__class.enabled?
67
+ logger.warn('Telemetry service is disabled!')
68
+ return false
69
+ end
70
+
71
+ logger.debug('Attempting to start telemetry thread') unless running?
72
+ true
73
+ end
74
+
75
+ def start_thread!
76
+ return if running?
77
+
78
+ # It is recommended that implementations send a single payload of
79
+ # general metrics every 3 hours, starting from implementation startup.
80
+ @_thread = Contrast::Agent::Thread.new do
81
+ logger.debug('Starting background telemetry thread.')
82
+ event = queue.pop
83
+
84
+ begin
85
+ logger.debug('This is the current processed event', event)
86
+ res = Contrast::Utils::RequestsClient.send_request event, connection
87
+ sleep_time = Contrast::Utils::RequestsClient.handle_response res
88
+ sleep(sleep_time) unless sleep_time.nil?
89
+ rescue StandardError => e
90
+ logger.error('Could not send message to service from telemetry queue.', e)
91
+ end
92
+ sleep(SUGGESTED_TIMEOUT)
93
+ end
94
+ end
95
+
96
+ def send_event event
97
+ if ::Contrast::AGENT.disabled?
98
+ logger.warn('Attempted to queue event with Agent disabled', caller: caller, event: event)
99
+ return
100
+ end
101
+
102
+ return unless cs__class.enabled?
103
+
104
+ logger.debug('Enqueued event for sending', event_type: event.cs__class)
105
+
106
+ queue << event if event
107
+ end
108
+
109
+ def delete_queue!
110
+ @_queue&.clear
111
+ @_queue&.close
112
+ @_queue = nil
113
+ end
114
+
115
+ def stop!
116
+ return unless running?
117
+
118
+ super
119
+ delete_queue!
120
+ end
121
+
122
+ private
123
+
124
+ def queue
125
+ @_queue ||= Queue.new
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,34 @@
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/utils/metrics_hash'
5
+
6
+ module Contrast
7
+ module Agent
8
+ # This class will hold the basic information for a Telemetry Event
9
+ class TelemetryEvent
10
+ include Contrast::Utils
11
+
12
+ attr_reader :timestamp, :tags
13
+
14
+ # The instance_id comes from the Telemetry Instance
15
+ def initialize
16
+ @tags = MetricsHash.new(String)
17
+ @timestamp = format_date
18
+ @instance_id = Contrast::Agent.telemetry_queue.__id__
19
+ end
20
+
21
+ def path
22
+ ''
23
+ end
24
+
25
+ def to_json **_args
26
+ { tags: @tags, timestamp: @timestamp, instance_id: @instance_id }
27
+ end
28
+
29
+ def format_date
30
+ Time.now.strftime('%Y-%m-%d %H:%M:%S.%L')
31
+ end
32
+ end
33
+ end
34
+ end
@@ -4,6 +4,7 @@
4
4
  require 'contrast/components/logger'
5
5
  require 'contrast/agent/service_heartbeat'
6
6
  require 'contrast/api/communication/messaging_queue'
7
+ require 'contrast/agent/telemetry'
7
8
 
8
9
  module Contrast
9
10
  module Agent
@@ -22,28 +23,22 @@ module Contrast
22
23
  @heapdump_util = Contrast::Utils::HeapDumpUtil.new
23
24
  @heartbeat = Contrast::Agent::ServiceHeartbeat.new
24
25
  @messaging_queue = Contrast::Api::Communication::MessagingQueue.new
26
+ @telemetry = Contrast::Agent::Telemetry.new if Contrast::Agent::Telemetry.enabled?
25
27
  end
26
28
 
27
29
  def startup!
28
30
  return unless ::Contrast::AGENT.enabled?
29
31
 
30
- unless heartbeat.running?
31
- logger.debug('Attempting to start heartbeat thread')
32
- heartbeat.start_thread!
33
- end
34
- heartbeat_result = heartbeat.running?
35
- logger.debug('Heartbeat thread status', alive: heartbeat_result)
36
-
37
- unless messaging_queue.running?
38
- logger.debug('Attempting to start messaging queue thread')
39
- messaging_queue.start_thread!
40
- end
41
- messaging_result = messaging_queue.running?
42
- logger.debug('Messaging thread status', alive: messaging_result)
32
+ telemetry_thread_status = telemetry_thread_init
33
+ heartbeat_thread_status = heartbeat_thread_init
34
+ messaging_thread_status = messaging_thread_init
43
35
 
44
36
  logger.debug('ThreadWatcher started threads')
45
37
 
46
- @pids[Process.pid] = messaging_result && heartbeat_result
38
+ @pids[Process.pid] = messaging_thread_status && heartbeat_thread_status
39
+ return @pids unless Contrast::Agent::Telemetry.enabled?
40
+
41
+ @pids[Process.pid] = messaging_thread_status && heartbeat_thread_status && telemetry_thread_status
47
42
  end
48
43
 
49
44
  def ensure_running?
@@ -57,6 +52,40 @@ module Contrast
57
52
  heartbeat.stop!
58
53
  messaging_queue.stop!
59
54
  heapdump_util.stop!
55
+ telemetry_queue&.stop!
56
+ end
57
+
58
+ def heartbeat_thread_init
59
+ unless heartbeat.running?
60
+ logger.debug('Attempting to start heartbeat thread')
61
+ heartbeat.start_thread!
62
+ end
63
+ heartbeat_result = heartbeat.running?
64
+ logger.debug('Heartbeat thread status', alive: heartbeat_result)
65
+ heartbeat_result
66
+ end
67
+
68
+ def telemetry_thread_init
69
+ @telemetry.start_thread! if @telemetry&.attempt_to_start?
70
+ telemetry_result = @telemetry&.running?
71
+ logger.debug('Telemetry thread status', alive: telemetry_result)
72
+ telemetry_result
73
+ end
74
+
75
+ def messaging_thread_init
76
+ unless messaging_queue.running?
77
+ logger.debug('Attempting to start messaging queue thread')
78
+ messaging_queue.start_thread!
79
+ end
80
+ messaging_result = messaging_queue.running?
81
+ logger.debug('Messaging thread status', alive: messaging_result)
82
+ messaging_result
83
+ end
84
+
85
+ def telemetry_queue
86
+ return if @telemetry.nil?
87
+
88
+ @telemetry
60
89
  end
61
90
  end
62
91
  end
@@ -27,18 +27,31 @@ module Contrast
27
27
 
28
28
  private
29
29
 
30
+ # Use the TracePoint from the :end event, meaning the completion of a definition of a Class or Module (or
31
+ # really the completion of that piece of a definition, as determined by an `end` statement since there could be
32
+ # definitions across multiple files) to carry out actions required on definition. This typically involves
33
+ # patching and usage analysis
34
+ #
35
+ # @param tracepoint_event [TracePoint] the TracePoint from the :end
30
36
  def process tracepoint_event
31
37
  with_contrast_scope do
32
- logger.trace('Received TracePoint end event', module: tracepoint_event.self.to_s)
33
-
38
+ # the Module or Class that was loaded during this event
34
39
  loaded_module = tracepoint_event.self
40
+ # the file being loaded that contained this definition
35
41
  path = tracepoint_event.path
36
42
  return if path&.include?('contrast')
37
43
 
44
+ logger.trace('Received TracePoint end event', module: loaded_module, path: path)
45
+
46
+ Contrast::Agent.framework_manager.register_late_framework(loaded_module)
38
47
  Contrast::Agent::Inventory::DependencyUsageAnalysis.instance.associate_file(path) if path
39
48
  Contrast::Agent::Patching::Policy::Patcher.patch_specific_module(loaded_module)
40
- Contrast::Agent::Assess::Policy::RewriterPatch.rewrite_interpolation(loaded_module) if RUBY_VERSION < '2.6.0' # TODO: RUBY-714 remove guard w/ EOL of 2.5
49
+ if RUBY_VERSION < '2.6.0' # TODO: RUBY-714 remove guard w/ EOL of 2.5
50
+ Contrast::Agent::Assess::Policy::RewriterPatch.rewrite_interpolation(loaded_module)
51
+ end
41
52
  Contrast::Agent::Assess::Policy::PolicyScanner.scan(tracepoint_event)
53
+ rescue StandardError => e
54
+ logger.error('Unable to complete TracePoint analysis', e, module: loaded_module, path: path)
42
55
  end
43
56
  end
44
57
  end
@@ -3,6 +3,6 @@
3
3
 
4
4
  module Contrast
5
5
  module Agent
6
- VERSION = '4.9.1'
6
+ VERSION = '4.13.0'
7
7
  end
8
8
  end
@@ -20,7 +20,6 @@ require 'contrast/extension/delegator'
20
20
  require 'contrast/extension/inventory'
21
21
  require 'contrast/extension/module'
22
22
  require 'contrast/extension/protect'
23
- require 'contrast/extension/protect/kernel'
24
23
 
25
24
  require 'contrast/utils/object_share'
26
25
  require 'contrast/utils/string_utils'
@@ -62,6 +61,12 @@ module Contrast
62
61
  thread_watcher.messaging_queue
63
62
  end
64
63
 
64
+ def self.telemetry_queue
65
+ return unless thread_watcher.telemetry_queue
66
+
67
+ thread_watcher.telemetry_queue
68
+ end
69
+
65
70
  def self.thread_watcher
66
71
  @_thread_watcher ||= Contrast::Agent::ThreadWatcher.new
67
72
  end
@@ -11,10 +11,9 @@ module Contrast
11
11
  class MessagingQueue < Contrast::Agent::WorkerThread
12
12
  include Contrast::Components::Logger::InstanceMethods
13
13
 
14
- attr_reader :queue, :speedracer
14
+ attr_reader :speedracer
15
15
 
16
16
  def initialize
17
- @queue = Queue.new
18
17
  @speedracer = Contrast::Api::Communication::Speedracer.new
19
18
  super
20
19
  end
@@ -28,6 +27,10 @@ module Contrast
28
27
  speedracer.return_response(event)
29
28
  end
30
29
 
30
+ def queue
31
+ @_queue ||= Queue.new
32
+ end
33
+
31
34
  # Use this to add a message to the queue and process the response internally
32
35
  def send_event_eventually event
33
36
  if ::Contrast::AGENT.disabled?
@@ -42,7 +45,6 @@ module Contrast
42
45
  speedracer.ensure_startup!
43
46
  return if running?
44
47
 
45
- @queue ||= Queue.new
46
48
  @_thread = Contrast::Agent::Thread.new do
47
49
  loop do
48
50
  event = queue.pop
@@ -58,13 +60,17 @@ module Contrast
58
60
  logger.debug('Started background sending thread.')
59
61
  end
60
62
 
63
+ def delete_queue!
64
+ @_queue&.clear
65
+ @_queue&.close
66
+ @_queue = nil
67
+ end
68
+
61
69
  def stop!
62
70
  return unless running?
63
71
 
64
72
  super
65
- @queue&.clear
66
- @queue&.close
67
- @queue = nil
73
+ delete_queue!
68
74
  end
69
75
  end
70
76
  end
@@ -6,10 +6,13 @@ require 'contrast/components/logger'
6
6
  module Contrast
7
7
  module Api
8
8
  module Communication
9
- # Handles local service startup
9
+ # Handles local service startup. As this should only ever be invoked by the Speedracer class, which includes
10
+ # this, all methods here are private.
10
11
  module ServiceLifecycle
11
12
  include Contrast::Components::Logger::InstanceMethods
12
13
 
14
+ private
15
+
13
16
  def attempt_local_service_startup
14
17
  zombie_check
15
18
  service_starter_thread.join(5)
@@ -37,8 +37,7 @@ module Contrast
37
37
  log_connection
38
38
  if ::Contrast::CONTRAST_SERVICE.use_tcp?
39
39
  Contrast::Api::Communication::TcpSocket.new(
40
- ::Contrast::CONTRAST_SERVICE.host, ::Contrast::CONTRAST_SERVICE.port
41
- )
40
+ ::Contrast::CONTRAST_SERVICE.host, ::Contrast::CONTRAST_SERVICE.port)
42
41
  else
43
42
  Contrast::Api::Communication::UnixSocket.new(::Contrast::CONTRAST_SERVICE.socket_path)
44
43
  end
@@ -61,8 +60,9 @@ module Contrast
61
60
 
62
61
  # Or something is not set.
63
62
  logger.warn(
64
- log_connection_error_msg, host: ::Contrast::CONTRAST_SERVICE.host, port: ::Contrast::CONTRAST_SERVICE.port
65
- )
63
+ log_connection_error_msg,
64
+ host: ::Contrast::CONTRAST_SERVICE.host,
65
+ port: ::Contrast::CONTRAST_SERVICE.port)
66
66
  end
67
67
 
68
68
  # If our connection isn't built properly, we need to warn the user. This builds out the context specific
@@ -41,11 +41,11 @@ module Contrast
41
41
  #
42
42
  # @param msg [Contrast::Api::Dtm::AgentStartup]
43
43
  def config! msg
44
- msg.version = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.server.version
45
- msg.environment = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.server.environment
46
- msg.server_tags = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.server.tags
44
+ msg.version = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.server.version
45
+ msg.server_tags = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.server.tags
46
+ msg.library_tags = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.inventory.tags
47
+ msg.environment = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.server.environment
47
48
  msg.application_tags = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.application.tags
48
- msg.library_tags = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.inventory.tags
49
49
  end
50
50
  end
51
51
  end
@@ -24,11 +24,12 @@ module Contrast
24
24
  # @return [Contrast::Api::Dtm::ApplicationCreate]
25
25
  def build
26
26
  msg = new
27
- msg.app_version = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.application.version.to_s
28
- msg.code = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.application.code
29
- msg.group = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.application.group
30
- msg.metadata = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.application.metadata
31
- msg.mode = Contrast::Api::Dtm::InstrumentationMode.build
27
+ msg.code = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.application.code
28
+ msg.group = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.application.group
29
+ msg.metadata = Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.application.metadata
30
+ msg.mode = Contrast::Api::Dtm::InstrumentationMode.build
31
+ msg.app_version =
32
+ Contrast::Utils::StringUtils.protobuf_format ::Contrast::CONFIG.root.application.version.to_s # rubocop:disable Layout/AssignmentIndentation Layout/FirstArgumentIndentation:
32
33
  session!(msg)
33
34
  msg
34
35
  end
@@ -46,7 +46,7 @@ module Contrast
46
46
  #
47
47
  # @param controller [::Sinatra::Base] the route's final controller.
48
48
  # @param method [String] GET, PUT, POST, etc...
49
- # @param method [::Mustermann::Sinatra] the pattern that was matched in routing.
49
+ # @param pattern [::Mustermann::Sinatra] the pattern that was matched in routing.
50
50
  # @param url [String, nil] use url from string instead matched pattern.
51
51
  # @return [Contrast::Api::Dtm::RouteCoverage]
52
52
  def from_sinatra_route controller, method, pattern, url = nil
@@ -59,6 +59,29 @@ module Contrast
59
59
  msg.url = Contrast::Utils::StringUtils.force_utf8(safe_url)
60
60
  msg
61
61
  end
62
+
63
+ # Convert Grape route data to dtm message.
64
+ #
65
+ # @param controller [::Grape::API] the route's final controller.
66
+ # @param method [String] GET, PUT, POST, etc...
67
+ # @param url [String, nil] use url from string instead matched pattern.
68
+ # @param pattern [String, Grape::Router::Route] the pattern that was matched in routing.
69
+ # @return [Contrast::Api::Dtm::RouteCoverage]
70
+ def from_grape_controller controller, method, pattern, url = nil
71
+ if pattern.cs__is_a?(Grape::Router::Route)
72
+ safe_pattern = pattern.pattern&.path&.to_s
73
+ safe_url = source_or_string(url || safe_pattern)
74
+ else
75
+ safe_pattern = source_or_string(pattern)
76
+ safe_url = source_or_string(url || pattern)
77
+ end
78
+
79
+ msg = new
80
+ msg.route = "#{ controller }##{ method } #{ safe_pattern }"
81
+ msg.verb = Contrast::Utils::StringUtils.force_utf8(method)
82
+ msg.url = Contrast::Utils::StringUtils.force_utf8(safe_url)
83
+ msg
84
+ end
62
85
  end
63
86
  end
64
87
  end
@@ -54,7 +54,9 @@ module Contrast
54
54
  end
55
55
 
56
56
  def interpolation_enabled?
57
- @_interpolation_enabled = !false?(::Contrast::CONFIG.root.agent.ruby.interpolate) if @_interpolation_enabled.nil?
57
+ if @_interpolation_enabled.nil?
58
+ @_interpolation_enabled = !false?(::Contrast::CONFIG.root.agent.ruby.interpolate)
59
+ end
58
60
  @_interpolation_enabled
59
61
  end
60
62
 
@@ -69,7 +71,8 @@ module Contrast
69
71
  status:
70
72
  ::Contrast::CONFIG.root.agent.ruby.exceptions.override_status || 403,
71
73
  message:
72
- ::Contrast::CONFIG.root.agent.ruby.exceptions.override_message || Contrast::Utils::ObjectShare::OVERRIDE_MESSAGE
74
+ ::Contrast::CONFIG.root.agent.ruby.exceptions.override_message ||
75
+ Contrast::Utils::ObjectShare::OVERRIDE_MESSAGE
73
76
  }
74
77
  end
75
78
 
@@ -0,0 +1,34 @@
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/components/base'
5
+ require 'contrast/components/config'
6
+
7
+ module Contrast
8
+ module Components
9
+ module Api
10
+ # A wrapper build around the Common Agent Configuration project to allow
11
+ # for Api keys to be mapped with their values contained in their
12
+ # parent_configuration_spec.yaml.
13
+ class Interface
14
+ include Contrast::Components::ComponentBase
15
+
16
+ def api_url
17
+ @_api_url ||= ::Contrast::CONFIG.root.api.url
18
+ end
19
+
20
+ def api_key
21
+ @_api_key ||= ::Contrast::CONFIG.root.api.api_key
22
+ end
23
+
24
+ def service_key
25
+ @_service_key ||= ::Contrast::CONFIG.root.api.service_key
26
+ end
27
+
28
+ def username
29
+ @_username ||= ::Contrast::CONFIG.root.api.user_name
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -23,6 +23,10 @@ module Contrast
23
23
  DEFAULT_SERVER_NAME = 'localhost'
24
24
  DEFAULT_SERVER_PATH = '/'
25
25
 
26
+ SUPPORTED_FRAMEWORKS = %w[rails sinatra grape rack].cs__freeze
27
+
28
+ SUPPORTED_SERVERS = %w[passenger puma thin unicorn].cs__freeze
29
+
26
30
  def initialize
27
31
  original_pid
28
32
  end
@@ -109,6 +113,26 @@ module Contrast
109
113
  @_client_id ||= [app_name, pgid].join('-')
110
114
  end
111
115
 
116
+ def app_and_server_information
117
+ {
118
+ application_info: find_gem_information(SUPPORTED_FRAMEWORKS),
119
+ server_info: find_gem_information(SUPPORTED_SERVERS)
120
+ }
121
+ end
122
+
123
+ def find_gem_information arr
124
+ arr.each do |framework|
125
+ next unless Gem.loaded_specs.key?(framework)
126
+
127
+ loaded = Gem.loaded_specs[framework]
128
+ next unless loaded
129
+
130
+ name = loaded.instance_variable_get(:@name)
131
+ version = loaded.instance_variable_get(:@version).to_s
132
+ return [name, version].join(' ')
133
+ end
134
+ end
135
+
112
136
  def instrument_middleware_stack?
113
137
  !Contrast::Utils::JobServersRunning.job_servers_running?
114
138
  end
@@ -5,7 +5,6 @@ require 'contrast/components/base'
5
5
  require 'contrast/components/config'
6
6
  require 'contrast/components/settings'
7
7
 
8
-
9
8
  module Contrast
10
9
  module Components
11
10
  module Assess
@@ -78,7 +77,9 @@ module Contrast
78
77
  end
79
78
 
80
79
  def track_frozen_sources?
81
- @_track_frozen_sources = !false?(::Contrast::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
82
83
  @_track_frozen_sources
83
84
  end
84
85
 
@@ -87,13 +88,22 @@ module Contrast
87
88
  @_require_scan
88
89
  end
89
90
 
91
+ def require_dynamic_sources?
92
+ if @_require_dynamic_sources.nil?
93
+ @_require_dynamic_sources = !false?(::Contrast::CONFIG.root.assess.enable_dynamic_sources)
94
+ end
95
+ @_require_dynamic_sources
96
+ end
97
+
90
98
  def tags
91
99
  ::Contrast::CONFIG.root.assess&.tags
92
100
  end
93
101
 
94
102
  def disabled_rules
95
103
  # TODO: RUBY-903
96
- ::Contrast::CONFIG.root.assess&.rules&.disabled_rules || ::Contrast::SETTINGS.assess_state.disabled_assess_rules || []
104
+ ::Contrast::CONFIG.root.assess&.rules&.disabled_rules ||
105
+ ::Contrast::SETTINGS.assess_state.disabled_assess_rules ||
106
+ []
97
107
  end
98
108
 
99
109
  private
@@ -18,7 +18,7 @@ module Contrast
18
18
  return true if config_param == false
19
19
  return false unless config_param.cs__is_a?(String)
20
20
 
21
- Contrast::Utils::ObjectShare::FALSE.casecmp?(config_param)
21
+ config_param.downcase == Contrast::Utils::ObjectShare::FALSE
22
22
  end
23
23
 
24
24
  # use this to determine if the configuration value is literally boolean
@@ -33,7 +33,7 @@ module Contrast
33
33
  return true if config_param == true
34
34
  return false unless config_param.cs__is_a?(String)
35
35
 
36
- Contrast::Utils::ObjectShare::TRUE.casecmp?(config_param)
36
+ config_param.downcase == Contrast::Utils::ObjectShare::TRUE
37
37
  end
38
38
  end
39
39
  end