From 2f66df0e10bad4002e36533721320049bded255b Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Sun, 17 Apr 2022 11:17:04 -0500 Subject: [PATCH] Avoid escaping paths when editing credentials `Shellwords.escape` escapes unquoted spaces with a backslash, but Windows does not treat backslash as an escape character. Escaping is also a problem when paths are expressed in shortened 8.3 format (e.g. `C:\Users\RubyOn~1\AppData\Local\Temp\...`) because a backslash will be erroneously added before the `~`. We can avoid the need to escape by using `system(command_name, *args)` instead of `system(command_line)`, but we must still support `ENV["EDITOR"]` values that embed command line arguments, such as `subl -w`. This commit changes to `system(command_name, *args)`, but uses `Shellwords.split` to extract any embedded arguments from `ENV["EDITOR"]`. This requires that Windows users put quotes around the entire path of their editor if it contains spaces, such as: ``` SET EDITOR="C:\Program Files\Microsoft VS Code\Code.exe" -w ``` In other words, the following are **not** supported on Windows: ``` SET "EDITOR=C:\Program Files\Microsoft VS Code\Code.exe" SET EDITOR=C:\Program Files\Microsoft VS Code\Code.exe SET EDITOR=C:\"Program Files"\"Microsoft VS Code"\Code.exe -w SET EDITOR=C:\Program^ Files\Microsoft^ VS^ Code\Code.exe -w SET EDITOR=C:\Program` Files\Microsoft` VS` Code\Code.exe -w ``` Fixes #41617 (again). Closes #44890. --- railties/lib/rails/commands/credentials/credentials_command.rb | 2 +- railties/test/commands/credentials_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/lib/rails/commands/credentials/credentials_command.rb b/railties/lib/rails/commands/credentials/credentials_command.rb index dd463874e22c9..c1a942ebe3853 100644 --- a/railties/lib/rails/commands/credentials/credentials_command.rb +++ b/railties/lib/rails/commands/credentials/credentials_command.rb @@ -92,7 +92,7 @@ def ensure_credentials_have_been_added def change_credentials_in_system_editor credentials.change do |tmp_path| - system("#{ENV["EDITOR"]} #{Shellwords.escape(tmp_path)}") + system(*Shellwords.split(ENV["EDITOR"]), tmp_path.to_s) end end diff --git a/railties/test/commands/credentials_test.rb b/railties/test/commands/credentials_test.rb index ffaef6eac3acd..5054e77613ee8 100644 --- a/railties/test/commands/credentials_test.rb +++ b/railties/test/commands/credentials_test.rb @@ -36,7 +36,7 @@ class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase end test "edit command does not overwrite by default if credentials already exists" do - run_edit_command(editor: "eval echo api_key: abc >") + run_edit_command(editor: 'ruby -e "File.write ARGV[0], %(api_key: abc)"') assert_match(/api_key: abc/, run_show_command) run_edit_command