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
|
module Contrast
|
|
@@ -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/policy/source_method'
|
|
@@ -8,11 +8,13 @@ module Contrast
|
|
|
8
8
|
module Assess
|
|
9
9
|
module Policy
|
|
10
10
|
module SourceValidation
|
|
11
|
-
# Validator used to assert a CROSS_SITE tag is actually applicable to
|
|
12
|
-
#
|
|
11
|
+
# Validator used to assert a CROSS_SITE tag is actually applicable to the given method before applying the
|
|
12
|
+
# tag to its target
|
|
13
13
|
module CrossSiteValidator
|
|
14
|
-
#
|
|
15
|
-
#
|
|
14
|
+
# Prevent the application of a tag if it is from a source known to not apply a tag in a provided context.
|
|
15
|
+
# Note that for Rack, the Header will be HTTP_REFERER. Rails does some help in
|
|
16
|
+
# ActionDispatch::Http::Headers to convert keys like `referer` to `HTTP_REFERER` before they get to the
|
|
17
|
+
# Rack::Request#get_header method
|
|
16
18
|
# https://bitbucket.org/contrastsecurity/assess-specifications/src/master/rules/dataflow/reflected_xss.md
|
|
17
19
|
def self.valid? tag, source_type, source_name
|
|
18
20
|
return true unless tag == 'CROSS_SITE'
|
|
@@ -20,7 +22,7 @@ module Contrast
|
|
|
20
22
|
return true unless source_type == Contrast::Agent::Assess::Policy::SourceMethod::HEADER_TYPE
|
|
21
23
|
return false unless source_name
|
|
22
24
|
|
|
23
|
-
source_name
|
|
25
|
+
source_name == 'HTTP_REFERER'
|
|
24
26
|
end
|
|
25
27
|
end
|
|
26
28
|
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/policy/source_validation/cross_site_validator'
|
|
@@ -11,9 +11,7 @@ module Contrast
|
|
|
11
11
|
# certain tags in a given context. This provides a single place from
|
|
12
12
|
# which those validations can be called.
|
|
13
13
|
module SourceValidation
|
|
14
|
-
VALIDATORS = [
|
|
15
|
-
Contrast::Agent::Assess::Policy::SourceValidation::CrossSiteValidator
|
|
16
|
-
].cs__freeze
|
|
14
|
+
VALIDATORS = [Contrast::Agent::Assess::Policy::SourceValidation::CrossSiteValidator].cs__freeze
|
|
17
15
|
|
|
18
16
|
# Determines if the conditions in which this source was called are
|
|
19
17
|
# valid and should result in the application of a tag
|
|
@@ -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
|
|
@@ -24,7 +24,7 @@ module Contrast
|
|
|
24
24
|
}.cs__freeze
|
|
25
25
|
TEMPLATE_PROPAGATION_NODE = Contrast::Agent::Assess::Policy::PropagationNode.new(NODE_HASH)
|
|
26
26
|
|
|
27
|
-
def xss_tilt_trigger
|
|
27
|
+
def xss_tilt_trigger trigger_node, _source, object, ret, *args
|
|
28
28
|
return unless (properties = Contrast::Agent::Assess::Tracker.properties!(ret))
|
|
29
29
|
|
|
30
30
|
scope = args[0]
|
|
@@ -44,7 +44,11 @@ module Contrast
|
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
if Contrast::Agent::Assess::Tracker.tracked?(ret)
|
|
47
|
-
Contrast::Agent::Assess::Policy::TriggerMethod.build_finding(
|
|
47
|
+
Contrast::Agent::Assess::Policy::TriggerMethod.build_finding(trigger_node,
|
|
48
|
+
ret,
|
|
49
|
+
erb_template_prerender,
|
|
50
|
+
ret,
|
|
51
|
+
interpolated_inputs)
|
|
48
52
|
end
|
|
49
53
|
|
|
50
54
|
ret
|
|
@@ -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/components/interface'
|
|
@@ -19,31 +19,30 @@ module Contrast
|
|
|
19
19
|
include Contrast::Components::Interface
|
|
20
20
|
|
|
21
21
|
class << self
|
|
22
|
-
def xpath_expression_trigger
|
|
22
|
+
def xpath_expression_trigger trigger_node, _source, object, ret, *args
|
|
23
23
|
return ret unless args
|
|
24
24
|
|
|
25
|
-
process(
|
|
25
|
+
process(trigger_node, object, ret, *args)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
def xpath_oga_trigger
|
|
28
|
+
def xpath_oga_trigger trigger_node, _source, object, ret, *args
|
|
29
29
|
return ret unless args
|
|
30
30
|
|
|
31
31
|
# convert the options arg in Oga::XML::CharacterNode#initialize into an
|
|
32
32
|
# array of its values so we can check if any are unsafe
|
|
33
33
|
args = args.first.values if args.first.cs__is_a?(Hash)
|
|
34
|
-
process(
|
|
34
|
+
process(trigger_node, object, ret, *args)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
private
|
|
38
38
|
|
|
39
|
-
def process
|
|
39
|
+
def process trigger_node, object, ret, *args
|
|
40
40
|
args.each do |arg|
|
|
41
41
|
next unless arg.cs__is_a?(String) || arg.cs__is_a?(Symbol)
|
|
42
42
|
next unless Contrast::Agent::Assess::Tracker.tracked?(arg)
|
|
43
43
|
next unless trigger_node.violated?(arg)
|
|
44
44
|
|
|
45
|
-
Contrast::Agent::Assess::Policy::TriggerMethod.build_finding(
|
|
46
|
-
context, trigger_node, arg, object, ret, *args)
|
|
45
|
+
Contrast::Agent::Assess::Policy::TriggerMethod.build_finding(trigger_node, arg, object, ret, *args)
|
|
47
46
|
end
|
|
48
47
|
|
|
49
48
|
ret
|
|
@@ -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/events/event_factory'
|
|
@@ -27,24 +27,6 @@ module Contrast
|
|
|
27
27
|
CURRENT_FINDING_VERSION = 4
|
|
28
28
|
|
|
29
29
|
class << self
|
|
30
|
-
# Append the given finding to the given context to be reported when
|
|
31
|
-
# the Context's activity is sent to the Service or, in the absence
|
|
32
|
-
# of that Context, generate an Activity and queue it manually
|
|
33
|
-
# @param finding [Contrast::Api::Dtm::Finding]
|
|
34
|
-
def report_finding finding
|
|
35
|
-
context = Contrast::Agent::REQUEST_TRACKER.current
|
|
36
|
-
if context
|
|
37
|
-
context.activity.findings << finding
|
|
38
|
-
else
|
|
39
|
-
activity = Contrast::Api::Dtm::Activity.new
|
|
40
|
-
activity.findings << finding
|
|
41
|
-
|
|
42
|
-
Contrast::Agent.messaging_queue.send_event_eventually(activity)
|
|
43
|
-
end
|
|
44
|
-
logger.debug('Finding reported',
|
|
45
|
-
rule: finding.rule_id)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
30
|
# This is called from within our woven proc. It will be called as if it
|
|
49
31
|
# were inline in the Rack application.
|
|
50
32
|
#
|
|
@@ -57,38 +39,23 @@ module Contrast
|
|
|
57
39
|
def apply_trigger_rule trigger_node, object, ret, args
|
|
58
40
|
return if trigger_node.nil?
|
|
59
41
|
|
|
60
|
-
current_context = Contrast::Agent::REQUEST_TRACKER.current
|
|
61
|
-
return unless current_context&.analyze_request? && ASSESS.enabled?
|
|
62
|
-
|
|
63
42
|
if trigger_node.sources&.any?
|
|
64
43
|
trigger_node.sources.each do |marker|
|
|
65
44
|
source = determine_source(marker, object, ret, args)
|
|
66
|
-
apply_trigger(
|
|
67
|
-
trigger_node,
|
|
68
|
-
source,
|
|
69
|
-
object,
|
|
70
|
-
ret,
|
|
71
|
-
*args)
|
|
45
|
+
apply_trigger(trigger_node, source, object, ret, *args)
|
|
72
46
|
end
|
|
73
47
|
else
|
|
74
|
-
apply_trigger(
|
|
75
|
-
trigger_node,
|
|
76
|
-
nil,
|
|
77
|
-
object,
|
|
78
|
-
ret,
|
|
79
|
-
*args)
|
|
48
|
+
apply_trigger(trigger_node, nil, object, ret, *args)
|
|
80
49
|
end
|
|
81
50
|
end
|
|
82
51
|
|
|
83
|
-
def apply_eval_trigger
|
|
84
|
-
apply_trigger(
|
|
52
|
+
def apply_eval_trigger trigger_node, source, object, ret, *args
|
|
53
|
+
apply_trigger(trigger_node, source, object, ret, *args)
|
|
85
54
|
end
|
|
86
55
|
|
|
87
56
|
# This converts the source of the finding, and the events leading
|
|
88
57
|
# up to it into a Finding
|
|
89
58
|
#
|
|
90
|
-
# @param context [Contrast::Agent::RequestContext] the current
|
|
91
|
-
# request context
|
|
92
59
|
# @param trigger_node [Contrast::Agent::Assess::Policy::TriggerNode]
|
|
93
60
|
# the node to direct applying this trigger event
|
|
94
61
|
# @param source [Object] the source of the Trigger Event
|
|
@@ -99,39 +66,94 @@ module Contrast
|
|
|
99
66
|
# @return [Contrast::Api::Dtm::Finding, nil] the
|
|
100
67
|
# Contrast::Api::Dtm::Finding to send to TeamServer or nil if
|
|
101
68
|
# conditions were not met
|
|
102
|
-
def build_finding
|
|
69
|
+
def build_finding trigger_node, source, object, ret, *args
|
|
103
70
|
return unless Contrast::Agent::Assess::Policy::TriggerValidation.valid?(trigger_node, object, ret, args)
|
|
104
71
|
|
|
105
|
-
request =
|
|
106
|
-
|
|
107
|
-
return if defined?(ActionController::Live) &&
|
|
108
|
-
env &&
|
|
109
|
-
env['action_controller.instance'].cs__class.included_modules.include?(ActionController::Live)
|
|
72
|
+
request = find_request(source)
|
|
73
|
+
return unless reportable?(request&.env)
|
|
110
74
|
|
|
111
75
|
finding = Contrast::Api::Dtm::Finding.new
|
|
112
76
|
finding.rule_id = Contrast::Utils::StringUtils.protobuf_safe_string(trigger_node.rule_id)
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
finding
|
|
116
|
-
|
|
117
|
-
finding.routes << context.route if context.route
|
|
77
|
+
|
|
78
|
+
append_events(finding, trigger_node, source, object, ret, args)
|
|
79
|
+
append_route(finding, request)
|
|
80
|
+
append_hash(finding, source, request)
|
|
118
81
|
finding.version = determine_compliance_version(finding)
|
|
119
|
-
logger.trace('Finding created',
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
rule: trigger_node.rule_id)
|
|
123
|
-
report_finding(finding)
|
|
82
|
+
logger.trace('Finding created', node_id: trigger_node.id, source_id: source.__id__,
|
|
83
|
+
rule: trigger_node.rule_id)
|
|
84
|
+
report_finding(finding, request)
|
|
124
85
|
rescue StandardError => e
|
|
125
86
|
logger.error('Unable to build a finding', e, rule: trigger_node.rule_id, node_id: trigger_node.id)
|
|
126
87
|
end
|
|
127
88
|
|
|
89
|
+
# Given a finding, append it to an activity message and send it to
|
|
90
|
+
# the Service for processing.
|
|
91
|
+
#
|
|
92
|
+
# @param finding [Contrast::Api::Dtm::Finding] the Finding to
|
|
93
|
+
# report.
|
|
94
|
+
# @param request [Contrast::Agent::Request] our wrapper around the
|
|
95
|
+
# Rack::Request.
|
|
96
|
+
def report_finding finding, request = nil
|
|
97
|
+
context = Contrast::Agent::REQUEST_TRACKER.current
|
|
98
|
+
if context
|
|
99
|
+
context.activity.findings << finding
|
|
100
|
+
return
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
activity = Contrast::Api::Dtm::Activity.new
|
|
104
|
+
activity.findings << finding
|
|
105
|
+
if request
|
|
106
|
+
activity.http_request = request.dtm
|
|
107
|
+
else
|
|
108
|
+
logger.debug('Attempted to report finding without request', finding: finding)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# If we're out of request context, then we need to report this
|
|
112
|
+
# finding ourselves, so we'll send it in the one-off activity we
|
|
113
|
+
# created.
|
|
114
|
+
Contrast::Agent.messaging_queue.send_event_eventually(activity)
|
|
115
|
+
end
|
|
116
|
+
|
|
128
117
|
private
|
|
129
118
|
|
|
119
|
+
# A request is reportable if it is not from ActionController::Live
|
|
120
|
+
#
|
|
121
|
+
# @param env [Hash] the env of the Request
|
|
122
|
+
# @return [Boolean]
|
|
123
|
+
def reportable? env
|
|
124
|
+
!(defined?(ActionController::Live) &&
|
|
125
|
+
env &&
|
|
126
|
+
env['action_controller.instance'].cs__class.included_modules.include?(ActionController::Live))
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Find the request for this finding. This assumes, for now, that if
|
|
130
|
+
# there is an active request, then that is the request to report.
|
|
131
|
+
# Otherwise, we'll use the first request found in the events of the
|
|
132
|
+
# source_object.
|
|
133
|
+
#
|
|
134
|
+
# @param source [Object,nil] some Object used as the source of a
|
|
135
|
+
# trigger event
|
|
136
|
+
# @return [Contrast::Agent::Request,nil] the request from which the
|
|
137
|
+
# dataflow on the request originated.
|
|
138
|
+
def find_request source
|
|
139
|
+
return Contrast::Agent::REQUEST_TRACKER.current.request if Contrast::Agent::REQUEST_TRACKER.current
|
|
140
|
+
return unless (properties = Contrast::Agent::Assess::Tracker.properties(source))
|
|
141
|
+
|
|
142
|
+
properties.events.each do |event|
|
|
143
|
+
next unless event.cs__is_a?(Contrast::Agent::Assess::Events::SourceEvent)
|
|
144
|
+
|
|
145
|
+
return event.request if event.request
|
|
146
|
+
end
|
|
147
|
+
nil
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def settings
|
|
151
|
+
Contrast::Agent::FeatureState.instance
|
|
152
|
+
end
|
|
153
|
+
|
|
130
154
|
# This is our method that actually checks the taint on the object
|
|
131
155
|
# our trigger_node targets.
|
|
132
156
|
#
|
|
133
|
-
# @param context [Contrast::Agent::RequestContext] the current
|
|
134
|
-
# request context
|
|
135
157
|
# @param trigger_node [Contrast::Agent::Assess::Policy::TriggerNode]
|
|
136
158
|
# the node to direct applying this trigger event
|
|
137
159
|
# @param source [Object] the source of the Trigger Event
|
|
@@ -139,19 +161,19 @@ module Contrast
|
|
|
139
161
|
# @param ret [Object] the Return of the invoked method
|
|
140
162
|
# @param args [Array<Object>] the Arguments with which the method
|
|
141
163
|
# was invoked
|
|
142
|
-
def apply_trigger
|
|
143
|
-
return unless
|
|
164
|
+
def apply_trigger trigger_node, source, object, ret, *args
|
|
165
|
+
return unless trigger_node
|
|
144
166
|
return if trigger_node.rule_disabled?
|
|
145
167
|
return if trigger_node.dataflow? && source.nil?
|
|
146
168
|
|
|
147
169
|
if trigger_node.regexp_rule?
|
|
148
|
-
apply_regexp_rule(
|
|
170
|
+
apply_regexp_rule(trigger_node, source, object, ret, *args)
|
|
149
171
|
elsif trigger_node.custom_trigger?
|
|
150
|
-
trigger_node.apply_custom_trigger(
|
|
172
|
+
trigger_node.apply_custom_trigger(trigger_node, source, object, ret, *args)
|
|
151
173
|
elsif trigger_node.dataflow?
|
|
152
|
-
apply_dataflow_rule(
|
|
174
|
+
apply_dataflow_rule(trigger_node, source, object, ret, *args)
|
|
153
175
|
else # trigger rule - just calling the method is dangerous
|
|
154
|
-
build_finding(
|
|
176
|
+
build_finding(trigger_node, source, object, ret, *args)
|
|
155
177
|
end
|
|
156
178
|
rescue StandardError => e
|
|
157
179
|
logger.warn('Unable to apply trigger', e, node_id: trigger_node.id)
|
|
@@ -199,8 +221,6 @@ module Contrast
|
|
|
199
221
|
# This is our method that actually checks the taint on the object
|
|
200
222
|
# our trigger_node targets for our Regexp based rules.
|
|
201
223
|
#
|
|
202
|
-
# @param context [Contrast::Agent::RequestContext] the current
|
|
203
|
-
# request context
|
|
204
224
|
# @param trigger_node [Contrast::Agent::Assess::Policy::TriggerNode]
|
|
205
225
|
# the node to direct applying this trigger event
|
|
206
226
|
# @param source [Object] the source of the Trigger Event
|
|
@@ -208,19 +228,17 @@ module Contrast
|
|
|
208
228
|
# @param ret [Object] the Return of the invoked method
|
|
209
229
|
# @param args [Array<Object>] the Arguments with which the method
|
|
210
230
|
# was invoked
|
|
211
|
-
def apply_regexp_rule
|
|
231
|
+
def apply_regexp_rule trigger_node, source, object, ret, *args
|
|
212
232
|
return unless source.is_a?(String)
|
|
213
233
|
return if trigger_node.good_value && source.match?(trigger_node.good_value)
|
|
214
234
|
return if trigger_node.bad_value && source !~ trigger_node.bad_value
|
|
215
235
|
|
|
216
|
-
build_finding(
|
|
236
|
+
build_finding(trigger_node, source, object, ret, *args)
|
|
217
237
|
end
|
|
218
238
|
|
|
219
239
|
# This is our method that actually checks the taint on the object
|
|
220
240
|
# our trigger_node targets for our Dataflow based rules.
|
|
221
241
|
#
|
|
222
|
-
# @param context [Contrast::Agent::RequestContext] the current
|
|
223
|
-
# request context
|
|
224
242
|
# @param trigger_node [Contrast::Agent::Assess::Policy::TriggerNode]
|
|
225
243
|
# the node to direct applying this trigger event
|
|
226
244
|
# @param source [Object] the source of the Trigger Event
|
|
@@ -228,22 +246,22 @@ module Contrast
|
|
|
228
246
|
# @param ret [Object] the Return of the invoked method
|
|
229
247
|
# @param args [Array<Object>] the Arguments with which the method
|
|
230
248
|
# was invoked
|
|
231
|
-
def apply_dataflow_rule
|
|
249
|
+
def apply_dataflow_rule trigger_node, source, object, ret, *args
|
|
232
250
|
return unless source
|
|
233
251
|
|
|
234
252
|
if Contrast::Agent::Assess::Tracker.trackable?(source)
|
|
235
253
|
return unless Contrast::Agent::Assess::Tracker.tracked?(source)
|
|
236
254
|
return unless trigger_node.violated?(source)
|
|
237
255
|
|
|
238
|
-
build_finding(
|
|
256
|
+
build_finding(trigger_node, source, object, ret, *args)
|
|
239
257
|
elsif Contrast::Utils::DuckUtils.iterable_hash?(source)
|
|
240
258
|
source.each_pair do |key, value|
|
|
241
|
-
apply_dataflow_rule(
|
|
242
|
-
apply_dataflow_rule(
|
|
259
|
+
apply_dataflow_rule(trigger_node, key, object, ret, *args)
|
|
260
|
+
apply_dataflow_rule(trigger_node, value, object, ret, *args)
|
|
243
261
|
end
|
|
244
262
|
elsif Contrast::Utils::DuckUtils.iterable_enumerable?(source)
|
|
245
263
|
source.each do |value|
|
|
246
|
-
apply_dataflow_rule(
|
|
264
|
+
apply_dataflow_rule(trigger_node, value, object, ret, *args)
|
|
247
265
|
end
|
|
248
266
|
else
|
|
249
267
|
logger.debug('Trigger source is untrackable. Unable to inspect.',
|
|
@@ -255,7 +273,13 @@ module Contrast
|
|
|
255
273
|
end
|
|
256
274
|
end
|
|
257
275
|
|
|
258
|
-
def
|
|
276
|
+
def append_events finding, trigger_node, source, object, ret, args
|
|
277
|
+
append_from_source(finding, source)
|
|
278
|
+
finding.events << Contrast::Agent::Assess::Events::EventFactory.build(trigger_node, source, object, ret,
|
|
279
|
+
args).to_dtm_event
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def append_from_source finding, source
|
|
259
283
|
return unless source
|
|
260
284
|
return unless Contrast::Agent::Assess::Tracker.trackable?(source)
|
|
261
285
|
|
|
@@ -286,8 +310,17 @@ module Contrast
|
|
|
286
310
|
finding.events << event.to_dtm_event
|
|
287
311
|
end
|
|
288
312
|
|
|
289
|
-
def
|
|
290
|
-
|
|
313
|
+
def append_route finding, request
|
|
314
|
+
context = Contrast::Agent::REQUEST_TRACKER.current
|
|
315
|
+
if context
|
|
316
|
+
finding.routes << context.route if context.route
|
|
317
|
+
elsif request&.route
|
|
318
|
+
finding.routes << request.route
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def append_hash finding, source, request
|
|
323
|
+
hash_code = Contrast::Utils::HashDigest.generate_event_hash(finding, source, request)
|
|
291
324
|
finding.hash_code = Contrast::Utils::StringUtils.force_utf8(hash_code)
|
|
292
325
|
finding.preflight = Contrast::Utils::PreflightUtil.create_preflight(finding)
|
|
293
326
|
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/policy/trigger/reflected_xss'
|
|
@@ -47,8 +47,8 @@ module Contrast
|
|
|
47
47
|
TRIGGER
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
def apply_custom_trigger
|
|
51
|
-
custom_trigger_class.send(@trigger_method,
|
|
50
|
+
def apply_custom_trigger trigger_node, source, object, ret, *args
|
|
51
|
+
custom_trigger_class.send(@trigger_method, trigger_node, source, object, ret, *args)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def custom_trigger_class
|
|
@@ -104,7 +104,8 @@ module Contrast
|
|
|
104
104
|
|
|
105
105
|
properties = Contrast::Agent::Assess::Tracker.properties(source)
|
|
106
106
|
# find the ranges that violate the rule (untrusted, etc)
|
|
107
|
-
vulnerable_ranges = ranges_with_all_tags(Contrast::Utils::StringUtils.ret_length(source), properties,
|
|
107
|
+
vulnerable_ranges = ranges_with_all_tags(Contrast::Utils::StringUtils.ret_length(source), properties,
|
|
108
|
+
required_tags)
|
|
108
109
|
# if there aren't any vulnerable ranges, nope out
|
|
109
110
|
return false if vulnerable_ranges.empty?
|
|
110
111
|
|
|
@@ -185,11 +186,7 @@ module Contrast
|
|
|
185
186
|
# @return [Array<Contrast::Agent::Assess::Tag>] the ranges satisfied
|
|
186
187
|
# by the given conditions
|
|
187
188
|
def ranges_with_all_tags length, properties, required_tags
|
|
188
|
-
|
|
189
|
-
# all the required tags, we can just return here.
|
|
190
|
-
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless properties.tracked?
|
|
191
|
-
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless required_tags&.any?
|
|
192
|
-
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless required_tags.all? { |tag| properties.tag_keys.include?(tag) }
|
|
189
|
+
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless matches_tags?(properties, required_tags)
|
|
193
190
|
|
|
194
191
|
ranges = []
|
|
195
192
|
chunking = false
|
|
@@ -229,8 +226,7 @@ module Contrast
|
|
|
229
226
|
# by the given conditions
|
|
230
227
|
def ranges_with_any_tag properties, tags
|
|
231
228
|
# if there aren't any all_tags or tags, break early
|
|
232
|
-
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless properties
|
|
233
|
-
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless tags&.any?
|
|
229
|
+
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless search_tags?(properties, tags)
|
|
234
230
|
|
|
235
231
|
ranges = []
|
|
236
232
|
tags.each do |desired|
|
|
@@ -243,6 +239,32 @@ module Contrast
|
|
|
243
239
|
end
|
|
244
240
|
ranges
|
|
245
241
|
end
|
|
242
|
+
|
|
243
|
+
# We should only try to match tags on properties if those properties have any tags (are tracked) and there
|
|
244
|
+
# are tags to try and match on. Some rules, like regexp rules, have no tags. Some rules, like trigger, have
|
|
245
|
+
# no properties.
|
|
246
|
+
#
|
|
247
|
+
# @param properties [Contrast::Agent::Assess::Properties] the properties to check for the tags
|
|
248
|
+
# @param tags [Set<String>] the list of tags on which to match
|
|
249
|
+
# @return [Boolean] if the given properties has instances of every tag in tags
|
|
250
|
+
def search_tags? properties, tags
|
|
251
|
+
return false unless properties.tracked?
|
|
252
|
+
return false unless tags&.any?
|
|
253
|
+
|
|
254
|
+
true
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Determine if the given properties have instances of all the given tags or not.
|
|
258
|
+
#
|
|
259
|
+
# @param properties [Contrast::Agent::Assess::Properties] the properties to check for the tags
|
|
260
|
+
# @param tags [Set<String>] the list of tags on which to match
|
|
261
|
+
# @return [Boolean] if the given properties has instances of every tag in tags
|
|
262
|
+
def matches_tags? properties, tags
|
|
263
|
+
return false unless search_tags?(properties, tags)
|
|
264
|
+
return false unless tags.all? { |tag| properties.tag_keys.include?(tag) }
|
|
265
|
+
|
|
266
|
+
true
|
|
267
|
+
end
|
|
246
268
|
end
|
|
247
269
|
end
|
|
248
270
|
end
|