mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Raise an error only when require_master_key
is specified
To prevent errors from being raise in environments where credentials is unnecessary. Context: https://github.com/rails/rails/issues/31283#issuecomment-348801489 Fixes #31283
This commit is contained in:
parent
daf15f58b9
commit
35373219c9
13 changed files with 94 additions and 27 deletions
|
@ -11,8 +11,9 @@ module ActiveSupport
|
|||
delegate :[], :fetch, to: :config
|
||||
delegate_missing_to :options
|
||||
|
||||
def initialize(config_path:, key_path:, env_key:)
|
||||
super content_path: config_path, key_path: key_path, env_key: env_key
|
||||
def initialize(config_path:, key_path:, env_key:, raise_if_missing_key:)
|
||||
super content_path: config_path, key_path: key_path,
|
||||
env_key: env_key, raise_if_missing_key: raise_if_missing_key
|
||||
end
|
||||
|
||||
# Allow a config to be started without a file present
|
||||
|
|
|
@ -26,11 +26,11 @@ module ActiveSupport
|
|||
end
|
||||
|
||||
|
||||
attr_reader :content_path, :key_path, :env_key
|
||||
attr_reader :content_path, :key_path, :env_key, :raise_if_missing_key
|
||||
|
||||
def initialize(content_path:, key_path:, env_key:)
|
||||
def initialize(content_path:, key_path:, env_key:, raise_if_missing_key:)
|
||||
@content_path, @key_path = Pathname.new(content_path), Pathname.new(key_path)
|
||||
@env_key = env_key
|
||||
@env_key, @raise_if_missing_key = env_key, raise_if_missing_key
|
||||
end
|
||||
|
||||
def key
|
||||
|
@ -38,7 +38,7 @@ module ActiveSupport
|
|||
end
|
||||
|
||||
def read
|
||||
if content_path.exist?
|
||||
if !key.nil? && content_path.exist?
|
||||
decrypt content_path.binread
|
||||
else
|
||||
raise MissingContentError, content_path
|
||||
|
@ -93,7 +93,7 @@ module ActiveSupport
|
|||
end
|
||||
|
||||
def handle_missing_key
|
||||
raise MissingKeyError, key_path: key_path, env_key: env_key
|
||||
raise MissingKeyError, key_path: key_path, env_key: env_key if raise_if_missing_key
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,8 +10,10 @@ class EncryptedConfigurationTest < ActiveSupport::TestCase
|
|||
@credentials_key_path = File.join(Dir.tmpdir, "master.key")
|
||||
File.write(@credentials_key_path, ActiveSupport::EncryptedConfiguration.generate_key)
|
||||
|
||||
@credentials = ActiveSupport::EncryptedConfiguration.new \
|
||||
config_path: @credentials_config_path, key_path: @credentials_key_path, env_key: "RAILS_MASTER_KEY"
|
||||
@credentials = ActiveSupport::EncryptedConfiguration.new(
|
||||
config_path: @credentials_config_path, key_path: @credentials_key_path,
|
||||
env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true
|
||||
)
|
||||
end
|
||||
|
||||
teardown do
|
||||
|
|
|
@ -12,8 +12,9 @@ class EncryptedFileTest < ActiveSupport::TestCase
|
|||
@key_path = File.join(Dir.tmpdir, "content.txt.key")
|
||||
File.write(@key_path, ActiveSupport::EncryptedFile.generate_key)
|
||||
|
||||
@encrypted_file = ActiveSupport::EncryptedFile.new \
|
||||
content_path: @content_path, key_path: @key_path, env_key: "CONTENT_KEY"
|
||||
@encrypted_file = ActiveSupport::EncryptedFile.new(
|
||||
content_path: @content_path, key_path: @key_path, env_key: "CONTENT_KEY", raise_if_missing_key: true
|
||||
)
|
||||
end
|
||||
|
||||
teardown do
|
||||
|
@ -47,4 +48,12 @@ class EncryptedFileTest < ActiveSupport::TestCase
|
|||
|
||||
assert_equal "#{@content} and went by the lake", @encrypted_file.read
|
||||
end
|
||||
|
||||
test "raise MissingKeyError when key is missing" do
|
||||
assert_raise(ActiveSupport::EncryptedFile::MissingKeyError) do
|
||||
ActiveSupport::EncryptedFile.new(
|
||||
content_path: @content_path, key_path: "", env_key: "", raise_if_missing_key: true
|
||||
).read
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -472,7 +472,8 @@ module Rails
|
|||
ActiveSupport::EncryptedConfiguration.new(
|
||||
config_path: Rails.root.join(path),
|
||||
key_path: Rails.root.join(key_path),
|
||||
env_key: env_key
|
||||
env_key: env_key,
|
||||
raise_if_missing_key: config.require_master_key
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -16,7 +16,8 @@ module Rails
|
|||
:ssl_options, :public_file_server,
|
||||
: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
|
||||
:read_encrypted_secrets, :log_level, :content_security_policy_report_only,
|
||||
:require_master_key
|
||||
|
||||
attr_reader :encoding, :api_only
|
||||
|
||||
|
@ -56,6 +57,7 @@ module Rails
|
|||
@read_encrypted_secrets = false
|
||||
@content_security_policy = nil
|
||||
@content_security_policy_report_only = false
|
||||
@require_master_key = false
|
||||
end
|
||||
|
||||
def load_defaults(target_version)
|
||||
|
|
|
@ -33,8 +33,7 @@ module Rails
|
|||
def show
|
||||
require_application_and_environment!
|
||||
|
||||
say Rails.application.credentials.read.presence ||
|
||||
"No credentials have been added yet. Use bin/rails credentials:edit to change that."
|
||||
say Rails.application.credentials.read.presence || missing_credentials_message
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -67,6 +66,14 @@ module Rails
|
|||
|
||||
Rails::Generators::CredentialsGenerator.new
|
||||
end
|
||||
|
||||
def missing_credentials_message
|
||||
if Rails.application.credentials.key.nil?
|
||||
"Missing master key to decrypt credentials. See bin/rails credentials:help"
|
||||
else
|
||||
"No credentials have been added yet. Use bin/rails credentials:edit to change that."
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -37,9 +37,9 @@ module Rails
|
|||
|
||||
def show(file_path)
|
||||
require_application_and_environment!
|
||||
encrypted = Rails.application.encrypted(file_path, key_path: options[:key])
|
||||
|
||||
say Rails.application.encrypted(file_path, key_path: options[:key]).read.presence ||
|
||||
"File '#{file_path}' does not exist. Use bin/rails encrypted:edit #{file_path} to change that."
|
||||
say encrypted.read.presence || missing_encrypted_message(key: encrypted.key, key_path: options[:key], file_path: file_path)
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -72,6 +72,14 @@ module Rails
|
|||
|
||||
Rails::Generators::EncryptedFileGenerator.new
|
||||
end
|
||||
|
||||
def missing_encrypted_message(key:, key_path:, file_path:)
|
||||
if key.nil?
|
||||
"Missing '#{key_path}' to decrypt data. See bin/rails encrypted:help"
|
||||
else
|
||||
"File '#{file_path}' does not exist. Use bin/rails encrypted:edit #{file_path} to change that."
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -36,7 +36,8 @@ module Rails
|
|||
ActiveSupport::EncryptedConfiguration.new(
|
||||
config_path: "config/credentials.yml.enc",
|
||||
key_path: "config/master.key",
|
||||
env_key: "RAILS_MASTER_KEY"
|
||||
env_key: "RAILS_MASTER_KEY",
|
||||
raise_if_missing_key: true
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ module Rails
|
|||
|
||||
def add_encrypted_file_silently(file_path, key_path, template = encrypted_file_template)
|
||||
unless File.exist?(file_path)
|
||||
setup = { content_path: file_path, key_path: key_path, env_key: "RAILS_MASTER_KEY" }
|
||||
setup = { content_path: file_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true }
|
||||
ActiveSupport::EncryptedFile.new(setup).write(template)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -707,6 +707,14 @@ module ApplicationTests
|
|||
assert_match(/Missing.*RAILS_MASTER_KEY/, error)
|
||||
end
|
||||
|
||||
test "credentials does not raise error when require_master_key is false and master key does not exist" do
|
||||
remove_file "config/master.key"
|
||||
add_to_config "config.require_master_key = false"
|
||||
app "development"
|
||||
|
||||
assert_not app.credentials.secret_key_base
|
||||
end
|
||||
|
||||
test "protect from forgery is the default in a new app" do
|
||||
make_basic_app
|
||||
|
||||
|
|
|
@ -26,10 +26,6 @@ class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
test "show credentials" do
|
||||
assert_match(/access_key_id: 123/, run_show_command)
|
||||
end
|
||||
|
||||
test "edit command does not add master key to gitignore when already exist" do
|
||||
run_edit_command
|
||||
|
||||
|
@ -47,6 +43,24 @@ class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase
|
|||
assert_match(/api_key: abc/, run_show_command)
|
||||
end
|
||||
|
||||
test "show credentials" do
|
||||
assert_match(/access_key_id: 123/, run_show_command)
|
||||
end
|
||||
|
||||
test "show command raise error when require_master_key is specified and key does not exist" do
|
||||
remove_file "config/master.key"
|
||||
add_to_config "config.require_master_key = true"
|
||||
|
||||
assert_match(/Missing encryption key to decrypt file with/, run_show_command(allow_failure: true))
|
||||
end
|
||||
|
||||
test "show command does not raise error when require_master_key is false and master key does not exist" do
|
||||
remove_file "config/master.key"
|
||||
add_to_config "config.require_master_key = false"
|
||||
|
||||
assert_match(/Missing master key to decrypt credentials/, run_show_command)
|
||||
end
|
||||
|
||||
private
|
||||
def run_edit_command(editor: "cat")
|
||||
switch_env("EDITOR", editor) do
|
||||
|
@ -54,7 +68,7 @@ class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def run_show_command
|
||||
rails "credentials:show"
|
||||
def run_show_command(**options)
|
||||
rails "credentials:show", **options
|
||||
end
|
||||
end
|
||||
|
|
|
@ -52,6 +52,20 @@ class Rails::Command::EncryptedCommandTest < ActiveSupport::TestCase
|
|||
assert_match(/access_key_id: 123/, run_show_command("config/tokens.yml.enc", key: "config/tokens.key"))
|
||||
end
|
||||
|
||||
test "show command raise error when require_master_key is specified and key does not exist" do
|
||||
add_to_config "config.require_master_key = true"
|
||||
|
||||
assert_match(/Missing encryption key to decrypt file with/,
|
||||
run_show_command("config/tokens.yml.enc", key: "unexist.key", allow_failure: true))
|
||||
end
|
||||
|
||||
test "show command does not raise error when require_master_key is false and master key does not exist" do
|
||||
remove_file "config/master.key"
|
||||
add_to_config "config.require_master_key = false"
|
||||
|
||||
assert_match(/Missing 'config\/master\.key' to decrypt data/, run_show_command("config/tokens.yml.enc"))
|
||||
end
|
||||
|
||||
test "won't corrupt encrypted file when passed wrong key" do
|
||||
run_edit_command("config/tokens.yml.enc", key: "config/tokens.key")
|
||||
|
||||
|
@ -68,8 +82,8 @@ class Rails::Command::EncryptedCommandTest < ActiveSupport::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def run_show_command(file, key: nil)
|
||||
rails "encrypted:show", prepare_args(file, key)
|
||||
def run_show_command(file, key: nil, **options)
|
||||
rails "encrypted:show", prepare_args(file, key), **options
|
||||
end
|
||||
|
||||
def prepare_args(file, key)
|
||||
|
|
Loading…
Reference in a new issue