contrast-agent 4.12.0 → 4.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/ext/cs__assess_module/cs__assess_module.c +48 -0
  3. data/ext/cs__assess_module/cs__assess_module.h +7 -0
  4. data/ext/cs__common/cs__common.c +5 -0
  5. data/ext/cs__common/cs__common.h +8 -0
  6. data/ext/cs__contrast_patch/cs__contrast_patch.c +16 -1
  7. data/ext/cs__os_information/cs__os_information.c +31 -0
  8. data/ext/cs__os_information/cs__os_information.h +7 -0
  9. data/ext/cs__os_information/extconf.rb +5 -0
  10. data/lib/contrast/agent/assess/policy/propagation_method.rb +2 -116
  11. data/lib/contrast/agent/assess/policy/propagation_node.rb +4 -4
  12. data/lib/contrast/agent/assess/policy/source_method.rb +2 -71
  13. data/lib/contrast/agent/assess/policy/trigger_method.rb +4 -106
  14. data/lib/contrast/agent/assess/property/tagged.rb +2 -128
  15. data/lib/contrast/agent/deadzone/policy/policy.rb +1 -1
  16. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +1 -0
  17. data/lib/contrast/agent/metric_telemetry_event.rb +26 -0
  18. data/lib/contrast/agent/middleware.rb +22 -0
  19. data/lib/contrast/agent/patching/policy/patch.rb +28 -235
  20. data/lib/contrast/agent/patching/policy/patcher.rb +2 -41
  21. data/lib/contrast/agent/request_handler.rb +7 -3
  22. data/lib/contrast/agent/startup_metrics_telemetry_event.rb +71 -0
  23. data/lib/contrast/agent/static_analysis.rb +4 -2
  24. data/lib/contrast/agent/telemetry.rb +129 -0
  25. data/lib/contrast/agent/telemetry_event.rb +34 -0
  26. data/lib/contrast/agent/thread_watcher.rb +43 -14
  27. data/lib/contrast/agent/version.rb +1 -1
  28. data/lib/contrast/agent.rb +6 -0
  29. data/lib/contrast/components/api.rb +34 -0
  30. data/lib/contrast/components/app_context.rb +24 -0
  31. data/lib/contrast/components/config.rb +90 -11
  32. data/lib/contrast/components/contrast_service.rb +6 -0
  33. data/lib/contrast/config/api_configuration.rb +22 -0
  34. data/lib/contrast/config/env_variables.rb +25 -0
  35. data/lib/contrast/config/root_configuration.rb +1 -0
  36. data/lib/contrast/config/service_configuration.rb +2 -1
  37. data/lib/contrast/config.rb +1 -0
  38. data/lib/contrast/configuration.rb +3 -0
  39. data/lib/contrast/framework/manager.rb +14 -12
  40. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +9 -6
  41. data/lib/contrast/framework/rails/patch/support.rb +31 -29
  42. data/lib/contrast/logger/application.rb +4 -0
  43. data/lib/contrast/utils/assess/propagation_method_utils.rb +129 -0
  44. data/lib/contrast/utils/assess/property/tagged_utils.rb +142 -0
  45. data/lib/contrast/utils/assess/source_method_utils.rb +83 -0
  46. data/lib/contrast/utils/assess/trigger_method_utils.rb +138 -0
  47. data/lib/contrast/utils/exclude_key.rb +20 -0
  48. data/lib/contrast/utils/metrics_hash.rb +59 -0
  49. data/lib/contrast/utils/os.rb +23 -0
  50. data/lib/contrast/utils/patching/policy/patch_utils.rb +232 -0
  51. data/lib/contrast/utils/patching/policy/patcher_utils.rb +54 -0
  52. data/lib/contrast/utils/requests_client.rb +150 -0
  53. data/lib/contrast/utils/telemetry.rb +78 -0
  54. data/lib/contrast/utils/telemetry_identifier.rb +137 -0
  55. data/lib/contrast.rb +18 -0
  56. data/ruby-agent.gemspec +2 -1
  57. data/service_executables/VERSION +1 -1
  58. data/service_executables/linux/contrast-service +0 -0
  59. data/service_executables/mac/contrast-service +0 -0
  60. metadata +32 -10
