|
module Gauntlt |
|
module Turnip |
|
|
|
module Cli |
|
def unescape(string) |
|
string.gsub('\n', "\n").gsub('\"', '"').gsub('\e', "\e") |
|
end |
|
|
|
def detect_ruby(cmd) |
|
if cmd =~ /^ruby\s/ |
|
cmd.gsub(/^ruby\s/, "#{current_ruby} ") |
|
else |
|
cmd |
|
end |
|
end |
|
|
|
def current_dir |
|
File.join(*dirs) |
|
end |
|
|
|
def dirs |
|
@dirs ||= ['tmp/aruba'] |
|
end |
|
|
|
def exit_timeout |
|
3 |
|
end |
|
|
|
def io_wait |
|
0.1 |
|
end |
|
|
|
def stop_process(process) |
|
@last_exit_status = process.stop(announcer, @aruba_keep_ansi) |
|
end |
|
|
|
def stop_processes! |
|
processes.each do |_, process| |
|
stop_process(process) |
|
end |
|
end |
|
|
|
|
|
def last_exit_status |
|
return @last_exit_status if @last_exit_status |
|
stop_processes! |
|
@last_exit_status |
|
end |
|
|
|
|
|
def run_simple(cmd, fail_on_error=true) |
|
run(cmd) do |process| |
|
stop_process(process) |
|
end |
|
@timed_out = last_exit_status.nil? |
|
assert_exit_status(0) if fail_on_error |
|
end |
|
|
|
def _mkdir(dir_name) |
|
FileUtils.mkdir_p(dir_name) unless File.directory?(dir_name) |
|
end |
|
|
|
def in_current_dir(&block) |
|
_mkdir(current_dir) |
|
Dir.chdir(current_dir, &block) |
|
end |
|
|
|
class Announcer |
|
def initialize(session, options = {}) |
|
@session, @options = session, options |
|
end |
|
|
|
def stdout(content) |
|
return unless @options[:stdout] |
|
print content |
|
end |
|
|
|
def stderr(content) |
|
return unless @options[:stderr] |
|
print content |
|
end |
|
|
|
def dir(dir) |
|
return unless @options[:dir] |
|
print "$ cd #{dir}" |
|
end |
|
|
|
def cmd(cmd) |
|
return unless @options[:cmd] |
|
print "$ #{cmd}" |
|
end |
|
|
|
def env(key, value) |
|
return unless @options[:env] |
|
print %{$ export #{key}="#{value}"} |
|
end |
|
|
|
private |
|
|
|
def print(message) |
|
@session.announce_or_puts(message) |
|
end |
|
end |
|
|
|
require 'childprocess' |
|
require 'tempfile' |
|
require 'shellwords' |
|
|
|
|
|
class Process |
|
include Shellwords |
|
|
|
def initialize(cmd, exit_timeout, io_wait) |
|
@exit_timeout = exit_timeout |
|
@io_wait = io_wait |
|
|
|
@out = Tempfile.new("aruba-out") |
|
@err = Tempfile.new("aruba-err") |
|
@process = ChildProcess.build(*shellwords(cmd)) |
|
@process.io.stdout = @out |
|
@process.io.stderr = @err |
|
@process.duplex = true |
|
end |
|
|
|
def run!(&block) |
|
@process.start |
|
yield self if block_given? |
|
end |
|
|
|
def stdin |
|
wait_for_io do |
|
@process.io.stdin.sync = true |
|
@process.io.stdin |
|
end |
|
end |
|
|
|
def output(keep_ansi) |
|
stdout(keep_ansi) + stderr(keep_ansi) |
|
end |
|
|
|
def stdout(keep_ansi) |
|
wait_for_io do |
|
@out.rewind |
|
filter_ansi(@out.read, keep_ansi) |
|
end |
|
end |
|
|
|
def stderr(keep_ansi) |
|
wait_for_io do |
|
@err.rewind |
|
filter_ansi(@err.read, keep_ansi) |
|
end |
|
end |
|
|
|
def stop(reader, keep_ansi) |
|
return unless @process |
|
unless @process.exited? |
|
reader.stdout stdout(keep_ansi) |
|
reader.stderr stderr(keep_ansi) |
|
@process.poll_for_exit(@exit_timeout) |
|
end |
|
@process.exit_code |
|
end |
|
|
|
def terminate(keep_ansi) |
|
if @process |
|
stdout(keep_ansi) && stderr(keep_ansi) # flush output |
|
@process.stop |
|
stdout(keep_ansi) && stderr(keep_ansi) # flush output |
|
end |
|
end |
|
|
|
private |
|
|
|
def wait_for_io(&block) |
|
sleep @io_wait if @process.alive? |
|
yield |
|
end |
|
|
|
def filter_ansi(string, keep_ansi) |
|
keep_ansi ? string : string.gsub(/\e\[\d+(?>(;\d+)*)m/, '') |
|
end |
|
|
|
end |
|
|
|
|
|
def announcer |
|
Announcer.new(self, |
|
:stdout => @announce_stdout, |
|
:stderr => @announce_stderr, |
|
:dir => @announce_dir, |
|
:cmd => @announce_cmd, |
|
:env => @announce_env) |
|
end |
|
|
|
def processes |
|
@processes ||= [] |
|
end |
|
|
|
def register_process(name, process) |
|
processes << [name, process] |
|
end |
|
|
|
|
|
def run(cmd) |
|
@commands ||= [] |
|
@commands << cmd |
|
|
|
cmd = detect_ruby(cmd) |
|
|
|
in_current_dir do |
|
#Aruba.config.hooks.execute(:before_cmd, self, cmd) |
|
|
|
announcer.dir(Dir.pwd) |
|
announcer.cmd(cmd) |
|
|
|
process = Process.new(cmd, exit_timeout, io_wait) |
|
register_process(cmd, process) |
|
process.run! |
|
|
|
block_given? ? yield(process) : process |
|
end |
|
end |
|
|
|
def assert_passing_with(expected) |
|
assert_exit_status_and_partial_output(true, expected) |
|
end |
|
|
|
def assert_exit_status_and_partial_output(expect_to_pass, expected) |
|
assert_success(expect_to_pass) |
|
assert_partial_output(expected, all_output) |
|
end |
|
|
|
def assert_success(success) |
|
success ? assert_exit_status(0) : assert_not_exit_status(0) |
|
end |
|
|
|
def assert_exit_status(status) |
|
last_exit_status.should eq(status), |
|
append_output_to("Exit status was #{last_exit_status} but expected it to be #{status}.") |
|
end |
|
|
|
def assert_partial_output(expected, actual) |
|
unescape(actual).should include(unescape(expected)) |
|
end |
|
|
|
def append_output_to(message) |
|
"#{message} Output:\n\n#{all_output}\n" |
|
end |
|
|
|
def all_stdout |
|
stop_processes! |
|
only_processes.inject("") { |out, ps| out << ps.stdout(@aruba_keep_ansi) } |
|
end |
|
|
|
def all_stderr |
|
stop_processes! |
|
only_processes.inject("") { |out, ps| out << ps.stderr(@aruba_keep_ansi) } |
|
end |
|
|
|
def all_output |
|
all_stdout << all_stderr |
|
end |
|
|
|
def only_processes |
|
processes.collect{ |_, process| process } |
|
end |
|
|
|
end |
|
end |
|
end |
|
|
|
module TurnipCliSteps |
|
include Gauntlt::Turnip::Cli |
|
extend ::Turnip::DSL |
|
|
|
step "the file :filename should contain: :partial_content" do |filename, partial_content| |
|
check_file_content(file, partial_content, true) |
|
end |
|
|
|
step 'I run :cmd' do |cmd| |
|
run_simple(unescape(cmd), false) |
|
end |
|
|
|
placeholder :cmd do |
|
match /`([^`]*)`/ do |cmd| |
|
cmd |
|
end |
|
end |
|
|
|
step "I successfully run `:cmd`" do |cmd| |
|
run_simple(unescape(cmd)) |
|
end |
|
|
|
step "it should pass with:" do |partial_output| |
|
assert_passing_with(partial_output) |
|
end |
|
|
|
end |
|
|
|
module Gauntlt::Turnip::NmapSteps |
|
extend ::Turnip::DSL |
|
|
|
step '"nmap" is installed' do |
|
if !(`which nmap` && $?.success?) |
|
raise "nmap not installed!" |
|
end |
|
end |
|
|
|
step 'the target hostname is "google.com"' do |
|
|
|
end |
|
|
|
step 'I launch an "nmap" attack with:' do |cmd| |
|
end |
|
|
|
step 'the output should contain:' do |string| |
|
end |
|
end |
|
|
|
RSpec.configure do |config| |
|
config.include TurnipCliSteps |
|
end |