# Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'contrast/utils/metrics_hash' require 'contrast/agent/telemetry/metric_event' require 'contrast/agent/version' module Contrast module Agent module Telemetry # This class will hold the Startup Metrics Telemetry Event # The class will include initialization of the agent version, language version # os type, arch and version # application framework and version and server framework # It will be initialized and send in Middleware#agent_startup_routine class StartupMetricsEvent < Contrast::Agent::Telemetry::MetricEvent APP_AND_SERVER_DATA = ::Contrast::APP_CONTEXT.app_and_server_information.cs__freeze # Multi-tenant Production Environments SAAS_DEFAULT = { addr: 'app.contrastsecurity.com', type: 'SAAS_DEFAULT' }.cs__freeze SAAS_CS = { addr: /cs[[:digit:]]+\.contrastsecurity\.com/, type: 'SAAS_DEFAULT' }.cs__freeze SAAS_JP = { addr: 'app.contrastsecurity.jp', type: 'SAAS_DEFAULT' }.cs__freeze SAAS_CE = { addr: 'ce.contrastsecurity.com', type: 'SAAS_CE' }.cs__freeze # Multi-tenant Demo Environments SAAS_DEMO = { addr: 'apptwo.contrastsecurity.com', type: 'SAAS_DEMO' }.cs__freeze SAAS_POV = { addr: 'eval.contrastsecurity.com', type: 'SAAS_POV' }.cs__freeze # Multi-tenant Testing Environment SAAS_RESEARCH = { addr: 'security-research.contrastsecurity.com', type: 'SAAS_RESEARCH' }.cs__freeze SAAS_ALPHA = { addr: 'alpha.contrastsecurity.com', type: 'SAAS_ALPHA' }.cs__freeze SAAS_STAGING = { addr: 'teamserver-staging.contsec.com', type: 'SAAS_TESTING' }.cs__freeze SAAS_STAGING_TOKYO = { addr: 'teamserver-staging.contsec.jp', type: 'SAAS_TESTING' }.cs__freeze SAAS_TESTING = { addr: 'teamserver-darpa.contsec.com', type: 'SAAS_TESTING' }.cs__freeze SAAS_OPS_TESTING = { addr: 'teamserver-ops.contsec.com', type: 'SAAS_TESTING' }.cs__freeze # Fallback for Single-tenant Production Environments SAAS_CUSTOM = { addr: 'contrastsecurity.com', type: 'SAAS_CUSTOM' }.cs__freeze SAAS_CUSTOM_JP = { addr: 'contrastsecurity.jp', type: 'SAAS_CUSTOM' }.cs__freeze SINGLE_MAP_TENANTS = [ SAAS_DEFAULT, SAAS_JP, SAAS_CE, SAAS_DEMO, SAAS_POV, SAAS_RESEARCH, SAAS_ALPHA, SAAS_STAGING, SAAS_STAGING_TOKYO, SAAS_TESTING, SAAS_OPS_TESTING ].cs__freeze REGEXP_MAP_TENANTS = [SAAS_CS].cs__freeze FALLBACK_TENANTS = [SAAS_CUSTOM, SAAS_CUSTOM_JP].cs__freeze # Fallback for Custom, most likely self-hosted, Environments EOP = 'EOP' REJECTED_VALUES = [nil, 'NEEDS_TO_BE_SET', Contrast::Utils::ObjectShare::EMPTY_STRING].cs__freeze def initialize super @settings = [] add_config_keys(::Contrast::CONFIG.config, 'root') @settings << ENV.keys.select { |v| v.start_with?('CONTRAST') } @settings.flatten add_tags end def path '/startup' end def add_tags add_system_tags @tags['app_framework_and_version'] = APP_AND_SERVER_DATA[:application_info].to_s @tags['server_framework_and_version'] = APP_AND_SERVER_DATA[:server_info].to_s @tags['ASSESS'] = Contrast::ASSESS.enabled?.to_s @tags['PROTECT'] = Contrast::PROTECT.enabled?.to_s @tags['settings'] = @settings.join(',') end def add_config_keys config, nested_key config.to_contrast_hash.reject! { |_k, v| REJECTED_VALUES.include?(v) } config.to_contrast_hash.each do |k, v| unless v.cs__class <= Contrast::Config::BaseConfiguration @settings << "#{ nested_key }.#{ k }" next end add_config_keys(v, "#{ nested_key }.#{ k }") end end private # Here we extract the TeamServer url type # # @return [String] the type of TeamServer environment to which we're connecting def teamserver_type @_teamserver_type ||= begin url = Contrast::API.api_url if (single = SINGLE_MAP_TENANTS.find { |tenant| url.include?(tenant[:addr]) }) single[:type] elsif (regexp = REGEXP_MAP_TENANTS.find { |tenant| tenant[:addr].match?(url) }) regexp[:type] elsif (fallback = FALLBACK_TENANTS.find { |tenant| url.include?(tenant[:addr]) }) fallback[:type] else EOP end end end # Here we attach the key-value pairs of the system # def add_system_tags @tags['teamserver'] = teamserver_type @tags['agent_version'] = VERSION @tags['ruby_version'] = RUBY_VERSION @tags['os_type'] = sys_info['os_type'] == 'Darwin' ? 'MacOS' : 'Linux' @tags['os_arch'] = sys_info['os_arch'] @tags['os_version'] = sys_info['os_version'] end end end end end