# Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'rubygems/version' require 'contrast/utils/object_share' require 'contrast/components/app_context_extend' require 'contrast/config/base_configuration' module Contrast module Components module AppContext # 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 Application, # including the Client, Process, and Server information. class Interface # rubocop:disable Metrics/ClassLength include Contrast::Components::AppContextExtend include Contrast::Components::ComponentBase include Contrast::Config::BaseConfiguration DEFAULT_APP_NAME = 'rails' DEFAULT_APP_PATH = '/' DEFAULT_SERVER_NAME = 'localhost' DEFAULT_SERVER_PATH = '/' CANON_NAME = 'application' CONFIG_VALUES = %w[name version language path group tags code metadata session_id session_metadata].cs__freeze # @return [String] attr_accessor :version # @return [String] attr_accessor :language # @return [String] attr_accessor :group attr_writer :tags # @return [String] attr_accessor :code # @return [String] attr_accessor :metadata # @return [String] attr_reader :canon_name # @return [Array] attr_reader :config_values def initialize hsh = {} original_pid @config_values = CONFIG_VALUES @canon_name = CANON_NAME return unless hsh @_name = hsh[:name] @version = hsh[:version] @language = hsh[:language] @_path = hsh[:path] @group = hsh[:group] @tags = hsh[:tags] @code = hsh[:code] @metadata = hsh[:metadata] @_session_id = hsh[:session_id] @_session_metadata = hsh[:session_metadata] end # @return [String, Contrast::Utils::ObjectShare::EMPTY_STRING] def session_id @_session_id ||= Contrast::Utils::ObjectShare::EMPTY_STRING end # Set session_id # # @param id [String] # @return [String] def session_id= id @_session_id = id end # @return [String, Contrast::Utils::ObjectShare::EMPTY_STRING] def session_metadata @_session_metadata ||= Contrast::Utils::ObjectShare::EMPTY_STRING end # Set session_metadata # # @param meta [String] # @return [String] def session_metadata= meta @_session_metadata = meta end def server_type @_server_type ||= begin tmp = ::Contrast::CONFIG.server.type tmp = Contrast::Agent.framework_manager.server_type unless Contrast::Utils::StringUtils.present?(tmp) tmp end end def name @_name ||= begin tmp = Contrast::Agent.framework_manager.app_name unless Contrast::Utils::StringUtils.present?(tmp) tmp = File.basename(Dir.pwd) unless Contrast::Utils::StringUtils.present?(tmp) Contrast::Utils::StringUtils.truncate(tmp, DEFAULT_APP_NAME) rescue StandardError DEFAULT_APP_NAME end end # Set application name # # @param app_name [String] application name # @return [String] def name= app_name @_name = app_name end def path @_path ||= begin tmp = Contrast::Agent.framework_manager.application_root unless Contrast::Utils::StringUtils.present?(tmp) Contrast::Utils::StringUtils.truncate(tmp, DEFAULT_APP_PATH) rescue StandardError DEFAULT_APP_PATH end end def server_name @_server_name ||= begin tmp = ::Contrast::CONFIG.server.name # rubocop:disable Security/Module/Name tmp = Socket.gethostname unless Contrast::Utils::StringUtils.present?(tmp) tmp = Contrast::Utils::StringUtils.force_utf8(tmp) Contrast::Utils::StringUtils.truncate(tmp, DEFAULT_SERVER_NAME) rescue StandardError DEFAULT_SERVER_NAME end end def server_path @_server_path ||= begin tmp = ::Contrast::CONFIG.server.path tmp = Dir.pwd unless Contrast::Utils::StringUtils.present?(tmp) Contrast::Utils::StringUtils.truncate(tmp, DEFAULT_SERVER_PATH) rescue StandardError DEFAULT_SERVER_PATH end end def tags stringify_array(@tags) end # Determines if the Process we're currently in matches that of the # Process in which the App Context instance was created. # If it doesn't, that indicates the running context is in a new # Process. # @return [Boolean] if we're in the original Process in which the # App Context instance was initialized. def in_new_process? current_pid = Process.pid original_pid = pid current_pid != original_pid end # Converts current configuration to effective config values class and appends them to # EffectiveConfig class. # # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig] def to_effective_config effective_config super Contrast::CONFIG.server.to_effective_config(effective_config) end private def original_pid @_original_pid ||= Process.pid end end end end end