contrast-agent 6.10.0 → 6.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|