Inline dotenv kamal secrets calls

This commit is contained in:
Donal McBreen
2024-09-06 16:56:54 +01:00
parent b99c044327
commit 57cbf7cdb5
4 changed files with 57 additions and 2 deletions

View File

@@ -1,5 +1,4 @@
require "thor"
require "dotenv"
require "kamal/sshkit_with_ext"
module Kamal::Cli

View File

@@ -1,6 +1,10 @@
require "dotenv"
class Kamal::Secrets
attr_reader :secrets_file
Kamal::Secrets::Dotenv::InlineCommandSubstitution.install!
def initialize(destination: nil)
@secrets_file = [ *(".kamal/secrets.#{destination}" if destination), ".kamal/secrets" ].find { |f| File.exist?(f) }
end
@@ -26,7 +30,7 @@ class Kamal::Secrets
def parse_secrets
if secrets_file
interrupting_parent_on_error { Dotenv.parse(secrets_file) }
interrupting_parent_on_error { ::Dotenv.parse(secrets_file) }
else
{}
end

View File

@@ -0,0 +1,37 @@
class Kamal::Secrets::Dotenv::InlineCommandSubstitution
class << self
def install!
::Dotenv::Parser.substitutions.map! { |sub| sub == ::Dotenv::Substitutions::Command ? self : sub }
end
def call(value, _env, overwrite: false)
# Process interpolated shell commands
value.gsub(Dotenv::Substitutions::Command.singleton_class::INTERPOLATED_SHELL_COMMAND) do |*|
# Eliminate opening and closing parentheses
command = $LAST_MATCH_INFO[:cmd][1..-2]
if $LAST_MATCH_INFO[:backslash]
# Command is escaped, don't replace it.
$LAST_MATCH_INFO[0][1..]
else
if command =~ /\A\s*kamal\s*secrets\s+/
# Inline the command
capture_stdout { Kamal::Cli::Main.start(command.shellsplit[1..]) }.chomp
else
# Execute the command and return the value
`#{command}`.chomp
end
end
end
end
def capture_stdout
old_stdout = $stdout
$stdout = StringIO.new
yield
$stdout.string
ensure
$stdout = old_stdout
end
end
end