aboutsummaryrefslogtreecommitdiffstats
path: root/railties/lib
diff options
context:
space:
mode:
Diffstat (limited to 'railties/lib')
-rw-r--r--railties/lib/rails/application.rb14
-rw-r--r--railties/lib/rails/application/bootstrap.rb6
-rw-r--r--railties/lib/rails/application/configuration.rb6
-rw-r--r--railties/lib/rails/command.rb27
-rw-r--r--railties/lib/rails/command/base.rb10
-rw-r--r--railties/lib/rails/commands/secrets/USAGE52
-rw-r--r--railties/lib/rails/commands/secrets/secrets_command.rb50
-rw-r--r--railties/lib/rails/generators.rb1
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt5
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/secrets.yml6
-rw-r--r--railties/lib/rails/generators/rails/encrypted_secrets/encrypted_secrets_generator.rb66
-rw-r--r--railties/lib/rails/generators/rails/encrypted_secrets/templates/config/secrets.yml.enc3
-rw-r--r--railties/lib/rails/secrets.rb111
13 files changed, 27 insertions, 330 deletions
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 89f7b5991f..1a6aed7ce4 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -4,7 +4,6 @@ require "active_support/core_ext/object/blank"
require "active_support/key_generator"
require "active_support/message_verifier"
require "rails/engine"
-require "rails/secrets"
module Rails
# An Engine with the responsibility of coordinating the whole boot process.
@@ -386,7 +385,18 @@ module Rails
def secrets
@secrets ||= begin
secrets = ActiveSupport::OrderedOptions.new
- secrets.merge! Rails::Secrets.parse(config.paths["config/secrets"].existent, env: Rails.env)
+ yaml = config.paths["config/secrets"].first
+
+ if File.exist?(yaml)
+ require "erb"
+
+ all_secrets = YAML.load(ERB.new(IO.read(yaml)).result) || {}
+ shared_secrets = all_secrets["shared"]
+ env_secrets = all_secrets[Rails.env]
+
+ secrets.merge!(shared_secrets.deep_symbolize_keys) if shared_secrets
+ secrets.merge!(env_secrets.deep_symbolize_keys) if env_secrets
+ end
# Fallback to config.secret_key_base if secrets.secret_key_base isn't set
secrets.secret_key_base ||= config.secret_key_base
diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb
index 4223c38146..6102af3fff 100644
--- a/railties/lib/rails/application/bootstrap.rb
+++ b/railties/lib/rails/application/bootstrap.rb
@@ -2,7 +2,6 @@ require "fileutils"
require "active_support/notifications"
require "active_support/dependencies"
require "active_support/descendants_tracker"
-require "rails/secrets"
module Rails
class Application
@@ -78,11 +77,6 @@ INFO
initializer :bootstrap_hook, group: :all do |app|
ActiveSupport.run_load_hooks(:before_initialize, app)
end
-
- initializer :set_secrets_root, group: :all do
- Rails::Secrets.root = root
- Rails::Secrets.read_encrypted_secrets = config.read_encrypted_secrets
- end
end
end
end
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index b0592151b7..b0d33f87a3 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -13,8 +13,7 @@ module Rails
:railties_order, :relative_url_root, :secret_key_base, :secret_token,
: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
+ :beginning_of_week, :filter_redirect, :x, :enable_dependency_loading
attr_writer :log_level
attr_reader :encoding, :api_only
@@ -52,7 +51,6 @@ module Rails
@debug_exception_response_format = nil
@x = Custom.new
@enable_dependency_loading = false
- @read_encrypted_secrets = false
end
def encoding=(value)
@@ -82,7 +80,7 @@ module Rails
@paths ||= begin
paths = super
paths.add "config/database", with: "config/database.yml"
- paths.add "config/secrets", with: "config", glob: "secrets.yml{,.enc}"
+ paths.add "config/secrets", with: "config/secrets.yml"
paths.add "config/environment", with: "config/environment.rb"
paths.add "lib/templates"
paths.add "log", with: "log/#{Rails.env}.log"
diff --git a/railties/lib/rails/command.rb b/railties/lib/rails/command.rb
index 73f9684ca4..13f3b90b6d 100644
--- a/railties/lib/rails/command.rb
+++ b/railties/lib/rails/command.rb
@@ -27,22 +27,15 @@ module Rails
end
# Receives a namespace, arguments and the behavior to invoke the command.
- def invoke(full_namespace, args = [], **config)
- namespace = full_namespace = full_namespace.to_s
+ def invoke(namespace, args = [], **config)
+ namespace = namespace.to_s
+ namespace = "help" if namespace.blank? || HELP_MAPPINGS.include?(namespace)
+ namespace = "version" if %w( -v --version ).include? namespace
- if char = namespace =~ /:(\w+)$/
- command_name, namespace = $1, namespace.slice(0, char)
+ if command = find_by_namespace(namespace)
+ command.perform(namespace, args, config)
else
- command_name = namespace
- end
-
- command_name = "help" if command_name.blank? || HELP_MAPPINGS.include?(command_name)
- namespace = "version" if %w( -v --version ).include?(command_name)
-
- if command = find_by_namespace(namespace, command_name)
- command.perform(command_name, args, config)
- else
- find_by_namespace("rake").perform(full_namespace, args, config)
+ find_by_namespace("rake").perform(namespace, args, config)
end
end
@@ -59,10 +52,8 @@ module Rails
#
# Notice that "rails:commands:webrat" could be loaded as well, what
# Rails looks for is the first and last parts of the namespace.
- def find_by_namespace(namespace, command_name = nil) # :nodoc:
- lookups = [ namespace ]
- lookups << "#{namespace}:#{command_name}" if command_name
- lookups.concat lookups.map { |lookup| "rails:#{lookup}" }
+ def find_by_namespace(name) # :nodoc:
+ lookups = [ name, "rails:#{name}" ]
lookup(lookups)
diff --git a/railties/lib/rails/command/base.rb b/railties/lib/rails/command/base.rb
index db20c71861..1435792536 100644
--- a/railties/lib/rails/command/base.rb
+++ b/railties/lib/rails/command/base.rb
@@ -56,9 +56,7 @@ module Rails
end
def perform(command, args, config) # :nodoc:
- if Rails::Command::HELP_MAPPINGS.include?(args.first)
- command, args = "help", []
- end
+ command = nil if Rails::Command::HELP_MAPPINGS.include?(args.first)
dispatch(command, args.dup, nil, config)
end
@@ -113,7 +111,7 @@ module Rails
# For a `Rails::Command::TestCommand` placed in `rails/command/test_command.rb`
# would return `rails/test`.
def default_command_root
- path = File.expand_path(File.join("../commands", command_root_namespace), __dir__)
+ path = File.expand_path(File.join("../commands", command_name), __dir__)
path if File.exist?(path)
end
@@ -131,10 +129,6 @@ module Rails
super
end
end
-
- def command_root_namespace
- (namespace.split(":") - %w( rails )).first
- end
end
def help
diff --git a/railties/lib/rails/commands/secrets/USAGE b/railties/lib/rails/commands/secrets/USAGE
deleted file mode 100644
index 4b7deb4e2a..0000000000
--- a/railties/lib/rails/commands/secrets/USAGE
+++ /dev/null
@@ -1,52 +0,0 @@
-=== Storing Encrypted Secrets in Source Control
-
-The Rails `secrets` commands helps encrypting secrets to slim a production
-environment's `ENV` hash. It's also useful for atomic deploys: no need to
-coordinate key changes to get everything working as the keys are shipped
-with the code.
-
-=== Setup
-
-Run `bin/rails secrets:setup` to opt in and generate the `config/secrets.yml.key`
-and `config/secrets.yml.enc` files.
-
-The latter contains all the keys to be encrypted while the former holds the
-encryption key.
-
-Don't lose the key! Put it in a password manager your team can access.
-Should you lose it no one, including you, will be able to access any encrypted
-secrets.
-Don't commit the key! Add `config/secrets.yml.key` to your source control's
-ignore file. If you use Git, Rails handles this for you.
-
-Rails also looks for the key in `ENV["RAILS_MASTER_KEY"]` if that's easier to
-manage.
-
-You could prepend that to your server's start command like this:
-
- RAILS_MASTER_KEY="im-the-master-now-hahaha" server.start
-
-
-The `config/secrets.yml.enc` has much the same format as `config/secrets.yml`:
-
- production:
- secret_key_base: so-secret-very-hidden-wow
- payment_processing_gateway_key: much-safe-very-gaedwey-wow
-
-But that's where the similarities between `secrets.yml` and `secrets.yml.enc`
-end, e.g. no keys from `secrets.yml` will be moved to `secrets.yml.enc` and
-be encrypted.
-
-A `shared:` top level key is also supported such that any keys there is merged
-into the other environments.
-
-=== Editing Secrets
-
-After `bin/rails secrets:setup`, run `bin/rails secrets:edit`.
-
-That command opens a temporary file in `$EDITOR` with the decrypted contents of
-`config/secrets.yml.enc` to edit the encrypted secrets.
-
-When the temporary file is next saved the contents are encrypted and written to
-`config/secrets.yml.enc` while the file itself is destroyed to prevent secrets
-from leaking.
diff --git a/railties/lib/rails/commands/secrets/secrets_command.rb b/railties/lib/rails/commands/secrets/secrets_command.rb
deleted file mode 100644
index 05e0c228e8..0000000000
--- a/railties/lib/rails/commands/secrets/secrets_command.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-require "active_support"
-require "rails/secrets"
-
-module Rails
- module Command
- class SecretsCommand < Rails::Command::Base # :nodoc:
- def help
- say "Usage:\n #{self.class.banner}"
- say ""
- say self.class.desc
- end
-
- def setup
- require "rails/generators"
- require "rails/generators/rails/encrypted_secrets/encrypted_secrets_generator"
-
- Rails::Generators::EncryptedSecretsGenerator.start
- end
-
- def edit
- require_application_and_environment!
-
- Rails::Secrets.read_for_editing do |tmp_path|
- watch tmp_path do
- puts "Waiting for secrets file to be saved. Abort with Ctrl-C."
- system("\$EDITOR #{tmp_path}")
- end
- end
-
- puts "New secrets encrypted and saved."
- rescue Interrupt
- puts "Aborted changing encrypted secrets: nothing saved."
- rescue Rails::Secrets::MissingKeyError => error
- say error.message
- end
-
- private
- def watch(tmp_path)
- mtime, start_time = File.mtime(tmp_path), Time.now
-
- yield
-
- editor_exits_after_open = $?.success? && (Time.now - start_time) < 1
- if editor_exits_after_open
- sleep 0.250 until File.mtime(tmp_path) != mtime
- end
- end
- end
- end
-end
diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb
index 3f1bf6a5bb..85f66cc416 100644
--- a/railties/lib/rails/generators.rb
+++ b/railties/lib/rails/generators.rb
@@ -214,7 +214,6 @@ module Rails
rails.map! { |n| n.sub(/^rails:/, "") }
rails.delete("app")
rails.delete("plugin")
- rails.delete("encrypted_secrets")
hidden_namespaces.each { |n| groups.delete(n.to_s) }
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
index 9c4a77fd1d..4a39e43e57 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -14,11 +14,6 @@ Rails.application.configure do
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
- # Attempt to read encrypted secrets from `config/secrets.yml.enc`.
- # Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or
- # `config/secrets.yml.key`.
- config.read_encrypted_secrets = true
-
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
diff --git a/railties/lib/rails/generators/rails/app/templates/config/secrets.yml b/railties/lib/rails/generators/rails/app/templates/config/secrets.yml
index 816efcc5b1..8e995a5df1 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/secrets.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/secrets.yml
@@ -23,10 +23,8 @@ development:
test:
secret_key_base: <%= app_secret %>
-# Do not keep production secrets in the unencrypted secrets file.
-# Instead, either read values from the environment.
-# Or, use `bin/rails secrets:setup` to configure encrypted secrets
-# and move the `production:` environment over there.
+# Do not keep production secrets in the repository,
+# instead read values from the environment.
production:
secret_key_base: <%%= ENV["SECRET_KEY_BASE"] %>
diff --git a/railties/lib/rails/generators/rails/encrypted_secrets/encrypted_secrets_generator.rb b/railties/lib/rails/generators/rails/encrypted_secrets/encrypted_secrets_generator.rb
deleted file mode 100644
index 8b29213610..0000000000
--- a/railties/lib/rails/generators/rails/encrypted_secrets/encrypted_secrets_generator.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-require "rails/generators/base"
-require "rails/secrets"
-
-module Rails
- module Generators
- class EncryptedSecretsGenerator < Base
- def add_secrets_key_file
- unless File.exist?("config/secrets.yml.key") || File.exist?("config/secrets.yml.enc")
- key = Rails::Secrets.generate_key
-
- say "Adding config/secrets.yml.key to store the encryption key: #{key}"
- say ""
- say "Save this in a password manager your team can access."
- say ""
- say "If you lose the key, no one, including you, can access any encrypted secrets."
-
- say ""
- create_file "config/secrets.yml.key", key
- say ""
- end
- end
-
- def ignore_key_file
- if File.exist?(".gitignore")
- unless File.read(".gitignore").include?(key_ignore)
- say "Ignoring config/secrets.yml.key so it won't end up in Git history:"
- say ""
- append_to_file ".gitignore", key_ignore
- say ""
- end
- else
- say "IMPORTANT: Don't commit config/secrets.yml.key. Add this to your ignore file:"
- say key_ignore, :on_green
- say ""
- end
- end
-
- def add_encrypted_secrets_file
- unless 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.encrypt(prefill)
- end
-
- say "You can edit encrypted secrets with `bin/rails secrets:edit`."
-
- say "Add this to your config/environments/production.rb:"
- say "config.read_encrypted_secrets = true"
- end
- end
-
- private
- def key_ignore
- [ "", "# Ignore encrypted secrets key file.", "config/secrets.yml.key", "" ].join("\n")
- end
- end
- end
-end
diff --git a/railties/lib/rails/generators/rails/encrypted_secrets/templates/config/secrets.yml.enc b/railties/lib/rails/generators/rails/encrypted_secrets/templates/config/secrets.yml.enc
deleted file mode 100644
index 70426a66a5..0000000000
--- a/railties/lib/rails/generators/rails/encrypted_secrets/templates/config/secrets.yml.enc
+++ /dev/null
@@ -1,3 +0,0 @@
-# See `secrets.yml` for tips on generating suitable keys.
-# production:
-# external_api_key: 1466aac22e6a869134be3d09b9e89232fc2c2289…
diff --git a/railties/lib/rails/secrets.rb b/railties/lib/rails/secrets.rb
deleted file mode 100644
index a083914109..0000000000
--- a/railties/lib/rails/secrets.rb
+++ /dev/null
@@ -1,111 +0,0 @@
-require "yaml"
-
-module Rails
- # Greatly inspired by Ara T. Howard's magnificent sekrets gem. 😘
- class Secrets # :nodoc:
- class MissingKeyError < RuntimeError
- def initialize
- super(<<-end_of_message.squish)
- Missing encryption key to decrypt secrets with.
- Ask your team for your master key and put it in ENV["RAILS_MASTER_KEY"]
- end_of_message
- end
- end
-
- @read_encrypted_secrets = false
- @root = File # Wonky, but ensures `join` uses the current directory.
-
- class << self
- attr_writer :root
- attr_accessor :read_encrypted_secrets
-
- def parse(paths, env:)
- paths.each_with_object(Hash.new) do |path, all_secrets|
- require "erb"
-
- secrets = YAML.load(ERB.new(preprocess(path)).result) || {}
- all_secrets.merge!(secrets["shared"].deep_symbolize_keys) if secrets["shared"]
- all_secrets.merge!(secrets[env].deep_symbolize_keys) if secrets[env]
- end
- end
-
- def generate_key
- cipher = new_cipher
- SecureRandom.hex(cipher.key_len)[0, cipher.key_len]
- end
-
- def key
- ENV["RAILS_MASTER_KEY"] || read_key_file || handle_missing_key
- end
-
- def encrypt(text)
- cipher(:encrypt, text)
- end
-
- def decrypt(data)
- cipher(:decrypt, data)
- end
-
- def read
- decrypt(IO.binread(path))
- end
-
- def write(contents)
- IO.binwrite("#{path}.tmp", encrypt(contents))
- FileUtils.mv("#{path}.tmp", path)
- end
-
- def read_for_editing
- tmp_path = File.join(Dir.tmpdir, File.basename(path))
- IO.binwrite(tmp_path, read)
-
- yield tmp_path
-
- write(IO.binread(tmp_path))
- ensure
- FileUtils.rm(tmp_path) if File.exist?(tmp_path)
- end
-
- private
- def handle_missing_key
- raise MissingKeyError
- end
-
- def read_key_file
- if File.exist?(key_path)
- IO.binread(key_path).strip
- end
- end
-
- def key_path
- @root.join("config", "secrets.yml.key")
- end
-
- def path
- @root.join("config", "secrets.yml.enc").to_s
- end
-
- def preprocess(path)
- if path.end_with?(".enc")
- if @read_encrypted_secrets
- decrypt(IO.binread(path))
- else
- ""
- end
- else
- IO.read(path)
- end
- end
-
- def new_cipher
- OpenSSL::Cipher.new("aes-256-cbc")
- end
-
- def cipher(mode, data)
- cipher = new_cipher.public_send(mode)
- cipher.key = key
- cipher.update(data) << cipher.final
- end
- end
- end
-end