config/application.rb
# frozen_string_literal: true
require_relative 'boot'
require 'active_record/railtie'
require 'action_controller/railtie'
require 'action_view/railtie'
require 'action_mailer/railtie'
require 'rails/test_unit/railtie'
require 'identity/logging/railtie'
require_relative '../lib/asset_sources'
require_relative '../lib/identity_config'
require_relative '../lib/feature_management'
require_relative '../lib/fingerprinter'
require_relative '../lib/identity_job_log_subscriber'
require_relative '../lib/email_delivery_observer'
require_relative '../lib/good_job_connection_pool_size'
require_relative '../lib/identity_cors'
require_relative '../lib/version_headers'
require_relative '../lib/idp/constants'
Bundler.require(*Rails.groups)
require_relative '../lib/mailer_sensitive_information_checker'
APP_NAME = 'Login.gov'
module Identity
class Application < Rails::Application
if (log_level = ENV['LOGIN_TASK_LOG_LEVEL'])
Identity::Hostdata.logger.level = log_level
end
Identity::Hostdata.load_config!(
app_root: Rails.root,
rails_env: Rails.env,
write_copy_to: nil,
&IdentityConfig::BUILDER
)
config.asset_sources = AssetSources.new(
manifest_path: Rails.public_path.join('packs', 'manifest.json'),
cache_manifest: Rails.env.production? || Rails.env.test?,
i18n_locales: Identity::Hostdata.config.available_locales,
)
console do
if ENV['ALLOW_CONSOLE_DB_WRITE_ACCESS'] != 'true' &&
Identity::Hostdata.config.database_readonly_username.present? &&
Identity::Hostdata.config.database_readonly_password.present?
warn <<-EOS.squish
WARNING: Loading database a configuration with the readonly database user.
If you wish to make changes to records in the database set
ALLOW_CONSOLE_DB_WRITE_ACCESS to "true" in the environment
EOS
ActiveRecord::Base.establish_connection :read_replica
end
end
config.load_defaults '7.1'
config.active_record.belongs_to_required_by_default = false
config.active_job.queue_adapter = :good_job
FileUtils.mkdir_p(Rails.root.join('log'))
config.active_job.logger = if FeatureManagement.log_to_stdout?
ActiveSupport::Logger.new(STDOUT)
else
ActiveSupport::Logger.new(
Rails.root.join('log', Idp::Constants::WORKER_LOG_FILENAME),
)
end
config.active_job.logger.formatter = config.log_formatter
config.logger = if FeatureManagement.log_to_stdout?
ActiveSupport::Logger.new(STDOUT)
else
ActiveSupport::Logger.new(
Rails.root.join('log', "#{Rails.env}.log"),
)
end
config.kms_logger = if FeatureManagement.log_to_stdout?
ActiveSupport::Logger.new(STDOUT)
else
ActiveSupport::Logger.new(
Rails.root.join('log', Idp::Constants::KMS_LOG_FILENAME),
)
end
config.good_job.execution_mode = :external
config.good_job.poll_interval = 5
config.good_job.enable_cron = true
config.good_job.max_threads = Identity::Hostdata.config.good_job_max_threads
config.good_job.queues = Identity::Hostdata.config.good_job_queues
config.good_job.preserve_job_records = false
config.good_job.enable_listen_notify = false
config.good_job.queue_select_limit = Identity::Hostdata.config.good_job_queue_select_limit
# see config/initializers/job_configurations.rb for cron schedule
includes_star_queue = config.good_job.queues.split(';').any? do |name_threads|
name, _threads = name_threads.split(':', 2)
name == '*'
end
raise 'good_job.queues does not contain *, but it should' if !includes_star_queue
GoodJob.active_record_parent_class = 'WorkerJobApplicationRecord'
GoodJob.retry_on_unhandled_error = false
GoodJob.on_thread_error = ->(exception) { NewRelic::Agent.notice_error(exception) }
config.time_zone = 'UTC'
require 'i18n_flat_yml_backend'
config.i18n.backend = I18nFlatYmlBackend.new
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{yml,rb}')]
config.i18n.available_locales = Identity::Hostdata.config.available_locales
config.i18n.default_locale = :en
config.action_controller.per_form_csrf_tokens = true
config.action_view.frozen_string_literal = true
routes.default_url_options[:host] = Identity::Hostdata.config.domain_name
config.action_mailer.default_options = {
from: Mail::Address.new.tap do |mail|
mail.address = Identity::Hostdata.config.email_from
mail.display_name = Identity::Hostdata.config.email_from_display_name
end.to_s,
}
config.action_mailer.observers = %w[EmailDeliveryObserver]
config.middleware.delete Rack::ETag
require 'headers_filter'
config.middleware.insert_before 0, HeadersFilter
require 'utf8_sanitizer'
config.middleware.use Utf8Sanitizer
require 'secure_cookies'
config.middleware.insert_after ActionDispatch::Static, SecureCookies
config.middleware.use VersionHeaders if Identity::Hostdata.config.version_headers_enabled
config.middleware.insert_before 0, Rack::Cors do
allow do
origins do |source, _env|
IdentityCors.allowed_redirect_uri?(source)
end
resource '/.well-known/openid-configuration', headers: :any, methods: [:get]
resource '/api/openid_connect/certs', headers: :any, methods: [:get]
resource '/api/openid_connect/token',
credentials: true,
headers: :any,
methods: %i[post options]
resource '/api/openid_connect/userinfo', headers: :any, methods: [:get]
end
allow do
origins IdentityCors.allowed_origins_static_sites
resource '/api/country-support', headers: :any, methods: [:get]
if Identity::Hostdata.config.in_person_public_address_search_enabled
resource '/api/usps_locations', headers: :any, methods: %i[post options]
end
end
end
if !Identity::Hostdata.config.enable_rate_limiting
# Rack::Attack auto-includes itself as a Railtie, so we need to
# explicitly remove it when we want to disable it
config.middleware.delete Rack::Attack
end
config.view_component.show_previews = Identity::Hostdata.config.component_previews_enabled
if Identity::Hostdata.config.component_previews_enabled
require 'lookbook'
config.view_component.preview_controller = 'ComponentPreviewController'
config.view_component.preview_paths = [Rails.root.join('spec', 'components', 'previews')]
config.view_component.default_preview_layout = 'component_preview'
config.lookbook.auto_refresh = false
config.lookbook.project_name = "#{APP_NAME} Component Previews"
config.lookbook.ui_theme = 'blue'
if Identity::Hostdata.config.component_previews_embed_frame_ancestors.present?
# so we can embed a lookbook component into the dev docs
config.lookbook.preview_embeds.policy = 'ALLOWALL'
# lookbook strips out CSP, this brings it back so we aren't so permissive
require 'component_preview_csp'
config.middleware.insert_after ActionDispatch::Static, ComponentPreviewCsp
end
end
end
end