diff --git a/lib/kamal/utils.rb b/lib/kamal/utils.rb index c61d4cf8a..ec98f3c82 100644 --- a/lib/kamal/utils.rb +++ b/lib/kamal/utils.rb @@ -92,6 +92,13 @@ def escape_shell_value(value) .gsub(DOLLAR_SIGN_WITHOUT_SHELL_EXPANSION_REGEX, '\$') end + # Escape a value to make it safe to dump in a docker file. + def escape_docker_env_file_value(value) + # Doublequotes are treated literally in docker env files + # so remove leading and trailing ones and unescape any others + value.to_s.dump[1..-2].gsub(/\\"/, "\"") + end + # Abbreviate a git revhash for concise display def abbreviate_version(version) if version @@ -109,10 +116,6 @@ def uncommitted_changes end def docker_env_file_line(key, value) - if key.include?("\n") || value.to_s.include?("\n") - raise ArgumentError, "docker env file format does not support newlines in keys or values, key: #{key}" - end - - "#{key.to_s}=#{value.to_s}\n" + "#{key.to_s}=#{escape_docker_env_file_value(value)}\n" end end diff --git a/test/utils_test.rb b/test/utils_test.rb index 3edfe8f5c..b268fb0fe 100644 --- a/test/utils_test.rb +++ b/test/utils_test.rb @@ -49,6 +49,30 @@ class UtilsTest < ActiveSupport::TestCase ENV.delete "PASSWORD" end + test "env file secret escaped newline" do + ENV["PASSWORD"] = "hello\\nthere" + env = { + "secret" => [ "PASSWORD" ] + } + + assert_equal "PASSWORD=hello\\\\nthere\n", \ + Kamal::Utils.env_file_with_secrets(env) + ensure + ENV.delete "PASSWORD" + end + + test "env file secret newline" do + ENV["PASSWORD"] = "hello\nthere" + env = { + "secret" => [ "PASSWORD" ] + } + + assert_equal "PASSWORD=hello\\nthere\n", \ + Kamal::Utils.env_file_with_secrets(env) + ensure + ENV.delete "PASSWORD" + end + test "env file missing secret" do env = { "secret" => [ "PASSWORD" ]