@@ -0,0 +1,71 @@
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
+ require 'contrast/agent/metric_telemetry_event'
6
+ require 'contrast/agent/version'
7
+ require 'contrast/utils/os'
8
+
9
+ module Contrast
10
+ module Agent
11
+ # This class will hold the Startup Metrics Telemetry Event
12
+ # The class will include initialization of the agent version, language version
13
+ # os type, arch and version
14
+ # application framework and version and server framework
15
+ # It will be initialized and send in Middleware#agent_startup_routine
16
+ class StartupMetricsTelemetryEvent < Contrast::Agent::MetricTelemetryEvent
17
+ include Contrast::Utils::OS
18
+
19
+ APP_AND_SERVER_DATA = ::Contrast::APP_CONTEXT.app_and_server_information.cs__freeze
20
+ SAAS_DEFAULT = { addr: 'app.contrastsecuirty.com', type: 'SAAS_DEFAULT' }.cs__freeze
21
+ SAAS_CE = { addr: 'ce.contrastsecurity.com', type: 'SAAS_CE' }.cs__freeze
22
+ SAAS_CUSTOM = { addr: 'contrastsecurite.com', type: 'SAAS_CUSTOM' }.cs__freeze
23
+ SAAS_POV = { addr: 'eval.contrastsecuirty.com', type: 'SAAS_POV' }.cs__freeze
24
+ EOP = 'EOP'
25
+
26
+ def initialize
27
+ super
28
+ add_tags
29
+ end
30
+
31
+ def path
32
+ '/startup'
33
+ end
34
+
35
+ def add_tags
36
+ @tags['teamserver'] = teamserver_type
37
+ @tags['agent_version'] = VERSION
38
+ @tags['ruby_version'] = RUBY_VERSION
39
+ @tags['os_type'] = sys_info['os_type'] == 'Darwin' ? 'MacOS' : 'Linux'
40
+ @tags['os_arch'] = sys_info['os_arch']
41
+ @tags['os_version'] = sys_info['os_version']
42
+ @tags['app_framework_and_version'] = APP_AND_SERVER_DATA[:application_info].to_s
43
+ @tags['server_framework_and_version'] = APP_AND_SERVER_DATA[:server_info].to_s
44
+ end
45
+
46
+ def sys_info
47
+ @sys_info ||= get_system_information if @sys_info.nil?
48
+ @sys_info
49
+ end
50
+
51
+ private
52
+
53
+ # Here we extract the Teamserver url type
54
+ #
55
+ # @return[String] type, it could be SAAS_DEFAULT, SAAS_POV, SAAS_CE, SAAS_CUSTOM, or EOP
56
+ def teamserver_type
57
+ @_teamserver_type ||= if Contrast::API.api_url.include?(SAAS_DEFAULT[:addr])
58
+ SAAS_DEFAULT[:type]
59
+ elsif Contrast::API.api_url.include?(SAAS_POV[:addr])
60
+ SAAS_POV[:type]
61
+ elsif Contrast::API.api_url.include?(SAAS_CE[:addr])
62
+ SAAS_CE[:type]
63
+ elsif Contrast::API.api_url.end_with? SAAS_CUSTOM[:addr]
64
+ SAAS_CUSTOM[:type]
65
+ else
66
+ EOP
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -14,8 +14,8 @@ module Contrast
14
14
  include Contrast::Components::Scope::InstanceMethods
15
15
 
16
16
  class << self
17
- # After the first request is complete, we do a one-time manual catchup to review and
18
- # report the already-loaded gems.
17
+ # After the first request is complete, we do a one-time manual catchup to review and report the already-loaded
18
+ # gems.
19
19
  def catchup
20
20
  @_catchup ||= begin
21
21
  threaded_analysis!
@@ -23,6 +23,8 @@ module Contrast
23
23
  end
24
24
  end
25
25
 
26
+ # TODO: RUBY-1354
27
+ # TODO: RUBY-1356
26
28
  def send_inventory_message
27
29
  return unless ::Contrast::INVENTORY.enabled?
28
30
 
@@ -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
@@ -3,6 +3,6 @@
3
3
 
4
4
  module Contrast
5
5
  module Agent
6
- VERSION = '4.12.0'
6
+ VERSION = '4.13.0'
7
7
  end
8
8
  end
@@ -61,6 +61,12 @@ module Contrast
61
61
  thread_watcher.messaging_queue
62
62
  end
63
63
 
64
+ def self.telemetry_queue
65
+ return unless thread_watcher.telemetry_queue
66
+
67
+ thread_watcher.telemetry_queue
68
+ end
69
+
64
70
  def self.thread_watcher
65
71
  @_thread_watcher ||= Contrast::Agent::ThreadWatcher.new
66
72
  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/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
@@ -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,7 @@ 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?
47
64
  @_valid
48
65
  end
49
66
 
@@ -59,20 +76,28 @@ module Contrast
59
76
 
60
77
  SESSION_VARIABLES = 'Invalid configuration. '\
61
78
  "Setting both application.session_id and application.session_metadata is not allowed.\n"
62
- 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
63
84
  # The config has information about how to construct the logger.
64
85
  # If the config is invalid, and you want to know about it, then
65
86
  # you have a circular dependency if you try to log it,
66
- # hence `log: false`.
87
+ # so we use basic proto_logger to do this job.
67
88
  if !session_id.empty? && !session_metadata.empty?
68
- if log
69
- cs__class.log_error(SESSION_VARIABLES)
70
- else
71
- puts SESSION_VARIABLES
72
- end
89
+ proto_logger.error(SESSION_VARIABLES)
73
90
  return false
74
91
  end
75
-
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
76
101
  true
77
102
  end
78
103
 
@@ -108,6 +133,60 @@ module Contrast
108
133
  def session_metadata
109
134
  @config.application.session_metadata
110
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
111
190
  end
112
191
  end
113
192
  end
@@ -31,6 +31,12 @@ 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
41
  @_host ||=
36
42
  (::Contrast::CONFIG.root.agent.service.host || Contrast::Config::ServiceConfiguration::DEFAULT_HOST).to_s
@@ -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
@@ -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'