1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Reorder first secrets edit flow.

Setup config/secrets.yml.enc with template contents for people to edit.

Then generate encryption key and encrypt the initial secrets.
This commit is contained in:
Kasper Timm Hansen 2017-05-23 21:54:01 +02:00
parent f504717519
commit 0338c81dc2
5 changed files with 61 additions and 33 deletions

View file

@ -13,10 +13,7 @@ module Rails
end
def setup
require "rails/generators"
require "rails/generators/rails/encrypted_secrets/encrypted_secrets_generator"
Rails::Generators::EncryptedSecretsGenerator.start
generator.start
end
def edit
@ -42,6 +39,21 @@ module Rails
say "Aborted changing encrypted secrets: nothing saved."
rescue Rails::Secrets::MissingKeyError => error
say error.message
rescue Errno::ENOENT => error
raise unless error.message =~ /secrets\.yml\.enc/
Rails::Secrets.read_template_for_editing do |tmp_path|
system("\$EDITOR #{tmp_path}")
generator.skip_secrets_file { setup }
end
end
private
def generator
require "rails/generators"
require "rails/generators/rails/encrypted_secrets/encrypted_secrets_generator"
Rails::Generators::EncryptedSecretsGenerator
end
end
end

View file

@ -36,25 +36,29 @@ module Rails
end
def add_encrypted_secrets_file
unless File.exist?("config/secrets.yml.enc")
unless (defined?(@@skip_secrets_file) && @@skip_secrets_file) || File.exist?("config/secrets.yml.enc")
say "Adding config/secrets.yml.enc to store secrets that needs to be encrypted."
say ""
template "config/secrets.yml.enc" do |prefill|
say ""
say "For now the file contains this but it's been encrypted with the generated key:"
say ""
say prefill, :on_green
say Secrets.template, :on_green
say ""
Secrets.encrypt(prefill)
end
Secrets.write(Secrets.template)
say "You can edit encrypted secrets with `bin/rails secrets:edit`."
say ""
end
say "Add this to your config/environments/production.rb:"
say "config.read_encrypted_secrets = true"
end
def self.skip_secrets_file
@@skip_secrets_file = true
yield
ensure
@@skip_secrets_file = false
end
private

View file

@ -1,3 +0,0 @@
# See `secrets.yml` for tips on generating suitable keys.
# production:
# external_api_key: 1466aac22e6a869134be3d09b9e89232fc2c2289…

View file

@ -1,5 +1,6 @@
require "yaml"
require "active_support/message_encryptor"
require "active_support/core_ext/string/strip"
module Rails
# Greatly inspired by Ara T. Howard's magnificent sekrets gem. 😘
@ -37,6 +38,15 @@ module Rails
ENV["RAILS_MASTER_KEY"] || read_key_file || handle_missing_key
end
def template
<<-end_of_template.strip_heredoc
# See `secrets.yml` for tips on generating suitable keys.
# production:
# external_api_key: 1466aac22e6a869134be3d09b9e89232fc2c2289…
end_of_template
end
def encrypt(data)
encryptor.encrypt_and_sign(data)
end
@ -54,15 +64,12 @@ module Rails
FileUtils.mv("#{path}.tmp", path)
end
def read_for_editing
tmp_path = File.join(Dir.tmpdir, File.basename(path))
IO.binwrite(tmp_path, read)
def read_for_editing(&block)
writing(read, &block)
end
yield tmp_path
write(IO.binread(tmp_path))
ensure
FileUtils.rm(tmp_path) if File.exist?(tmp_path)
def read_template_for_editing(&block)
writing(template, &block)
end
private
@ -92,6 +99,17 @@ module Rails
end
end
def writing(contents)
tmp_path = File.join(Dir.tmpdir, File.basename(path))
File.write(tmp_path, contents)
yield tmp_path
write(File.read(tmp_path))
ensure
FileUtils.rm(tmp_path) if File.exist?(tmp_path)
end
def encryptor
@encryptor ||= ActiveSupport::MessageEncryptor.new([ key ].pack("H*"), cipher: @cipher)
end

View file

@ -18,7 +18,8 @@ class Rails::Command::SecretsCommandTest < ActiveSupport::TestCase
end
test "edit secrets" do
run_setup_command
# Runs setup before first edit.
assert_match(/Adding config\/secrets\.yml\.key to store the encryption key/, run_edit_command)
# Run twice to ensure encrypted secrets can be reread after first edit pass.
2.times do
@ -30,8 +31,4 @@ class Rails::Command::SecretsCommandTest < ActiveSupport::TestCase
def run_edit_command(editor: "cat")
Dir.chdir(app_path) { `EDITOR="#{editor}" bin/rails secrets:edit` }
end
def run_setup_command
Dir.chdir(app_path) { `bin/rails secrets:setup` }
end
end