# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'rubygems/version' require 'contrast/agent/rule_set' require 'contrast/components/logger' require 'contrast/components/security_logger' require 'contrast/components/heap_dump' require 'contrast/components/service' require 'contrast/components/ruby_component' module Contrast module Components module Agent # A wrapper build around the Common Agent Configuration project to allow # for access of the values contained in its parent_configuration_spec.yaml. # Specifically, this allows for querying the state of the Agent. class Interface include Contrast::Components::ComponentBase def initialize hsh = {} return unless hsh @_enable = hsh[:enable] @_start_bundled_service = hsh[:start_bundled_service] @_omit_body = hsh[:omit_body] @_service = Contrast::Components::Service::Interface.new(hsh[:service]) @_logger = Contrast::Components::Logger::Interface.new(hsh[:logger]) @_security_logger = Contrast::Components::SecurityLogger::Interface.new(hsh[:security_logger]) @_ruby = Contrast::Components::Ruby::Interface.new(hsh[:ruby]) @_heap_dump = Contrast::Components::HeapDump::Interface.new(hsh[:heap_dump]) end # @return [Boolean, true] def start_bundled_service? @_start_bundled_service.nil? ? true : @_start_bundled_service end def service return @_service unless @_service.nil? @_service = Contrast::Components::Service::Interface.new end def logger return @_logger unless @_logger.nil? @_logger = Contrast::Components::Logger::Interface.new end def security_logger return @_security_logger unless @_security_logger.nil? @_security_logger = Contrast::Components::SecurityLogger::Interface.new end def ruby return @_ruby unless @_ruby.nil? @_ruby = Contrast::Components::Ruby::Interface.new end def heap_dump return @_heap_dump unless @_heap_dump.nil? @_heap_dump = Contrast::Components::HeapDump::Interface.new end def enabled? @_enable = !false?(::Contrast::CONFIG.enable) if @_enable.nil? @_enable end def disabled? !enabled? end def enable! @_enable = true end def disable! @_enable = false Contrast::Agent::TracePointHook.disable Contrast::Agent.thread_watcher&.shutdown! end def ruleset @_ruleset ||= Contrast::Agent::RuleSet.new(retrieve_protect_ruleset.values) end def reset_ruleset @_ruleset = nil end def patch_yield? !false?(ruby.propagate_yield) end def omit_body? @_omit_body end def exception_control @_exception_control ||= { enable: true?(ruby.exceptions.capture), status: ruby.exceptions.override_status || 403, message: ruby.exceptions.override_message || Contrast::Utils::ObjectShare::OVERRIDE_MESSAGE } end def skip_instrumentation? loaded_module_name return true unless loaded_module_name loaded_module_name.start_with?(*::Contrast::CONFIG.agent.ruby.uninstrument_namespace) end # Insert ourselves into the application, keeping our middleware at the outermost layer of the onion def insert_middleware app app.middleware.insert_before(0, Contrast::Agent::Middleware) end def enable_tracepoint Contrast::Agent::TracePointHook.enable! end protected def retrieve_protect_ruleset return {} unless enabled? && ::Contrast::PROTECT.enabled? ::Contrast::PROTECT.defend_rules end end end end end