diff options
Diffstat (limited to 'railties/lib')
7 files changed, 89 insertions, 87 deletions
diff --git a/railties/lib/rails/command/helpers/pretty_credentials.rb b/railties/lib/rails/command/helpers/pretty_credentials.rb deleted file mode 100644 index 873ed0e825..0000000000 --- a/railties/lib/rails/command/helpers/pretty_credentials.rb +++ /dev/null @@ -1,55 +0,0 @@ -# frozen_string_literal: true - -require "fileutils" - -module Rails - module Command - module Helpers - module PrettyCredentials - Error = Class.new(StandardError) - - def opt_in_pretty_credentials - unless already_answered? || already_opted_in? - answer = yes?("Would you like to make the credentials diff from git more readable in the future? [Y/n]") - end - - opt_in! if answer - FileUtils.touch(tracker) unless answer.nil? - rescue Error - say("Couldn't setup git to prettify the credentials diff") - end - - private - def already_answered? - tracker.exist? - end - - def already_opted_in? - system_call("git config --get 'diff.rails_credentials.textconv'", accepted_codes: [0, 1]) - end - - def opt_in! - system_call("git config diff.rails_credentials.textconv 'bin/rails credentials:show'", accepted_codes: [0]) - - git_attributes = Rails.root.join(".gitattributes") - File.open(git_attributes, "a+") do |file| - file.write(<<~EOM) - config/credentials/*.yml.enc diff=rails_credentials - config/credentials.yml.enc diff=rails_credentials - EOM - end - end - - def tracker - Rails.root.join("tmp", "rails_pretty_credentials") - end - - def system_call(command_line, accepted_codes:) - result = system(command_line) - raise(Error) if accepted_codes.exclude?($?.exitstatus) - result - end - end - end - end -end diff --git a/railties/lib/rails/commands/credentials/USAGE b/railties/lib/rails/commands/credentials/USAGE index c8d3fb9eda..6b896ab02a 100644 --- a/railties/lib/rails/commands/credentials/USAGE +++ b/railties/lib/rails/commands/credentials/USAGE @@ -30,6 +30,21 @@ You could prepend that to your server's start command like this: RAILS_MASTER_KEY="very-secret-and-secure" server.start +=== Set up Git to Diff Credentials + +Rails provides `rails credentials:diff --enable` to instruct Git to call `rails credentials:diff` +when `git diff` is run on a credentials file. + +Running the command enrolls the project such that all credentials files use the +"rails_credentials" diff driver in .gitattributes. + +Additionally since Git requires the driver itself to be set up in a config file +that isn't tracked Rails automatically ensures it's configured when running +`credentials:edit`. + +Otherwise each co-worker would have to run enable manually, including on each new +repo clone. + === Editing Credentials This will open a temporary file in `$EDITOR` with the decrypted contents to edit diff --git a/railties/lib/rails/commands/credentials/credentials_command.rb b/railties/lib/rails/commands/credentials/credentials_command.rb index 772e105007..9cde44558b 100644 --- a/railties/lib/rails/commands/credentials/credentials_command.rb +++ b/railties/lib/rails/commands/credentials/credentials_command.rb @@ -1,18 +1,19 @@ # frozen_string_literal: true +require "pathname" require "active_support" require "rails/command/helpers/editor" -require "rails/command/helpers/pretty_credentials" require "rails/command/environment_argument" -require "pathname" module Rails module Command class CredentialsCommand < Rails::Command::Base # :nodoc: include Helpers::Editor - include Helpers::PrettyCredentials include EnvironmentArgument + require_relative "credentials_command/diffing" + include Diffing + self.environment_desc = "Uses credentials from config/credentials/:environment.yml.enc encrypted by config/credentials/:environment.key key" no_commands do @@ -31,35 +32,44 @@ module Rails ensure_encryption_key_has_been_added if credentials.key.nil? ensure_credentials_have_been_added + ensure_rails_credentials_driver_is_set catch_editing_exceptions do change_credentials_in_system_editor end say "File encrypted and saved." - opt_in_pretty_credentials rescue ActiveSupport::MessageEncryptor::InvalidMessage say "Couldn't decrypt #{content_path}. Perhaps you passed the wrong key?" end - def show(git_textconv_path = nil) - if git_textconv_path - default_environment = extract_environment_from_path(git_textconv_path) - fallback_message = File.read(git_textconv_path) - end - - extract_environment_option_from_argument(default_environment: default_environment) + def show + extract_environment_option_from_argument(default_environment: nil) require_application! - say credentials(git_textconv_path).read.presence || fallback_message || missing_credentials_message - rescue => e - raise(e) unless git_textconv_path - fallback_message + say credentials.read.presence || missing_credentials_message + end + + option :enroll, type: :boolean, default: false, + desc: "Enrolls project in credential file diffing with `git diff`" + + def diff(content_path = nil) + if @content_path = content_path + extract_environment_option_from_argument(default_environment: extract_environment_from_path(content_path)) + require_application! + + say credentials.read.presence || credentials.content_path.read + else + require_application! + enroll_project_in_credentials_diffing if options[:enroll] + end + rescue ActiveSupport::MessageEncryptor::InvalidMessage + say credentials.content_path.read end private - def credentials(content = nil) - Rails.application.encrypted(content || content_path, key_path: key_path) + def credentials + Rails.application.encrypted(content_path, key_path: key_path) end def ensure_encryption_key_has_been_added @@ -89,8 +99,9 @@ module Rails end end + def content_path - options[:environment] ? "config/credentials/#{options[:environment]}.yml.enc" : "config/credentials.yml.enc" + @content_path ||= options[:environment] ? "config/credentials/#{options[:environment]}.yml.enc" : "config/credentials.yml.enc" end def key_path @@ -98,15 +109,7 @@ module Rails end def extract_environment_from_path(path) - regex = %r{ - ([A-Za-z0-9]+) # match the environment - (?<!credentials) # don't match if file contains the word "credentials" - # in such case, the environment should be the default one - \.yml\.enc # look for `.yml.enc` file extension - }x - path.match(regex) - - Regexp.last_match(1) + available_environments.find { |env| path.include? env } if path.match?(/\.yml\.enc$/) end def encryption_key_file_generator diff --git a/railties/lib/rails/commands/credentials/credentials_command/diffing.rb b/railties/lib/rails/commands/credentials/credentials_command/diffing.rb new file mode 100644 index 0000000000..1d34c68074 --- /dev/null +++ b/railties/lib/rails/commands/credentials/credentials_command/diffing.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Rails::Command::CredentialsCommand::Diffing # :nodoc: + def enroll_project_in_credentials_diffing + if enrolled? + true + else + gitattributes.write(<<~end_of_template, mode: "a") + config/credentials/*.yml.enc diff=rails_credentials + config/credentials.yml.enc diff=rails_credentials + end_of_template + + say "Project successfully enrolled!" + say "Rails ensures the rails_credentials diff driver is set when running `credentials:edit`. See `credentials:help` for more." + end + end + + def ensure_rails_credentials_driver_is_set + set_driver if enrolled? && !driver_configured? + end + + private + def enrolled? + gitattributes.read.match?(/config\/credentials(\/\*)?\.yml\.enc diff=rails_credentials/) + rescue Errno::ENOENT + false + end + + def driver_configured? + system "git config --get diff.rails_credentials.textconv", out: File::NULL + end + + def set_driver + puts "running" + system "git config diff.rails_credentials.textconv 'bin/rails credentials:diff'" + end + + def gitattributes + Rails.root.join(".gitattributes") + end +end diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index b4c0028b1f..f8f5ff443a 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -3,6 +3,7 @@ require "rails/railtie" require "rails/engine/railties" require "active_support/core_ext/module/delegation" +require "active_support/core_ext/object/try" require "pathname" require "thread" diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index 436315ce1e..aa7ef1077e 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -128,11 +128,6 @@ module Rails end end - # Remove the color from output. - def no_color! - Thor::Base.shell = Thor::Shell::Basic - end - # Returns an array of generator namespaces that are hidden. # Generator namespaces may be hidden for a variety of reasons. # Some are aliased such as "rails:migration" and can be diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt index c66e349442..41dabb87df 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt @@ -3,6 +3,8 @@ # your test database is "scratch space" for the test suite and is wiped # and recreated between test runs. Don't rely on the data there! +require "active_support/core_ext/integer/time" + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. <%# Spring executes the reloaders when files change. %> |