contrast-agent 4.3.2 → 4.7.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/.gitmodules +1 -1
- data/.simplecov +1 -1
- data/Gemfile +1 -1
- data/LICENSE.txt +1 -1
- data/Rakefile +2 -3
- data/exe/contrast_service +1 -1
- data/ext/build_funchook.rb +4 -4
- data/ext/cs__assess_active_record_named/cs__active_record_named.c +1 -1
- data/ext/cs__assess_active_record_named/extconf.rb +1 -1
- data/ext/cs__assess_array/cs__assess_array.c +1 -1
- data/ext/cs__assess_array/extconf.rb +1 -1
- data/ext/cs__assess_basic_object/cs__assess_basic_object.c +1 -1
- data/ext/cs__assess_basic_object/extconf.rb +1 -1
- data/ext/cs__assess_fiber_track/cs__assess_fiber_track.c +1 -1
- data/ext/cs__assess_fiber_track/extconf.rb +1 -1
- data/ext/cs__assess_hash/cs__assess_hash.c +4 -2
- data/ext/cs__assess_hash/extconf.rb +1 -1
- data/ext/cs__assess_kernel/cs__assess_kernel.c +1 -1
- data/ext/cs__assess_kernel/extconf.rb +1 -1
- data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +1 -1
- data/ext/cs__assess_marshal_module/extconf.rb +1 -1
- data/ext/cs__assess_module/cs__assess_module.c +1 -1
- data/ext/cs__assess_module/extconf.rb +1 -1
- data/ext/cs__assess_regexp/cs__assess_regexp.c +1 -1
- data/ext/cs__assess_regexp/extconf.rb +1 -1
- data/ext/cs__assess_string/cs__assess_string.c +1 -1
- data/ext/cs__assess_string/extconf.rb +1 -1
- data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.c +1 -1
- data/ext/cs__assess_string_interpolation26/extconf.rb +1 -1
- data/ext/cs__assess_yield_track/cs__assess_yield_track.c +1 -1
- data/ext/cs__assess_yield_track/extconf.rb +1 -1
- data/ext/cs__common/cs__common.c +5 -5
- data/ext/cs__common/cs__common.h +4 -4
- data/ext/cs__common/extconf.rb +1 -1
- data/ext/cs__contrast_patch/cs__contrast_patch.c +22 -25
- data/ext/cs__contrast_patch/extconf.rb +1 -1
- data/ext/cs__protect_kernel/cs__protect_kernel.c +1 -1
- data/ext/cs__protect_kernel/extconf.rb +1 -1
- data/ext/extconf_common.rb +2 -6
- data/lib/contrast-agent.rb +1 -1
- data/lib/contrast.rb +20 -1
- data/lib/contrast/agent.rb +6 -4
- data/lib/contrast/agent/assess.rb +2 -11
- data/lib/contrast/agent/assess/contrast_event.rb +54 -71
- data/lib/contrast/agent/assess/contrast_object.rb +7 -4
- data/lib/contrast/agent/assess/events/event_factory.rb +3 -2
- data/lib/contrast/agent/assess/events/source_event.rb +7 -2
- data/lib/contrast/agent/assess/finalizers/freeze.rb +1 -1
- data/lib/contrast/agent/assess/finalizers/hash.rb +33 -34
- data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +34 -16
- data/lib/contrast/agent/assess/policy/patcher.rb +11 -18
- data/lib/contrast/agent/assess/policy/policy.rb +1 -1
- data/lib/contrast/agent/assess/policy/policy_node.rb +26 -34
- data/lib/contrast/agent/assess/policy/policy_scanner.rb +1 -1
- data/lib/contrast/agent/assess/policy/preshift.rb +4 -2
- data/lib/contrast/agent/assess/policy/propagation_method.rb +32 -30
- data/lib/contrast/agent/assess/policy/propagation_node.rb +20 -9
- data/lib/contrast/agent/assess/policy/propagator.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/append.rb +29 -14
- data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/center.rb +3 -2
- data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +22 -17
- data/lib/contrast/agent/assess/policy/propagator/insert.rb +4 -2
- data/lib/contrast/agent/assess/policy/propagator/keep.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/match_data.rb +3 -2
- data/lib/contrast/agent/assess/policy/propagator/next.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/prepend.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/remove.rb +23 -19
- data/lib/contrast/agent/assess/policy/propagator/replace.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/reverse.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/select.rb +3 -13
- data/lib/contrast/agent/assess/policy/propagator/splat.rb +24 -14
- data/lib/contrast/agent/assess/policy/propagator/split.rb +18 -15
- data/lib/contrast/agent/assess/policy/propagator/substitution.rb +32 -22
- data/lib/contrast/agent/assess/policy/propagator/trim.rb +64 -45
- data/lib/contrast/agent/assess/policy/rewriter_patch.rb +7 -4
- data/lib/contrast/agent/assess/policy/source_method.rb +92 -81
- data/lib/contrast/agent/assess/policy/source_node.rb +1 -1
- data/lib/contrast/agent/assess/policy/source_validation/cross_site_validator.rb +8 -6
- data/lib/contrast/agent/assess/policy/source_validation/source_validation.rb +2 -4
- data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +7 -3
- data/lib/contrast/agent/assess/policy/trigger/xpath.rb +7 -8
- data/lib/contrast/agent/assess/policy/trigger_method.rb +109 -76
- data/lib/contrast/agent/assess/policy/trigger_node.rb +33 -11
- data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +60 -0
- data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +3 -5
- data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +7 -5
- data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +4 -13
- data/lib/contrast/agent/assess/properties.rb +1 -3
- data/lib/contrast/agent/assess/property/evented.rb +9 -6
- data/lib/contrast/agent/assess/property/tagged.rb +38 -20
- data/lib/contrast/agent/assess/property/updated.rb +1 -1
- data/lib/contrast/agent/assess/rule/provider.rb +1 -1
- data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +12 -6
- data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +5 -2
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +4 -6
- data/lib/contrast/agent/assess/tag.rb +1 -1
- data/lib/contrast/agent/assess/tracker.rb +2 -2
- data/lib/contrast/agent/at_exit_hook.rb +1 -1
- data/lib/contrast/agent/class_reopener.rb +4 -2
- data/lib/contrast/agent/deadzone/policy/deadzone_node.rb +1 -1
- data/lib/contrast/agent/deadzone/policy/policy.rb +7 -3
- data/lib/contrast/agent/disable_reaction.rb +2 -4
- data/lib/contrast/agent/exclusion_matcher.rb +6 -12
- data/lib/contrast/agent/inventory.rb +1 -2
- data/lib/contrast/agent/inventory/dependencies.rb +3 -1
- data/lib/contrast/agent/inventory/dependency_analysis.rb +1 -1
- data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +35 -23
- data/lib/contrast/agent/inventory/policy/datastores.rb +1 -1
- data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
- data/lib/contrast/agent/inventory/policy/trigger_node.rb +1 -1
- data/lib/contrast/agent/middleware.rb +111 -110
- data/lib/contrast/agent/module_data.rb +4 -4
- data/lib/contrast/agent/patching/policy/after_load_patch.rb +1 -1
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +9 -4
- data/lib/contrast/agent/patching/policy/method_policy.rb +7 -3
- data/lib/contrast/agent/patching/policy/module_policy.rb +15 -8
- data/lib/contrast/agent/patching/policy/patch.rb +23 -29
- data/lib/contrast/agent/patching/policy/patch_status.rb +8 -9
- data/lib/contrast/agent/patching/policy/patcher.rb +72 -64
- data/lib/contrast/agent/patching/policy/policy.rb +14 -21
- data/lib/contrast/agent/patching/policy/policy_node.rb +15 -5
- data/lib/contrast/agent/patching/policy/trigger_node.rb +26 -10
- data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +2 -2
- data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +2 -2
- data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +2 -2
- data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +3 -4
- data/lib/contrast/agent/protect/policy/applies_sqli_rule.rb +2 -2
- data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +6 -10
- data/lib/contrast/agent/protect/policy/policy.rb +1 -1
- data/lib/contrast/agent/protect/policy/rule_applicator.rb +6 -6
- data/lib/contrast/agent/protect/policy/trigger_node.rb +1 -1
- data/lib/contrast/agent/protect/rule.rb +1 -1
- data/lib/contrast/agent/protect/rule/base.rb +19 -33
- data/lib/contrast/agent/protect/rule/base_service.rb +10 -6
- data/lib/contrast/agent/protect/rule/cmd_injection.rb +15 -19
- data/lib/contrast/agent/protect/rule/default_scanner.rb +1 -1
- data/lib/contrast/agent/protect/rule/deserialization.rb +7 -14
- data/lib/contrast/agent/protect/rule/http_method_tampering.rb +4 -15
- data/lib/contrast/agent/protect/rule/no_sqli.rb +7 -3
- data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +2 -4
- data/lib/contrast/agent/protect/rule/path_traversal.rb +6 -6
- data/lib/contrast/agent/protect/rule/sqli.rb +19 -13
- data/lib/contrast/agent/protect/rule/sqli/default_sql_scanner.rb +1 -1
- data/lib/contrast/agent/protect/rule/sqli/mysql_sql_scanner.rb +1 -1
- data/lib/contrast/agent/protect/rule/sqli/postgres_sql_scanner.rb +2 -2
- data/lib/contrast/agent/protect/rule/sqli/sqlite_sql_scanner.rb +1 -1
- data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +2 -2
- data/lib/contrast/agent/protect/rule/xss.rb +2 -2
- data/lib/contrast/agent/protect/rule/xxe.rb +6 -13
- data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +2 -3
- data/lib/contrast/agent/railtie.rb +1 -1
- data/lib/contrast/agent/reaction_processor.rb +12 -11
- data/lib/contrast/agent/request.rb +25 -24
- data/lib/contrast/agent/request_context.rb +25 -23
- data/lib/contrast/agent/request_handler.rb +1 -1
- data/lib/contrast/agent/response.rb +1 -1
- data/lib/contrast/agent/rewriter.rb +6 -4
- data/lib/contrast/agent/rule_set.rb +3 -3
- data/lib/contrast/agent/scope.rb +1 -1
- data/lib/contrast/agent/service_heartbeat.rb +3 -4
- data/lib/contrast/agent/static_analysis.rb +1 -1
- data/lib/contrast/agent/thread.rb +2 -2
- data/lib/contrast/agent/thread_watcher.rb +21 -6
- data/lib/contrast/agent/tracepoint_hook.rb +2 -2
- data/lib/contrast/agent/version.rb +2 -2
- data/lib/contrast/agent/worker_thread.rb +1 -1
- data/lib/contrast/api.rb +1 -1
- data/lib/contrast/api/communication.rb +1 -1
- data/lib/contrast/api/communication/connection_status.rb +1 -1
- data/lib/contrast/api/communication/messaging_queue.rb +19 -22
- data/lib/contrast/api/communication/response_processor.rb +13 -8
- data/lib/contrast/api/communication/service_lifecycle.rb +5 -3
- data/lib/contrast/api/communication/socket.rb +1 -1
- data/lib/contrast/api/communication/socket_client.rb +30 -35
- data/lib/contrast/api/communication/speedracer.rb +6 -10
- data/lib/contrast/api/communication/tcp_socket.rb +1 -1
- data/lib/contrast/api/communication/unix_socket.rb +1 -1
- data/lib/contrast/api/decorators.rb +3 -1
- data/lib/contrast/api/decorators/address.rb +1 -1
- data/lib/contrast/api/decorators/agent_startup.rb +58 -0
- data/lib/contrast/api/decorators/application_settings.rb +1 -1
- data/lib/contrast/api/decorators/application_startup.rb +57 -0
- data/lib/contrast/api/decorators/application_update.rb +1 -1
- data/lib/contrast/api/decorators/http_request.rb +1 -1
- data/lib/contrast/api/decorators/input_analysis.rb +1 -1
- data/lib/contrast/api/decorators/instrumentation_mode.rb +37 -0
- data/lib/contrast/api/decorators/library.rb +9 -7
- data/lib/contrast/api/decorators/library_usage_update.rb +1 -1
- data/lib/contrast/api/decorators/message.rb +4 -4
- data/lib/contrast/api/decorators/rasp_rule_sample.rb +1 -1
- data/lib/contrast/api/decorators/route_coverage.rb +16 -6
- data/lib/contrast/api/decorators/server_features.rb +1 -1
- data/lib/contrast/api/decorators/trace_event.rb +46 -16
- data/lib/contrast/api/decorators/trace_event_object.rb +2 -4
- data/lib/contrast/api/decorators/trace_event_signature.rb +1 -1
- data/lib/contrast/api/decorators/trace_taint_range.rb +1 -1
- data/lib/contrast/api/decorators/trace_taint_range_tags.rb +2 -7
- data/lib/contrast/api/decorators/user_input.rb +1 -1
- data/lib/contrast/components/agent.rb +16 -15
- data/lib/contrast/components/app_context.rb +11 -29
- data/lib/contrast/components/assess.rb +6 -11
- data/lib/contrast/components/config.rb +3 -2
- data/lib/contrast/components/contrast_service.rb +8 -9
- data/lib/contrast/components/heap_dump.rb +1 -1
- data/lib/contrast/components/interface.rb +4 -3
- data/lib/contrast/components/inventory.rb +1 -1
- data/lib/contrast/components/logger.rb +1 -1
- data/lib/contrast/components/protect.rb +11 -14
- data/lib/contrast/components/sampling.rb +55 -7
- data/lib/contrast/components/scope.rb +2 -1
- data/lib/contrast/components/settings.rb +29 -99
- data/lib/contrast/config.rb +1 -1
- data/lib/contrast/config/agent_configuration.rb +1 -1
- data/lib/contrast/config/application_configuration.rb +1 -1
- data/lib/contrast/config/assess_configuration.rb +1 -1
- data/lib/contrast/config/assess_rules_configuration.rb +2 -4
- data/lib/contrast/config/base_configuration.rb +5 -6
- data/lib/contrast/config/default_value.rb +1 -1
- data/lib/contrast/config/exception_configuration.rb +2 -6
- data/lib/contrast/config/heap_dump_configuration.rb +13 -7
- data/lib/contrast/config/inventory_configuration.rb +1 -1
- data/lib/contrast/config/logger_configuration.rb +2 -6
- data/lib/contrast/config/protect_configuration.rb +1 -1
- data/lib/contrast/config/protect_rule_configuration.rb +23 -1
- data/lib/contrast/config/protect_rules_configuration.rb +1 -1
- data/lib/contrast/config/root_configuration.rb +1 -1
- data/lib/contrast/config/ruby_configuration.rb +1 -1
- data/lib/contrast/config/sampling_configuration.rb +1 -1
- data/lib/contrast/config/server_configuration.rb +1 -1
- data/lib/contrast/config/service_configuration.rb +1 -1
- data/lib/contrast/configuration.rb +4 -15
- data/lib/contrast/delegators/input_analysis.rb +12 -0
- data/lib/contrast/extension/assess.rb +1 -1
- data/lib/contrast/extension/assess/array.rb +2 -7
- data/lib/contrast/extension/assess/erb.rb +2 -8
- data/lib/contrast/extension/assess/eval_trigger.rb +3 -11
- data/lib/contrast/extension/assess/exec_trigger.rb +4 -14
- data/lib/contrast/extension/assess/fiber.rb +3 -13
- data/lib/contrast/extension/assess/hash.rb +1 -1
- data/lib/contrast/extension/assess/kernel.rb +3 -10
- data/lib/contrast/extension/assess/marshal.rb +3 -11
- data/lib/contrast/extension/assess/regexp.rb +2 -7
- data/lib/contrast/extension/assess/string.rb +4 -2
- data/lib/contrast/extension/delegator.rb +1 -1
- data/lib/contrast/extension/inventory.rb +1 -1
- data/lib/contrast/extension/kernel.rb +5 -3
- data/lib/contrast/extension/module.rb +1 -1
- data/lib/contrast/extension/protect.rb +1 -1
- data/lib/contrast/extension/protect/kernel.rb +1 -1
- data/lib/contrast/extension/protect/psych.rb +1 -1
- data/lib/contrast/extension/thread.rb +1 -1
- data/lib/contrast/framework/base_support.rb +1 -1
- data/lib/contrast/framework/manager.rb +14 -17
- data/lib/contrast/framework/platform_version.rb +1 -1
- data/lib/contrast/framework/rack/patch/session_cookie.rb +6 -19
- data/lib/contrast/framework/rack/patch/support.rb +7 -5
- data/lib/contrast/framework/rack/support.rb +1 -1
- data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +1 -1
- data/lib/contrast/framework/rails/patch/assess_configuration.rb +8 -3
- data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +4 -4
- data/lib/contrast/framework/rails/patch/support.rb +5 -3
- data/lib/contrast/framework/rails/rewrite/action_controller_railties_helper_inherited.rb +5 -2
- data/lib/contrast/framework/rails/rewrite/active_record_attribute_methods_read.rb +3 -1
- data/lib/contrast/framework/rails/rewrite/active_record_named.rb +3 -1
- data/lib/contrast/framework/rails/rewrite/active_record_time_zone_inherited.rb +3 -1
- data/lib/contrast/framework/rails/support.rb +45 -46
- data/lib/contrast/framework/sinatra/support.rb +103 -42
- data/lib/contrast/funchook/funchook.rb +2 -6
- data/lib/contrast/logger/application.rb +13 -10
- data/lib/contrast/logger/format.rb +3 -6
- data/lib/contrast/logger/log.rb +36 -19
- data/lib/contrast/logger/request.rb +2 -3
- data/lib/contrast/logger/time.rb +1 -1
- data/lib/contrast/security_exception.rb +2 -2
- data/lib/contrast/tasks/config.rb +1 -1
- data/lib/contrast/tasks/service.rb +6 -2
- data/lib/contrast/utils/assess/sampling_util.rb +1 -1
- data/lib/contrast/utils/assess/tracking_util.rb +2 -3
- data/lib/contrast/utils/class_util.rb +18 -12
- data/lib/contrast/utils/duck_utils.rb +1 -1
- data/lib/contrast/utils/env_configuration_item.rb +1 -1
- data/lib/contrast/utils/hash_digest.rb +16 -24
- data/lib/contrast/utils/heap_dump_util.rb +104 -88
- data/lib/contrast/utils/invalid_configuration_util.rb +22 -13
- data/lib/contrast/utils/inventory_util.rb +1 -1
- data/lib/contrast/utils/io_util.rb +2 -2
- data/lib/contrast/utils/job_servers_running.rb +10 -5
- data/lib/contrast/utils/object_share.rb +1 -1
- data/lib/contrast/utils/os.rb +3 -2
- data/lib/contrast/utils/preflight_util.rb +1 -1
- data/lib/contrast/utils/resource_loader.rb +1 -1
- data/lib/contrast/utils/ruby_ast_rewriter.rb +3 -2
- data/lib/contrast/utils/sha256_builder.rb +1 -1
- data/lib/contrast/utils/stack_trace_utils.rb +1 -1
- data/lib/contrast/utils/string_utils.rb +1 -1
- data/lib/contrast/utils/tag_util.rb +1 -1
- data/lib/contrast/utils/thread_tracker.rb +1 -1
- data/lib/contrast/utils/timer.rb +1 -1
- data/resources/assess/policy.json +8 -11
- data/resources/deadzone/policy.json +7 -17
- data/ruby-agent.gemspec +66 -27
- data/service_executables/VERSION +1 -1
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- data/sonar-project.properties +9 -0
- metadata +154 -156
- data/lib/contrast/agent/assess/rule.rb +0 -18
- data/lib/contrast/agent/assess/rule/base.rb +0 -52
- data/lib/contrast/agent/assess/rule/redos.rb +0 -67
- data/lib/contrast/agent/inventory/gemfile_digest_cache.rb +0 -38
- data/lib/contrast/common_agent_configuration.rb +0 -87
- data/lib/contrast/framework/sinatra/patch/base.rb +0 -83
- data/lib/contrast/framework/sinatra/patch/support.rb +0 -27
- data/lib/contrast/utils/prevent_serialization.rb +0 -52
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
$TO_MAKE = File.basename(__dir__)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
$TO_MAKE = File.basename(__dir__)
|
data/ext/extconf_common.rb
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require 'mkmf'
|
|
5
5
|
require_relative '../lib/contrast/agent/version'
|
|
6
6
|
|
|
7
|
-
def name
|
|
8
|
-
$TO_MAKE
|
|
9
|
-
end
|
|
10
|
-
|
|
11
7
|
def make!
|
|
12
|
-
create_makefile "#{
|
|
8
|
+
create_makefile "#{ $TO_MAKE }/#{ $TO_MAKE }"
|
|
13
9
|
end
|
|
14
10
|
|
|
15
11
|
def ext_path
|
data/lib/contrast-agent.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
# We need this to make bundler happy since it's the name of the gem, unless we
|
data/lib/contrast.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
# Used to prevent deprecation warnings from flooding stdout
|
|
@@ -25,6 +25,19 @@ class Object
|
|
|
25
25
|
alias_method :cs__singleton_class, :singleton_class
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
if RUBY_VERSION >= '3.0.0'
|
|
29
|
+
# This fixes Ruby 3.0 issues with Module#(some instance method) patching by preventing the prepending of
|
|
30
|
+
# a JSON helper on protobuf load. String.instance_method(:+) is one of the most noticable.
|
|
31
|
+
# TODO: RUBY-1132 Remove this once Ruby 3 is fixed.
|
|
32
|
+
# See bug here: https://bugs.ruby-lang.org/issues/17725
|
|
33
|
+
class Class
|
|
34
|
+
alias_method(:cs__orig_prepend, :prepend)
|
|
35
|
+
def prepend other
|
|
36
|
+
include(other)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
28
41
|
# component interface for class creation
|
|
29
42
|
# config gets built as a consequence of this require
|
|
30
43
|
require 'contrast/components/interface'
|
|
@@ -47,3 +60,9 @@ require 'contrast/utils/preflight_util'
|
|
|
47
60
|
|
|
48
61
|
require 'contrast/utils/assess/sampling_util'
|
|
49
62
|
require 'contrast/agent'
|
|
63
|
+
|
|
64
|
+
if RUBY_VERSION >= '3.0.0'
|
|
65
|
+
# Put prepend back as it was.
|
|
66
|
+
Class.alias_method(:prepend, :cs__orig_prepend)
|
|
67
|
+
Class.remove_method(:cs__orig_prepend)
|
|
68
|
+
end
|
data/lib/contrast/agent.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require 'English'
|
|
@@ -27,8 +27,6 @@ require 'contrast/utils/string_utils'
|
|
|
27
27
|
require 'contrast/utils/io_util'
|
|
28
28
|
require 'contrast/utils/os'
|
|
29
29
|
|
|
30
|
-
require 'contrast/common_agent_configuration'
|
|
31
|
-
|
|
32
30
|
require 'contrast/utils/hash_digest'
|
|
33
31
|
require 'contrast/utils/invalid_configuration_util'
|
|
34
32
|
|
|
@@ -56,8 +54,12 @@ module Contrast
|
|
|
56
54
|
@_framework_manager ||= Contrast::Framework::Manager.new
|
|
57
55
|
end
|
|
58
56
|
|
|
57
|
+
def self.heapdump_util
|
|
58
|
+
thread_watcher.heapdump_util
|
|
59
|
+
end
|
|
60
|
+
|
|
59
61
|
def self.messaging_queue
|
|
60
|
-
|
|
62
|
+
thread_watcher.messaging_queue
|
|
61
63
|
end
|
|
62
64
|
|
|
63
65
|
def self.thread_watcher
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
module Contrast
|
|
@@ -10,21 +10,12 @@ module Contrast
|
|
|
10
10
|
module Assess
|
|
11
11
|
require 'contrast/agent/assess/tracker'
|
|
12
12
|
require 'contrast/agent/module_data'
|
|
13
|
-
require 'contrast/agent/rewriter'
|
|
13
|
+
require 'contrast/agent/rewriter' if RUBY_VERSION < '2.6.0' # TODO: RUBY-714 remove guard w/ EOL of 2.5
|
|
14
14
|
require 'contrast/agent/assess/policy/preshift'
|
|
15
15
|
|
|
16
|
-
require 'contrast/utils/prevent_serialization'
|
|
17
|
-
|
|
18
|
-
# Rules - generic
|
|
19
|
-
require 'contrast/agent/assess/rule'
|
|
20
|
-
require 'contrast/agent/assess/rule/base'
|
|
21
|
-
|
|
22
16
|
# Dynamic Sources
|
|
23
17
|
require 'contrast/agent/assess/policy/dynamic_source_factory'
|
|
24
18
|
|
|
25
|
-
# Rule: REDOS
|
|
26
|
-
require 'contrast/agent/assess/rule/redos'
|
|
27
|
-
|
|
28
19
|
# reporting / tracking
|
|
29
20
|
require 'contrast/agent/assess/properties'
|
|
30
21
|
require 'contrast/agent/assess/tag'
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require 'contrast/utils/assess/tracking_util'
|
|
5
5
|
require 'contrast/utils/class_util'
|
|
6
6
|
require 'contrast/utils/duck_utils'
|
|
7
7
|
require 'contrast/utils/object_share'
|
|
8
|
-
require 'contrast/utils/prevent_serialization'
|
|
9
8
|
require 'contrast/utils/stack_trace_utils'
|
|
10
9
|
require 'contrast/utils/string_utils'
|
|
11
10
|
require 'contrast/utils/timer'
|
|
@@ -15,38 +14,27 @@ require 'contrast/agent/assess/contrast_object'
|
|
|
15
14
|
module Contrast
|
|
16
15
|
module Agent
|
|
17
16
|
module Assess
|
|
18
|
-
# This class holds the data about an event in the application
|
|
19
|
-
#
|
|
20
|
-
# the object to which this event belongs ends in a trigger.
|
|
17
|
+
# This class holds the data about an event in the application We'll use it to build an event that TeamServer can
|
|
18
|
+
# consume if the object to which this event belongs ends in a trigger.
|
|
21
19
|
#
|
|
22
20
|
# @attr_reader event_id [Integer] the atomic id of this event
|
|
23
|
-
# @attr_reader policy_node [Contrast::Agent::Assess::Policy::PolicyNode]
|
|
24
|
-
#
|
|
25
|
-
# @attr_reader
|
|
26
|
-
#
|
|
27
|
-
# @attr_reader
|
|
28
|
-
#
|
|
29
|
-
# @attr_reader
|
|
30
|
-
#
|
|
31
|
-
# @attr_reader
|
|
32
|
-
#
|
|
33
|
-
# @attr_reader ret [Contrast::Agent::Assess::ContrastObject] the safe
|
|
34
|
-
# representation of the Return of the invoked method
|
|
35
|
-
# @attr_reader args [Array<Contrast::Agent::Assess::ContrastObject>] the
|
|
36
|
-
# safe representation of the Arguments with which the method was invoked
|
|
21
|
+
# @attr_reader policy_node [Contrast::Agent::Assess::Policy::PolicyNode] the node that governs this event.
|
|
22
|
+
# @attr_reader stack_trace [Array<String>] the execution stack at the time the method for this event was invoked
|
|
23
|
+
# @attr_reader time [Integer] the time, in epoch ms, when this event was created
|
|
24
|
+
# @attr_reader thread [Integer] the object id of the thread on which this event was generated
|
|
25
|
+
# @attr_reader object [Contrast::Agent::Assess::ContrastObject] the safe representation of the Object on which
|
|
26
|
+
# the method was invoked
|
|
27
|
+
# @attr_reader ret [Contrast::Agent::Assess::ContrastObject] the safe representation of the Return of the invoked
|
|
28
|
+
# method
|
|
29
|
+
# @attr_reader args [Array<Contrast::Agent::Assess::ContrastObject>] the safe representation of the Arguments
|
|
30
|
+
# with which the method was invoked
|
|
37
31
|
class ContrastEvent
|
|
38
|
-
include Contrast::Utils::PreventSerialization
|
|
39
32
|
include Contrast::Components::Interface
|
|
40
33
|
access_component :analysis
|
|
41
34
|
|
|
42
|
-
attr_reader :event_id, :policy_node, :stack_trace, :time, :thread,
|
|
43
|
-
:object,
|
|
44
|
-
:ret,
|
|
45
|
-
:args,
|
|
46
|
-
:tags
|
|
35
|
+
attr_reader :event_id, :policy_node, :stack_trace, :time, :thread, :object, :ret, :args, :tags
|
|
47
36
|
|
|
48
|
-
# We need this to track the parent id's of events to build up a flow
|
|
49
|
-
# chart of the finding
|
|
37
|
+
# We need this to track the parent id's of events to build up a flow chart of the finding
|
|
50
38
|
@atomic_id = 0
|
|
51
39
|
@atomic_mutex = Mutex.new
|
|
52
40
|
def self.next_atomic_id
|
|
@@ -58,26 +46,13 @@ module Contrast
|
|
|
58
46
|
end
|
|
59
47
|
end
|
|
60
48
|
|
|
61
|
-
# @param policy_node [Contrast::Agent::Assess::Policy::PolicyNode]
|
|
62
|
-
# the node that governs this event.
|
|
49
|
+
# @param policy_node [Contrast::Agent::Assess::Policy::PolicyNode] the node that governs this event.
|
|
63
50
|
# @param tagged [Object] the Target to which this event pertains.
|
|
64
51
|
# @param object [Object] the Object on which the method was invoked
|
|
65
52
|
# @param ret [Object] the Return of the invoked method
|
|
66
|
-
# @param args [Array<Object>] the Arguments with which the method
|
|
67
|
-
# was invoked
|
|
53
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
|
68
54
|
def initialize policy_node, tagged, object, ret, args
|
|
69
55
|
@policy_node = policy_node
|
|
70
|
-
|
|
71
|
-
# Capture stacktraces only as configured.
|
|
72
|
-
#
|
|
73
|
-
# So long as this event is built in a factory, we know Contrast Code
|
|
74
|
-
# will be the first three events
|
|
75
|
-
@stack_trace = if ASSESS.capture_stacktrace?(policy_node)
|
|
76
|
-
caller(3, 20)
|
|
77
|
-
else
|
|
78
|
-
Contrast::Utils::ObjectShare::EMPTY_ARRAY
|
|
79
|
-
end
|
|
80
|
-
|
|
81
56
|
@time = Contrast::Utils::Timer.now_ms
|
|
82
57
|
@thread = Thread.current.object_id
|
|
83
58
|
|
|
@@ -86,17 +61,17 @@ module Contrast
|
|
|
86
61
|
@tags = Contrast::Agent::Assess::Tracker.properties(tagged)&.tags
|
|
87
62
|
find_parent_events!(policy_node, object, ret, args)
|
|
88
63
|
snapshot!(object, ret, args)
|
|
64
|
+
capture_stacktrace!
|
|
89
65
|
end
|
|
90
66
|
|
|
91
67
|
def parent_events
|
|
92
68
|
@_parent_events ||= []
|
|
93
69
|
end
|
|
94
70
|
|
|
95
|
-
# We have to do a little work to figure out what our TS appropriate
|
|
96
|
-
#
|
|
97
|
-
# 1) If my policy_node has a target, work on targets. Else, work on sources.
|
|
98
|
-
#
|
|
99
|
-
# The only type of policy_node w/o targets is a Trigger, but that may
|
|
71
|
+
# We have to do a little work to figure out what our TS appropriate target is. To break this down, the logic is
|
|
72
|
+
# as follows:
|
|
73
|
+
# 1) If my policy_node has a target, work on targets. Else, work on sources. Per TS law, each policy_node must
|
|
74
|
+
# have at least a source or a target. The only type of policy_node w/o targets is a Trigger, but that may
|
|
100
75
|
# change.
|
|
101
76
|
# 2) I'll set the event's source and target to TS values.
|
|
102
77
|
# 3) Return the first source/target as the taint target.
|
|
@@ -119,21 +94,17 @@ module Contrast
|
|
|
119
94
|
|
|
120
95
|
private
|
|
121
96
|
|
|
122
|
-
# Parent events are the events of all the sources of this event which
|
|
123
|
-
#
|
|
124
|
-
# any of the sources were tracked, there may be more than one parent.
|
|
97
|
+
# Parent events are the events of all the sources of this event which were tracked prior to this event
|
|
98
|
+
# occurring. Depending on which, if any of the sources were tracked, there may be more than one parent.
|
|
125
99
|
#
|
|
126
|
-
# All events except for [Contrast::Agent::Assess::Events::SourceEvent]
|
|
127
|
-
# will have at least one parent.
|
|
100
|
+
# All events except for [Contrast::Agent::Assess::Events::SourceEvent] will have at least one parent.
|
|
128
101
|
#
|
|
129
102
|
# We set those events to this event's instance variables.
|
|
130
103
|
#
|
|
131
|
-
# @param policy_node [Contrast::Agent::Assess::Policy::PolicyNode]
|
|
132
|
-
# the node that governs this event.
|
|
104
|
+
# @param policy_node [Contrast::Agent::Assess::Policy::PolicyNode] the node that governs this event.
|
|
133
105
|
# @param object [Object] the Object on which the method was invoked
|
|
134
106
|
# @param ret [Object] the Return of the invoked method
|
|
135
|
-
# @param args [Array<Object>] the Arguments with which the method
|
|
136
|
-
# was invoked
|
|
107
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
|
137
108
|
def find_parent_events! policy_node, object, ret, args
|
|
138
109
|
policy_node.sources.each do |source_marker|
|
|
139
110
|
source = value_of_source(source_marker, object, ret, args)
|
|
@@ -147,10 +118,8 @@ module Contrast
|
|
|
147
118
|
# @param source [String] the marker for the source type
|
|
148
119
|
# @param object [Object] the Object on which the method was invoked
|
|
149
120
|
# @param ret [Object] the Return of the invoked method
|
|
150
|
-
# @param args [Array<Object>] the Arguments with which the method
|
|
151
|
-
#
|
|
152
|
-
# @return [Object,nil] the literal value of the source indicated by the
|
|
153
|
-
# given marker
|
|
121
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
|
122
|
+
# @return [Object,nil] the literal value of the source indicated by the given marker
|
|
154
123
|
def value_of_source source, object, ret, args
|
|
155
124
|
case source
|
|
156
125
|
when Contrast::Utils::ObjectShare::OBJECT_KEY
|
|
@@ -162,16 +131,13 @@ module Contrast
|
|
|
162
131
|
end
|
|
163
132
|
end
|
|
164
133
|
|
|
165
|
-
# Everything* is mutable in Ruby. As such, to ensure we can accurately
|
|
166
|
-
#
|
|
167
|
-
#
|
|
168
|
-
# them for our later use. We set those safe values to this event's
|
|
169
|
-
# instance variables.
|
|
134
|
+
# Everything* is mutable in Ruby. As such, to ensure we can accurately report the application state at the time
|
|
135
|
+
# of this method's invocation, we have to snapshot the given values, making safe representations of them for
|
|
136
|
+
# our later use. We set those safe values to this event's instance variables.
|
|
170
137
|
#
|
|
171
138
|
# @param object [Object] the Object on which the method was invoked
|
|
172
139
|
# @param ret [Object] the Return of the invoked method
|
|
173
|
-
# @param args [Array<Object>] the Arguments with which the method
|
|
174
|
-
# was invoked
|
|
140
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
|
175
141
|
def snapshot! object, ret, args
|
|
176
142
|
@object = Contrast::Agent::Assess::ContrastObject.new(object) if object
|
|
177
143
|
@ret = Contrast::Agent::Assess::ContrastObject.new(ret) if ret
|
|
@@ -179,18 +145,35 @@ module Contrast
|
|
|
179
145
|
self
|
|
180
146
|
end
|
|
181
147
|
|
|
182
|
-
# Given an array of arguments, copy them into a safe, meaning String,
|
|
183
|
-
#
|
|
148
|
+
# Given an array of arguments, copy them into a safe, meaning String, format that we can use to send to SR and
|
|
149
|
+
# TS for rendering.
|
|
184
150
|
#
|
|
185
151
|
# @param args [Array<Object>] the arguments to translate
|
|
186
|
-
# @return [Array<Contrast::Agent::Assess::ContrastObject>] the String forms of those Objects, as
|
|
187
|
-
#
|
|
152
|
+
# @return [Array<Contrast::Agent::Assess::ContrastObject>] the String forms of those Objects, as determined by
|
|
153
|
+
# Contrast::Utils::ClassUtil.to_contrast_string
|
|
188
154
|
def safe_args_representation args
|
|
189
155
|
return unless args
|
|
190
156
|
return Contrast::Utils::ObjectShare::EMPTY_ARRAY if args.empty?
|
|
191
157
|
|
|
192
158
|
args.map { |arg| arg ? Contrast::Agent::Assess::ContrastObject.new(arg) : nil }
|
|
193
159
|
end
|
|
160
|
+
|
|
161
|
+
# Capture stack traces only as configured. We'll use this to grab the start of the call stack as if the
|
|
162
|
+
# instrumented method were the caller. This means we'll start at the entry just after the first block of
|
|
163
|
+
# Contrast code.
|
|
164
|
+
def capture_stacktrace!
|
|
165
|
+
# If we're configured to not capture the stacktrace, usually for performance reasons, then don't and return an
|
|
166
|
+
# empty array instead
|
|
167
|
+
unless ASSESS.capture_stacktrace?(policy_node)
|
|
168
|
+
@stack_trace = Contrast::Utils::ObjectShare::EMPTY_ARRAY
|
|
169
|
+
return
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Otherwise, find where in the stack the application / Ruby code starts
|
|
173
|
+
start = caller(0, 20)&.find_index { |stack| !stack.include?('/lib/contrast') }
|
|
174
|
+
# And then use that to build out the reported stacktrace, or a fallback if we couldn't find it.
|
|
175
|
+
@stack_trace = start ? caller(start + 1, 20) : caller(20, 20)
|
|
176
|
+
end
|
|
194
177
|
end
|
|
195
178
|
end
|
|
196
179
|
end
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require 'contrast/utils/class_util'
|
|
5
|
+
require 'contrast/utils/object_share'
|
|
6
|
+
require 'contrast/agent/assess/tracker'
|
|
5
7
|
|
|
6
8
|
module Contrast
|
|
7
9
|
module Agent
|
|
@@ -28,17 +30,18 @@ module Contrast
|
|
|
28
30
|
# Capture the details about the object which we need to render it in
|
|
29
31
|
# TeamServer.
|
|
30
32
|
#
|
|
31
|
-
# @param object [Object] the thing to keep a Contrast String of
|
|
33
|
+
# @param object [Object, nil] the thing to keep a Contrast String of
|
|
32
34
|
def initialize object
|
|
33
35
|
if object
|
|
34
36
|
@object = Contrast::Utils::ClassUtil.to_contrast_string(object)
|
|
35
|
-
@object_type = object.cs__class.
|
|
37
|
+
@object_type = object.cs__class.cs__name
|
|
36
38
|
# TODO: RUBY-1084 determine if we need to copy these tags to
|
|
37
39
|
# restore immutability. For instance, if these tags were on a
|
|
38
40
|
# String that was then #reverse!'d, would our tags be wrong?
|
|
39
41
|
@tags = Contrast::Agent::Assess::Tracker.properties(object)&.tags
|
|
40
42
|
else
|
|
41
|
-
@
|
|
43
|
+
@object = Contrast::Utils::ObjectShare::NIL_STRING
|
|
44
|
+
@object_type = nil.cs__class.cs__name
|
|
42
45
|
end
|
|
43
46
|
end
|
|
44
47
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require 'contrast/agent/assess/contrast_event'
|
|
@@ -13,7 +13,8 @@ module Contrast
|
|
|
13
13
|
def self.build policy_node, tagged, object, ret, args, source_type = nil, source_name = nil
|
|
14
14
|
case policy_node
|
|
15
15
|
when Contrast::Agent::Assess::Policy::SourceNode
|
|
16
|
-
Contrast::Agent::Assess::Events::SourceEvent.new(policy_node, tagged, object, ret, args, source_type,
|
|
16
|
+
Contrast::Agent::Assess::Events::SourceEvent.new(policy_node, tagged, object, ret, args, source_type,
|
|
17
|
+
source_name)
|
|
17
18
|
when Contrast::Agent::Assess::Policy::PolicyNode
|
|
18
19
|
Contrast::Agent::Assess::ContrastEvent.new(policy_node, tagged, object, ret, args)
|
|
19
20
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require 'contrast/agent/assess/contrast_event'
|
|
@@ -11,8 +11,13 @@ module Contrast
|
|
|
11
11
|
# This class holds the data about an event in the application
|
|
12
12
|
# We'll use it to build an event that TeamServer can consume if
|
|
13
13
|
# the object to which this event belongs ends in a trigger.
|
|
14
|
+
#
|
|
15
|
+
# @attr_reader request [Contrast::Agent::Request] our wrapper around the Rack::Request at the time this source
|
|
16
|
+
# was created
|
|
17
|
+
# @attr_reader source_name [String] the name of the source if it comes from a map-like entity
|
|
18
|
+
# @attr_reader source_type [String] the TeamServer understood type of source; i.e. parameter
|
|
14
19
|
class SourceEvent < Contrast::Agent::Assess::ContrastEvent
|
|
15
|
-
attr_reader :
|
|
20
|
+
attr_reader :request, :source_name, :source_type
|
|
16
21
|
|
|
17
22
|
def initialize policy_node, tagged, object, ret, args, source_type = nil, source_name = nil
|
|
18
23
|
super(policy_node, tagged, object, ret, args)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require 'contrast/agent/assess/tracker'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require 'contrast/utils/duck_utils'
|
|
@@ -7,20 +7,22 @@ module Contrast
|
|
|
7
7
|
module Agent
|
|
8
8
|
module Assess
|
|
9
9
|
module Finalizers
|
|
10
|
-
# An extension of Hash that doesn't impact GC of the object being
|
|
11
|
-
#
|
|
12
|
-
# finalizer on the object to remove its entry from the Hash immediately
|
|
13
|
-
# after it's GC'd.
|
|
10
|
+
# An extension of Hash that doesn't impact GC of the object being stored by storing its ID as a Key to lookup
|
|
11
|
+
# and registering a finalizer on the object to remove its entry from the Hash immediately after it's GC'd.
|
|
14
12
|
class Hash < Hash
|
|
13
|
+
include Contrast::Components::Interface
|
|
14
|
+
access_component :agent, :analysis
|
|
15
|
+
|
|
15
16
|
FROZEN_FINALIZED_IDS = Set.new
|
|
16
17
|
|
|
17
18
|
def []= key, obj
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
return unless AGENT.enabled? && ASSESS.enabled?
|
|
20
|
+
|
|
21
|
+
# We can't finalize frozen things, so only act on those that went through .pre_freeze
|
|
20
22
|
if key.cs__frozen?
|
|
21
23
|
return unless FROZEN_FINALIZED_IDS.include?(key.__id__)
|
|
22
24
|
else
|
|
23
|
-
ObjectSpace.define_finalizer(key,
|
|
25
|
+
ObjectSpace.define_finalizer(key, finalizing_proc)
|
|
24
26
|
end
|
|
25
27
|
super key.__id__, obj
|
|
26
28
|
end
|
|
@@ -29,62 +31,59 @@ module Contrast
|
|
|
29
31
|
super key.__id__
|
|
30
32
|
end
|
|
31
33
|
|
|
32
|
-
# Something is trackable if it is not a collection and either not
|
|
33
|
-
#
|
|
34
|
+
# Something is trackable if it is not a collection and either not frozen or it was frozen after we put a
|
|
35
|
+
# finalizer on it.
|
|
34
36
|
#
|
|
35
37
|
# @param key [Object] the thing to determine if trackable
|
|
36
38
|
# @return [Boolean]
|
|
37
39
|
def trackable? key
|
|
40
|
+
return false unless key
|
|
38
41
|
# Track things in these, not them themselves.
|
|
39
42
|
return false if Contrast::Utils::DuckUtils.iterable_hash?(key)
|
|
40
43
|
return false if Contrast::Utils::DuckUtils.iterable_enumerable?(key)
|
|
41
44
|
# If it's not frozen, we can finalize/ track it.
|
|
42
45
|
return true unless key.cs__frozen?
|
|
43
46
|
|
|
44
|
-
# Otherwise, we can only track it if we've finalized it in our
|
|
45
|
-
# freeze patch.
|
|
47
|
+
# Otherwise, we can only track it if we've finalized it in our freeze patch.
|
|
46
48
|
FROZEN_FINALIZED_IDS.include?(key.__id__)
|
|
47
49
|
end
|
|
48
50
|
|
|
49
|
-
# Determine if the given Object is tracked, meaning it has a known
|
|
50
|
-
#
|
|
51
|
+
# Determine if the given Object is tracked, meaning it has a known set of properties and those properties are
|
|
52
|
+
# tracked.
|
|
51
53
|
#
|
|
52
|
-
# @param key [Object] the Object whose properties, by id, we want to
|
|
53
|
-
# check for tracked status
|
|
54
|
+
# @param key [Object] the Object whose properties, by id, we want to check for tracked status
|
|
54
55
|
# @return [Boolean]
|
|
55
56
|
def tracked? key
|
|
56
57
|
key?(key.__id__) && fetch(key.__id__, nil)&.tracked?
|
|
57
58
|
end
|
|
58
59
|
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
# purpose of this.
|
|
60
|
+
# Create a Proc to remove the given key from our frozen and properties tracking during finalization of the
|
|
61
|
+
# Object to which the given key_id pertains. The ObjectSpace's finalizer mechanism will handle passing this
|
|
62
|
+
# ID in, so we only need to define the Proc once.
|
|
63
|
+
#
|
|
64
|
+
# NOTE: by necessity, this is the only method which takes the __id__, not the Object itself. You CANNOT pass
|
|
65
|
+
# the Object to this as a finalizer cannot hold reference to the Object being finalized; that prevents GC,
|
|
66
|
+
# which introduces a memory leak and defeats the entire purpose of this.
|
|
66
67
|
#
|
|
67
|
-
# @
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
proc do
|
|
68
|
+
# @return [Proc] the Proc to remove references to the ID of the GC'd object from our Hash
|
|
69
|
+
def finalizing_proc
|
|
70
|
+
@_finalizing_proc ||= proc do |key_id|
|
|
71
71
|
FROZEN_FINALIZED_IDS.delete(key_id)
|
|
72
72
|
delete(key_id)
|
|
73
73
|
end
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
-
# Frozen things cannot be finalized. To avoid any issue here, we
|
|
77
|
-
#
|
|
78
|
-
#
|
|
79
|
-
# our tracking.
|
|
76
|
+
# Frozen things cannot be finalized. To avoid any issue here, we intercept the #freeze call and set
|
|
77
|
+
# finalizers on the Object. To ensure later we know it's been pre-finalized, we add it's __id__ to our
|
|
78
|
+
# tracking.
|
|
80
79
|
#
|
|
81
|
-
# @param key [Object] the Object on which we need to pre-define
|
|
82
|
-
# finalizers
|
|
80
|
+
# @param key [Object] the Object on which we need to pre-define finalizers
|
|
83
81
|
def pre_freeze key
|
|
82
|
+
return unless AGENT.enabled? && ASSESS.enabled?
|
|
84
83
|
return if key.cs__frozen?
|
|
85
84
|
return if FROZEN_FINALIZED_IDS.include?(key.__id__)
|
|
86
85
|
|
|
87
|
-
ObjectSpace.define_finalizer(key,
|
|
86
|
+
ObjectSpace.define_finalizer(key, finalizing_proc)
|
|
88
87
|
|
|
89
88
|
FROZEN_FINALIZED_IDS << key.__id__
|
|
90
89
|
rescue StandardError => _e
|