# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true cs__scoped_require 'monitor' module Contrast module Components module ContrastService # 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 connection to # the Service, as well as sending a message to the Service. class Interface include Contrast::Components::ComponentBase include Contrast::Components::Interface access_component :config, :agent def update_received? state.update_received? end def enabled? state.service_enabled? end def unavailable? !enabled? end def disabled? state.service_forcibly_disabled? end def host @_host ||= (CONFIG.root.agent.service.host || Contrast::Configuration::DEFAULT_HOST).to_s end def port @_port ||= (CONFIG.root.agent.service.port || Contrast::Configuration::DEFAULT_PORT).to_i end def socket_path @_socket_path ||= CONFIG.root.agent.service.socket end def logger_path @_logger_path ||= CONFIG.root.agent.service.logger.path || DEFAULT_LOG_FILENAME end def use_tcp? socket_path.nil? end def last_update state.last_update end def use_bundled_service? # Validates the config to decide if it's suitable for starting # the bundled service @_use_bundled_service ||= begin # Requirement says "must be true" but that # should be "must not be false" -- oops. !false?(CONFIG.root.agent.start_bundled_service) && # Either a valid host or a valid socket (CONFIG.root.agent.service.host.nil? || CONFIG.root.agent.service.host == 'localhost' || CONFIG.root.agent.service.host == '127.0.0.1' || CONFIG.root.agent.service.host.empty?) || # Path validity is the service's problem !CONFIG.root.agent.service.socket.empty? end end # TODO: As part of RUBY-356. Add new handling for SQL analysis via RPC (SPEED-211) # The API for Agent to Service communication. These methods abstract away implementation # details, responsibilities of sending messages to the service, and requirements mandated # within the Agent<>SpeedRacer contract. # Pushes a message onto a queue to later be consumed when the service sender thread is ready to # handle it. The service response is not returned; rather, it is processed by the service sender # thread. All messages sent to SpeedRacer should be queued rather than sent unless the calling method # explicitly needs to act on the response object with custom logic (i.e. RequestContext#service_extract_response) # @param msg [Contrast::Api::Dtm::Message] the message to be sent def queue_message msg return unless msg Contrast::Utils::ServiceSenderUtil.push_to_ready_queue(msg) end # TODO: RUBY-662. Add additional check before we queue/send a message to see if we were unable # to connect to the service. # Bypass the queue and send the message directly to SpeedRacer. This is the only way # to receive the response object back from SpeedRacer. An invoking method that needs # to process the response object with custom logic should use this method. # # @param msg [Contrast::Api::Dtm::Message] the message to be sent # @return [Array] the response from SpeedRacer def send_message msg return unless msg state.client.send_to_speedracer(msg) end end COMPONENT_INTERFACE = Interface.new end end end