From d0cb138410b04dad2d30ffe881b57771cfe73623 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 14 Mar 2017 01:49:04 +0300 Subject: [PATCH] hipe_compile: reject blank, non-existent paths and those with insufficient permissions References #178. --- lib/rabbitmq/cli/core/exit_codes.ex | 1 + lib/rabbitmq/cli/core/helpers.ex | 2 +- .../cli/ctl/commands/hipe_compile_command.ex | 26 +++++++++++++++++-- mix.exs | 1 + test/hipe_compile_command_test.exs | 24 +++++++++++++---- 5 files changed, 46 insertions(+), 8 deletions(-) diff --git a/lib/rabbitmq/cli/core/exit_codes.ex b/lib/rabbitmq/cli/core/exit_codes.ex index 3b0e7447..ceaf7d76 100644 --- a/lib/rabbitmq/cli/core/exit_codes.ex +++ b/lib/rabbitmq/cli/core/exit_codes.ex @@ -38,6 +38,7 @@ defmodule RabbitMQ.CLI.Core.ExitCodes do def exit_code_for({:validation_failure, {:too_many_args, _}}), do: exit_usage() def exit_code_for({:validation_failure, {:bad_argument, _}}), do: exit_dataerr() def exit_code_for({:validation_failure, :bad_argument}), do: exit_dataerr() + def exit_code_for({:validation_failure, :eperm}), do: exit_dataerr() def exit_code_for({:validation_failure, {:bad_option, _}}), do: exit_usage() def exit_code_for({:validation_failure, _}), do: exit_usage() def exit_code_for({:badrpc, :timeout}), do: exit_tempfail() diff --git a/lib/rabbitmq/cli/core/helpers.ex b/lib/rabbitmq/cli/core/helpers.ex index 05abd9fd..09291dc4 100644 --- a/lib/rabbitmq/cli/core/helpers.ex +++ b/lib/rabbitmq/cli/core/helpers.ex @@ -100,7 +100,7 @@ defmodule RabbitMQ.CLI.Core.Helpers do def require_rabbit(opts) do try_load_rabbit_code(opts) end - + def require_rabbit_and_plugins(opts) do with :ok <- try_load_rabbit_code(opts), :ok <- try_load_rabbit_plugins(opts), diff --git a/lib/rabbitmq/cli/ctl/commands/hipe_compile_command.ex b/lib/rabbitmq/cli/ctl/commands/hipe_compile_command.ex index afaba38e..395b8c36 100644 --- a/lib/rabbitmq/cli/ctl/commands/hipe_compile_command.ex +++ b/lib/rabbitmq/cli/ctl/commands/hipe_compile_command.ex @@ -32,15 +32,32 @@ defmodule RabbitMQ.CLI.Ctl.Commands.HipeCompileCommand do def usage, do: "hipe_compile " def validate([], _), do: {:validation_failure, :not_enough_args} - def validate([_], opts) do + def validate([target_dir], opts) do :ok + |> Helpers.validate_step(fn() -> + case acceptable_path?(target_dir) do + true -> :ok + false -> {:error, {:bad_argument, "Target directory path cannot be blank"}} + end + end) + |> Helpers.validate_step(fn() -> + case File.dir?(target_dir) do + true -> :ok + false -> + case File.mkdir_p(target_dir) do + :ok -> :ok + {:error, :eperm} -> + {:error, {:bad_argument, "Cannot create target directory #{target_dir}: insufficient permissions"}} + end + end + end) |> Helpers.validate_step(fn() -> Helpers.require_rabbit(opts) end) end def validate(_, _), do: {:validation_failure, :too_many_args} def run([target_dir], _opts) do Code.ensure_loaded(:rabbit_hipe) - hipe_compile(target_dir) + hipe_compile(String.trim(target_dir)) end def banner([target_dir], _) do @@ -51,6 +68,11 @@ defmodule RabbitMQ.CLI.Ctl.Commands.HipeCompileCommand do # Implementation # + # Accepts any non-blank path + defp acceptable_path?(value) do + String.length(String.trim(value)) != 0 + end + defp hipe_compile(target_dir) do case :rabbit_hipe.can_hipe_compile() do true -> diff --git a/mix.exs b/mix.exs index 642ca313..b5ead6bf 100644 --- a/mix.exs +++ b/mix.exs @@ -106,6 +106,7 @@ defmodule RabbitMQCtl.MixfileBase do override: true }, {:amqp, "~> 0.1.5", only: :test}, + {:temp, "~> 0.4", only: :test}, {:json, "~> 1.0.0"}, {:csv, "~> 1.4.2"}, {:simetric, "~> 0.1.0"} diff --git a/test/hipe_compile_command_test.exs b/test/hipe_compile_command_test.exs index d01fc661..98fb8047 100644 --- a/test/hipe_compile_command_test.exs +++ b/test/hipe_compile_command_test.exs @@ -17,6 +17,8 @@ defmodule HipeCompileCommandTest do use ExUnit.Case, async: false import TestHelper + require Temp + @command RabbitMQ.CLI.Ctl.Commands.HipeCompileCommand @vhost "/" @@ -32,13 +34,17 @@ defmodule HipeCompileCommandTest do end setup do - rabbitmq_home = :rabbit_misc.rpc_call(node, :code, :lib_dir, [:rabbit]) + rabbitmq_home = :rabbit_misc.rpc_call(node(), :code, :lib_dir, [:rabbit]) + + {:ok, tmp_dir} = Temp.path {:ok, opts: %{ node: get_rabbit_hostname(), vhost: @vhost, rabbitmq_home: rabbitmq_home - }} + }, + target_dir: tmp_dir + } end test "validate: providing no arguments fails validation", context do @@ -56,12 +62,20 @@ defmodule HipeCompileCommandTest do {:validation_failure, :too_many_args} end - test "validate: providing one directory path and required options succeeds", context do - assert @command.validate(["/path/one"], context[:opts]) == :ok + test "validate: providing one blank directory path and required options fails", context do + assert match?({:validation_failure, {:bad_argument, _}}, @command.validate([""], context[:opts])) + end + + test "validate: providing one path argument that only contains spaces and required options fails", context do + assert match?({:validation_failure, {:bad_argument, _}}, @command.validate([" "], context[:opts])) + end + + test "validate: providing one non-blank directory path and required options succeeds", context do + assert @command.validate([context[:target_dir]], context[:opts]) == :ok end test "validate: failure to load the rabbit application is reported as an error", context do assert {:validation_failure, {:unable_to_load_rabbit, _}} = - @command.validate(["/path/to/beam/files"], Map.delete(context[:opts], :rabbitmq_home)) + @command.validate([context[:target_dir]], Map.delete(context[:opts], :rabbitmq_home)) end end