Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

optionize reject nil value #531

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/kamal/env_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ def docker_env_file_line(key, value)

# Escape a value to make it safe to dump in a docker file.
def escape_docker_env_file_value(value)
# keep non-ascii(UTF-8) characters as is
value.to_s.scan(/[\x00-\x7F]+|[^\x00-\x7F]+/).map do |part|
part.ascii_only? ? escape_docker_env_file_ascii_value(part) : part
end.join
end

def escape_docker_env_file_ascii_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(/\\"/, "\"")
Expand Down
5 changes: 3 additions & 2 deletions lib/kamal/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ def argumentize(argument, attributes, sensitive: false)

# Returns a list of shell-dashed option arguments. If the value is true, it's treated like a value-less option.
def optionize(args, with: nil)
args = flatten_args(args).reject { |(_key, value)| value.nil? }
options = if with
flatten_args(args).collect { |(key, value)| value == true ? "--#{key}" : "--#{key}#{with}#{escape_shell_value(value)}" }
args.collect { |(key, value)| value == true ? "--#{key}" : "--#{key}#{with}#{escape_shell_value(value)}" }
else
flatten_args(args).collect { |(key, value)| [ "--#{key}", value == true ? nil : escape_shell_value(value) ] }
args.collect { |(key, value)| [ "--#{key}", value == true ? nil : escape_shell_value(value) ] }
end

options.flatten.compact
Expand Down
27 changes: 27 additions & 0 deletions test/env_file_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,33 @@ class EnvFileTest < ActiveSupport::TestCase
Kamal::EnvFile.new(env).to_s
end

test "to_str won't escape chinese characters" do
env = {
"foo" => '你好 means hello, "欢迎" means welcome, that\'s simple! 😃 {smile}'
}

assert_equal "foo=你好 means hello, \"欢迎\" means welcome, that's simple! 😃 {smile}\n",
Kamal::EnvFile.new(env).to_s
end

test "to_s won't escape japanese characters" do
env = {
"foo" => 'こんにちは means hello, "ようこそ" means welcome, that\'s simple! 😃 {smile}'
}

assert_equal "foo=こんにちは means hello, \"ようこそ\" means welcome, that's simple! 😃 {smile}\n", \
Kamal::EnvFile.new(env).to_s
end

test "to_s won't escape korean characters" do
env = {
"foo" => '안녕하세요 means hello, "어서 오십시오" means welcome, that\'s simple! 😃 {smile}'
}

assert_equal "foo=안녕하세요 means hello, \"어서 오십시오\" means welcome, that's simple! 😃 {smile}\n", \
Kamal::EnvFile.new(env).to_s
end

test "to_s empty" do
assert_equal "\n", Kamal::EnvFile.new({}).to_s
end
Expand Down
2 changes: 1 addition & 1 deletion test/integration/docker/deployer/app/.env.erb
Original file line number Diff line number Diff line change
@@ -1 +1 @@
SECRET_TOKEN=1234
SECRET_TOKEN='1234 with "中文"'
2 changes: 1 addition & 1 deletion test/integration/docker/deployer/app_with_roles/.env.erb
Original file line number Diff line number Diff line change
@@ -1 +1 @@
SECRET_TOKEN=1234
SECRET_TOKEN='1234 with "中文"'
6 changes: 3 additions & 3 deletions test/integration/main_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
class MainTest < IntegrationTest
test "envify, deploy, redeploy, rollback, details and audit" do
kamal :envify
assert_local_env_file "SECRET_TOKEN=1234"
assert_remote_env_file "SECRET_TOKEN=1234"
assert_local_env_file "SECRET_TOKEN='1234 with \"中文\"'"
assert_remote_env_file "SECRET_TOKEN=1234 with \"中文\""
remove_local_env_file

first_version = latest_app_version
Expand All @@ -16,7 +16,7 @@ class MainTest < IntegrationTest
assert_hooks_ran "pre-connect", "pre-build", "pre-deploy", "post-deploy"
assert_env :CLEAR_TOKEN, "4321", version: first_version
assert_env :HOST_TOKEN, "abcd", version: first_version
assert_env :SECRET_TOKEN, "1234", version: first_version
assert_env :SECRET_TOKEN, "1234 with \"中文\"", version: first_version

second_version = update_app_rev

Expand Down
5 changes: 5 additions & 0 deletions test/utils_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ class UtilsTest < ActiveSupport::TestCase
Kamal::Utils.optionize({ foo: "bar", baz: "qux", quux: true }, with: "=")
end

test "optionize reject nil value" do
assert_equal [ "--foo", "\"bar\"", "--baz", "\"qux\"" ], \
Kamal::Utils.optionize({ foo: "bar", baz: "qux", quux: nil })
end

test "no redaction from #to_s" do
assert_equal "secret", Kamal::Utils.sensitive("secret").to_s
end
Expand Down