# Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'fileutils' require 'yaml' module Contrast module Config # Helper module with methods to find active configuration file used by the agent or create it.\ # This file is used before the agent start so methods added here must not be dependent on Agent # instrumentation. module YamlFile CONFIG_FILE_NAME = 'contrast_security' EXT = { yml: 'yml', yaml: 'yaml' }.freeze # rubocop:disable Security/Object/Freeze POSSIBLE_TARGET_PATHS = %w[ ./ ./config/ /etc/contrast/ruby/ /etc/contrast/ /etc/ ].freeze # rubocop:disable Security/Object/Freeze HEADER = "# +-------------------------------------------------------------------------+\n" \ "# This Contrast Security configuration is Auto-generated by rake task.\n" \ "# To List all available rake task use 'rake -T'. \n" \ "#\n" \ "# Please enter valid api information, for the Ruby Agent to be able to\n" \ "# connect to Contrast UI. You can validate your config file by running: \n" \ "# 'bundle exec rake contrast:config:validate' \n" \ "#\n" \ "# To find your organization keys please follow this documentation:\n" \ "# https://docs.contrastsecurity.com/en/find-the-agent-keys.html\n" \ "# +-------------------------------------------------------------------------+\n" FOOTER = "\n# For more information visit the full Ruby agent configuration guide:\n" \ '# https://docs.contrastsecurity.com/en/ruby-configuration.html' COMMENT = "#agent:\n" \ "# logger:\n" \ "# level: WARN\n" \ "# path: contrast_agent.log\n" \ "#server:\n" \ "# name: Server name\n" \ "#application:\n" \ "# name: Application name\n" \ "# code: Application name\n" \ "# group: Application group\n" \ "# session_metadata: Application metadata used for creation of Session ID\n" \ "# version: Application version\n" DEFAULT_CONFIG = { 'api' => { 'url' => 'https://app.contrastsecurity.com', 'api_key' => 'contrast_user', 'service_key' => 'demo', 'user_name' => 'demo' } }.freeze # rubocop:disable Security/Object/Freeze class << self # Checks all accessible by the agent path for active configuration created. # # @return [Boolean] def created? return true if File.exist?(Contrast::Config::YamlFile.target_path) return true unless find!.empty? false end # Finds active configuration used. # # @return [String] path of the config file. def find! found = '' paths = POSSIBLE_TARGET_PATHS.dup paths << ENV['CONTRAST_CONFIG_PATH'] if ENV['CONTRAST_CONFIG_PATH'] paths.each do |path| EXT.each_value do |extension| effective_config = "#{ path }#{ file_name }.#{ extension }" found = effective_config if File.exist?(effective_config) end end found end # Create new config file to the default destination. # def create # rubocop:disable Rails/Output puts("\u{1F48E} Generating: Contrast Configuration file.") if Contrast::Config::YamlFile.created? puts("\u{2705} Configuration file already exists: #{ Contrast::Config::YamlFile.find! }") else File.open(Contrast::Config::YamlFile.target_path, 'w') do |file| file.write(HEADER) file.write(YAML.dump(DEFAULT_CONFIG).gsub('---', ' ')) file.write(COMMENT) file.write(FOOTER) file.close end puts("\u{2728} Created! path #{ Contrast::Config::YamlFile.target_path }\n") puts("\nOpen the file and enter your Contrast Security api keys or set them via environment variables.\n") puts('Visit our documentation for more details: ' \ 'https://docs.contrastsecurity.com/en/ruby-configuration.html') end rescue StandardError => e puts("\u{2757} WARNING configuration could not be created due to error: '#{ e }'. " \ "Try created in manually by running 'bundle exec rake contrast:config:create'.") # rubocop:enable Rails/Output end def target_path File.join(execution_directory, "#{ file_name }.#{ EXT[:yml] }") end def execution_directory Dir.pwd end def file_name ENV['CONTRAST_YAML_FILE_TEST_CREATE_CONFIG_FILE_NAME_VALUE'] || CONFIG_FILE_NAME end end end end end