diff options
Diffstat (limited to 'railties/lib/rails')
17 files changed, 113 insertions, 44 deletions
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 99e42ebefb..656786246d 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -232,7 +232,10 @@ module Rails if yaml.exist? require "erb" - (YAML.load(ERB.new(yaml.read).result) || {})[env] || {} + require "active_support/ordered_options" + + config = (YAML.load(ERB.new(yaml.read).result) || {})[env] || {} + ActiveSupport::InheritableOptions.new(config.deep_symbolize_keys) else raise "Could not load configuration. No such file - #{yaml}" end @@ -435,8 +438,12 @@ module Rails # Decrypts the credentials hash as kept in +config/credentials.yml.enc+. This file is encrypted with # the Rails master key, which is either taken from <tt>ENV["RAILS_MASTER_KEY"]</tt> or from loading # +config/master.key+. + # If specific credentials file exists for current environment, it takes precedence, thus for +production+ + # environment look first for +config/credentials/production.yml.enc+ with master key taken + # from <tt>ENV["RAILS_MASTER_KEY"]</tt> or from loading +config/credentials/production.key+. + # Default behavior can be overwritten by setting +config.credentials.content_path+ and +config.credentials.key_path+. def credentials - @credentials ||= encrypted("config/credentials.yml.enc") + @credentials ||= encrypted(config.credentials.content_path, key_path: config.credentials.key_path) end # Shorthand to decrypt any encrypted configurations or files. diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index f4cbd2b9d0..eae902a938 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -17,7 +17,7 @@ module Rails :session_options, :time_zone, :reload_classes_only_on_change, :beginning_of_week, :filter_redirect, :x, :enable_dependency_loading, :read_encrypted_secrets, :log_level, :content_security_policy_report_only, - :content_security_policy_nonce_generator, :require_master_key + :content_security_policy_nonce_generator, :require_master_key, :credentials attr_reader :encoding, :api_only, :loaded_config_version @@ -60,6 +60,9 @@ module Rails @content_security_policy_nonce_generator = nil @require_master_key = false @loaded_config_version = nil + @credentials = ActiveSupport::OrderedOptions.new + @credentials.content_path = default_credentials_content_path + @credentials.key_path = default_credentials_key_path end def load_defaults(target_version) @@ -273,6 +276,27 @@ module Rails true end end + + private + def credentials_available_for_current_env? + File.exist?("#{root}/config/credentials/#{Rails.env}.yml.enc") + end + + def default_credentials_content_path + if credentials_available_for_current_env? + File.join(root, "config", "credentials", "#{Rails.env}.yml.enc") + else + File.join(root, "config", "credentials.yml.enc") + end + end + + def default_credentials_key_path + if credentials_available_for_current_env? + File.join(root, "config", "credentials", "#{Rails.env}.key") + else + File.join(root, "config", "master.key") + end + end end end end diff --git a/railties/lib/rails/commands/credentials/USAGE b/railties/lib/rails/commands/credentials/USAGE index ea429f58d8..6b33d1ab74 100644 --- a/railties/lib/rails/commands/credentials/USAGE +++ b/railties/lib/rails/commands/credentials/USAGE @@ -38,3 +38,12 @@ the encrypted credentials. When the temporary file is next saved the contents are encrypted and written to `config/credentials.yml.enc` while the file itself is destroyed to prevent credentials from leaking. + +=== Environment Specific Credentials + +It is possible to have credentials for each environment. If the file for current environment exists it will take +precedence over `config/credentials.yml.enc`, thus for `production` environment first look for +`config/credentials/production.yml.enc` that can be decrypted using master key taken from `ENV["RAILS_MASTER_KEY"]` +or stored in `config/credentials/production.key`. +To edit given file use command `rails credentials:edit --environment production` +Default paths can be overwritten by setting `config.credentials.content_path` and `config.credentials.key_path`. diff --git a/railties/lib/rails/commands/credentials/credentials_command.rb b/railties/lib/rails/commands/credentials/credentials_command.rb index 65c5218fc8..4b30d208e0 100644 --- a/railties/lib/rails/commands/credentials/credentials_command.rb +++ b/railties/lib/rails/commands/credentials/credentials_command.rb @@ -8,6 +8,9 @@ module Rails class CredentialsCommand < Rails::Command::Base # :nodoc: include Helpers::Editor + class_option :environment, aliases: "-e", type: :string, + desc: "Uses credentials from config/credentials/:environment.yml.enc encrypted by config/credentials/:environment.key key" + no_commands do def help say "Usage:\n #{self.class.banner}" @@ -20,58 +23,74 @@ module Rails require_application_and_environment! ensure_editor_available(command: "bin/rails credentials:edit") || (return) - ensure_master_key_has_been_added if Rails.application.credentials.key.nil? - ensure_credentials_have_been_added + + encrypted = Rails.application.encrypted(content_path, key_path: key_path) + + ensure_encryption_key_has_been_added(key_path) if encrypted.key.nil? + ensure_encrypted_file_has_been_added(content_path, key_path) catch_editing_exceptions do - change_credentials_in_system_editor + change_encrypted_file_in_system_editor(content_path, key_path) end - say "New credentials encrypted and saved." + say "File encrypted and saved." + rescue ActiveSupport::MessageEncryptor::InvalidMessage + say "Couldn't decrypt #{content_path}. Perhaps you passed the wrong key?" end def show require_application_and_environment! - say Rails.application.credentials.read.presence || missing_credentials_message + encrypted = Rails.application.encrypted(content_path, key_path: key_path) + + say encrypted.read.presence || missing_encrypted_message(key: encrypted.key, key_path: key_path, file_path: content_path) end private - def ensure_master_key_has_been_added - master_key_generator.add_master_key_file - master_key_generator.ignore_master_key_file + def content_path + options[:environment] ? "config/credentials/#{options[:environment]}.yml.enc" : "config/credentials.yml.enc" + end + + def key_path + options[:environment] ? "config/credentials/#{options[:environment]}.key" : "config/master.key" + end + + + def ensure_encryption_key_has_been_added(key_path) + encryption_key_file_generator.add_key_file(key_path) + encryption_key_file_generator.ignore_key_file(key_path) end - def ensure_credentials_have_been_added - credentials_generator.add_credentials_file_silently + def ensure_encrypted_file_has_been_added(file_path, key_path) + encrypted_file_generator.add_encrypted_file_silently(file_path, key_path) end - def change_credentials_in_system_editor - Rails.application.credentials.change do |tmp_path| + def change_encrypted_file_in_system_editor(file_path, key_path) + Rails.application.encrypted(file_path, key_path: key_path).change do |tmp_path| system("#{ENV["EDITOR"]} #{tmp_path}") end end - def master_key_generator + def encryption_key_file_generator require "rails/generators" - require "rails/generators/rails/master_key/master_key_generator" + require "rails/generators/rails/encryption_key_file/encryption_key_file_generator" - Rails::Generators::MasterKeyGenerator.new + Rails::Generators::EncryptionKeyFileGenerator.new end - def credentials_generator + def encrypted_file_generator require "rails/generators" - require "rails/generators/rails/credentials/credentials_generator" + require "rails/generators/rails/encrypted_file/encrypted_file_generator" - Rails::Generators::CredentialsGenerator.new + Rails::Generators::EncryptedFileGenerator.new end - def missing_credentials_message - if Rails.application.credentials.key.nil? - "Missing master key to decrypt credentials. See `rails credentials:help`" + def missing_encrypted_message(key:, key_path:, file_path:) + if key.nil? + "Missing '#{key_path}' to decrypt credentials. See `rails credentials:help`" else - "No credentials have been added yet. Use `rails credentials:edit` to change that." + "File '#{file_path}' does not exist. Use `rails credentials:edit` to change that." end end end diff --git a/railties/lib/rails/commands/dbconsole/dbconsole_command.rb b/railties/lib/rails/commands/dbconsole/dbconsole_command.rb index 806b7de6d6..0fac7d34a0 100644 --- a/railties/lib/rails/commands/dbconsole/dbconsole_command.rb +++ b/railties/lib/rails/commands/dbconsole/dbconsole_command.rb @@ -75,7 +75,7 @@ module Rails args += ["-P", "#{config['password']}"] if config["password"] if config["host"] - host_arg = "#{config['host']}".dup + host_arg = +"#{config['host']}" host_arg << ":#{config['port']}" if config["port"] args += ["-S", host_arg] end diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 6a13a84108..901934826b 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -403,6 +403,12 @@ module Rails define_method(:railtie_helpers_paths) { railtie.helpers_paths } end + unless mod.respond_to?(:railtie_include_helpers) + define_method(:railtie_include_helpers) { |klass, include_path_helpers| + railtie.routes.include_helpers(klass, include_path_helpers) + } + end + unless mod.respond_to?(:railtie_routes_url_helpers) define_method(:railtie_routes_url_helpers) { |include_path_helpers = true| railtie.routes.url_helpers(include_path_helpers) } end @@ -473,9 +479,13 @@ module Rails # files inside eager_load paths. def eager_load! config.eager_load_paths.each do |load_path| - matcher = /\A#{Regexp.escape(load_path.to_s)}\/(.*)\.rb\Z/ - Dir.glob("#{load_path}/**/*.rb").sort.each do |file| - require_dependency file.sub(matcher, '\1') + if File.file?(load_path) + require_dependency load_path + else + matcher = /\A#{Regexp.escape(load_path.to_s)}\/(.*)\.rb\Z/ + Dir.glob("#{load_path}/**/*.rb").sort.each do |file| + require_dependency file.sub(matcher, '\1') + end end end end diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 6bf0406b21..7595272c03 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -38,6 +38,7 @@ module Rails @paths ||= begin paths = Rails::Paths::Root.new(@root) + paths.add "config/routes.rb", eager_load: true paths.add "app", eager_load: true, glob: "{*,*/concerns}" paths.add "app/assets", glob: "*" paths.add "app/controllers", eager_load: true @@ -55,7 +56,6 @@ module Rails paths.add "config/environments", glob: "#{Rails.env}.rb" paths.add "config/initializers", glob: "**/*.rb" paths.add "config/locales", glob: "*.{rb,yml}" - paths.add "config/routes.rb" paths.add "db" paths.add "db/migrate" diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index a6dc60342c..8991c547ca 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -299,7 +299,7 @@ module Rails def gem_for_database # %w( mysql postgresql sqlite3 oracle frontbase ibm_db sqlserver jdbcmysql jdbcsqlite3 jdbcpostgresql ) case options[:database] - when "mysql" then ["mysql2", [">= 0.4.4", "< 0.6.0"]] + when "mysql" then ["mysql2", [">= 0.4.4"]] when "postgresql" then ["pg", [">= 0.18", "< 2.0"]] when "oracle" then ["activerecord-oracle_enhanced-adapter", nil] when "frontbase" then ["ruby-frontbase", nil] diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index f7fd30a5fb..3f20f5a718 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -153,7 +153,7 @@ module Rails end def inject_options - "".dup.tap { |s| options_for_migration.each { |k, v| s << ", #{k}: #{v.inspect}" } } + (+"").tap { |s| options_for_migration.each { |k, v| s << ", #{k}: #{v.inspect}" } } end def inject_index_options diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml.tt b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml.tt index 97f9a92ff3..f39593372c 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml.tt @@ -1,4 +1,4 @@ -# MySQL. Versions 5.1.10 and up are supported. +# MySQL. Versions 5.5.8 and up are supported. # # Install the MySQL driver: # gem install activerecord-jdbcmysql-adapter diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt index 1dc508b14f..5860563908 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt @@ -1,4 +1,4 @@ -# MySQL. Versions 5.1.10 and up are supported. +# MySQL. Versions 5.5.8 and up are supported. # # Install the MySQL driver # gem install mysql2 @@ -11,7 +11,6 @@ # default: &default adapter: mysql2 - encoding: utf8 pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt index 755d19ef5d..4f7a8d3d6e 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt @@ -10,8 +10,7 @@ ActiveRecord::Migrator.migrations_paths << File.expand_path('../db/migrate', __d <% end -%> require "rails/test_help" -# Filter out Minitest backtrace while allowing backtrace from other libraries -# to be shown. +# Filter out the backtrace from minitest while preserving the one from other libraries. Minitest.backtrace_filter = Minitest::BacktraceFilter.new <% unless engine? -%> diff --git a/railties/lib/rails/info.rb b/railties/lib/rails/info.rb index d5c9973c6b..3df36efc4c 100644 --- a/railties/lib/rails/info.rb +++ b/railties/lib/rails/info.rb @@ -41,7 +41,7 @@ module Rails alias inspect to_s def to_html - "<table>".dup.tap do |table| + (+"<table>").tap do |table| properties.each do |(name, value)| table << %(<tr><td class="name">#{CGI.escapeHTML(name.to_s)}</td>) formatted_value = if value.kind_of?(Array) diff --git a/railties/lib/rails/mailers_controller.rb b/railties/lib/rails/mailers_controller.rb index 0b0e802358..e2d36d7654 100644 --- a/railties/lib/rails/mailers_controller.rb +++ b/railties/lib/rails/mailers_controller.rb @@ -10,6 +10,8 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: helper_method :part_query, :locale_query + content_security_policy(false) + def index @previews = ActionMailer::Preview.all @page_title = "Mailer Previews" diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb index 2d66a4dc7d..d7170e6282 100644 --- a/railties/lib/rails/source_annotation_extractor.rb +++ b/railties/lib/rails/source_annotation_extractor.rb @@ -50,7 +50,7 @@ module Rails # If +options+ has a flag <tt>:tag</tt> the tag is shown as in the example above. # Otherwise the string contains just line and text. def to_s(options = {}) - s = "[#{line.to_s.rjust(options[:indent])}] ".dup + s = +"[#{line.to_s.rjust(options[:indent])}] " s << "[#{tag}] " if options[:tag] s << text end diff --git a/railties/lib/rails/tasks/yarn.rake b/railties/lib/rails/tasks/yarn.rake index cf45a392e8..4fb8586b69 100644 --- a/railties/lib/rails/tasks/yarn.rake +++ b/railties/lib/rails/tasks/yarn.rake @@ -9,7 +9,7 @@ namespace :yarn do rails_env = ENV["RAILS_ENV"] valid_node_envs.include?(rails_env) ? rails_env : "production" end - system({ "NODE_ENV" => node_env }, "./bin/yarn install --no-progress --frozen-lockfile") + system({ "NODE_ENV" => node_env }, "#{Rails.root}/bin/yarn install --no-progress --frozen-lockfile") end end diff --git a/railties/lib/rails/test_unit/runner.rb b/railties/lib/rails/test_unit/runner.rb index 2fa7573bdf..d38952bb30 100644 --- a/railties/lib/rails/test_unit/runner.rb +++ b/railties/lib/rails/test_unit/runner.rb @@ -12,8 +12,8 @@ module Rails class << self def attach_before_load_options(opts) - opts.on("--warnings", "-w", "Run with Ruby warnings enabled") {} - opts.on("-e", "--environment ENV", "Run tests in the ENV environment") {} + opts.on("--warnings", "-w", "Run with Ruby warnings enabled") { } + opts.on("-e", "--environment ENV", "Run tests in the ENV environment") { } end def parse_options(argv) @@ -87,7 +87,7 @@ module Rails @filters = [ @named_filter, *derive_line_filters(patterns) ].compact end - # Minitest uses === to find matching filters. + # minitest uses === to find matching filters. def ===(method) @filters.any? { |filter| filter === method } end @@ -96,7 +96,7 @@ module Rails def derive_named_filter(filter) if filter.respond_to?(:named_filter) filter.named_filter - elsif filter =~ %r%/(.*)/% # Regexp filtering copied from Minitest. + elsif filter =~ %r%/(.*)/% # Regexp filtering copied from minitest. Regexp.new $1 elsif filter.is_a?(String) filter |