contrast-agent 6.10.0 → 6.11.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.
- checksums.yaml +4 -4
- data/ext/build_funchook.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/split.rb +1 -4
- data/lib/contrast/agent/middleware.rb +1 -1
- data/lib/contrast/agent/patching/policy/method_policy_extend.rb +6 -2
- data/lib/contrast/agent/patching/policy/trigger_node.rb +1 -1
- data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +2 -2
- data/lib/contrast/agent/protect/rule/base_service.rb +1 -2
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +1 -1
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +1 -1
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_chained_command.rb +1 -1
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_dangerous_path.rb +1 -1
- data/lib/contrast/agent/protect/rule/sqli/postgres_sql_scanner.rb +0 -1
- data/lib/contrast/agent/reporting/reporter.rb +4 -8
- data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +9 -5
- data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +8 -5
- data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +7 -7
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +4 -4
- data/lib/contrast/agent/telemetry/base.rb +2 -5
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/components/config.rb +1 -1
- data/lib/contrast/framework/rack/patch/session_cookie.rb +2 -1
- data/lib/contrast/utils/duck_utils.rb +18 -0
- data/lib/contrast/utils/heap_dump_util.rb +1 -1
- data/lib/contrast/utils/log_utils.rb +1 -1
- data/lib/contrast/utils/middleware_utils.rb +1 -1
- data/lib/contrast/utils/patching/policy/patch_utils.rb +2 -2
- data/lib/contrast/utils/routes_sent.rb +4 -0
- data/lib/contrast/utils/telemetry.rb +1 -1
- data/ruby-agent.gemspec +5 -5
- metadata +14 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fddcf57afedf79d84cacef08c959a190f29f6db9248d34d1a01c3abe1b13553b
|
4
|
+
data.tar.gz: 599882cd812552c2cc12c86f6ecd526e7a7d1e458cf8ea4d961d17ef5179c9ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e91dd42c9aa9f9cb934bfe878e0f6be951f9397978c874dd2a4b38c0a78f1cfe6b7e957ec6abaa3bb97a194f6494950f9ec93ebad408cf2767df06b1475bd373
|
7
|
+
data.tar.gz: ad17804c1abf24410ba2bbe7798ce142eba284cb0911830e40f6f92917a47961d4cfaefa79ed8affb8d1d821e27a85f57ace126a64417f6fe672f965916c3dba
|
data/ext/build_funchook.rb
CHANGED
@@ -17,7 +17,7 @@ unless find_header('funchook.h', ext_path)
|
|
17
17
|
extension_paths = Dir[contrast_gem_dir_search]
|
18
18
|
extension_paths.map! do |extension_path|
|
19
19
|
target_path = File.join(extension_path, 'shared_libraries')
|
20
|
-
FileUtils.mkdir_p(target_path)
|
20
|
+
FileUtils.mkdir_p(target_path)
|
21
21
|
target_path
|
22
22
|
end
|
23
23
|
bundler_install_target_paths += extension_paths
|
@@ -17,12 +17,11 @@ module Contrast
|
|
17
17
|
module Propagator
|
18
18
|
# This class is specifically for String#split & String#grapheme_clusters propagation
|
19
19
|
# it propagates tag ranges from a string to elements within an untracked array
|
20
|
-
class Split < Contrast::Agent::Assess::Policy::Propagator::Base
|
20
|
+
class Split < Contrast::Agent::Assess::Policy::Propagator::Base # rubocop:disable Metrics/ClassLength
|
21
21
|
extend Contrast::Components::Scope::InstanceMethods
|
22
22
|
extend Contrast::Components::Logger::InstanceMethods
|
23
23
|
extend Contrast::Utils::Assess::SplitUtils
|
24
24
|
extend Contrast::Utils::Assess::EventLimitUtils
|
25
|
-
|
26
25
|
SPLIT_TRACKER = Contrast::Utils::ThreadTracker.new
|
27
26
|
|
28
27
|
class << self
|
@@ -61,7 +60,6 @@ module Contrast
|
|
61
60
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
62
61
|
logger.warn('Unable to record split context', e)
|
63
62
|
end
|
64
|
-
|
65
63
|
yield
|
66
64
|
ensure
|
67
65
|
# String#split exit. Remove propagation context.
|
@@ -158,7 +156,6 @@ module Contrast
|
|
158
156
|
# Get tags for element from source by element range.
|
159
157
|
range = current_index...(current_index + target_elem.length)
|
160
158
|
tags = source_properties.tags_at_range(range)
|
161
|
-
|
162
159
|
# Set element properties accordingly.
|
163
160
|
elem_properties.clear_tags
|
164
161
|
tags.each_pair { |key, value| elem_properties.set_tags(key, value) }
|
@@ -44,7 +44,7 @@ module Contrast
|
|
44
44
|
@app = app # THIS MUST BE FIRST AND ALWAYS SET!
|
45
45
|
setup_agent # THIS MUST BE SECOND AND ALWAYS CALLED!
|
46
46
|
unless ::Contrast::AGENT.enabled?
|
47
|
-
logger.error('The Agent was unable to initialize before the application middleware was initialized. '\
|
47
|
+
logger.error('The Agent was unable to initialize before the application middleware was initialized. ' \
|
48
48
|
'Disabling permanently.')
|
49
49
|
::Contrast::AGENT.disable! # ensure the agent is disabled (probably redundant)
|
50
50
|
return
|
@@ -57,8 +57,12 @@ module Contrast
|
|
57
57
|
nodes.find { |node| node }&.method_visibility
|
58
58
|
end
|
59
59
|
|
60
|
-
def check_method_policy_nodes_empty?(source_node,
|
61
|
-
|
60
|
+
def check_method_policy_nodes_empty?(source_node,
|
61
|
+
propagation_node,
|
62
|
+
trigger_node,
|
63
|
+
protect_node,
|
64
|
+
inventory_node,
|
65
|
+
deadzone_node)
|
62
66
|
return false unless source_node.nil? && propagation_node.nil? && trigger_node.nil? && protect_node.nil? &&
|
63
67
|
inventory_node.nil? && deadzone_node.nil?
|
64
68
|
|
@@ -46,7 +46,7 @@ module Contrast
|
|
46
46
|
super
|
47
47
|
unless applicator.public_methods(false).any?(applicator_method)
|
48
48
|
raise(ArgumentError,
|
49
|
-
"#{ id } did not have a proper applicator method: "\
|
49
|
+
"#{ id } did not have a proper applicator method: " \
|
50
50
|
"#{ applicator } does not respond to #{ applicator_method }. Unable to create.")
|
51
51
|
end
|
52
52
|
validate_properties
|
@@ -101,10 +101,10 @@ module Contrast
|
|
101
101
|
CS__SAFER_REL_PATHS = %w[public app log tmp].cs__freeze
|
102
102
|
def safer_abs_paths
|
103
103
|
@_safer_abs_paths ||= begin
|
104
|
-
pwd = ENV
|
104
|
+
pwd = ENV.fetch('PWD', nil)
|
105
105
|
if pwd
|
106
106
|
tmp = CS__SAFER_REL_PATHS.map { |r| "#{ pwd }/#{ r }" }
|
107
|
-
gems = ENV
|
107
|
+
gems = ENV.fetch('GEM_PATH', nil)
|
108
108
|
tmp += gems.split(Contrast::Utils::ObjectShare::COLON) if gems
|
109
109
|
tmp.map!(&:downcase)
|
110
110
|
tmp
|
@@ -91,8 +91,7 @@ module Contrast
|
|
91
91
|
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless context&.agent_input_analysis&.results
|
92
92
|
|
93
93
|
context.agent_input_analysis.results.select do |ia_result|
|
94
|
-
ia_result.rule_id == rule_name &&
|
95
|
-
ia_result.score_level != Contrast::Agent::Reporting::ScoreLevel::IGNORE
|
94
|
+
ia_result.rule_id == rule_name && ia_result.score_level != Contrast::Agent::Reporting::ScoreLevel::IGNORE
|
96
95
|
end
|
97
96
|
end
|
98
97
|
|
@@ -70,7 +70,7 @@ module Contrast
|
|
70
70
|
# @raise [Contrast::SecurityException]
|
71
71
|
def raise_error classname, method
|
72
72
|
raise(Contrast::SecurityException.new(self,
|
73
|
-
'Command Injection Command Backdoor rule triggered. '\
|
73
|
+
'Command Injection Command Backdoor rule triggered. ' \
|
74
74
|
"Call to #{ classname }.#{ method } blocked."))
|
75
75
|
end
|
76
76
|
|
@@ -78,7 +78,7 @@ module Contrast
|
|
78
78
|
# @raise [Contrast::SecurityException]
|
79
79
|
def raise_error classname, method
|
80
80
|
raise(Contrast::SecurityException.new(self,
|
81
|
-
'Command Injection Rule triggered. '\
|
81
|
+
'Command Injection Rule triggered. ' \
|
82
82
|
"Call to #{ classname }.#{ method } blocked."))
|
83
83
|
end
|
84
84
|
|
@@ -32,7 +32,7 @@ module Contrast
|
|
32
32
|
# @raise [Contrast::SecurityException]
|
33
33
|
def raise_error classname, method
|
34
34
|
raise(Contrast::SecurityException.new(self,
|
35
|
-
'Command Injection Semantic Chained Commands rule triggered. '\
|
35
|
+
'Command Injection Semantic Chained Commands rule triggered. ' \
|
36
36
|
"Call to #{ classname }.#{ method } blocked."))
|
37
37
|
end
|
38
38
|
|
@@ -32,7 +32,7 @@ module Contrast
|
|
32
32
|
# @raise [Contrast::SecurityException]
|
33
33
|
def raise_error classname, method
|
34
34
|
raise(Contrast::SecurityException.new(self,
|
35
|
-
'Command Injection Dangerous Path rule triggered. '\
|
35
|
+
'Command Injection Dangerous Path rule triggered. ' \
|
36
36
|
"Call to #{ classname }.#{ method } blocked."))
|
37
37
|
end
|
38
38
|
|
@@ -73,13 +73,11 @@ module Contrast
|
|
73
73
|
return unless event
|
74
74
|
|
75
75
|
if queue.size >= MAX_QUEUE_SIZE
|
76
|
-
|
77
|
-
|
78
|
-
end
|
76
|
+
Contrast::Agent::Telemetry::Base.enabled? && Contrast::Agent.thread_watcher.telemetry_queue.
|
77
|
+
send_event(queue_limit_telemetry_event)
|
79
78
|
|
80
79
|
return
|
81
80
|
end
|
82
|
-
|
83
81
|
queue << event
|
84
82
|
end
|
85
83
|
|
@@ -89,9 +87,8 @@ module Contrast
|
|
89
87
|
# @return [Net::HTTPResponse, nil]
|
90
88
|
def send_event_immediately event
|
91
89
|
if ::Contrast::AGENT.disabled?
|
92
|
-
logger.warn('[Reporter] attempted to send event immediately with Agent disabled',
|
93
|
-
|
94
|
-
event: event)
|
90
|
+
logger.warn('[Reporter] attempted to send event immediately with Agent disabled', caller: caller,
|
91
|
+
event: event)
|
95
92
|
return
|
96
93
|
end
|
97
94
|
return unless event
|
@@ -157,7 +154,6 @@ module Contrast
|
|
157
154
|
else
|
158
155
|
stack_trace[1].path.delete_prefix(Dir.pwd)
|
159
156
|
end
|
160
|
-
|
161
157
|
stack_frame_function = stack_trace.nil? || stack_trace[1].nil? ? 'none' : stack_trace[1].label
|
162
158
|
Contrast::Agent::Telemetry::TelemetryException::StackFrame.build(stack_frame_function, stack_frame_type, nil)
|
163
159
|
end
|
@@ -5,6 +5,7 @@ require 'json'
|
|
5
5
|
require 'contrast/components/logger'
|
6
6
|
require 'contrast/agent/reporting/reporting_events/reporting_event'
|
7
7
|
require 'contrast/utils/object_share'
|
8
|
+
require 'contrast/utils/duck_utils'
|
8
9
|
|
9
10
|
module Contrast
|
10
11
|
module Agent
|
@@ -16,9 +17,9 @@ module Contrast
|
|
16
17
|
# includes the literal URL and HTTP Verb used to invoke them, as they must have been called at this point to be
|
17
18
|
# recorded.
|
18
19
|
class DiscoveredRoute < Contrast::Agent::Reporting::ObservedRoute
|
19
|
-
include Contrast::Components::Logger::InstanceMethods
|
20
|
-
|
21
20
|
class << self
|
21
|
+
include Contrast::Components::Logger::InstanceMethods
|
22
|
+
|
22
23
|
# @param obj [Regexp, Object]
|
23
24
|
# @return [String]
|
24
25
|
def source_or_string obj
|
@@ -100,9 +101,7 @@ module Contrast
|
|
100
101
|
def initialize
|
101
102
|
super
|
102
103
|
@event_type = :discovered_route
|
103
|
-
@signature = Contrast::Utils::ObjectShare::EMPTY_STRING
|
104
104
|
@verb = Contrast::Utils::ObjectShare::EMPTY_STRING
|
105
|
-
@url = Contrast::Utils::ObjectShare::EMPTY_STRING
|
106
105
|
end
|
107
106
|
|
108
107
|
def to_controlled_hash
|
@@ -116,7 +115,12 @@ module Contrast
|
|
116
115
|
end
|
117
116
|
|
118
117
|
def validate
|
119
|
-
|
118
|
+
if Contrast::Utils::DuckUtils.empty_duck?(signature)
|
119
|
+
raise(ArgumentError, "#{ self } did not have a proper signature. Unable to continue.")
|
120
|
+
end
|
121
|
+
if Contrast::Utils::DuckUtils.empty_duck?(url)
|
122
|
+
raise(ArgumentError, "#{ self } did not have a proper url. Unable to continue.")
|
123
|
+
end
|
120
124
|
|
121
125
|
nil
|
122
126
|
end
|
@@ -6,6 +6,7 @@ require 'json'
|
|
6
6
|
require 'contrast/components/logger'
|
7
7
|
require 'contrast/agent/reporting/reporting_events/application_reporting_event'
|
8
8
|
require 'contrast/utils/object_share'
|
9
|
+
require 'contrast/utils/duck_utils'
|
9
10
|
|
10
11
|
module Contrast
|
11
12
|
module Agent
|
@@ -32,9 +33,7 @@ module Contrast
|
|
32
33
|
def initialize
|
33
34
|
@event_endpoint = Contrast::Agent::Reporting::Endpoints.observed_route
|
34
35
|
@sources = []
|
35
|
-
@signature = Contrast::Utils::ObjectShare::EMPTY_STRING
|
36
36
|
@verb = Contrast::Utils::ObjectShare::EMPTY_STRING
|
37
|
-
@url = Contrast::Utils::ObjectShare::EMPTY_STRING
|
38
37
|
super()
|
39
38
|
end
|
40
39
|
|
@@ -69,7 +68,7 @@ module Contrast
|
|
69
68
|
# @return [String]
|
70
69
|
#
|
71
70
|
def hash_id
|
72
|
-
hashable_data = to_controlled_hash.
|
71
|
+
hashable_data = to_controlled_hash.reject { |key, _value| key == :session_id } # rubocop:disable Style/HashExcept
|
73
72
|
hashable_data[:sources] = hashable_data[:sources].sort_by { |s| s[:name] }
|
74
73
|
|
75
74
|
Digest::SHA2.new(256).hexdigest(hashable_data.to_s)
|
@@ -78,8 +77,12 @@ module Contrast
|
|
78
77
|
# @raise [ArgumentError]
|
79
78
|
def validate
|
80
79
|
raise(ArgumentError, "#{ self } did not have a proper sources. Unable to continue.") if @sources.nil?
|
81
|
-
|
82
|
-
|
80
|
+
if Contrast::Utils::DuckUtils.empty_duck?(signature)
|
81
|
+
raise(ArgumentError, "#{ self } did not have a proper signature. Unable to continue.")
|
82
|
+
end
|
83
|
+
if Contrast::Utils::DuckUtils.empty_duck?(url)
|
84
|
+
raise(ArgumentError, "#{ self } did not have a proper url. Unable to continue.")
|
85
|
+
end
|
83
86
|
|
84
87
|
nil
|
85
88
|
end
|
@@ -89,7 +89,7 @@ module Contrast
|
|
89
89
|
#
|
90
90
|
# @return [String]
|
91
91
|
def application_endpoint
|
92
|
-
@_application_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/applications"\
|
92
|
+
@_application_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/applications" \
|
93
93
|
"#{ server_path_segment }#{ application_path_segment }"
|
94
94
|
end
|
95
95
|
|
@@ -97,7 +97,7 @@ module Contrast
|
|
97
97
|
#
|
98
98
|
# @return [String]
|
99
99
|
def route_endpoint
|
100
|
-
@_route_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/routes"\
|
100
|
+
@_route_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/routes" \
|
101
101
|
"#{ server_path_segment }#{ application_path_segment }"
|
102
102
|
end
|
103
103
|
|
@@ -105,7 +105,7 @@ module Contrast
|
|
105
105
|
#
|
106
106
|
# @return [String]
|
107
107
|
def server_endpoint
|
108
|
-
@_server_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/servers"\
|
108
|
+
@_server_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/servers" \
|
109
109
|
"#{ server_path_segment }"
|
110
110
|
end
|
111
111
|
|
@@ -113,7 +113,7 @@ module Contrast
|
|
113
113
|
#
|
114
114
|
# @return [String]
|
115
115
|
def trace_endpoint
|
116
|
-
@_trace_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/traces"\
|
116
|
+
@_trace_endpoint ||= "#{ Contrast::API.api_url }/agents#{ ENDPOINT_VERSION }/traces" \
|
117
117
|
"#{ server_path_segment }#{ application_path_segment }"
|
118
118
|
end
|
119
119
|
|
@@ -121,8 +121,8 @@ module Contrast
|
|
121
121
|
#
|
122
122
|
# @return [String]
|
123
123
|
def server_path_segment
|
124
|
-
@_server_path_segment ||= "/#{ Base64.urlsafe_encode64(server_host_name, padding: false) }"\
|
125
|
-
"/#{ Base64.urlsafe_encode64(server_path, padding: false) }"\
|
124
|
+
@_server_path_segment ||= "/#{ Base64.urlsafe_encode64(server_host_name, padding: false) }" \
|
125
|
+
"/#{ Base64.urlsafe_encode64(server_path, padding: false) }" \
|
126
126
|
"/#{ Base64.urlsafe_encode64(server_type, padding: false) }"
|
127
127
|
end
|
128
128
|
|
@@ -130,7 +130,7 @@ module Contrast
|
|
130
130
|
#
|
131
131
|
# @return [String]
|
132
132
|
def application_path_segment
|
133
|
-
@_application_path_segment ||= "/#{ Base64.urlsafe_encode64(APP_LANGUAGE, padding: false) }"\
|
133
|
+
@_application_path_segment ||= "/#{ Base64.urlsafe_encode64(APP_LANGUAGE, padding: false) }" \
|
134
134
|
"/#{ Base64.urlsafe_encode64(app_name, padding: false) }"
|
135
135
|
end
|
136
136
|
|
@@ -22,14 +22,14 @@ module Contrast
|
|
22
22
|
unprocessable_entity: '422',
|
23
23
|
too_many_requests: '429'
|
24
24
|
}.cs__freeze
|
25
|
-
APP_NON_EXISTENT_MSG = 'Application does not exist! Either it has not been created or has '\
|
26
|
-
'been deleted or archived. '\
|
25
|
+
APP_NON_EXISTENT_MSG = 'Application does not exist! Either it has not been created or has ' \
|
26
|
+
'been deleted or archived. ' \
|
27
27
|
'Disabling permanently.'
|
28
28
|
SUSPEND_MSG = 'Reporter is temporarily suspended.'
|
29
29
|
UNSUCCESSFULLY_RECEIVED_MSG = 'The Reporter was unable to send message.'
|
30
|
-
FORBIDDEN_MSG = 'Access was forbidden for current Report because the request authentication '\
|
30
|
+
FORBIDDEN_MSG = 'Access was forbidden for current Report because the request authentication ' \
|
31
31
|
'information was not provided'
|
32
|
-
FORBIDDEN_NO_ACTION_MSG = 'Report access was forbidden because the supplied credentials failed '\
|
32
|
+
FORBIDDEN_NO_ACTION_MSG = 'Report access was forbidden because the supplied credentials failed ' \
|
33
33
|
'to authenticate the Agent'
|
34
34
|
UNPROCESSABLE_ENTITY_MSG = 'Reporter received Unprocessable Entity response. Disabling permanently.'
|
35
35
|
RETRY_AFTER_MSG = "There are too many requests of this type being sent by this Agent. #{ SUSPEND_MSG }"
|
@@ -14,7 +14,6 @@ module Contrast
|
|
14
14
|
# This class will initialize and hold everything needed for the telemetry
|
15
15
|
class Base < WorkerThread
|
16
16
|
include Contrast::Components::Logger::InstanceMethods
|
17
|
-
|
18
17
|
# this is where we will send the data from the agents
|
19
18
|
URL = 'https://telemetry.ruby.contrastsecurity.com/'
|
20
19
|
# Suggested timeout after each send is to be 3 hours (10800 seconds)
|
@@ -108,8 +107,7 @@ module Contrast
|
|
108
107
|
end
|
109
108
|
|
110
109
|
def request_with_response event
|
111
|
-
|
112
|
-
client.handle_response(res)
|
110
|
+
client.handle_response(client.send_request(event, connection))
|
113
111
|
end
|
114
112
|
|
115
113
|
private
|
@@ -134,8 +132,7 @@ module Contrast
|
|
134
132
|
event = queue.pop
|
135
133
|
begin
|
136
134
|
logger.debug('[Telemetry] This is the current processed event', event)
|
137
|
-
sleep_time = request_with_response(event)
|
138
|
-
if sleep_time
|
135
|
+
if (sleep_time = request_with_response(event))
|
139
136
|
sleep(sleep_time)
|
140
137
|
logger.debug('[Telemetry] Retrying to process event', event)
|
141
138
|
retry_sleep_time = request_with_response(event)
|
@@ -30,7 +30,7 @@ module Contrast
|
|
30
30
|
DATE_TIME = '%Y-%m-%dT%H:%M:%S.%L%z'
|
31
31
|
|
32
32
|
class Interface # :nodoc: # rubocop:disable Metrics/ClassLength
|
33
|
-
SESSION_VARIABLES = 'Invalid configuration. '\
|
33
|
+
SESSION_VARIABLES = 'Invalid configuration. ' \
|
34
34
|
"Setting both application.session_id and application.session_metadata is not allowed.\n"
|
35
35
|
API_URL = "Invalid configuration. Missing a required connection value 'url' is not set."
|
36
36
|
API_KEY = "Invalid configuration. Missing a required connection value 'api_key' is not set."
|
@@ -48,7 +48,8 @@ module Contrast
|
|
48
48
|
|
49
49
|
def vulnerable_setting?(setting_key,
|
50
50
|
safe_settings_value,
|
51
|
-
options,
|
51
|
+
options,
|
52
|
+
safe_default: true,
|
52
53
|
comparison_type: nil)
|
53
54
|
# In most cases, Rack is pretty nice and the default value is safe
|
54
55
|
return !safe_default unless options&.key?(setting_key)
|
@@ -63,6 +63,24 @@ module Contrast
|
|
63
63
|
# otherwise, don't risk it
|
64
64
|
false
|
65
65
|
end
|
66
|
+
|
67
|
+
# Every duck quacks to nil, we need to check if it is empty?
|
68
|
+
# Utils method to check for blank ( nil or empty object ).
|
69
|
+
#
|
70
|
+
# @param [Object] object to test.
|
71
|
+
# @return [Boolean]
|
72
|
+
def empty_duck? object
|
73
|
+
# If not quacking to empty it is True/False class, Integer, Regexp or Time instance.
|
74
|
+
return false if object.instance_of?(TrueClass) || object.instance_of?(FalseClass)
|
75
|
+
|
76
|
+
if object.cs__respond_to?(:empty?)
|
77
|
+
return true if object.empty?
|
78
|
+
elsif object.nil?
|
79
|
+
return true
|
80
|
+
end
|
81
|
+
|
82
|
+
false
|
83
|
+
end
|
66
84
|
end
|
67
85
|
end
|
68
86
|
end
|
@@ -12,7 +12,7 @@ module Contrast
|
|
12
12
|
LANGUAGE_DEPRECATION_VERSION = '2.7'
|
13
13
|
LANGUAGE_DEPRECATION_YEAR = '2023'
|
14
14
|
LANGUAGE_DEPRECATION_WARNING =
|
15
|
-
"[Contrast Security] [DEPRECATION] Support for Ruby #{ LANGUAGE_DEPRECATION_VERSION } will be removed in "\
|
15
|
+
"[Contrast Security] [DEPRECATION] Support for Ruby #{ LANGUAGE_DEPRECATION_VERSION } will be removed in " \
|
16
16
|
"April #{ LANGUAGE_DEPRECATION_YEAR }. Please contact Customer Support prior if you require continued support."
|
17
17
|
|
18
18
|
def setup_agent
|
@@ -23,8 +23,8 @@ module Contrast
|
|
23
23
|
# Given a method, return a symbol in the format
|
24
24
|
# <method_start>_unbound_<method_name>
|
25
25
|
def build_unbound_method_name patcher_method
|
26
|
-
"#{ Contrast::Utils::ObjectShare::CONTRAST_PATCHED_METHOD_START }unbound"\
|
27
|
-
"#{ Contrast::Utils::ObjectShare::UNDERSCORE }"\
|
26
|
+
"#{ Contrast::Utils::ObjectShare::CONTRAST_PATCHED_METHOD_START }unbound" \
|
27
|
+
"#{ Contrast::Utils::ObjectShare::UNDERSCORE }" \
|
28
28
|
"#{ patcher_method }".to_sym
|
29
29
|
end
|
30
30
|
|
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
# require 'contrast/components/logger'
|
5
5
|
# require 'contrast/agent/telemetry/events/exceptions/telemetry_exception_event'
|
6
|
+
require 'contrast/utils/duck_utils'
|
6
7
|
|
7
8
|
module Contrast
|
8
9
|
module Utils
|
@@ -25,6 +26,9 @@ module Contrast
|
|
25
26
|
# @param route [Contrast::Agent::Reporting::ObservedRoute] the route
|
26
27
|
# @return [boolean]
|
27
28
|
def sendable? route
|
29
|
+
return false if Contrast::Utils::DuckUtils.empty_duck?(route.signature)
|
30
|
+
return false if Contrast::Utils::DuckUtils.empty_duck?(route.url)
|
31
|
+
|
28
32
|
route_hash = route.hash_id
|
29
33
|
|
30
34
|
# If hash doesn't exist in @cache...
|
@@ -81,7 +81,7 @@ module Contrast
|
|
81
81
|
#
|
82
82
|
# @return[Boolean] true if success, false if fails
|
83
83
|
def touch_marker dir, file
|
84
|
-
FileUtils.mkdir_p(dir)
|
84
|
+
FileUtils.mkdir_p(dir)
|
85
85
|
FileUtils.touch(dir + file)
|
86
86
|
File.file?(dir + file)
|
87
87
|
rescue StandardError => _e
|
data/ruby-agent.gemspec
CHANGED
@@ -75,7 +75,7 @@ def self.add_specs spec
|
|
75
75
|
spec.add_development_dependency 'factory_bot'
|
76
76
|
spec.add_development_dependency 'fake_ftp'
|
77
77
|
spec.add_development_dependency 'openssl'
|
78
|
-
spec.add_development_dependency 'parallel_tests'
|
78
|
+
spec.add_development_dependency 'parallel_tests', '~> 3.0'
|
79
79
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
80
80
|
spec.add_development_dependency 'rspec-benchmark'
|
81
81
|
spec.add_development_dependency 'rspec_junit_formatter', '0.3.0'
|
@@ -92,11 +92,11 @@ end
|
|
92
92
|
|
93
93
|
# Dependencies used to run all of our Rubocop during the linting phase.
|
94
94
|
def self.add_rubocop spec
|
95
|
-
spec.add_development_dependency 'rubocop', '1.
|
96
|
-
spec.add_development_dependency 'rubocop-performance', '1.
|
97
|
-
spec.add_development_dependency 'rubocop-rails', '2.
|
95
|
+
spec.add_development_dependency 'rubocop', '1.37.1'
|
96
|
+
spec.add_development_dependency 'rubocop-performance', '1.15.0'
|
97
|
+
spec.add_development_dependency 'rubocop-rails', '2.17.2'
|
98
98
|
spec.add_development_dependency 'rubocop-rake', '0.6.0'
|
99
|
-
spec.add_development_dependency 'rubocop-rspec', '2.
|
99
|
+
spec.add_development_dependency 'rubocop-rspec', '2.14.2'
|
100
100
|
end
|
101
101
|
|
102
102
|
# Dependencies not mocked out during RSpec that we test real code of, beyond just frameworks.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: contrast-agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.
|
4
|
+
version: 6.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- galen.palmer@contrastsecurity.com
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: exe
|
15
15
|
cert_chain: []
|
16
|
-
date: 2022-11-
|
16
|
+
date: 2022-11-09 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: bundler
|
@@ -161,42 +161,42 @@ dependencies:
|
|
161
161
|
requirements:
|
162
162
|
- - '='
|
163
163
|
- !ruby/object:Gem::Version
|
164
|
-
version: 1.
|
164
|
+
version: 1.37.1
|
165
165
|
type: :development
|
166
166
|
prerelease: false
|
167
167
|
version_requirements: !ruby/object:Gem::Requirement
|
168
168
|
requirements:
|
169
169
|
- - '='
|
170
170
|
- !ruby/object:Gem::Version
|
171
|
-
version: 1.
|
171
|
+
version: 1.37.1
|
172
172
|
- !ruby/object:Gem::Dependency
|
173
173
|
name: rubocop-performance
|
174
174
|
requirement: !ruby/object:Gem::Requirement
|
175
175
|
requirements:
|
176
176
|
- - '='
|
177
177
|
- !ruby/object:Gem::Version
|
178
|
-
version: 1.
|
178
|
+
version: 1.15.0
|
179
179
|
type: :development
|
180
180
|
prerelease: false
|
181
181
|
version_requirements: !ruby/object:Gem::Requirement
|
182
182
|
requirements:
|
183
183
|
- - '='
|
184
184
|
- !ruby/object:Gem::Version
|
185
|
-
version: 1.
|
185
|
+
version: 1.15.0
|
186
186
|
- !ruby/object:Gem::Dependency
|
187
187
|
name: rubocop-rails
|
188
188
|
requirement: !ruby/object:Gem::Requirement
|
189
189
|
requirements:
|
190
190
|
- - '='
|
191
191
|
- !ruby/object:Gem::Version
|
192
|
-
version: 2.
|
192
|
+
version: 2.17.2
|
193
193
|
type: :development
|
194
194
|
prerelease: false
|
195
195
|
version_requirements: !ruby/object:Gem::Requirement
|
196
196
|
requirements:
|
197
197
|
- - '='
|
198
198
|
- !ruby/object:Gem::Version
|
199
|
-
version: 2.
|
199
|
+
version: 2.17.2
|
200
200
|
- !ruby/object:Gem::Dependency
|
201
201
|
name: rubocop-rake
|
202
202
|
requirement: !ruby/object:Gem::Requirement
|
@@ -217,14 +217,14 @@ dependencies:
|
|
217
217
|
requirements:
|
218
218
|
- - '='
|
219
219
|
- !ruby/object:Gem::Version
|
220
|
-
version: 2.
|
220
|
+
version: 2.14.2
|
221
221
|
type: :development
|
222
222
|
prerelease: false
|
223
223
|
version_requirements: !ruby/object:Gem::Requirement
|
224
224
|
requirements:
|
225
225
|
- - '='
|
226
226
|
- !ruby/object:Gem::Version
|
227
|
-
version: 2.
|
227
|
+
version: 2.14.2
|
228
228
|
- !ruby/object:Gem::Dependency
|
229
229
|
name: simplecov
|
230
230
|
requirement: !ruby/object:Gem::Requirement
|
@@ -473,16 +473,16 @@ dependencies:
|
|
473
473
|
name: parallel_tests
|
474
474
|
requirement: !ruby/object:Gem::Requirement
|
475
475
|
requirements:
|
476
|
-
- - "
|
476
|
+
- - "~>"
|
477
477
|
- !ruby/object:Gem::Version
|
478
|
-
version: '0'
|
478
|
+
version: '3.0'
|
479
479
|
type: :development
|
480
480
|
prerelease: false
|
481
481
|
version_requirements: !ruby/object:Gem::Requirement
|
482
482
|
requirements:
|
483
|
-
- - "
|
483
|
+
- - "~>"
|
484
484
|
- !ruby/object:Gem::Version
|
485
|
-
version: '0'
|
485
|
+
version: '3.0'
|
486
486
|
- !ruby/object:Gem::Dependency
|
487
487
|
name: rspec
|
488
488
|
requirement: !ruby/object:Gem::Requirement
|