Merge pull request #928 from basecamp/kamal-secrets-inline-aware
Make the secrets commands inline aware
This commit is contained in:
@@ -3,26 +3,26 @@ class Kamal::Cli::Secrets < Kamal::Cli::Base
|
|||||||
option :adapter, type: :string, aliases: "-a", required: true, desc: "Which vault adapter to use"
|
option :adapter, type: :string, aliases: "-a", required: true, desc: "Which vault adapter to use"
|
||||||
option :account, type: :string, required: true, desc: "The account identifier or username"
|
option :account, type: :string, required: true, desc: "The account identifier or username"
|
||||||
option :from, type: :string, required: false, desc: "A vault or folder to fetch the secrets from"
|
option :from, type: :string, required: false, desc: "A vault or folder to fetch the secrets from"
|
||||||
|
option :inline, type: :boolean, required: false, hidden: true
|
||||||
def fetch(*secrets)
|
def fetch(*secrets)
|
||||||
|
handle_output(inline: options[:inline]) do
|
||||||
results = adapter(options[:adapter]).fetch(secrets, **options.slice(:account, :from).symbolize_keys)
|
results = adapter(options[:adapter]).fetch(secrets, **options.slice(:account, :from).symbolize_keys)
|
||||||
puts JSON.dump(results).shellescape
|
JSON.dump(results).shellescape
|
||||||
rescue => e
|
end
|
||||||
handle_error(e)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "extract", "Extract a single secret from the results of a fetch call"
|
desc "extract", "Extract a single secret from the results of a fetch call"
|
||||||
|
option :inline, type: :boolean, required: false, hidden: true
|
||||||
def extract(name, secrets)
|
def extract(name, secrets)
|
||||||
|
handle_output(inline: options[:inline]) do
|
||||||
parsed_secrets = JSON.parse(secrets)
|
parsed_secrets = JSON.parse(secrets)
|
||||||
|
|
||||||
if (value = parsed_secrets[name]).nil?
|
value = parsed_secrets[name] || parsed_secrets.find { |k, v| k.end_with?("/#{name}") }&.last
|
||||||
value = parsed_secrets.find { |k, v| k.end_with?("/#{name}") }&.last
|
|
||||||
end
|
|
||||||
|
|
||||||
raise "Could not find secret #{name}" if value.nil?
|
raise "Could not find secret #{name}" if value.nil?
|
||||||
|
|
||||||
puts value
|
value
|
||||||
rescue => e
|
end
|
||||||
handle_error(e)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -30,11 +30,18 @@ class Kamal::Cli::Secrets < Kamal::Cli::Base
|
|||||||
Kamal::Secrets::Adapters.lookup(adapter)
|
Kamal::Secrets::Adapters.lookup(adapter)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_output(inline: nil)
|
||||||
|
yield.tap do |output|
|
||||||
|
puts output unless inline
|
||||||
|
end
|
||||||
|
rescue => e
|
||||||
|
handle_error(e)
|
||||||
|
end
|
||||||
|
|
||||||
def handle_error(e)
|
def handle_error(e)
|
||||||
$stderr.puts " \e[31mERROR (#{e.class}): #{e.message}\e[0m"
|
$stderr.puts " \e[31mERROR (#{e.class}): #{e.message}\e[0m"
|
||||||
$stderr.puts e.backtrace if ENV["VERBOSE"]
|
$stderr.puts e.backtrace if ENV["VERBOSE"]
|
||||||
|
|
||||||
Process.kill("INT", Process.ppid) if ENV["KAMAL_SECRETS_INT_PARENT"]
|
|
||||||
exit 1
|
exit 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -30,17 +30,9 @@ class Kamal::Secrets
|
|||||||
|
|
||||||
def parse_secrets
|
def parse_secrets
|
||||||
if secrets_file
|
if secrets_file
|
||||||
interrupting_parent_on_error { ::Dotenv.parse(secrets_file) }
|
::Dotenv.parse(secrets_file)
|
||||||
else
|
else
|
||||||
{}
|
{}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def interrupting_parent_on_error
|
|
||||||
# Make any `kamal secrets` calls in dotenv interpolation interrupt this process if there are errors
|
|
||||||
ENV["KAMAL_SECRETS_INT_PARENT"] = "1"
|
|
||||||
yield
|
|
||||||
ensure
|
|
||||||
ENV.delete("KAMAL_SECRETS_INT_PARENT")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class Kamal::Secrets::Dotenv::InlineCommandSubstitution
|
|||||||
else
|
else
|
||||||
if command =~ /\A\s*kamal\s*secrets\s+/
|
if command =~ /\A\s*kamal\s*secrets\s+/
|
||||||
# Inline the command
|
# Inline the command
|
||||||
capture_stdout { Kamal::Cli::Main.start(command.shellsplit[1..]) }.chomp
|
inline_secrets_command(command)
|
||||||
else
|
else
|
||||||
# Execute the command and return the value
|
# Execute the command and return the value
|
||||||
`#{command}`.chomp
|
`#{command}`.chomp
|
||||||
@@ -25,13 +25,8 @@ class Kamal::Secrets::Dotenv::InlineCommandSubstitution
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def capture_stdout
|
def inline_secrets_command(command)
|
||||||
old_stdout = $stdout
|
Kamal::Cli::Main.start(command.shellsplit[1..] + [ "--inline" ]).chomp
|
||||||
$stdout = StringIO.new
|
|
||||||
yield
|
|
||||||
$stdout.string
|
|
||||||
ensure
|
|
||||||
$stdout = old_stdout
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ require "test_helper"
|
|||||||
|
|
||||||
class SecretsInlineCommandSubstitution < SecretAdapterTestCase
|
class SecretsInlineCommandSubstitution < SecretAdapterTestCase
|
||||||
test "inlines kamal secrets commands" do
|
test "inlines kamal secrets commands" do
|
||||||
Kamal::Cli::Main.expects(:start).with { |command| puts "results"; command == [ "secrets", "fetch", "..." ] }
|
Kamal::Cli::Main.expects(:start).with { |command| command == [ "secrets", "fetch", "...", "--inline" ] }.returns("results")
|
||||||
substituted = Kamal::Secrets::Dotenv::InlineCommandSubstitution.call("FOO=$(kamal secrets fetch ...)", nil, overwrite: false)
|
substituted = Kamal::Secrets::Dotenv::InlineCommandSubstitution.call("FOO=$(kamal secrets fetch ...)", nil, overwrite: false)
|
||||||
assert_equal "FOO=results", substituted
|
assert_equal "FOO=results", substituted
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user