contrast-agent 6.3.0 → 6.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -3
- data/.simplecov +1 -0
- data/Rakefile +0 -27
- data/ext/cs__contrast_patch/cs__contrast_patch.c +14 -1
- data/lib/contrast/agent/assess/finalizers/hash.rb +1 -0
- data/lib/contrast/agent/assess/policy/propagation_method.rb +5 -3
- data/lib/contrast/agent/assess/policy/propagator/custom.rb +4 -0
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +5 -0
- data/lib/contrast/agent/assess/policy/propagator/split.rb +3 -0
- data/lib/contrast/agent/assess/policy/source_method.rb +5 -0
- data/lib/contrast/agent/assess/policy/trigger_method.rb +9 -3
- data/lib/contrast/agent/assess/tracker.rb +12 -0
- data/lib/contrast/agent/inventory/dependency_analysis.rb +2 -2
- data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +1 -1
- data/lib/contrast/agent/inventory/policy/datastores.rb +1 -1
- data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
- data/lib/contrast/agent/patching/policy/method_policy.rb +3 -3
- data/lib/contrast/agent/protect/rule/base.rb +1 -1
- data/lib/contrast/agent/reporting/reporter_heartbeat.rb +1 -3
- data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +17 -21
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +26 -3
- data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +5 -5
- data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +1 -1
- data/lib/contrast/agent/request_context.rb +8 -0
- data/lib/contrast/agent/service_heartbeat.rb +2 -3
- data/lib/contrast/agent/static_analysis.rb +1 -1
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/agent/worker_thread.rb +10 -0
- data/lib/contrast/api/communication/response_processor.rb +1 -1
- data/lib/contrast/api/dtm.pb.rb +1 -1
- data/lib/contrast/api/settings.pb.rb +1 -1
- data/lib/contrast/components/agent.rb +52 -14
- data/lib/contrast/components/api.rb +60 -23
- data/lib/contrast/components/assess.rb +16 -0
- data/lib/contrast/components/contrast_service.rb +1 -1
- data/lib/contrast/components/heap_dump.rb +51 -1
- data/lib/contrast/components/inventory.rb +19 -13
- data/lib/contrast/components/logger.rb +18 -0
- data/lib/contrast/components/protect.rb +41 -1
- data/lib/contrast/components/sampling.rb +29 -0
- data/lib/contrast/config/assess_configuration.rb +33 -3
- data/lib/contrast/config/base_configuration.rb +8 -2
- data/lib/contrast/config/root_configuration.rb +19 -16
- data/lib/contrast/config/service_configuration.rb +4 -4
- data/lib/contrast/config.rb +0 -9
- data/lib/contrast/extension/object.rb +19 -0
- data/lib/contrast/framework/rails/support.rb +4 -1
- data/lib/contrast/logger/log.rb +2 -1
- data/lib/contrast/utils/assess/event_limit_utils.rb +96 -0
- data/lib/contrast/utils/assess/propagation_method_utils.rb +27 -7
- data/lib/contrast/utils/log_utils.rb +2 -2
- data/lib/contrast/utils/net_http_base.rb +2 -2
- data/lib/contrast/utils/patching/policy/patch_utils.rb +6 -23
- data/lib/contrast.rb +39 -20
- data/lib/protobuf/code_generator.rb +129 -0
- data/lib/protobuf/decoder.rb +28 -0
- data/lib/protobuf/deprecation.rb +117 -0
- data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +79 -0
- data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +360 -0
- data/lib/protobuf/descriptors.rb +3 -0
- data/lib/protobuf/encoder.rb +11 -0
- data/lib/protobuf/enum.rb +365 -0
- data/lib/protobuf/exceptions.rb +9 -0
- data/lib/protobuf/field/base_field.rb +380 -0
- data/lib/protobuf/field/base_field_object_definitions.rb +504 -0
- data/lib/protobuf/field/bool_field.rb +64 -0
- data/lib/protobuf/field/bytes_field.rb +67 -0
- data/lib/protobuf/field/double_field.rb +25 -0
- data/lib/protobuf/field/enum_field.rb +56 -0
- data/lib/protobuf/field/field_array.rb +102 -0
- data/lib/protobuf/field/field_hash.rb +122 -0
- data/lib/protobuf/field/fixed32_field.rb +25 -0
- data/lib/protobuf/field/fixed64_field.rb +28 -0
- data/lib/protobuf/field/float_field.rb +43 -0
- data/lib/protobuf/field/int32_field.rb +21 -0
- data/lib/protobuf/field/int64_field.rb +34 -0
- data/lib/protobuf/field/integer_field.rb +23 -0
- data/lib/protobuf/field/message_field.rb +51 -0
- data/lib/protobuf/field/sfixed32_field.rb +27 -0
- data/lib/protobuf/field/sfixed64_field.rb +28 -0
- data/lib/protobuf/field/signed_integer_field.rb +29 -0
- data/lib/protobuf/field/sint32_field.rb +21 -0
- data/lib/protobuf/field/sint64_field.rb +21 -0
- data/lib/protobuf/field/string_field.rb +51 -0
- data/lib/protobuf/field/uint32_field.rb +21 -0
- data/lib/protobuf/field/uint64_field.rb +21 -0
- data/lib/protobuf/field/varint_field.rb +77 -0
- data/lib/protobuf/field.rb +74 -0
- data/lib/protobuf/generators/base.rb +85 -0
- data/lib/protobuf/generators/enum_generator.rb +39 -0
- data/lib/protobuf/generators/extension_generator.rb +27 -0
- data/lib/protobuf/generators/field_generator.rb +193 -0
- data/lib/protobuf/generators/file_generator.rb +262 -0
- data/lib/protobuf/generators/group_generator.rb +122 -0
- data/lib/protobuf/generators/message_generator.rb +104 -0
- data/lib/protobuf/generators/option_generator.rb +17 -0
- data/lib/protobuf/generators/printable.rb +160 -0
- data/lib/protobuf/generators/service_generator.rb +50 -0
- data/lib/protobuf/lifecycle.rb +33 -0
- data/lib/protobuf/logging.rb +39 -0
- data/lib/protobuf/message/fields.rb +233 -0
- data/lib/protobuf/message/serialization.rb +85 -0
- data/lib/protobuf/message.rb +241 -0
- data/lib/protobuf/optionable.rb +72 -0
- data/lib/protobuf/tasks/compile.rake +80 -0
- data/lib/protobuf/tasks.rb +1 -0
- data/lib/protobuf/varint.rb +20 -0
- data/lib/protobuf/varint_pure.rb +31 -0
- data/lib/protobuf/version.rb +3 -0
- data/lib/protobuf/wire_type.rb +10 -0
- data/lib/protobuf.rb +91 -0
- data/proto/dynamic_discovery.proto +46 -0
- data/proto/google/protobuf/compiler/plugin.proto +183 -0
- data/proto/google/protobuf/descriptor.proto +911 -0
- data/proto/rpc.proto +71 -0
- data/resources/assess/policy.json +15 -12
- data/resources/deadzone/policy.json +132 -19
- data/ruby-agent.gemspec +3 -1
- metadata +112 -28
- data/lib/contrast/config/agent_configuration.rb +0 -63
- data/lib/contrast/config/api_configuration.rb +0 -56
- data/lib/contrast/config/heap_dump_configuration.rb +0 -59
- data/lib/contrast/config/inventory_configuration.rb +0 -33
- data/lib/contrast/config/logger_configuration.rb +0 -26
- data/lib/contrast/config/protect_configuration.rb +0 -33
- data/lib/contrast/config/sampling_configuration.rb +0 -35
@@ -1,6 +1,8 @@
|
|
1
1
|
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require 'contrast/components/sampling'
|
5
|
+
|
4
6
|
module Contrast
|
5
7
|
module Config
|
6
8
|
# Common Configuration settings. Those in this section pertain to the
|
@@ -15,6 +17,10 @@ module Contrast
|
|
15
17
|
attr_writer :enable_scan_response, :enable_dynamic_sources, :sampling, :rules, :stacktraces
|
16
18
|
|
17
19
|
DEFAULT_STACKTRACES = 'ALL'
|
20
|
+
DEFAULT_MAX_SOURCE_EVENTS = 50_000
|
21
|
+
DEFAULT_MAX_PROPAGATION_EVENTS = 50_000
|
22
|
+
DEFAULT_MAX_RULE_REPORTED = 50_000
|
23
|
+
DEFAULT_MAX_RULE_TIME_THRESHOLD = 300_000
|
18
24
|
|
19
25
|
def initialize hsh = {}
|
20
26
|
return unless hsh
|
@@ -24,9 +30,13 @@ module Contrast
|
|
24
30
|
@enable_scan_response = hsh[:enable_scan_response]
|
25
31
|
@enable_dynamic_sources = hsh[:enable_dynamic_sources]
|
26
32
|
@enable_original_object = hsh[:enable_original_object]
|
27
|
-
@sampling = Contrast::
|
33
|
+
@sampling = Contrast::Components::Sampling::Interface.new(hsh[:sampling])
|
28
34
|
@rules = Contrast::Config::AssessRulesConfiguration.new(hsh[:rules])
|
29
35
|
@stacktraces = hsh[:stacktraces]
|
36
|
+
@max_context_source_events = hsh[:max_context_source_events]
|
37
|
+
@max_propagation_events = hsh[:max_propagation_events]
|
38
|
+
@max_rule_reported = hsh[:max_rule_reported]
|
39
|
+
@time_limit_threshold = hsh[:time_limit_threshold]
|
30
40
|
end
|
31
41
|
|
32
42
|
# @return [Boolean, true]
|
@@ -44,9 +54,9 @@ module Contrast
|
|
44
54
|
@enable_original_object.nil? ? true : @enable_original_object
|
45
55
|
end
|
46
56
|
|
47
|
-
# @return [Contrast::
|
57
|
+
# @return [Contrast::Components::Sampling::Interface]
|
48
58
|
def sampling
|
49
|
-
@sampling ||= Contrast::
|
59
|
+
@sampling ||= Contrast::Components::Sampling::Interface.new
|
50
60
|
end
|
51
61
|
|
52
62
|
# @return [Contrast::Config::AssessRulesConfiguration]
|
@@ -58,6 +68,26 @@ module Contrast
|
|
58
68
|
def stacktraces
|
59
69
|
@stacktraces ||= DEFAULT_STACKTRACES
|
60
70
|
end
|
71
|
+
|
72
|
+
# @return [int] max number of context source events in single request
|
73
|
+
def max_context_source_events
|
74
|
+
@max_context_source_events ||= DEFAULT_MAX_SOURCE_EVENTS
|
75
|
+
end
|
76
|
+
|
77
|
+
# @return [int] max number of propagation events in single request
|
78
|
+
def max_propagation_events
|
79
|
+
@max_propagation_events ||= DEFAULT_MAX_PROPAGATION_EVENTS
|
80
|
+
end
|
81
|
+
|
82
|
+
# @return [int] max number of rules reported within time_limit_threshold
|
83
|
+
def max_rule_reported
|
84
|
+
@max_rule_reported ||= DEFAULT_MAX_RULE_REPORTED
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [int] max ms threshold for reporting rules
|
88
|
+
def time_limit_threshold
|
89
|
+
@time_limit_threshold ||= DEFAULT_MAX_RULE_TIME_THRESHOLD
|
90
|
+
end
|
61
91
|
end
|
62
92
|
end
|
63
93
|
end
|
@@ -10,12 +10,18 @@ module Contrast
|
|
10
10
|
# Configuration settings to usable Ruby classes.
|
11
11
|
module BaseConfiguration
|
12
12
|
extend Forwardable
|
13
|
+
AT_UNDERSCORE = '@_'
|
13
14
|
|
14
15
|
def to_hash
|
15
16
|
hsh = {}
|
16
17
|
instance_variables.each do |iv|
|
17
|
-
# strip the '@' to get the key
|
18
|
-
|
18
|
+
# strip the '@' of '@_' to get the key
|
19
|
+
string_iv = iv.to_s
|
20
|
+
key = if string_iv.include?(AT_UNDERSCORE)
|
21
|
+
string_iv[2..]
|
22
|
+
else
|
23
|
+
string_iv[1..]
|
24
|
+
end
|
19
25
|
hsh[key] = send(key.to_sym)
|
20
26
|
end
|
21
27
|
hsh
|
@@ -1,15 +1,18 @@
|
|
1
1
|
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require 'contrast/components/agent'
|
5
|
+
require 'contrast/components/inventory'
|
6
|
+
require 'contrast/components/protect'
|
4
7
|
module Contrast
|
5
8
|
module Config
|
6
9
|
# The base of the Common Configuration settings.
|
7
10
|
class RootConfiguration
|
8
11
|
include Contrast::Config::BaseConfiguration
|
9
12
|
|
10
|
-
# @return [Contrast::
|
13
|
+
# @return [Contrast::Components::Api::Interface]
|
11
14
|
attr_writer :api
|
12
|
-
# @return [Contrast::
|
15
|
+
# @return [Contrast::Components::Agent::Interface]
|
13
16
|
attr_writer :agent
|
14
17
|
# @return [Contrast::Config::ApplicationConfiguration]
|
15
18
|
attr_writer :application
|
@@ -17,9 +20,9 @@ module Contrast
|
|
17
20
|
attr_writer :server
|
18
21
|
# @return [Contrast::Config::AssessConfiguration]
|
19
22
|
attr_writer :assess
|
20
|
-
# @return [Contrast::
|
23
|
+
# @return [Contrast::Components::Inventory::Interface]
|
21
24
|
attr_writer :inventory
|
22
|
-
# @return [Contrast::
|
25
|
+
# @return [Contrast::Components::Protect::Interface]
|
23
26
|
attr_writer :protect
|
24
27
|
# @return [Contrast::Config::ServiceConfiguration]
|
25
28
|
attr_writer :service
|
@@ -30,25 +33,25 @@ module Contrast
|
|
30
33
|
def initialize hsh = {}
|
31
34
|
raise(ArgumentError, 'Expected a hash') unless hsh.is_a?(Hash)
|
32
35
|
|
33
|
-
@api = Contrast::
|
36
|
+
@api = Contrast::Components::Api::Interface.new(hsh[:api])
|
34
37
|
@enable = hsh[:enable]
|
35
|
-
@agent = Contrast::
|
38
|
+
@agent = Contrast::Components::Agent::Interface.new(hsh[:agent])
|
36
39
|
@application = Contrast::Config::ApplicationConfiguration.new(hsh[:application])
|
37
40
|
@server = Contrast::Config::ServerConfiguration.new(hsh[:server])
|
38
41
|
@assess = Contrast::Config::AssessConfiguration.new(hsh[:assess])
|
39
|
-
@inventory = Contrast::
|
40
|
-
@protect = Contrast::
|
42
|
+
@inventory = Contrast::Components::Inventory::Interface.new(hsh[:inventory])
|
43
|
+
@protect = Contrast::Components::Protect::Interface.new(hsh[:protect])
|
41
44
|
@service = Contrast::Config::ServiceConfiguration.new(hsh[:service])
|
42
45
|
end
|
43
46
|
|
44
|
-
# @return [Contrast::
|
47
|
+
# @return [Contrast::Components::Api::Interface]
|
45
48
|
def api
|
46
|
-
@api ||= Contrast::
|
49
|
+
@api ||= Contrast::Components::Api::Interface.new
|
47
50
|
end
|
48
51
|
|
49
|
-
# @return [Contrast::
|
52
|
+
# @return [Contrast::Components::Agent::Interface]
|
50
53
|
def agent
|
51
|
-
@agent ||= Contrast::
|
54
|
+
@agent ||= Contrast::Components::Agent::Interface.new
|
52
55
|
end
|
53
56
|
|
54
57
|
# @return [Contrast::Config::ApplicationConfiguration]
|
@@ -66,14 +69,14 @@ module Contrast
|
|
66
69
|
@assess ||= Contrast::Config::AssessConfiguration.new
|
67
70
|
end
|
68
71
|
|
69
|
-
# @return [Contrast::
|
72
|
+
# @return [Contrast::Components::Inventory::Interface]
|
70
73
|
def inventory
|
71
|
-
@inventory ||= Contrast::
|
74
|
+
@inventory ||= Contrast::Components::Inventory::Interface.new
|
72
75
|
end
|
73
76
|
|
74
|
-
# @return [Contrast::
|
77
|
+
# @return [Contrast::Components::Protect::Interface]
|
75
78
|
def protect
|
76
|
-
@protect ||= Contrast::
|
79
|
+
@protect ||= Contrast::Components::Protect::Interface.new
|
77
80
|
end
|
78
81
|
|
79
82
|
# @return [Contrast::Config::ServiceConfiguration]
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require 'contrast/
|
4
|
+
require 'contrast/components/logger'
|
5
5
|
|
6
6
|
module Contrast
|
7
7
|
module Config
|
@@ -31,13 +31,13 @@ module Contrast
|
|
31
31
|
@host = hsh[:host]
|
32
32
|
@port = hsh[:port]
|
33
33
|
@socket = hsh[:socket]
|
34
|
-
@logger = Contrast::
|
34
|
+
@logger = Contrast::Components::Logger::Interface.new(hsh[:logger])
|
35
35
|
@bypass = hsh[:bypass]
|
36
36
|
end
|
37
37
|
|
38
|
-
# @return [Contrast::
|
38
|
+
# @return [Contrast::Components::Logger::Interface]
|
39
39
|
def logger
|
40
|
-
@logger ||= Contrast::
|
40
|
+
@logger ||= Contrast::Components::Logger::Interface.new
|
41
41
|
end
|
42
42
|
|
43
43
|
# @return [Boolean, false]
|
data/lib/contrast/config.rb
CHANGED
@@ -11,23 +11,14 @@ module Contrast
|
|
11
11
|
end
|
12
12
|
|
13
13
|
require 'contrast/config/base_configuration'
|
14
|
-
|
15
|
-
require 'contrast/config/logger_configuration'
|
16
|
-
|
17
|
-
require 'contrast/config/heap_dump_configuration'
|
18
14
|
require 'contrast/config/service_configuration'
|
19
15
|
require 'contrast/config/exception_configuration'
|
20
16
|
require 'contrast/config/assess_rules_configuration'
|
21
17
|
require 'contrast/config/protect_rule_configuration'
|
22
18
|
require 'contrast/config/protect_rules_configuration'
|
23
|
-
require 'contrast/config/sampling_configuration'
|
24
19
|
|
25
20
|
require 'contrast/config/ruby_configuration'
|
26
|
-
require 'contrast/config/api_configuration'
|
27
|
-
require 'contrast/config/agent_configuration'
|
28
21
|
require 'contrast/config/application_configuration'
|
29
22
|
require 'contrast/config/server_configuration'
|
30
23
|
require 'contrast/config/assess_configuration'
|
31
|
-
require 'contrast/config/inventory_configuration'
|
32
|
-
require 'contrast/config/protect_configuration'
|
33
24
|
require 'contrast/config/root_configuration'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Some developers override various methods on Object, which can often involve
|
5
|
+
# changing expected method parity/behavior which in turn prevents us from being
|
6
|
+
# able to reliably use affected methods.
|
7
|
+
# We alias these method so that we always have access to them.
|
8
|
+
#
|
9
|
+
# Because we use these methods in constructing classes (e.g., calling #freeze
|
10
|
+
# on constants within class definitions) we do this aliasing ASAP.
|
11
|
+
class Object
|
12
|
+
alias_method :cs__class, :class
|
13
|
+
alias_method :cs__freeze, :freeze
|
14
|
+
alias_method :cs__frozen?, :frozen?
|
15
|
+
alias_method :cs__is_a?, :is_a?
|
16
|
+
alias_method :cs__method, :method
|
17
|
+
alias_method :cs__respond_to?, :respond_to?
|
18
|
+
alias_method :cs__singleton_class, :singleton_class
|
19
|
+
end
|
@@ -135,8 +135,11 @@ module Contrast
|
|
135
135
|
# @return [bool] whether the router is an engine or not.
|
136
136
|
def engine_route? route
|
137
137
|
return false unless route&.app&.app
|
138
|
+
return false unless route.app.is_a?(::ActionDispatch::Routing::Mapper::Constraints) ||
|
139
|
+
route.app.is_a?(::ActionDispatch::Routing::RouteSet::Dispatcher)
|
138
140
|
|
139
|
-
route.app.is_a?(
|
141
|
+
clazz = route.app.app.is_a?(Class) ? route.app.app : route.app.app.cs__class
|
142
|
+
clazz < ::Rails::Engine
|
140
143
|
end
|
141
144
|
|
142
145
|
# Recursively get final route traversing engines as required. Because this can only be called once, we store
|
data/lib/contrast/logger/log.rb
CHANGED
@@ -134,7 +134,8 @@ module Contrast
|
|
134
134
|
|
135
135
|
enable_trace_timing if current_level_const == ::Ougai::Logging::TRACE
|
136
136
|
|
137
|
-
|
137
|
+
progname = Contrast::CONFIG.root.agent.logger.progname
|
138
|
+
@_logger = build(path: current_path, level_const: current_level_const, progname: progname)
|
138
139
|
# If we're logging to a new path, then let's start it w/ our helpful
|
139
140
|
# data gathering messages
|
140
141
|
log_update if path_change
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'contrast/components/logger'
|
5
|
+
|
6
|
+
module Contrast
|
7
|
+
module Utils
|
8
|
+
module Assess
|
9
|
+
# EventLimitUtils is used to check and validate the number of source, propagation, or trigger events collected
|
10
|
+
# during the reporting time frame
|
11
|
+
module EventLimitUtils
|
12
|
+
include Contrast::Components::Logger::InstanceMethods
|
13
|
+
# Checks to see if the event limit for the policy type has been met or exceeded
|
14
|
+
# @param method_policy [Contrast::Agent::Patching::Policy::MethodPolicy] method to check for event limit
|
15
|
+
def event_limit? method_policy
|
16
|
+
return false unless (context = Contrast::Agent::REQUEST_TRACKER.current)
|
17
|
+
|
18
|
+
if method_policy.source_node
|
19
|
+
max = (::Contrast::ASSESS.max_source_events ||
|
20
|
+
Contrast::Config::AssessConfiguration::DEFAULT_MAX_SOURCE_EVENTS)
|
21
|
+
return at_limit?(method_policy, context.source_event_count, max)
|
22
|
+
|
23
|
+
end
|
24
|
+
if method_policy.propagation_node
|
25
|
+
max = (::Contrast::ASSESS.max_propagation_events ||
|
26
|
+
Contrast::Config::AssessConfiguration::DEFAULT_MAX_PROPAGATION_EVENTS)
|
27
|
+
return at_limit?(method_policy, context.propagation_event_count, max)
|
28
|
+
end
|
29
|
+
|
30
|
+
false # policy does not have limit
|
31
|
+
end
|
32
|
+
|
33
|
+
def event_limit_for_rule? rule_id
|
34
|
+
if Contrast::Utils::Timer.now_ms > threshold_time_limit
|
35
|
+
@_rule_counts = nil
|
36
|
+
@_threshold_time_limit = nil
|
37
|
+
threshold_time_limit
|
38
|
+
end
|
39
|
+
rule_counts[rule_id] += 1
|
40
|
+
# TODO: RUBY-1680 remove default
|
41
|
+
rule_counts[rule_id] >=
|
42
|
+
(::Contrast::ASSESS.max_rule_reported || Contrast::Config::AssessConfiguration::DEFAULT_MAX_RULE_REPORTED)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Increments the event count for the type of event that is being tracked
|
46
|
+
#
|
47
|
+
# @param node [Contrast::Agent::Assess::Policy::PolicyNode] policy to increment
|
48
|
+
def increment_event_count node
|
49
|
+
return unless (context = Contrast::Agent::REQUEST_TRACKER.current)
|
50
|
+
|
51
|
+
context.source_event_count += 1 if node.cs__is_a?(Contrast::Agent::Assess::Policy::SourceNode)
|
52
|
+
context.propagation_event_count += 1 if node.cs__is_a?(Contrast::Agent::Assess::Policy::PropagationNode)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# helper method to check limit and log when necessary
|
58
|
+
def at_limit? method_policy, current_count, event_max
|
59
|
+
if current_count == event_max
|
60
|
+
logger.warn('Event Limit Reached:',
|
61
|
+
{
|
62
|
+
count: current_count,
|
63
|
+
max: event_max,
|
64
|
+
policy: method_policy.method_name,
|
65
|
+
node: method_policy
|
66
|
+
})
|
67
|
+
# increment to be over count for logging purposes
|
68
|
+
increment_event_count(method_policy)
|
69
|
+
return true
|
70
|
+
elsif current_count > event_max
|
71
|
+
# increment to be over count for logging purposes
|
72
|
+
increment_event_count(method_policy)
|
73
|
+
logger.warn('Event Limit Exceeded:',
|
74
|
+
{
|
75
|
+
count: current_count,
|
76
|
+
policy: method_policy.method_name,
|
77
|
+
node: method_policy
|
78
|
+
})
|
79
|
+
return true
|
80
|
+
end
|
81
|
+
false
|
82
|
+
end
|
83
|
+
|
84
|
+
def rule_counts
|
85
|
+
@_rule_counts ||= Hash.new { |h, k| h[k] = 0 }
|
86
|
+
end
|
87
|
+
|
88
|
+
# the time threshold for which to track rule counts resets when now >= threshold_time_limit
|
89
|
+
# @return [Integer]
|
90
|
+
def threshold_time_limit
|
91
|
+
@_threshold_time_limit ||= Contrast::Utils::Timer.now_ms + (::Contrast::ASSESS.time_limit_threshold || 0)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -92,20 +92,24 @@ module Contrast
|
|
92
92
|
# @param preshift [Contrast::Agent::Assess::PreShift] The capture of the state of the code just prior to
|
93
93
|
# the invocation of the patched method.
|
94
94
|
# @param target [Object] the thing to which to propagate
|
95
|
+
# @param propagation_data [Contrast::Agent::Assess::Events::EventData] this will hold the
|
96
|
+
# object [Object] the Object on which the method was invoked
|
97
|
+
# args [Array<Object>] the Arguments with which the method was invoked
|
95
98
|
# @return [Boolean]
|
96
|
-
def can_propagate? propagation_node, preshift, target
|
99
|
+
def can_propagate? propagation_node, preshift, target, propagation_data
|
97
100
|
return false unless appropriate_target?(propagation_node, target)
|
98
101
|
return true if Contrast::Utils::Assess::TrackingUtil.tracked?(target)
|
99
|
-
|
100
|
-
# return true since we don't have preshift while using the original object.
|
101
|
-
return true
|
102
|
-
end
|
103
|
-
return false unless preshift
|
102
|
+
return false unless appropriate_source?(propagation_node, propagation_data, preshift)
|
104
103
|
|
105
104
|
propagation_node.sources.each do |source|
|
106
105
|
case source
|
107
106
|
when Contrast::Utils::ObjectShare::OBJECT_KEY
|
108
|
-
|
107
|
+
source_object = if propagation_node.use_original_object?
|
108
|
+
propagation_data.object
|
109
|
+
else
|
110
|
+
preshift.object
|
111
|
+
end
|
112
|
+
return true if Contrast::Utils::Assess::TrackingUtil.tracked?(source_object)
|
109
113
|
else
|
110
114
|
# has to be P, there's no ret source type (yet? ever?)
|
111
115
|
return true if preshift.args && Contrast::Utils::Assess::TrackingUtil.tracked?(preshift.args[source])
|
@@ -129,6 +133,22 @@ module Contrast
|
|
129
133
|
|
130
134
|
Contrast::Agent::Assess::Tracker.trackable?(target)
|
131
135
|
end
|
136
|
+
|
137
|
+
# A source is appropriate if it is available for propagation
|
138
|
+
#
|
139
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
140
|
+
# propagation event.
|
141
|
+
# @param propagation_data [Contrast::Agent::Assess::Events::EventData] this will hold the
|
142
|
+
# object [Object] the Object on which the method was invoked
|
143
|
+
# args [Array<Object>] the Arguments with which the method was invoked
|
144
|
+
# @param preshift [Contrast::Agent::Assess::PreShift] The capture of the state of the code just prior to
|
145
|
+
# the invocation of the patched method.
|
146
|
+
# @return [Boolean]
|
147
|
+
def appropriate_source? propagation_node, propagation_data, preshift
|
148
|
+
return true if preshift
|
149
|
+
|
150
|
+
propagation_node.use_original_object? && propagation_data&.object
|
151
|
+
end
|
132
152
|
end
|
133
153
|
end
|
134
154
|
end
|
@@ -19,7 +19,7 @@ module Contrast
|
|
19
19
|
|
20
20
|
private
|
21
21
|
|
22
|
-
def build path: STDOUT_STR, level_const: DEFAULT_LEVEL
|
22
|
+
def build path: STDOUT_STR, level_const: DEFAULT_LEVEL, progname: PROGNAME
|
23
23
|
logger = case path
|
24
24
|
when STDOUT_STR, STDERR_STR
|
25
25
|
::Ougai::Logger.new(Object.cs__const_get(path))
|
@@ -27,7 +27,7 @@ module Contrast
|
|
27
27
|
::Ougai::Logger.new(path)
|
28
28
|
end
|
29
29
|
add_contrast_loggers(logger)
|
30
|
-
logger.progname =
|
30
|
+
logger.progname = progname
|
31
31
|
logger.level = level_const
|
32
32
|
logger.formatter = Contrast::Logger::Format.new
|
33
33
|
logger.formatter.datetime_format = DATE_TIME_FORMAT
|
@@ -131,7 +131,7 @@ module Contrast
|
|
131
131
|
end
|
132
132
|
return initialize_client if addr.host.to_s.include?('localhost') # TODO: RUBY-99999 allow http w/ localhost
|
133
133
|
|
134
|
-
assign_cert(initialize_client) if use_custom_cert && Contrast::API.
|
134
|
+
assign_cert(initialize_client) if use_custom_cert && Contrast::API.certification_enable
|
135
135
|
initialize_client.use_ssl = true
|
136
136
|
initialize_client.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
137
137
|
initialize_client.verify_depth = 5
|
@@ -150,7 +150,7 @@ module Contrast
|
|
150
150
|
def proxy_enabled?
|
151
151
|
return @_proxy_enabled unless @_proxy_enabled.nil?
|
152
152
|
|
153
|
-
@_proxy_enabled = Contrast::API.
|
153
|
+
@_proxy_enabled = Contrast::API.proxy_enable && !Contrast::API.proxy_url.nil?
|
154
154
|
end
|
155
155
|
|
156
156
|
# Retrieve the IP address from the client.
|
@@ -7,18 +7,6 @@ module Contrast
|
|
7
7
|
# This module will include all methods for different patch applies from Patch module and some other module
|
8
8
|
# methods from the same place, so we can ease the main module
|
9
9
|
module PatchUtils
|
10
|
-
# Method to choose which replaced return from the post_patch to actually return.
|
11
|
-
#
|
12
|
-
# @param propagated_ret [Object, nil] The replaced return from the propagation patch.
|
13
|
-
# @param source_ret [Object, nil] The replaced return from the source patch.
|
14
|
-
# @param ret [Object, nil] The original return of the patched method.
|
15
|
-
# @return [Object, nil] The thing to return from the post patch.
|
16
|
-
def handle_return propagated_ret, source_ret, ret
|
17
|
-
safe_return = propagated_ret || source_ret || ret
|
18
|
-
safe_return.rewind if Contrast::Utils::IOUtil.should_rewind?(safe_return)
|
19
|
-
safe_return
|
20
|
-
end
|
21
|
-
|
22
10
|
# Given a module and method, construct an expected name for the alias by which Contrast will reference the
|
23
11
|
# original.
|
24
12
|
#
|
@@ -107,7 +95,7 @@ module Contrast
|
|
107
95
|
# @param object [Object] The object on which the method is invoked, typically what would be returned by self.
|
108
96
|
# @param args [Array<Object>] The arguments passed to the method being invoked.
|
109
97
|
def apply_inventory method_policy, method, exception, object, args
|
110
|
-
return unless ::Contrast::INVENTORY.
|
98
|
+
return unless ::Contrast::INVENTORY.enable
|
111
99
|
|
112
100
|
apply_trigger_only(method_policy&.inventory_node, method, exception, object, args)
|
113
101
|
end
|
@@ -123,8 +111,6 @@ module Contrast
|
|
123
111
|
# @param args [Array<Object>] The arguments passed to the method being invoked.
|
124
112
|
# @param block [Proc] The block passed to the method that was invoked.
|
125
113
|
def apply_assess method_policy, preshift, object, ret, args, block
|
126
|
-
source_ret = nil
|
127
|
-
propagated_ret = nil
|
128
114
|
return ret unless method_policy && ::Contrast::ASSESS.enabled?
|
129
115
|
|
130
116
|
current_context = Contrast::Agent::REQUEST_TRACKER.current
|
@@ -135,27 +121,24 @@ module Contrast
|
|
135
121
|
Contrast::Agent::Assess::Policy::TriggerMethod.apply_trigger_rule(trigger_node, object, ret, args)
|
136
122
|
end
|
137
123
|
if method_policy.source_node
|
138
|
-
|
139
|
-
# we'll need to replace the return. Note, this is not the default case.
|
140
|
-
source_ret = Contrast::Agent::Assess::Policy::SourceMethod.apply_source(method_policy, object, ret, args)
|
124
|
+
Contrast::Agent::Assess::Policy::SourceMethod.apply_source(method_policy, object, ret, args)
|
141
125
|
end
|
142
126
|
if method_policy.propagation_node
|
143
|
-
|
127
|
+
Contrast::Agent::Assess::Policy::PropagationMethod.apply_propagation(
|
144
128
|
method_policy,
|
145
129
|
preshift,
|
146
130
|
object,
|
147
|
-
|
131
|
+
ret,
|
148
132
|
args,
|
149
133
|
block)
|
150
134
|
end
|
151
|
-
handle_return(propagated_ret, source_ret, ret)
|
152
135
|
rescue StandardError => e
|
153
136
|
logger.error('Unable to assess method call.', e)
|
154
|
-
handle_return(propagated_ret, source_ret, ret)
|
155
137
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
156
138
|
logger.error('Unable to assess method call.', e)
|
157
|
-
handle_return(propagated_ret, source_ret, ret)
|
158
139
|
raise(e)
|
140
|
+
ensure
|
141
|
+
ret.rewind if Contrast::Utils::IOUtil.should_rewind?(ret)
|
159
142
|
end
|
160
143
|
|
161
144
|
# Generic invocation of the Inventory or Protect patch which apply to the given method.
|
data/lib/contrast.rb
CHANGED
@@ -4,21 +4,39 @@
|
|
4
4
|
# Used to prevent deprecation warnings from flooding stdout
|
5
5
|
ENV['PB_IGNORE_DEPRECATIONS'] = 'true'
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
7
|
+
require 'contrast/extension/object'
|
8
|
+
|
9
|
+
# ActiveRecord gives access to the `String#blank?` method, which we've started using. We need to make sure that method
|
10
|
+
# actually exists.
|
11
|
+
# From https://github.com/rails/rails/blob/main/activesupport/lib/active_support/core_ext/object/blank.rb
|
12
|
+
class String
|
13
|
+
unless cs__respond_to?(:blank?)
|
14
|
+
|
15
|
+
CS__BLANK_RE = /\A[[:space:]]*\z/.cs__freeze
|
16
|
+
# A string is blank if it's empty or contains whitespaces only:
|
17
|
+
#
|
18
|
+
# ''.blank? # => true
|
19
|
+
# ' '.blank? # => true
|
20
|
+
# "\t\n\r".blank? # => true
|
21
|
+
# ' blah '.blank? # => false
|
22
|
+
#
|
23
|
+
# Unicode whitespace is supported:
|
24
|
+
#
|
25
|
+
# "\u00a0".blank? # => true
|
26
|
+
#
|
27
|
+
# @return [true, false]
|
28
|
+
def blank?
|
29
|
+
# The regexp that matches blank strings is expensive. For the case of empty
|
30
|
+
# strings we can speed up this method (~3.5x) with an empty? call. The
|
31
|
+
# penalty for the rest of strings is marginal.
|
32
|
+
empty? ||
|
33
|
+
begin
|
34
|
+
CS__BLANK_RE.match?(self)
|
35
|
+
rescue Encoding::CompatibilityError
|
36
|
+
false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
22
40
|
end
|
23
41
|
|
24
42
|
if RUBY_VERSION >= '3.0.0' && RUBY_VERSION < '3.1.0'
|
@@ -50,17 +68,18 @@ require 'contrast/components/settings'
|
|
50
68
|
require 'contrast/utils/telemetry_hash'
|
51
69
|
require 'contrast/utils/telemetry'
|
52
70
|
require 'contrast/agent/telemetry/events/exceptions/telemetry_exception_event'
|
71
|
+
require 'protobuf' # TODO: RUBY-1438
|
53
72
|
|
54
73
|
module Contrast
|
55
|
-
API = Contrast::Components::Api::Interface.new
|
56
|
-
SCOPE = Contrast::Components::Scope::Interface.new
|
57
74
|
CONFIG = Contrast::Components::Config::Interface.new
|
75
|
+
SCOPE = Contrast::Components::Scope::Interface.new
|
76
|
+
API = CONFIG.root.api
|
58
77
|
SETTINGS = Contrast::Components::Settings::Interface.new
|
59
78
|
ASSESS = Contrast::Components::Assess::Interface.new
|
60
79
|
PROTECT = Contrast::Components::Protect::Interface.new
|
61
|
-
INVENTORY =
|
62
|
-
|
63
|
-
|
80
|
+
INVENTORY = CONFIG.root.inventory
|
81
|
+
AGENT = CONFIG.root.agent
|
82
|
+
LOGGER = AGENT.logger
|
64
83
|
CONTRAST_SERVICE = Contrast::Components::ContrastService::Interface.new
|
65
84
|
APP_CONTEXT = Contrast::Components::AppContext::Interface.new
|
66
85
|
end
|