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:
parent
f504717519
commit
0338c81dc2
5 changed files with 61 additions and 33 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
# See `secrets.yml` for tips on generating suitable keys.
|
||||
# production:
|
||||
# external_api_key: 1466aac22e6a869134be3d09b9e89232fc2c2289…
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue