Previously, there was a set of headers used: * ubi-command-execute: For the command to execute * ubi-command-arg: For the argument to the command * ubi-command-argv-tail: For the argv index to include the rest of argv in command * ubi-command-argv-initial: For the argv index to include before the argument to the command This was too limiting, as it doesn't allow specifying both options and arguments to exec-ed commands. This changes things so that ubi-command-execute still specifies the command, but the arguments are passed in the response body, separated by "\0". The client checks each argument for validity: * At least one argument must be "--" * At most one argument not already present in argv is allowed * The argument not already present in argv must be after "--" So the worst a malicious server can do is rearrange argument order and insert a single new argument, which will be parsed as an argument and not as an option. That's about the same security as before, with a lot less complexity and a lot more flexibility. Use the new flexibility to support passing options to the vm ssh, vm sftp, and vm scp commands: vm ssh location vm-name -A -- vm sftp location vm-name -A vm scp location vm-name local-path :remote-path -A For vm ssh, the -- is required to separate ssh options from ssh arguments. In addition to making the code significantly less complex, this makes the specs much more understandable. To ease debugging of bin/ubi, add support for an UBI_DEBUG environment variable, which will print the arguments passed to Process.exec, so you can more easily confirm correct behavior.
30 lines
823 B
Ruby
30 lines
823 B
Ruby
# frozen_string_literal: true
|
|
|
|
require_relative "../spec_helper"
|
|
|
|
RSpec.configure do |config|
|
|
def cli(argv, status: 200, env: {})
|
|
post("/cli", {"argv" => argv}.to_json, env)
|
|
expect(last_response.status).to eq(status)
|
|
expect(last_response["content-type"]).to eq("text/plain")
|
|
last_response.body
|
|
end
|
|
|
|
def cli_exec(argv, env: {})
|
|
body = cli(argv, env:)
|
|
[last_response.headers["ubi-command-execute"], *body.split("\0")]
|
|
end
|
|
|
|
config.define_derived_metadata(file_path: %r{\A\./spec/routes/api/cli/}) do |metadata|
|
|
metadata[:clover_cli] = true
|
|
end
|
|
|
|
config.before do |example|
|
|
next unless example.metadata[:clover_cli]
|
|
header "Accept", "text/plain"
|
|
@account = create_account
|
|
@use_pat = true
|
|
@project = project_with_default_policy(@account, name: "project-1")
|
|
end
|
|
end
|