# 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') || # Path validity is the service's problem !!CONFIG.root.agent.service.socket) 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 event [Contrast::Api::Dtm] One of the DTMs valid for the event # field of Contrast::Api::Dtm::Message # TODO: rename method to queue_event def queue_message event return unless event Contrast::Utils::ServiceSenderUtil.push_to_ready_queue(event) 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 event [Contrast::Api::Dtm] One of the DTMs valid for the event # field of Contrast::Api::Dtm::Message # @return [Array] the response from SpeedRacer # TODO: rename method to send_event def send_message event return unless event state.client.send_to_speedracer(event) end end COMPONENT_INTERFACE = Interface.new end end end