diff --git a/.env.development b/.env.development index be97e459..a042eca0 100644 --- a/.env.development +++ b/.env.development @@ -3,4 +3,4 @@ DB_PASSWORD=postgres DB_PORT=5432 DB_USERNAME=postgres REDIS_URL=redis://host.docker.internal:6379/7 -PORT=3000 +PORT=3001 diff --git a/.env.production b/.env.production new file mode 100644 index 00000000..9bd25a9a --- /dev/null +++ b/.env.production @@ -0,0 +1,15 @@ +DB_HOST= +DB_POOL=25 +DB_PORT=5432 +DB_SSLCERT=/config/rds-combined-ca-bundle.pem +DB_SSLMODE=verify-full +REDIS_URL= +PORT=3000 +S3_ATTACHMENTS_BUCKET= +ACTIVE_STORAGE_PUBLIC=true +FORCE_SSL=true +AIRBRAKE_ID= +AIRBRAKE_KEY= +NEWRELIC_LICENSE_KEY= +NEWRELIC_APP_NAME= +WEB_CONCURRENCY=2 \ No newline at end of file diff --git a/.env.staging b/.env.staging index 0a4eecef..cf0a1b06 100644 --- a/.env.staging +++ b/.env.staging @@ -8,3 +8,9 @@ PORT=3000 S3_ATTACHMENTS_BUCKET= ACTIVE_STORAGE_PUBLIC=true FORCE_SSL=true +AIRBRAKE_ID= +AIRBRAKE_KEY= +NEWRELIC_LICENSE_KEY= +NEWRELIC_APP_NAME= +NEWRELIC_MONITOR_MODE= +WEB_CONCURRENCY=2 diff --git a/Dockerfile b/Dockerfile index b34389b4..30ae7ad6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -79,6 +79,7 @@ COPY ./tmp ./tmp COPY LICENSE README.md Rakefile config.ru .version ./ COPY .version ./public/version COPY ./.env.staging ./.env.staging +COPY ./.env.production ./.env.production COPY ./config/rds-combined-ca-bundle.pem /config/rds-combined-ca-bundle.pem COPY --from=download /fonts/GoNotoKurrent-Regular.ttf /fonts/GoNotoKurrent-Bold.ttf /fonts/DancingScript-Regular.otf /fonts/OFL.txt /fonts diff --git a/Gemfile b/Gemfile index 2373d2d3..b4352fa7 100644 --- a/Gemfile +++ b/Gemfile @@ -44,6 +44,9 @@ gem 'turbo-rails' gem 'twitter_cldr', require: false gem 'tzinfo-data' +gem 'airbrake' +gem 'newrelic_rpm' + group :development, :test do gem 'better_html' gem 'bullet' diff --git a/Gemfile.lock b/Gemfile.lock index d38ce518..52baffbd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -74,6 +74,10 @@ GEM uri (>= 0.13.1) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) + airbrake (13.0.5) + airbrake-ruby (~> 6.0) + airbrake-ruby (6.2.2) + rbtree3 (~> 0.6) annotaterb (4.14.0) arabic-letter-connector (0.1.1) ast (2.4.2) @@ -336,6 +340,7 @@ GEM timeout net-smtp (0.5.0) net-protocol + newrelic_rpm (9.17.0) nio4r (2.7.4) nokogiri (1.18.8) mini_portile2 (~> 2.8.2) @@ -433,6 +438,7 @@ GEM zeitwerk (~> 2.6) rainbow (3.1.1) rake (13.2.1) + rbtree3 (0.7.1) rdoc (6.10.0) psych (>= 4.0.0) redis-client (0.23.0) @@ -588,6 +594,7 @@ PLATFORMS x86_64-linux-musl DEPENDENCIES + airbrake annotaterb arabic-letter-connector aws-sdk-s3 @@ -618,6 +625,7 @@ DEPENDENCIES jwt letter_opener_web lograge + newrelic_rpm oj pagy pg diff --git a/bin/start_production b/bin/start_production new file mode 100755 index 00000000..6b9be8e8 --- /dev/null +++ b/bin/start_production @@ -0,0 +1,271 @@ +#!/bin/sh -e + +echo "=== CP Docuseal Production Startup ===" + +# Enable jemalloc for reduced memory usage and latency. +if [ -z "${LD_PRELOAD+x}" ]; then + LD_PRELOAD=$(find /usr/lib -name libjemalloc.so.2 -print -quit) + export LD_PRELOAD +fi + +check_aws_setup() { + if [ -z "$AWS_REGION" ]; then + echo "ERROR: AWS_REGION environment variable is not set" + exit 1 + fi + + if ! command -v aws &> /dev/null; then + echo "ERROR: AWS CLI is not installed. Please install it to proceed." + exit 1 + fi +} + +# Function to fetch secrets from AWS Secrets Manager +fetch_db_credentials() { + echo "Fetching database credentials from AWS Secrets Manager..." + + if [ -z "$DB_SECRETS_NAME" ]; then + echo "ERROR: DB_SECRETS_NAME environment variable is not set" + exit 1 + fi + + # Fetch the secret + echo "Retrieving secret: $DB_SECRETS_NAME" + SECRET_JSON=$(aws secretsmanager get-secret-value \ + --region "$AWS_REGION" \ + --secret-id "$DB_SECRETS_NAME" \ + --query SecretString \ + --output text) + + if [ $? -ne 0 ]; then + echo "ERROR: Failed to retrieve secrets from AWS Secrets Manager" + exit 1 + fi + + # Parse JSON and export environment variables + export DB_USERNAME=$(echo "$SECRET_JSON" | jq -r '.username') + export DB_PASSWORD=$(echo "$SECRET_JSON" | jq -r '.password') + + # Validate that we got the credentials + if [ "$DB_USERNAME" = "null" ] || [ "$DB_PASSWORD" = "null" ] || [ -z "$DB_USERNAME" ] || [ -z "$DB_PASSWORD" ]; then + echo "ERROR: Failed to parse database credentials from secrets" + echo "Expected JSON format: {\"username\": \"...\", \"password\": \"...\"}" + exit 1 + fi + + # Write credentials to .env.production file + echo "Writing database credentials to .env.production..." + + # Remove existing DB_USERNAME and DB_PASSWORD lines if they exist + if [ -f "./.env.production" ]; then + echo "Removing existing DB_USERNAME and DB_PASSWORD from .env.production" + grep -v "^DB_USERNAME=" ./.env.production > ./.env.production.tmp || true + grep -v "^DB_PASSWORD=" ./.env.production.tmp > ./.env.production || true + rm -f ./.env.production.tmp + fi + + # Append the new credentials + echo "DB_USERNAME=$DB_USERNAME" >> ./.env.production + echo "DB_PASSWORD=$DB_PASSWORD" >> ./.env.production + + echo "✓ Database credentials successfully retrieved and written to .env.production" +} + +# Function to fetch encryption key from AWS Secrets Manager and write to config/master.key +fetch_encryption_key() { + echo "Fetching encryption key from AWS Secrets Manager..." + + ENCRYPTION_SECRET_NAME="cpdocuseal/encryption_key" + if [ -z "$AWS_REGION" ]; then + echo "ERROR: AWS_REGION environment variable is not set" + exit 1 + fi + + # Fetch the secret value (assume it's a plain string, not JSON) + ENCRYPTION_KEY=$(aws secretsmanager get-secret-value \ + --region "$AWS_REGION" \ + --secret-id "$ENCRYPTION_SECRET_NAME" \ + --query SecretString \ + --output text) + + if [ $? -ne 0 ] || [ -z "$ENCRYPTION_KEY" ] || [ "$ENCRYPTION_KEY" = "null" ]; then + echo "ERROR: Failed to retrieve encryption key from AWS Secrets Manager" + exit 1 + fi + + # Write the key to config/master.key + echo -n "$ENCRYPTION_KEY" > config/master.key + chmod 600 config/master.key + echo "✓ Encryption key written to config/master.key" +} + +# Function to fetch allowed hosts values +fetch_allowed_hosts() { + echo "Fetching allowed hosts from AWS Secrets Manager..." + + if [ -z "$ALLOWED_HOSTS_NAME" ]; then + echo "ERROR: ALLOWED_HOSTS_NAME environment variable is not set" + exit 1 + fi + + # Fetch the secret value, assume kept as JSON array + ALLOWED_HOSTS_JSON=$(aws secretsmanager get-secret-value \ + --region "$AWS_REGION" \ + --secret-id "$ALLOWED_HOSTS_NAME" \ + --query SecretString \ + --output text) + + if [ $? -ne 0 ] || [ -z "$ALLOWED_HOSTS_JSON" ] || [ "$ALLOWED_HOSTS_JSON" = "null" ]; then + echo "ERROR: Failed to retrieve allowed hosts from AWS Secrets Manager" + exit 1 + fi + + # Extract the array and convert to comma-separated string + ALLOWED_HOSTS=$(echo "$ALLOWED_HOSTS_JSON" | jq -r '.allowed_hosts | join(",")') + + if [ -z "$ALLOWED_HOSTS" ] || [ "$ALLOWED_HOSTS" = "null" ]; then + echo "ERROR: Failed to parse allowed hosts from secrets. Check that the secret contains 'allowed_hosts' key." + exit 1 + fi + + # Write allowed hosts to .env.production file + echo "Writing allowed hosts to .env.production..." + echo "ALLOWED_HOSTS=$ALLOWED_HOSTS" >> ./.env.production + echo "✓ Allowed hosts successfully retrieved and written to .env.production" +} + +# Function to fetch various environment variables and write to .env file for use by app +fetch_env_variables() { + echo "Fetching environment variables from AWS Secrets Manager..." + + if [ -z "$CP_VARIABLES_NAME" ]; then + echo "ERROR: CP_VARIABLES_NAME environment variable is not set" + exit 1 + fi + + # Fetch the secret + echo "Retrieving secret: $CP_VARIABLES_NAME" + SECRET_JSON=$(aws secretsmanager get-secret-value \ + --region "$AWS_REGION" \ + --secret-id "$CP_VARIABLES_NAME" \ + --query SecretString \ + --output text) + + if [ $? -ne 0 ]; then + echo "ERROR: Failed to retrieve secrets from AWS Secrets Manager" + exit 1 + fi + + export DB_HOST=$(echo "$SECRET_JSON" | jq -r '.host') + export REDIS_URL=$(echo "$SECRET_JSON" | jq -r '.redis_url') + export S3_ATTACHMENTS_BUCKET=$(echo "$SECRET_JSON" | jq -r '.s3_attachments_bucket') + export AIRBRAKE_ID=$(echo "$SECRET_JSON" | jq -r '.airbrake_id') + export AIRBRAKE_KEY=$(echo "$SECRET_JSON" | jq -r '.airbrake_key') + export NEWRELIC_LICENSE_KEY=$(echo "$SECRET_JSON" | jq -r '.newrelic_license_key') + export NEWRELIC_APP_NAME=$(echo "$SECRET_JSON" | jq -r '.newrelic_app_name') + export NEWRELIC_MONITOR_MODE=$(echo "$SECRET_JSON" | jq -r '.newrelic_monitor_mode') + + # Validate that we got the values + if [ "$DB_HOST" = "null" ] || [ "$REDIS_URL" = "null" ] || [ "$S3_ATTACHMENTS_BUCKET" = "null" ] || [ -z "$DB_HOST" ] || [ -z "$REDIS_URL" ] || [ -z "$S3_ATTACHMENTS_BUCKET" ]; then + echo "ERROR: Failed to parse variables from secrets" + echo "Expected JSON format: {\"key\": \"...\", ...}" + exit 1 + fi + + # Validate license keys exist for logging + if [ "$AIRBRAKE_ID" = "null" ] || [ "$AIRBRAKE_KEY" = "null" ] || [ "$NEWRELIC_LICENSE_KEY" = "null" ] || [ "$NEWRELIC_APP_NAME" = "null" ]; then + echo "ERROR: One or more monitor/logging license keys are missing" + exit 1 + fi + + # Write variables to .env.production file + echo "Writing environment variables to .env.production..." + + # Remove existing DB_HOST, REDIS_URL, and S3_ATTACHMENTS_BUCKET lines if they exist + if [ -f "./.env.production" ]; then + echo "Removing existing variables from .env.production" + grep -v "^DB_HOST=" ./.env.production > ./.env.production.tmp || true + grep -v "^REDIS_URL=" ./.env.production.tmp > ./.env.production || true + grep -v "^S3_ATTACHMENTS_BUCKET=" ./.env.production.tmp > ./.env.production || true + grep -v "^AIRBRAKE_ID=" ./.env.production.tmp > ./.env.production || true + grep -v "^AIRBRAKE_KEY=" ./.env.production.tmp > ./.env.production || true + grep -v "^NEWRELIC_LICENSE_KEY=" ./.env.production.tmp > ./.env.production || true + grep -v "^NEWRELIC_APP_NAME=" ./.env.production.tmp > ./.env.production || true + grep -v "^NEWRELIC_MONITOR_MODE=" ./.env.production.tmp > ./.env.production || true + rm -f ./.env.production.tmp + fi + + # Append the new credentials + echo "DB_HOST=$DB_HOST" >> ./.env.production + echo "REDIS_URL=$REDIS_URL" >> ./.env.production + echo "S3_ATTACHMENTS_BUCKET=$S3_ATTACHMENTS_BUCKET" >> ./.env.production + echo "AIRBRAKE_ID=$AIRBRAKE_ID" >> ./.env.production + echo "AIRBRAKE_KEY=$AIRBRAKE_KEY" >> ./.env.production + echo "NEWRELIC_LICENSE_KEY=$NEWRELIC_LICENSE_KEY" >> ./.env.production + echo "NEWRELIC_APP_NAME=$NEWRELIC_APP_NAME" >> ./.env.production + echo "NEWRELIC_MONITOR_MODE=$NEWRELIC_MONITOR_MODE" >> ./.env.production + + echo "✓ Environment variables successfully retrieved and written to .env.production" +} + +# Function to setup database +setup_database() { + echo "Running database migrations..." + ./bin/rails db:migrate + + if [ $? -eq 0 ]; then + echo "✓ Database migrations completed successfully" + else + echo "ERROR: Database migrations failed" + exit 1 + fi +} + +set_environment() { + if [ -f "./.env.production" ]; then + echo "Setting environment variables from .env.production" + set -a + . ./.env.production + set +a + fi +} + +# Main execution +main() { + cd ../../app/ + + set_environment + + check_aws_setup + + echo "Starting CP Docuseal in production mode..." + echo "Rails Environment: ${RAILS_ENV:-production}" + + # Fetch database credentials from Secrets Manager + fetch_db_credentials + + # Fetch encryption key and write to config/master.key + fetch_encryption_key + + # Fetch allowed hosts from Secrets Manager + fetch_allowed_hosts + + # Fetch other environment variables from Secrets Manager + fetch_env_variables + + # Load updated environment variables + set_environment + + # Setup and migrate database + setup_database + + echo "=== Startup Complete - Starting Rails Server ===" + echo "Database Host: ${DB_HOST:-not set}" + echo "Database Port: ${DB_PORT:-not set}" + + # Start the Rails server + exec ./bin/rails server -b 0.0.0.0 -p "${PORT:-3000}" +} + +# Execute main function +main "$@" diff --git a/bin/start_staging b/bin/start_staging index e9d9df5c..4647a620 100755 --- a/bin/start_staging +++ b/bin/start_staging @@ -71,6 +71,46 @@ fetch_db_credentials() { echo "✓ Database credentials successfully retrieved and written to .env.staging" } +# Function to fetch allowed hosts from AWS Secrets Manager and write to .env.staging +fetch_allowed_hosts() { + echo "Fetching allowed hosts from AWS Secrets Manager..." + + if [ -z "$ALLOWED_HOSTS_NAME" ]; then + echo "ERROR: ALLOWED_HOSTS_NAME environment variable is not set" + exit 1 + fi + + # Fetch the secret value, assume kept as JSON array + ALLOWED_HOSTS_JSON=$(aws secretsmanager get-secret-value \ + --region "$AWS_REGION" \ + --secret-id "$ALLOWED_HOSTS_NAME" \ + --query SecretString \ + --output text) + + if [ $? -ne 0 ] || [ -z "$ALLOWED_HOSTS_JSON" ] || [ "$ALLOWED_HOSTS_JSON" = "null" ]; then + echo "ERROR: Failed to retrieve allowed hosts from AWS Secrets Manager" + exit 1 + fi + + # Extract the array and convert to comma-separated string + ALLOWED_HOSTS=$(echo "$ALLOWED_HOSTS_JSON" | jq -r '.allowed_hosts | join(",")') + + if [ -z "$ALLOWED_HOSTS" ] || [ "$ALLOWED_HOSTS" = "null" ]; then + echo "ERROR: Failed to parse allowed hosts from secrets. Check that the secret contains 'allowed_hosts' key." + exit 1 + fi + + # Remove existing ALLOWED_HOSTS line if it exists + if [ -f "./.env.staging" ]; then + grep -v "^ALLOWED_HOSTS=" ./.env.staging > ./.env.staging.tmp || true + mv ./.env.staging.tmp ./.env.staging + fi + + # Append the new allowed hosts + echo "ALLOWED_HOSTS=$ALLOWED_HOSTS" >> ./.env.staging + echo "✓ Allowed hosts successfully retrieved and written to .env.staging" +} + # Function to fetch encryption key from AWS Secrets Manager and write to config/master.key fetch_encryption_key() { echo "Fetching encryption key from AWS Secrets Manager..." @@ -123,6 +163,12 @@ fetch_env_variables() { export DB_HOST=$(echo "$SECRET_JSON" | jq -r '.host') export REDIS_URL=$(echo "$SECRET_JSON" | jq -r '.redis_url') export S3_ATTACHMENTS_BUCKET=$(echo "$SECRET_JSON" | jq -r '.s3_attachments_bucket') + export AIRBRAKE_ID=$(echo "$SECRET_JSON" | jq -r '.airbrake_id') + export AIRBRAKE_KEY=$(echo "$SECRET_JSON" | jq -r '.airbrake_key') + export NEWRELIC_LICENSE_KEY=$(echo "$SECRET_JSON" | jq -r '.newrelic_license_key') + export NEWRELIC_APP_NAME=$(echo "$SECRET_JSON" | jq -r '.newrelic_app_name') + export NEWRELIC_MONITOR_MODE=$(echo "$SECRET_JSON" | jq -r '.newrelic_monitor_mode') + # Validate that we got the values if [ "$DB_HOST" = "null" ] || [ "$REDIS_URL" = "null" ] || [ "$S3_ATTACHMENTS_BUCKET" = "null" ] || [ -z "$DB_HOST" ] || [ -z "$REDIS_URL" ] || [ -z "$S3_ATTACHMENTS_BUCKET" ]; then @@ -130,6 +176,12 @@ fetch_env_variables() { echo "Expected JSON format: {\"key\": \"...\", ...}" exit 1 fi + + # Validate license keys exist for logging + if [ "$AIRBRAKE_ID" = "null" ] || [ "$AIRBRAKE_KEY" = "null" ] || [ "$NEWRELIC_LICENSE_KEY" = "null" ] || [ "$NEWRELIC_APP_NAME" = "null" ]; then + echo "ERROR: One or more monitor/logging license keys are missing" + exit 1 + fi # Write variables to .env.staging file echo "Writing environment variables to .env.staging..." @@ -140,6 +192,11 @@ fetch_env_variables() { grep -v "^DB_HOST=" ./.env.staging > ./.env.staging.tmp || true grep -v "^REDIS_URL=" ./.env.staging.tmp > ./.env.staging || true grep -v "^S3_ATTACHMENTS_BUCKET=" ./.env.staging.tmp > ./.env.staging || true + grep -v "^AIRBRAKE_ID=" ./.env.staging.tmp > ./.env.staging || true + grep -v "^AIRBRAKE_KEY=" ./.env.staging.tmp > ./.env.staging || true + grep -v "^NEWRELIC_LICENSE_KEY=" ./.env.staging.tmp > ./.env.staging || true + grep -v "^NEWRELIC_APP_NAME=" ./.env.staging.tmp > ./.env.staging || true + grep -v "^NEWRELIC_MONITOR_MODE=" ./.env.staging.tmp > ./.env.staging || true rm -f ./.env.staging.tmp fi @@ -147,6 +204,11 @@ fetch_env_variables() { echo "DB_HOST=$DB_HOST" >> ./.env.staging echo "REDIS_URL=$REDIS_URL" >> ./.env.staging echo "S3_ATTACHMENTS_BUCKET=$S3_ATTACHMENTS_BUCKET" >> ./.env.staging + echo "AIRBRAKE_ID=$AIRBRAKE_ID" >> ./.env.staging + echo "AIRBRAKE_KEY=$AIRBRAKE_KEY" >> ./.env.staging + echo "NEWRELIC_LICENSE_KEY=$NEWRELIC_LICENSE_KEY" >> ./.env.staging + echo "NEWRELIC_APP_NAME=$NEWRELIC_APP_NAME" >> ./.env.staging + echo "NEWRELIC_MONITOR_MODE=$NEWRELIC_MONITOR_MODE" >> ./.env.staging echo "✓ Environment variables successfully retrieved and written to .env.staging" } @@ -190,6 +252,9 @@ main() { # Fetch encryption key and write to config/master.key fetch_encryption_key + # Fetch allowed hosts from Secrets Manager + fetch_allowed_hosts + # Fetch other environment variables from Secrets Manager fetch_env_variables diff --git a/config/environments/production.rb b/config/environments/production.rb index 36b0bfaa..7e422baa 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -40,10 +40,6 @@ Rails.application.configure do config.active_storage.service = if ENV['S3_ATTACHMENTS_BUCKET'].present? :aws_s3 - elsif ENV['GCS_BUCKET'].present? - :google - elsif ENV['AZURE_CONTAINER'].present? - :azure else :disk end @@ -57,10 +53,10 @@ Rails.application.configure do # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] # Assume all access to the app is happening through a SSL-terminating reverse proxy. - config.assume_ssl = ENV['FORCE_SSL'].present? && ENV['FORCE_SSL'] != 'false' + config.assume_ssl = true # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - config.force_ssl = ENV['FORCE_SSL'].present? && ENV['FORCE_SSL'] != 'false' + config.force_ssl = true # Include generic and useful information about system operation, but avoid logging too much # information to avoid inadvertent exposure of personally identifiable information (PII). @@ -162,4 +158,12 @@ Rails.application.configure do raid: resource.try(:account_id) } end + + config.host_authorization = { exclude: ->(request) { request.path == '/up' } } + + # Load allowed hosts from environment variable + allowed_hosts = ENV['ALLOWED_HOSTS']&.split(',')&.map(&:strip) || ['.*\\.careerplug\\.com\\Z'] + + config.host_authorization = { exclude: ->(request) { request.path == '/up' } } + allowed_hosts.each { |host_pattern| config.hosts << Regexp.new(host_pattern) } end diff --git a/config/environments/staging.rb b/config/environments/staging.rb index 180b6005..286a868a 100644 --- a/config/environments/staging.rb +++ b/config/environments/staging.rb @@ -95,9 +95,28 @@ Rails.application.configure do # require "syslog/logger" # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") - logger = ActiveSupport::Logger.new($stdout) - logger.formatter = config.log_formatter - config.logger = ActiveSupport::TaggedLogging.new(logger) + # logger = ActiveSupport::Logger.new($stdout) + # logger.formatter = config.log_formatter + # config.logger = ActiveSupport::TaggedLogging.new(logger) + + # NEWRELIC_MONITOR_MODE enables stdout logger sync for worker/web via NR APM + if ENV['NEWRELIC_MONITOR_MODE'].presence + config.logger = ActiveSupport::TaggedLogging.new( + Logger.new($stdout) + ) + + config.active_job.logger = ActiveSupport::TaggedLogging.new( + Logger.new($stdout) + ) + else + config.logger = ActiveSupport::TaggedLogging.new( + Syslog::Logger.new('rails-main') + ) + + config.active_job.logger = ActiveSupport::TaggedLogging.new( + Syslog::Logger.new('rails-sidekiq') + ) + end encryption_secret = ENV['ENCRYPTION_SECRET'].presence || Digest::SHA256.hexdigest(ENV['SECRET_KEY_BASE'].to_s) @@ -154,11 +173,9 @@ Rails.application.configure do } end + # Load allowed hosts from environment variable + allowed_hosts = ENV['ALLOWED_HOSTS']&.split(',')&.map(&:strip) || ['.*\\.careerplug\\.com\\Z'] + config.host_authorization = { exclude: ->(request) { request.path == '/up' } } - [ - /.*\.careerplug\.org\Z/, - /.*\.careerplug\.com\Z/, - /.*\.cpstaging\d\.click\Z/, - /.*\.cpstaging\d+\.name\Z/ - ].each { |hrexp| config.hosts << hrexp } + allowed_hosts.each { |host_pattern| config.hosts << Regexp.new(host_pattern) } end diff --git a/config/initializers/airbrake.rb b/config/initializers/airbrake.rb new file mode 100644 index 00000000..ff7ef2af --- /dev/null +++ b/config/initializers/airbrake.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +unless ENV['DOCKER_BUILD'] || ENV['CI_BUILD'] + Airbrake.configure do |config| + config.project_key = ENV['AIRBRAKE_KEY'] # rubocop:disable Style/FetchEnvVar + config.project_id = ENV['AIRBRAKE_ID'] # rubocop:disable Style/FetchEnvVar + config.environment = Rails.env + config.ignore_environments = %w[development test] + config.root_directory = '/var/cpd/app' + end +end diff --git a/config/newrelic.yml b/config/newrelic.yml new file mode 100644 index 00000000..05b6041c --- /dev/null +++ b/config/newrelic.yml @@ -0,0 +1,1117 @@ +# +# This file configures the New Relic agent. New Relic monitors Ruby, Java, +# .NET, PHP, Python, Node, and Go applications with deep visibility and low +# overhead. For more information, visit www.newrelic.com. + +common: &default_settings + # Required license key associated with your New Relic account. + license_key: <%= ENV['NEWRELIC_LICENSE_KEY'] %> + + # Your application name. Renaming here affects where data displays in New + # Relic. For more details, see https://docs.newrelic.com/docs/apm/new-relic-apm/maintenance/renaming-applications + app_name: <%= ENV['NEWRELIC_APP_NAME'] %> + + # To disable the agent regardless of other settings, uncomment the following: + # agent_enabled: false + + # Logging level for log/newrelic_agent.log; options are error, warn, info, or + # debug. + log_level: warn + + # All of the following configuration options are optional. Review them, and + # uncomment or edit them if they appear relevant to your application needs. + + # An array of ActiveSupport custom event names to subscribe to and instrument. + # For example, + # - one.custom.event + # - another.event + # - a.third.event + # active_support_custom_events_names: [] + + # If false, all LLM instrumentation (OpenAI only for now) will be disabled and + # no metrics, events, or spans will be sent. AI Monitoring is automatically + # disabled if high_security mode is enabled. + # ai_monitoring.enabled: false + + # If false, LLM instrumentation (OpenAI only for now) will not capture input and + # output content on specific LLM events. + # + # The excluded attributes include: + # - content from LlmChatCompletionMessage events + # - input from LlmEmbedding events + # + # This is an optional security setting to prevent recording sensitive data sent + # to and received from your LLMs. + # ai_monitoring.record_content.enabled: true + + # If true, enables capture of all HTTP request headers for all destinations. + # allow_all_headers: false + + # Your New Relic userKey. Required when using the New Relic REST API v2 to + # record deployments using the newrelic deployments command. + # api_key: "" + + # If true, enables log decoration and the collection of log events and metrics. + application_logging.enabled: true + + # A hash with key/value pairs to add as custom attributes to all log events + # forwarded to New Relic. If sending using an environment variable, the value + # must be formatted like: "key1=value1,key2=value2" + # NOTE: We can add custom attributes HERE. + # application_logging.forwarding.custom_attributes: { + # user_id: current_user&.id + # } + + # If true, the agent captures log records emitted by your application. + application_logging.forwarding.enabled: true + + # If true, the agent attaches labels to log records. + # application_logging.forwarding.labels.enabled: false + + # A case-insensitive array or comma-delimited string containing the labels to + # exclude from log records. + # application_logging.forwarding.labels.exclude: [] + + # Sets the minimum level a log event must have to be forwarded to New Relic. + # + # This is based on the integer values of Ruby's Logger::Severity constants. + # + # The intention is to forward logs with the level given to the configuration, as + # well as any logs with a higher level of severity. + # + # For example, setting this value to "debug" will forward all log events to New + # Relic. Setting this value to "error" will only forward log events with the + # levels "error", "fatal", and "unknown". + # + # Valid values (ordered lowest to highest): + # - "debug" + # - "info" + # - "warn" + # - "error" + # - "fatal" + # - "unknown" + application_logging.forwarding.log_level: warn + + # Defines the maximum number of log records to buffer in memory at a time. + # application_logging.forwarding.max_samples_stored: 10000 + + # If true, the agent decorates logs with metadata to link to entities, hosts, + # traces, and spans. + # application_logging.local_decorating.enabled: false + + # If true, the agent captures metrics related to logging for your application. + # application_logging.metrics.enabled: true + + # If true, enables capture of attributes for all destinations. + # attributes.enabled: true + + # Prefix of attributes to exclude from all destinations. Allows * as wildcard at + # end. + # attributes.exclude: [] + + # Prefix of attributes to include in all destinations. Allows * as wildcard at + # end. + # attributes.include: [] + + # If true, enables an audit log which logs communications with the New Relic + # collector. + # audit_log.enabled: false + + # List of allowed endpoints to include in audit log. + # audit_log.endpoints: [".*"] + + # Specifies a path to the audit log file (including the filename). + # audit_log.path: log/newrelic_audit.log + + # An array of CLASS#METHOD (for instance methods) and/or CLASS.METHOD (for class + # methods) strings representing Ruby methods that the agent can automatically + # add custom instrumentation to. This doesn't require any modifications of the + # source code that defines the methods. + # + # Use fully qualified class names (using the :: delimiter) that include any + # module or class namespacing. + # + # Here is some Ruby source code that defines a render_png instance method for an + # Image class and a notify class method for a User class, both within a + # MyCompany module namespace: + # + # module MyCompany + # class Image + # def render_png + # # code to render a PNG + # end + # end + # + # class User + # def self.notify + # # code to notify users + # end + # end + # end + # + # + # Given that source code, the newrelic.yml config file might request + # instrumentation for both of these methods like so: + # + # automatic_custom_instrumentation_method_list: + # - MyCompany::Image#render_png + # - MyCompany::User.notify + # + # + # That configuration example uses YAML array syntax to specify both methods. + # Alternatively, you can use a comma-delimited string: + # + # automatic_custom_instrumentation_method_list: 'MyCompany::Image#render_png, + # MyCompany::User.notify' + # + # + # Whitespace around the comma(s) in the list is optional. When configuring the + # agent with a list of methods via the + # NEW_RELIC_AUTOMATIC_CUSTOM_INSTRUMENTATION_METHOD_LIST environment variable, + # use this comma-delimited string format: + # + # export + # NEW_RELIC_AUTOMATIC_CUSTOM_INSTRUMENTATION_METHOD_LIST='MyCompany::Image#render_png, + # MyCompany::User.notify' + # automatic_custom_instrumentation_method_list: [] + + # Specify a list of constants that should prevent the agent from starting + # automatically. Separate individual constants with a comma ,. For example, + # "Rails::Console,UninstrumentedBackgroundJob". + # autostart.denylisted_constants: Rails::Command::ConsoleCommand,Rails::Command::CredentialsCommand,Rails::Command::Db::System::ChangeCommand,Rails::Command::DbConsoleCommand,Rails::Command::DestroyCommand,Rails::Command::DevCommand,Rails::Command::EncryptedCommand,Rails::Command::GenerateCommand,Rails::Command::InitializersCommand,Rails::Command::NotesCommand,Rails::Command::RoutesCommand,Rails::Command::RunnerCommand,Rails::Command::SecretsCommand,Rails::Console,Rails::DBConsole + + # Defines a comma-delimited list of executables that the agent should not + # instrument. For example, "rake,my_ruby_script.rb". + # autostart.denylisted_executables: irb,rspec + + # Defines a comma-delimited list of Rake tasks that the agent should not + # instrument. For example, "assets:precompile,db:migrate". + # autostart.denylisted_rake_tasks: about,assets:clean,assets:clobber,assets:environment,assets:precompile,assets:precompile:all,db:create,db:drop,db:fixtures:load,db:migrate,db:migrate:status,db:rollback,db:schema:cache:clear,db:schema:cache:dump,db:schema:dump,db:schema:load,db:seed,db:setup,db:structure:dump,db:version,doc:app,log:clear,middleware,notes,notes:custom,rails:template,rails:update,routes,secret,spec,spec:features,spec:requests,spec:controllers,spec:helpers,spec:models,spec:views,spec:routing,spec:rcov,stats,test,test:all,test:all:db,test:recent,test:single,test:uncommitted,time:zones:all,tmp:clear,tmp:create,webpacker:compile + + # Backports the faster ActiveRecord connection lookup introduced in Rails 6, + # which improves agent performance when instrumenting ActiveRecord. Note that + # this setting may not be compatible with other gems that patch ActiveRecord. + # backport_fast_active_record_connection_lookup: false + + # If true, the agent captures attributes from browser monitoring. + # browser_monitoring.attributes.enabled: false + + # Prefix of attributes to exclude from browser monitoring. Allows * as wildcard + # at end. + # browser_monitoring.attributes.exclude: [] + + # Prefix of attributes to include in browser monitoring. Allows * as wildcard at + # end. + # browser_monitoring.attributes.include: [] + + # If true, enables auto-injection of the JavaScript header for page load timing + # (sometimes referred to as real user monitoring or RUM). + # browser_monitoring.auto_instrument: true + + # If true, enables auto-injection of Content Security Policy Nonce in browser + # monitoring scripts. For now, auto-injection only works with Rails 5.2+. + # browser_monitoring.content_security_policy_nonce: true + + # Manual override for the path to your local CA bundle. This CA bundle validates + # the SSL certificate presented by New Relic's data collection service. + # ca_bundle_path: nil + + # Enable or disable the capture of memcache keys from transaction traces. + # capture_memcache_keys: false + + # When true, the agent captures HTTP request parameters and attaches them to + # transaction traces, traced errors, and TransactionError events. + # + # When using the capture_params setting, the Ruby agent will not attempt to + # filter secret information. Recommendation: To filter secret information from + # request parameters, use the attributes.include setting instead. For more + # information, see the Ruby attribute examples. + # capture_params: false + + # If true, the agent will clear Tracer::State in Agent.drop_buffered_data. + # clear_transaction_state_after_fork: false + + # The AWS account ID for the AWS account associated with this app + # cloud.aws.account_id: nil + + # If true, the agent will report source code level metrics for traced methods. + # See: + # https://docs.newrelic.com/docs/apm/agents/ruby-agent/features/ruby-codestream-integration/ + # code_level_metrics.enabled: true + + # Path to newrelic.yml. If undefined, the agent checks the following directories + # (in order): + # - config/newrelic.yml + # - newrelic.yml + # - $HOME/.newrelic/newrelic.yml + # - $HOME/newrelic.yml + # config_path: newrelic.yml + + # If false, custom attributes will not be sent on events. + # custom_attributes.enabled: true + + # If true, the agent captures custom events. + # custom_insights_events.enabled: true + + # - Specify a maximum number of custom events to buffer in memory at a time. + # - When configuring the agent for AI monitoring, set to max value 100000. + # This ensures the agent captures the maximum amount of LLM events. + # custom_insights_events.max_samples_stored: 3000 + + # If false, the agent will not add database_name parameter to transaction or + # slow sql traces. + # datastore_tracer.database_name_reporting.enabled: true + + # If false, the agent will not report datastore instance metrics, nor add host + # or port_path_or_id parameters to transaction or slow SQL traces. + # datastore_tracer.instance_reporting.enabled: true + + # If true, disables Action Cable instrumentation. + # disable_action_cable_instrumentation: false + + # If true, disables Action Controller instrumentation. + # disable_action_controller: false + + # If true, disables Action Mailbox instrumentation. + # disable_action_mailbox: false + + # If true, disables Action Mailer instrumentation. + # disable_action_mailer: false + + # If true, disables Active Record instrumentation. + # disable_active_record_instrumentation: false + + # If true, disables instrumentation for Active Record 4+ + # disable_active_record_notifications: false + + # If true, disables Active Storage instrumentation. + # disable_active_storage: false + + # If true, disables Active Support instrumentation. + # disable_active_support: false + + # If true, disables Active Job instrumentation. + # disable_activejob: false + + # If true, the agent won't sample the CPU usage of the host process. + # disable_cpu_sampler: false + + # If true, the agent won't measure the depth of Delayed Job queues. + # disable_delayed_job_sampler: false + + # If true, disables the use of GC::Profiler to measure time spent in garbage + # collection + # disable_gc_profiler: false + + # If true, the agent won't sample the memory usage of the host process. + # disable_memory_sampler: false + + # If true, the agent won't wrap third-party middlewares in instrumentation + # (regardless of whether they are installed via Rack::Builder or Rails). + # + # When middleware instrumentation is disabled, if an application is using + # middleware that could alter the response code, the HTTP status code reported + # on the transaction may not reflect the altered value. + # disable_middleware_instrumentation: false + + # If true, disables agent middleware for Roda. This middleware is responsible + # for advanced feature support such as page load timing and error collection. + # disable_roda_auto_middleware: false + + # If true, disables the collection of sampler metrics. Sampler metrics are + # metrics that are not event-based (such as CPU time or memory usage). + # disable_samplers: false + + # If true, disables Sequel instrumentation. + # disable_sequel_instrumentation: false + + # If true, disables Sidekiq instrumentation. + # disable_sidekiq: false + + # If true, disables agent middleware for Sinatra. This middleware is responsible + # for advanced feature support such as cross application tracing, page load + # timing, and error collection. + # + # Cross application tracing is deprecated in favor of distributed tracing. + # Distributed tracing is on by default for Ruby agent versions 8.0.0 and above. + # Middlewares are not required to support distributed tracing. + # + # To continue using cross application tracing, update the following options in + # your newrelic.yml configuration file: + # + # cross_application_tracer: + # enabled: true + # distributed_tracing: + # enabled: false + # disable_sinatra_auto_middleware: false + + # If true, disables view instrumentation. + # disable_view_instrumentation: false + + # If true, the agent won't sample performance measurements from the Ruby VM. + # disable_vm_sampler: false + + # Distributed tracing lets you see the path that a request takes through your + # distributed system. Enabling distributed tracing changes the behavior of some + # New Relic features, so carefully consult the transition guide before you + # enable this feature. + # distributed_tracing.enabled: true + + # This setting controls the behavior of transaction sampling when a remote + # parent is not sampled and the trace flag is not set in the traceparent. + # Available values are default, always_on, and always_off. + # distributed_tracing.sampler.remote_parent_not_sampled: default + + # This setting controls the behavior of transaction sampling when a remote + # parent is sampled and the trace flag is set in the traceparent. Available + # values are default, always_on, and always_off. + # distributed_tracing.sampler.remote_parent_sampled: default + + # If true, the agent captures the Elasticsearch cluster name in transaction + # traces. + # elasticsearch.capture_cluster_name: true + + # If true, the agent captures Elasticsearch queries in transaction traces. + # elasticsearch.capture_queries: true + + # If true, the agent obfuscates Elasticsearch queries in transaction traces. + # elasticsearch.obfuscate_queries: true + + # If true, the agent captures attributes from error collection. + # error_collector.attributes.enabled: true + + # Prefix of attributes to exclude from error collection. Allows * as wildcard at + # end. + # error_collector.attributes.exclude: [] + + # Prefix of attributes to include in error collection. Allows * as wildcard at + # end. + # error_collector.attributes.include: [] + + # If true, the agent collects TransactionError events. + error_collector.capture_events: true + + # If true, the agent captures traced errors and error count metrics. + error_collector.enabled: true + + # A list of error classes that the agent should treat as expected. + # This option can't be set via environment variable. + # error_collector.expected_classes: [] + + # A map of error classes to a list of messages. When an error of one of the + # classes specified here occurs, if its error message contains one of the + # strings corresponding to it here, that error will be treated as expected. + # This option can't be set via environment variable. + # error_collector.expected_messages: {} + + # A comma separated list of status codes, possibly including ranges. Errors + # associated with these status codes, where applicable, will be treated as + # expected. + # error_collector.expected_status_codes: "" + + # A list of error classes that the agent should ignore. + # This option can't be set via environment variable. + # error_collector.ignore_classes: ["ActionController::RoutingError", "Sinatra::NotFound"] + + # A map of error classes to a list of messages. When an error of one of the + # classes specified here occurs, if its error message contains one of the + # strings corresponding to it here, that error will be ignored. + # This option can't be set via environment variable. + # error_collector.ignore_messages: {ThreadError: ["queue empty"]} + + # A comma separated list of status codes, possibly including ranges. Errors + # associated with these status codes, where applicable, will be ignored. + # error_collector.ignore_status_codes: "" + + # Defines the maximum number of frames in an error backtrace. Backtraces over + # this amount are truncated in the middle, preserving the beginning and the end + # of the stack trace. + error_collector.max_backtrace_frames: 50 + + # Defines the maximum number of TransactionError events reported per harvest + # cycle. + error_collector.max_event_samples_stored: 100 + + # Allows newrelic distributed tracing headers to be suppressed on outbound + # requests. + # exclude_newrelic_header: false + + # The exit handler that sends all cached data to the collector before shutting + # down is forcibly installed. This is true even when it detects scenarios where + # it generally should not be. The known use case for this option is when Sinatra + # runs as an embedded service within another framework. The agent detects the + # Sinatra app and skips the at_exit handler as a result. Sinatra classically + # runs the entire application in an at_exit block and would otherwise misbehave + # if the agent's at_exit handler was also installed in those circumstances. + # Note: send_data_on_exit should also be set to true in tandem with this + # setting. + # force_install_exit_handler: false + + # If true, enables high security mode. Ensure you understand the implications of + # high security mode before enabling this setting. + # high_security: false + + # If true (the default), data sent to the trace observer is batched instead of + # sending each span individually. + # infinite_tracing.batching: true + + # Configure the compression level for data sent to the trace observer. May be + # one of: :none, :low, :medium, :high. Set the level to :none to disable + # compression. + # infinite_tracing.compression_level: high + + # Configures the hostname for the trace observer Host. When configured, enables + # tail-based sampling by sending all recorded spans to a trace observer for + # further sampling decisions, irrespective of any usual agent sampling decision. + # infinite_tracing.trace_observer.host: "" + + # Configures the TCP/IP port for the trace observer Host + # infinite_tracing.trace_observer.port: 443 + + # Controls auto-instrumentation of ActiveSupport::BroadcastLogger at start up. + # May be one of: auto, prepend, chain, disabled. Used in Rails versions >= 7.1. + # instrumentation.active_support_broadcast_logger: auto + + # Controls auto-instrumentation of ActiveSupport::Logger at start up. May be one + # of: auto, prepend, chain, disabled. Used in Rails versions below 7.1. + # instrumentation.active_support_logger: auto + + # Controls auto-instrumentation of Async::HTTP at start up. May be one of: auto, + # prepend, chain, disabled. + # instrumentation.async_http: auto + + # Controls auto-instrumentation of the aws-sdk-firehose library at start-up. May + # be one of auto, prepend, chain, disabled. + # instrumentation.aws_sdk_firehose: auto + + # Controls auto-instrumentation of the aws-sdk-kinesis library at start-up. May + # be one of auto, prepend, chain, disabled. + # instrumentation.aws_sdk_kinesis: auto + + # Controls auto-instrumentation of the aws_sdk_lambda library at start-up. May + # be one of auto, prepend, chain, disabled. + # instrumentation.aws_sdk_lambda: auto + + # Controls auto-instrumentation of the aws-sdk-sqs library at start-up. May be + # one of: auto, prepend, chain, disabled. + # instrumentation.aws_sqs: auto + + # Controls auto-instrumentation of bunny at start-up. May be one of: auto, + # prepend, chain, disabled. + # instrumentation.bunny: auto + + # Controls auto-instrumentation of the concurrent-ruby library at start-up. May + # be one of: auto, prepend, chain, disabled. + # instrumentation.concurrent_ruby: auto + + # Controls auto-instrumentation of Curb at start-up. May be one of: auto, + # prepend, chain, disabled. + # instrumentation.curb: auto + + # Controls auto-instrumentation of Delayed Job at start-up. May be one of: auto, + # prepend, chain, disabled. + # instrumentation.delayed_job: auto + + # Controls auto-instrumentation of the aws-sdk-dynamodb library at start-up. May + # be one of auto, prepend, chain, disabled. + # instrumentation.dynamodb: auto + + # Controls auto-instrumentation of the elasticsearch library at start-up. May be + # one of: auto, prepend, chain, disabled. + # instrumentation.elasticsearch: auto + + # Controls auto-instrumentation of ethon at start up. May be one of auto, + # prepend, chain, disabled + # instrumentation.ethon: auto + + # Controls auto-instrumentation of Excon at start-up. May be one of: enabled, + # disabled. + # instrumentation.excon: enabled + + # Controls auto-instrumentation of the Fiber class at start-up. May be one of: + # auto, prepend, chain, disabled. + # instrumentation.fiber: auto + + # Controls auto-instrumentation of Grape at start-up. May be one of: auto, + # prepend, chain, disabled. + # instrumentation.grape: auto + + # Specifies a list of hostname patterns separated by commas that will match gRPC + # hostnames that traffic is to be ignored by New Relic for. New Relic's gRPC + # client instrumentation will ignore traffic streamed to a host matching any of + # these patterns, and New Relic's gRPC server instrumentation will ignore + # traffic for a server running on a host whose hostname matches any of these + # patterns. By default, no traffic is ignored when gRPC instrumentation is + # itself enabled. For example, "private.com$,exception.*" + # instrumentation.grpc.host_denylist: [] + + # Controls auto-instrumentation of gRPC clients at start-up. May be one of: + # auto, prepend, chain, disabled. + # instrumentation.grpc_client: auto + + # Controls auto-instrumentation of gRPC servers at start-up. May be one of: + # auto, prepend, chain, disabled. + # instrumentation.grpc_server: auto + + # Controls auto-instrumentation of HTTPClient at start-up. May be one of: auto, + # prepend, chain, disabled. + # instrumentation.httpclient: auto + + # Controls auto-instrumentation of http.rb gem at start-up. May be one of: auto, + # prepend, chain, disabled. + # instrumentation.httprb: auto + + # Controls auto-instrumentation of httpx at start up. May be one of auto, + # prepend, chain, disabled + # instrumentation.httpx: auto + + # Controls auto-instrumentation of Ruby standard library Logger at start-up. May + # be one of: auto, prepend, chain, disabled. + # instrumentation.logger: auto + + # Controls auto-instrumentation of the LogStasher library at start-up. May be + # one of: auto, prepend, chain, disabled. + # instrumentation.logstasher: auto + + # Controls auto-instrumentation of dalli gem for Memcache at start-up. May be + # one of: auto, prepend, chain, disabled. + # instrumentation.memcache: auto + + # Controls auto-instrumentation of memcache-client gem for Memcache at start-up. + # May be one of: auto, prepend, chain, disabled. + # instrumentation.memcache_client: auto + + # Controls auto-instrumentation of memcached gem for Memcache at start-up. May + # be one of: auto, prepend, chain, disabled. + # instrumentation.memcached: auto + + # Controls auto-instrumentation of Mongo at start-up. May be one of: enabled, + # disabled. + # instrumentation.mongo: enabled + + # Controls auto-instrumentation of Net::HTTP at start-up. May be one of: auto, + # prepend, chain, disabled. + instrumentation.net_http: prepend + + # Controls auto-instrumentation of the opensearch-ruby library at start-up. May + # be one of auto, prepend, chain, disabled. + # instrumentation.opensearch: auto + + # Controls auto-instrumentation of Puma::Rack. When enabled, the agent hooks + # into the to_app method in Puma::Rack::Builder to find gems to instrument + # during application startup. May be one of: auto, prepend, chain, disabled. + # instrumentation.puma_rack: auto + + # Controls auto-instrumentation of Puma::Rack::URLMap at start-up. May be one + # of: auto, prepend, chain, disabled. + # instrumentation.puma_rack_urlmap: auto + + # Controls auto-instrumentation of Rack. When enabled, the agent hooks into the + # to_app method in Rack::Builder to find gems to instrument during application + # startup. May be one of: auto, prepend, chain, disabled. + # instrumentation.rack: auto + + # Controls auto-instrumentation of Rack::URLMap at start-up. May be one of: + # auto, prepend, chain, disabled. + # instrumentation.rack_urlmap: auto + + # Controls auto-instrumentation of rake at start-up. May be one of: auto, + # prepend, chain, disabled. + # instrumentation.rake: auto + + # Controls auto-instrumentation of the rdkafka library at start-up. May be one + # of auto, prepend, chain, disabled. + # instrumentation.rdkafka: auto + + # Controls auto-instrumentation of Redis at start-up. May be one of: auto, + # prepend, chain, disabled. + # instrumentation.redis: auto + + # Controls auto-instrumentation of resque at start-up. May be one of: auto, + # prepend, chain, disabled. + # instrumentation.resque: auto + + # Controls auto-instrumentation of Roda at start-up. May be one of: auto, + # prepend, chain, disabled. + # instrumentation.roda: auto + + # Controls auto-instrumentation of the ruby-kafka library at start-up. May be + # one of auto, prepend, chain, disabled. + # instrumentation.ruby_kafka: auto + + # Controls auto-instrumentation of the ruby-openai gem at start-up. May be one + # of: auto, prepend, chain, disabled. Defaults to disabled in high security + # mode. + # instrumentation.ruby_openai: auto + + # Controls auto-instrumentation of Sinatra at start-up. May be one of: auto, + # prepend, chain, disabled. + # instrumentation.sinatra: auto + + # Controls auto-instrumentation of Stripe at startup. May be one of: enabled, + # disabled. + # instrumentation.stripe: enabled + + # Controls auto-instrumentation of the Thread class at start-up to allow the + # agent to correctly nest spans inside of an asynchronous transaction. This does + # not enable the agent to automatically trace all threads created (see + # instrumentation.thread.tracing). May be one of: auto, prepend, chain, + # disabled. + # instrumentation.thread: auto + + # Controls auto-instrumentation of the Thread class at start-up to automatically + # add tracing to all Threads created in the application. + instrumentation.thread.tracing: false + + # Controls auto-instrumentation of the Tilt template rendering library at + # start-up. May be one of: auto, prepend, chain, disabled. + # instrumentation.tilt: auto + + # Controls auto-instrumentation of Typhoeus at start-up. May be one of: auto, + # prepend, chain, disabled. + # instrumentation.typhoeus: auto + + # Controls auto-instrumentation of ViewComponent at startup. May be one of: + # auto, prepend, chain, disabled. + # instrumentation.view_component: auto + + # A dictionary of label names and values that will be applied to the data sent + # from this agent. May also be expressed as a semicolon-delimited ; string of + # colon-separated : pairs. For example, Server:One;Data Center:Primary. + # labels: "" + + # Defines a name for the log file. + # log_file_name: newrelic_agent.log + + # Defines a path to the agent log file, excluding the filename. + # log_file_path: log/ + + # Specifies a marshaller for transmitting data to the New Relic collector. + # Currently json is the only valid value for this setting. + # marshaller: json + + # If true, the agent will collect metadata about messages and attach them as + # segment parameters. + # message_tracer.segment_parameters.enabled: true + + # If true, the agent captures Mongo queries in transaction traces. + # mongo.capture_queries: true + + # If true, the agent obfuscates Mongo queries in transaction traces. + # mongo.obfuscate_queries: true + + # When true, the agent transmits data about your app to the New Relic collector. + # monitor_mode: true + + # If true, the agent captures OpenSearch queries in transaction traces. + # opensearch.capture_queries: true + + # If true, the agent obfuscates OpenSearch queries in transaction traces. + # opensearch.obfuscate_queries: true + + # If true, uses Module#prepend rather than alias_method for ActiveRecord + # instrumentation. + # prepend_active_record_instrumentation: false + + # Specify a custom host name for display in the New Relic UI. + # process_host.display_name: default hostname + + # Defines a host for communicating with the New Relic collector via a proxy + # server. + # proxy_host: nil + + # Defines a password for communicating with the New Relic collector via a proxy + # server. + # proxy_pass: nil + + # Defines a port for communicating with the New Relic collector via a proxy + # server. + # proxy_port: 8080 + + # Defines a user for communicating with the New Relic collector via a proxy + # server. + # proxy_user: nil + + # Timeout for waiting on connect to complete before a rake task + # rake.connect_timeout: 10 + + # Specify an Array of Rake tasks to automatically instrument. This configuration + # option converts the Array to a RegEx list. If you'd like to allow all tasks by + # default, use rake.tasks: [.+]. No rake tasks will be instrumented unless + # they're added to this list. For more information, visit the New Relic Rake + # Instrumentation docs. + # rake.tasks: [] + + # Define transactions you want the agent to ignore, by specifying a list of + # patterns matching the URI you want to ignore. For more detail, see the docs on + # ignoring specific transactions. + # rules.ignore_url_regexes: [] + + # Applies Language Agent Security Policy settings. + # security_policies_token: "" + + # If true, enables the exit handler that sends data to the New Relic collector + # before shutting down. + # send_data_on_exit: true + + # If true, the agent will operate in a streamlined mode suitable for use with + # short-lived serverless functions. NOTE: Only AWS Lambda functions are + # supported currently and this option isn't intended for use without New Relic's + # Ruby Lambda layer offering. + # serverless_mode.enabled: false + + # An array of strings that will collectively serve as a denylist for filtering + # which Sidekiq job arguments get reported to New Relic. To capture any Sidekiq + # arguments, 'job.sidekiq.args.*' must be added to the separate + # :'attributes.include' configuration option. Each string in this array will be + # turned into a regular expression via Regexp.new to permit advanced matching. + # For job argument hashes, if either a key or value matches the pair will be + # excluded. All matching job argument array elements and job argument scalars + # will be excluded. + # sidekiq.args.exclude: [] + + # An array of strings that will collectively serve as an allowlist for filtering + # which Sidekiq job arguments get reported to New Relic. To capture any Sidekiq + # arguments, 'job.sidekiq.args.*' must be added to the separate + # :'attributes.include' configuration option. Each string in this array will be + # turned into a regular expression via Regexp.new to permit advanced matching. + # For job argument hashes, if either a key or value matches the pair will be + # included. All matching job argument array elements and job argument scalars + # will be included. + # sidekiq.args.include: [] + + # If true, the agent collects slow SQL queries. + # slow_sql.enabled: true + + # If true, the agent collects explain plans in slow SQL queries. If this setting + # is omitted, the transaction_tracer.explain_enabled setting will be applied as + # the default setting for explain plans in slow SQL as well. + # slow_sql.explain_enabled: true + + # Specify a threshold in seconds. The agent collects slow SQL queries and + # explain plans that exceed this threshold. + # slow_sql.explain_threshold: 0.5 + + # Defines an obfuscation level for slow SQL queries. Valid options are + # obfuscated, raw, or none. + # slow_sql.record_sql: obfuscated + + # Generate a longer sql_id for slow SQL traces. sql_id is used for aggregation + # of similar queries. + # slow_sql.use_longer_sql_id: false + + # If true, the agent captures attributes on span events. + # span_events.attributes.enabled: true + + # Prefix of attributes to exclude from span events. Allows * as wildcard at end. + # span_events.attributes.exclude: [] + + # Prefix of attributes to include on span events. Allows * as wildcard at end. + # span_events.attributes.include: [] + + # If true, enables span event sampling. + # span_events.enabled: true + + # - Defines the maximum number of span events reported from a single harvest. + # Any Integer between 1 and 10000 is valid.' + # - When configuring the agent for AI monitoring, set to max value 10000.This + # ensures the agent captures the maximum amount of distributed traces. + # span_events.max_samples_stored: 2000 + + # Sets the maximum number of span events to buffer when streaming to the trace + # observer. + # span_events.queue_size: 10000 + + # Specify a list of exceptions you do not want the agent to strip when + # strip_exception_messages is true. Separate exceptions with a comma. For + # example, "ImportantException,PreserveMessageException". + # strip_exception_messages.allowed_classes: "" + + # If true, the agent strips messages from all exceptions except those in the + # allowed classes list. Enabled automatically in high security mode. + # strip_exception_messages.enabled: false + + # An array of strings to specify which keys and/or values inside a Stripe + # event's user_data hash should + # not be reported to New Relic. Each string in this array will be turned into a + # regular expression via + # Regexp.new to permit advanced matching. For each hash pair, if either the key + # or value is matched the pair + # isn't reported. By default, no user_data is reported. Use this option only if + # the + # stripe.user_data.include option is also used. + # stripe.user_data.exclude: [] + + # An array of strings to specify which keys inside a Stripe event's user_data + # hash should be reported + # to New Relic. Each string in this array will be turned into a regular + # expression via Regexp.new to + # enable advanced matching. Setting the value to ["."] will report all + # user_data. + # stripe.user_data.include: [] + + # When set to true, forces a synchronous connection to the New Relic collector + # during application startup. For very short-lived processes, this helps ensure + # the New Relic agent has time to report. + # sync_startup: false + + # If true, tracer state storage is thread-local, otherwise, fiber-local + # thread_local_tracer_state: false + + # If true, enables use of the thread profiler. + # thread_profiler.enabled: false + + # Defines the maximum number of seconds the agent should spend attempting to + # connect to the collector. + # timeout: 120 + + # If true, the agent captures attributes from transaction events. + # transaction_events.attributes.enabled: true + + # Prefix of attributes to exclude from transaction events. Allows * as wildcard + # at end. + # transaction_events.attributes.exclude: [] + + # Prefix of attributes to include in transaction events. Allows * as wildcard at + # end. + # transaction_events.attributes.include: [] + + # If true, enables transaction event sampling. + # transaction_events.enabled: true + + # Defines the maximum number of transaction events reported from a single + # harvest. + # transaction_events.max_samples_stored: 1200 + + # If true, the agent captures attributes on transaction segments. + # transaction_segments.attributes.enabled: true + + # Prefix of attributes to exclude from transaction segments. Allows * as + # wildcard at end. + # transaction_segments.attributes.exclude: [] + + # Prefix of attributes to include on transaction segments. Allows * as wildcard + # at end. + # transaction_segments.attributes.include: [] + + # If true, the agent captures attributes from transaction traces. + # transaction_tracer.attributes.enabled: true + + # Prefix of attributes to exclude from transaction traces. Allows * as wildcard + # at end. + # transaction_tracer.attributes.exclude: [] + + # Prefix of attributes to include in transaction traces. Allows * as wildcard at + # end. + # transaction_tracer.attributes.include: [] + + # If true, enables collection of transaction traces. + # transaction_tracer.enabled: true + + # If true, enables the collection of explain plans in transaction traces. This + # setting will also apply to explain plans in slow SQL traces if + # slow_sql.explain_enabled isn't set separately. + # transaction_tracer.explain_enabled: true + + # Threshold (in seconds) above which the agent will collect explain plans. + # Relevant only when explain_enabled is true. + # transaction_tracer.explain_threshold: 0.5 + + # Maximum number of transaction trace nodes to record in a single transaction + # trace. + # transaction_tracer.limit_segments: 4000 + + # If true, the agent records Redis command arguments in transaction traces. + # transaction_tracer.record_redis_arguments: false + + # Obfuscation level for SQL queries reported in transaction trace nodes. + # By default, this is set to obfuscated, which strips out the numeric and string + # literals. + # - If you do not want the agent to capture query information, set this to none. + # - If you want the agent to capture all query information in its original form, + # set this to raw. + # - When you enable high security mode, this is automatically set to obfuscated. + # transaction_tracer.record_sql: obfuscated + + # Specify a threshold in seconds. The agent includes stack traces in transaction + # trace nodes when the stack trace duration exceeds this threshold. + # transaction_tracer.stack_trace_threshold: 0.5 + + # Specify a threshold in seconds. Transactions with a duration longer than this + # threshold are eligible for transaction traces. Specify a float value or the + # string apdex_f. + # transaction_tracer.transaction_threshold: 1.0 + + # If true, the agent automatically detects that it is running in an AWS + # environment. + # utilization.detect_aws: true + + # If true, the agent automatically detects that it is running in an Azure + # environment. + # utilization.detect_azure: true + + # If true, the agent automatically detects that it is running in Docker. + # utilization.detect_docker: true + + # If true, the agent automatically detects that it is running in an Google Cloud + # Platform environment. + # utilization.detect_gcp: true + + # If true, the agent automatically detects that it is running in Kubernetes. + # utilization.detect_kubernetes: true + + # If true, the agent automatically detects that it is running in a Pivotal Cloud + # Foundry environment. + # utilization.detect_pcf: true + + # BEGIN security agent + # + # NOTE: At this time, the security agent is intended for use only within + # a dedicated security testing environment with data that can tolerate + # modification or deletion. The security agent is available as a + # separate Ruby gem, newrelic_security. It is recommended that this + # separate gem only be introduced to a security testing environment + # by leveraging Bundler grouping like so: + # + # # Gemfile + # gem 'newrelic_rpm' # New Relic APM observability agent + # gem 'newrelic-infinite_tracing' # New Relic Infinite Tracing + # + # group :security do + # gem 'newrelic_security', require: false # New Relic security agent + # end + # + # NOTE: All "security.*" configuration parameters are related only to the + # security agent, and all other configuration parameters that may + # have "security" in the name somewhere are related to the APM agent. + + # If true, the security agent is loaded (a Ruby 'require' is performed) + # security.agent.enabled: false + + # The port the application is listening on. This setting is mandatory for + # Passenger servers. The agent detects other servers by default. + # security.application_info.port: nil + + # If true, the security agent is started (the agent runs in its event loop) + # security.enabled: false + + # Defines API paths the security agent should ignore in IAST scans. Accepts an + # array of regex patterns matching the URI to ignore. The regex pattern should + # find a complete match for the URL without the endpoint. For example, + # [".*account.*"], [".*/\api\/v1\/.*?\/login"] + # security.exclude_from_iast_scan.api: [] + + # An array of HTTP request body keys the security agent should ignore in IAST + # scans. + # security.exclude_from_iast_scan.http_request_parameters.body: [] + + # An array of HTTP request headers the security agent should ignore in IAST + # scans. The array should specify a list of patterns matching the headers to + # ignore. + # security.exclude_from_iast_scan.http_request_parameters.header: [] + + # An array of HTTP request query parameters the security agent should ignore in + # IAST scans. The array should specify a list of patterns matching the HTTP + # request query parameters to ignore. + # security.exclude_from_iast_scan.http_request_parameters.query: [] + + # If true, disables system command injection detection in IAST scans. + # security.exclude_from_iast_scan.iast_detection_category.command_injection: false + + # If true, disables the detection of low-severity insecure settings. For + # example, hash, crypto, cookie, random generators, trust boundary). + # security.exclude_from_iast_scan.iast_detection_category.insecure_settings: false + + # If true, disables file operation-related IAST detections (File Access & + # Application integrity violation) + # security.exclude_from_iast_scan.iast_detection_category.invalid_file_access: false + + # If true, disables Javascript injection detection in IAST scans. + # security.exclude_from_iast_scan.iast_detection_category.javascript_injection: false + + # If true, disables LDAP injection detection in IAST scans. + # security.exclude_from_iast_scan.iast_detection_category.ldap_injection: false + + # If true, disables NOSQL injection detection in IAST scans. + # security.exclude_from_iast_scan.iast_detection_category.nosql_injection: false + + # If true, disables Reflected Cross-Site Scripting (RXSS) detection in IAST + # scans. + # security.exclude_from_iast_scan.iast_detection_category.rxss: false + + # If true, disables SQL injection detection in IAST scans. + # security.exclude_from_iast_scan.iast_detection_category.sql_injection: false + + # If true, disables Sever-Side Request Forgery (SSRF) detection in IAST scans. + # security.exclude_from_iast_scan.iast_detection_category.ssrf: false + + # If true, disables XPATH injection detection in IAST scans. + # security.exclude_from_iast_scan.iast_detection_category.xpath_injection: false + + # A unique test identifier when runnning IAST in a CI/CD environment to + # differentiate between different test runs. For example, a build number. + # security.iast_test_identifier: nil + + # Defines the mode for the security agent to operate in. Currently only IAST is + # supported + # security.mode: IAST + + # Sets the maximum number of HTTP requests allowed for the IAST scan per minute. + # Any Integer between 12 and 3600 is valid. The default value is 3600. + # security.scan_controllers.iast_scan_request_rate_limit: 3600 + + # If true, enables the sending of HTTP responses bodies. Disabling this also + # disables Reflected Cross-Site Scripting (RXSS) vulnerability detection. + # security.scan_controllers.report_http_response_body: true + + # The number of application instances for a specific entity to perform IAST + # analysis on. + # security.scan_controllers.scan_instance_count: 0 + + # If true, allows IAST to continuously gather trace data in the background. The + # security agent uses collected data to perform an IAST scan at the scheduled + # time. + # security.scan_schedule.always_sample_traces: false + + # Specifies the delay time (in minutes) before the IAST scan begins after the + # application starts. + # security.scan_schedule.delay: 0 + + # Indicates the duration (in minutes) for which the IAST scan will be performed. + # security.scan_schedule.duration: 0 + + # Specifies a cron expression that sets when the IAST scan should run. + # security.scan_schedule.schedule: "" + + # Defines the endpoint URL for posting security-related data + # security.validator_service_url: wss://csec.nr-data.net + + # END security agent + +# Environment-specific settings are in this section. +# RAILS_ENV or RACK_ENV (as appropriate) is used to determine the environment. +# If your application has other named environments, configure them here. +development: + <<: *default_settings + development_mode: true + monitor_mode: false + app_name: Development + distributed_tracing.enabled: false + +test: + <<: *default_settings + # It doesn't make sense to report to New Relic from automated test runs. + monitor_mode: false + distributed_tracing.enabled: false + +staging: + <<: *default_settings + monitor_mode: <%= ENV['NEWRELIC_MONITOR_MODE'].presence || false %> + app_name: <%= ENV['NEWRELIC_APP_NAME'] %> Staging + distributed_tracing.enabled: false + +production: + <<: *default_settings + app_name: <%= ENV['NEWRELIC_APP_NAME'] %> Production + monitor_mode: <%= ENV['NEWRELIC_MONITOR_MODE'].presence || true %> + distributed_tracing.enabled: false \ No newline at end of file diff --git a/config/puma.rb b/config/puma.rb index ed99f0c9..ec60e285 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -8,7 +8,7 @@ require_relative 'dotenv' -max_threads_count = ENV.fetch('RAILS_MAX_THREADS', 15) +max_threads_count = ENV.fetch('RAILS_MAX_THREADS', 5) min_threads_count = ENV.fetch('RAILS_MIN_THREADS') { max_threads_count } threads min_threads_count, max_threads_count @@ -39,7 +39,7 @@ if ENV['WEB_CONCURRENCY_AUTO'] == 'true' workers Etc.nprocessors else - workers ENV.fetch('WEB_CONCURRENCY', 0) + workers ENV.fetch('WEB_CONCURRENCY', 1) end # Use the `preload_app!` method when specifying a `workers` number.