Files
ubicloud/bin/ubi
Jeremy Evans a94f0e5081 Have cli program send version in header
This allows the server to take appropriate action based on client version.
It we add new features that require an updated client version, we can
check the client's version, and give them a give the clients a nice error
message instructing them to upgrade.

This required a minor change to Rodish to execute code after option
parsing and before subcommand processing, even if there are no valid
subcommands provided.  I made that change and released a new version,
so this bumps the rodish version.

The cli version is stored in cli/version.txt.  bin/ubi reads this
file when run.  In the rake ubi/ubi-cross tasks, the Rakefile
reads this file and sets the version in the compiled go file.
2025-03-04 16:55:53 -08:00

122 lines
3.0 KiB
Ruby
Executable File

#!/usr/bin/env ruby
# frozen_string_literal: true
begin
require_relative "../.env"
rescue LoadError
end
require "net/http"
require "json"
unless (token = ENV["UBI_TOKEN"])
warn "! Personal access token must be provided in UBI_TOKEN env variable for use"
exit 1
end
url = ENV["UBI_URL"] || "https://api.ubicloud.com/cli"
allowed_progs = %w[ssh scp sftp psql pg_dump pg_dumpall]
get_prog = lambda do |prog|
return unless allowed_progs.include?(prog)
ENV["UBI_#{prog.upcase}"] || prog
end
uri = URI(url)
argv = ARGV
headers = {
"authorization" => "Bearer: #{token}",
"x-ubi-version" => File.read(File.expand_path("../../cli/version.txt", __FILE__)).chomp,
"content-type" => "application/json",
"accept" => "text/plain",
"connection" => "close"
}
confirmation_prompt = false
confirmation = nil
1.times do
if ENV["UBI_DEBUG"] == "1"
p [:sending, *argv]
end
response = Net::HTTP.post(uri, {"argv" => argv}.to_json, headers)
case response.code.to_i
when 200...300
if (prog_type = response["ubi-command-execute"])
unless ARGV.include?(prog_type)
warn "! Invalid server response, not executing program not in original argv"
exit 1
end
unless (prog = get_prog[prog_type])
warn "! Invalid server response, unsupported program requested"
exit 1
end
argv_set = ARGV.to_set
args = response.body.split("\0")
invalid_message = nil
sep_seen = false
custom_arg_seen = false
pg_dumpall = false
args.each do |arg|
if arg == "--"
sep_seen = true
elsif !argv_set.include?(arg)
if custom_arg_seen
invalid_message = "! Invalid server response, multiple arguments not in submitted argv"
break
elsif sep_seen
custom_arg_seen = true
elsif prog_type == "pg_dumpall" && arg.start_with?("-d")
pg_dumpall = true
custom_arg_seen = true
else
invalid_message = "! Invalid server response, argument before '--' not in submitted argv"
break
end
end
end
unless sep_seen || pg_dumpall
invalid_message ||= "! Invalid server response, no '--' in returned argv"
end
if invalid_message
if ENV["UBI_DEBUG"] == "1"
p [:failure, prog, *args]
end
warn invalid_message
exit 1
else
if ENV["UBI_DEBUG"] == "1"
p [:exec, prog, *args]
end
Process.exec(prog, *args)
end
else
if (confirmation_prompt = response["ubi-confirm"])
if confirmation
warn "! Invalid server response, repeated confirmation attempt"
exit 1
else
$stdout.print response.body
$stdout.print "\n#{confirmation_prompt}: "
confirmation = $stdin.readline.chomp
argv.unshift(confirmation)
argv.unshift("--confirm")
redo
end
else
$stdout.print response.body
end
exit 0
end
else
warn response.body
exit 1
end
end