gauntlt 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -1
- data/.travis.yml +7 -1
- data/Gemfile +1 -1
- data/README.md +14 -8
- data/bin/gauntlt +28 -46
- data/examples/curl/cookies.attack +12 -0
- data/examples/curl/simple.attack +9 -0
- data/examples/curl/verbs.attack +19 -0
- data/examples/nmap/os_detection.attack +16 -0
- data/examples/nmap/simple.attack +16 -0
- data/examples/nmap/tcp_ping_ports.attack +16 -0
- data/examples/nmap/xml_output.attack +18 -0
- data/examples/sslyze/sslyze.attack +23 -0
- data/features/attack.feature +30 -19
- data/features/attacks/curl.feature +23 -15
- data/features/attacks/nmap.feature +16 -93
- data/features/attacks/sqlmap.feature +2 -3
- data/features/attacks/sslyze.feature +7 -29
- data/features/help.feature +3 -30
- data/features/step_definitions/config_steps.rb +1 -1
- data/features/step_definitions/support_steps.rb +15 -0
- data/features/support/hooks.rb +2 -2
- data/features/tags.feature +44 -0
- data/gauntlt.gemspec +0 -2
- data/lib/gauntlt.rb +7 -11
- data/lib/gauntlt/attack.rb +26 -22
- data/lib/gauntlt/attack_adapters/curl.rb +35 -1
- data/lib/gauntlt/attack_adapters/support/cli_helper.rb +1 -1
- data/lib/gauntlt/attack_adapters/support/cookie_helper.rb +3 -10
- data/lib/gauntlt/version.rb +1 -1
- data/spec/gauntlt/attack_spec.rb +13 -35
- data/spec/gauntlt_spec.rb +7 -14
- metadata +12 -30
- data/features/attacks/cookies.feature +0 -25
- data/features/attacks/http_methods.feature +0 -33
- data/features/step_definitions/aruba_extension_steps.rb +0 -3
- data/features/support/attack_steps.rb +0 -1
- data/features/support/profile/profile.xml +0 -5
- data/lib/gauntlt/attack_adapters/cookies.rb +0 -11
- data/lib/gauntlt/attack_adapters/http_methods.rb +0 -12
| @@ -9,9 +9,8 @@ Feature: sqlmap attack | |
| 9 9 | 
             
                    Background:
         | 
| 10 10 | 
             
                      Given "sqlmap" is installed
         | 
| 11 11 | 
             
                  """
         | 
| 12 | 
            -
                When I run `gauntlt | 
| 13 | 
            -
                Then it should pass
         | 
| 14 | 
            -
                And the output should contain:
         | 
| 12 | 
            +
                When I run `gauntlt`
         | 
| 13 | 
            +
                Then it should pass with:
         | 
| 15 14 | 
             
                  """
         | 
| 16 15 | 
             
                  1 step (1 passed)
         | 
| 17 16 | 
             
                  """
         | 
| @@ -1,36 +1,14 @@ | |
| 1 1 | 
             
            Feature: sslyze attack
         | 
| 2 2 |  | 
| 3 | 
            +
              @slow
         | 
| 3 4 | 
             
              Scenario:
         | 
| 4 5 | 
             
                Given an attack "sslyze" exists
         | 
| 5 | 
            -
                And  | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
                      And the target hostname is "google.com"
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                    Scenario: Ensure no anonymous certificates
         | 
| 14 | 
            -
                      When I launch an "sslyze" attack with:
         | 
| 15 | 
            -
                        \"\"\"
         | 
| 16 | 
            -
                          python <sslyze_path> <hostname>:443
         | 
| 17 | 
            -
                        \"\"\"
         | 
| 18 | 
            -
                      Then the output should not contain:
         | 
| 19 | 
            -
                        \"\"\"
         | 
| 20 | 
            -
                        Anon
         | 
| 21 | 
            -
                        \"\"\"
         | 
| 22 | 
            -
             | 
| 23 | 
            -
                    # Scenario: Make sure that the certificate key size is at least 2048
         | 
| 24 | 
            -
                    #   Given the target hostname is "google.com"
         | 
| 25 | 
            -
                    #   When I launch an "sslyze" attack with:
         | 
| 26 | 
            -
                    #     \"\"\"
         | 
| 27 | 
            -
                    #       python <sslyze_path> <hostname>:443
         | 
| 28 | 
            -
                    #     \"\"\"
         | 
| 29 | 
            -
                    #   Then the key size should be at least 2048
         | 
| 30 | 
            -
                  """
         | 
| 31 | 
            -
                When I run `gauntlt attack --name sslyze --attack-file sslyze.attack`
         | 
| 32 | 
            -
                Then it should pass
         | 
| 33 | 
            -
                And the output should contain:
         | 
| 6 | 
            +
                And I copy the attack files from the "examples/sslyze" folder
         | 
| 7 | 
            +
                And the following attack files exist:
         | 
| 8 | 
            +
                  | filename      |
         | 
| 9 | 
            +
                  | sslyze.attack |
         | 
| 10 | 
            +
                When I run `gauntlt`
         | 
| 11 | 
            +
                Then it should pass with:
         | 
| 34 12 | 
             
                  """
         | 
| 35 13 | 
             
                  4 steps (4 passed)
         | 
| 36 14 | 
             
                  """
         | 
    
        data/features/help.feature
    CHANGED
    
    | @@ -8,35 +8,8 @@ Feature: Display help info | |
| 8 8 | 
             
                When I run `gauntlt --help`
         | 
| 9 9 | 
             
                Then the output should contain:
         | 
| 10 10 | 
             
                  """
         | 
| 11 | 
            -
                   | 
| 12 | 
            -
                  """
         | 
| 13 | 
            -
             | 
| 14 | 
            -
              Scenario: Attack help
         | 
| 15 | 
            -
                When I run `gauntlt attack -h -n nmap`
         | 
| 16 | 
            -
                Then the output should contain:
         | 
| 17 | 
            -
                  """
         | 
| 18 | 
            -
                  usage: gauntlt attack -n [attack-name] -a [attack-file]
         | 
| 19 | 
            -
                  """
         | 
| 20 | 
            -
             | 
| 21 | 
            -
              Scenario: A user runs gauntlt without any arguments
         | 
| 22 | 
            -
                When I run `gauntlt`
         | 
| 23 | 
            -
                Then the output should contain:
         | 
| 24 | 
            -
                  """
         | 
| 25 | 
            -
                  Try --help for help
         | 
| 26 | 
            -
                  """
         | 
| 27 | 
            -
             | 
| 28 | 
            -
              Scenario: A user runs the attack command without specifying attack name
         | 
| 29 | 
            -
                When I run `gauntlt attack`
         | 
| 30 | 
            -
                Then the output should contain:
         | 
| 31 | 
            -
                  """
         | 
| 32 | 
            -
                  Available attacks:
         | 
| 33 | 
            -
             | 
| 34 | 
            -
                    cookies
         | 
| 35 | 
            -
                    curl
         | 
| 36 | 
            -
                    http_methods
         | 
| 37 | 
            -
                    nmap
         | 
| 38 | 
            -
                    sqlmap
         | 
| 39 | 
            -
                    sslyze
         | 
| 11 | 
            +
                  gauntlt is a ruggedization framework
         | 
| 40 12 |  | 
| 41 | 
            -
             | 
| 13 | 
            +
                  Usage:
         | 
| 14 | 
            +
                         gauntlt <path>+
         | 
| 42 15 | 
             
                  """
         | 
| @@ -2,4 +2,19 @@ Then /^debug$/ do | |
| 2 2 | 
             
              require 'debugger'
         | 
| 3 3 | 
             
              debugger
         | 
| 4 4 | 
             
              nil
         | 
| 5 | 
            +
            end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            require 'pathname'
         | 
| 8 | 
            +
            Given /^I copy the attack files from the "(.*?)" folder$/ do |folder|
         | 
| 9 | 
            +
              Dir.glob("./#{folder}/**/*.attack").each do |path|
         | 
| 10 | 
            +
                name     = Pathname.new(path).basename.to_s
         | 
| 11 | 
            +
                contents = File.read(path)
         | 
| 12 | 
            +
                write_file(name, contents)
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            Given /^the following attack files exist:$/ do |table|
         | 
| 17 | 
            +
              table.hashes.each do |hsh|
         | 
| 18 | 
            +
                check_file_presence [hsh['filename']], true
         | 
| 19 | 
            +
              end
         | 
| 5 20 | 
             
            end
         | 
    
        data/features/support/hooks.rb
    CHANGED
    
    | @@ -1,3 +1,3 @@ | |
| 1 1 | 
             
            Before('@slow') do
         | 
| 2 | 
            -
              @aruba_timeout_seconds =  | 
| 3 | 
            -
            end
         | 
| 2 | 
            +
              @aruba_timeout_seconds = 30
         | 
| 3 | 
            +
            end
         | 
| @@ -0,0 +1,44 @@ | |
| 1 | 
            +
            Feature: Run attacks by tag
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              Background:
         | 
| 4 | 
            +
                Given an attack "nmap" exists
         | 
| 5 | 
            +
                And a file named "nmap.attack" with:
         | 
| 6 | 
            +
                """
         | 
| 7 | 
            +
                Feature: my nmap attacks
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  @foo
         | 
| 10 | 
            +
                  Scenario: Foo
         | 
| 11 | 
            +
                    Given the target hostname is "foo"
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  @bar
         | 
| 14 | 
            +
                  Scenario: Bar
         | 
| 15 | 
            +
                    Given the target hostname is "bar"
         | 
| 16 | 
            +
                """
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              Scenario: Run attack for one tag
         | 
| 19 | 
            +
                When I run `gauntlt --tags @foo`
         | 
| 20 | 
            +
                Then it should pass with:
         | 
| 21 | 
            +
                """
         | 
| 22 | 
            +
                Feature: my nmap attacks
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  @foo
         | 
| 25 | 
            +
                """
         | 
| 26 | 
            +
                And the stdout should contain:
         | 
| 27 | 
            +
                """
         | 
| 28 | 
            +
                1 scenario (1 passed)
         | 
| 29 | 
            +
                1 step (1 passed)
         | 
| 30 | 
            +
                """
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              Scenario: Run attack by exluding one tag
         | 
| 33 | 
            +
                When I run `gauntlt --tags ~@foo`
         | 
| 34 | 
            +
                Then it should pass with:
         | 
| 35 | 
            +
                """
         | 
| 36 | 
            +
                Feature: my nmap attacks
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  @bar
         | 
| 39 | 
            +
                """
         | 
| 40 | 
            +
                And the stdout should contain:
         | 
| 41 | 
            +
                """
         | 
| 42 | 
            +
                1 scenario (1 passed)
         | 
| 43 | 
            +
                1 step (1 passed)
         | 
| 44 | 
            +
                """
         | 
    
        data/gauntlt.gemspec
    CHANGED
    
    | @@ -16,7 +16,6 @@ Gem::Specification.new do |s| | |
| 16 16 | 
             
              s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
         | 
| 17 17 | 
             
              s.require_paths = ["lib"]
         | 
| 18 18 |  | 
| 19 | 
            -
              # specify any dependencies here; for example:
         | 
| 20 19 | 
             
              s.add_development_dependency "cucumber"
         | 
| 21 20 | 
             
              s.add_development_dependency "rspec", "~> 2.11"
         | 
| 22 21 | 
             
              s.add_development_dependency "aruba"
         | 
| @@ -24,7 +23,6 @@ Gem::Specification.new do |s| | |
| 24 23 |  | 
| 25 24 | 
             
              s.add_runtime_dependency "cucumber"
         | 
| 26 25 | 
             
              s.add_runtime_dependency "aruba"
         | 
| 27 | 
            -
              s.add_runtime_dependency "curb"
         | 
| 28 26 | 
             
              s.add_runtime_dependency "nokogiri"
         | 
| 29 27 | 
             
              s.add_runtime_dependency "trollop"
         | 
| 30 28 | 
             
            end
         | 
    
        data/lib/gauntlt.rb
    CHANGED
    
    | @@ -13,27 +13,23 @@ module Gauntlt | |
| 13 13 |  | 
| 14 14 | 
             
              GAUNTLT_DIR = File.join(CURRENT_DIR, 'gauntlt')
         | 
| 15 15 |  | 
| 16 | 
            -
               | 
| 16 | 
            +
              ATTACK_ADAPTERS_DIR = File.join(GAUNTLT_DIR, 'attack_adapters')
         | 
| 17 17 |  | 
| 18 | 
            -
               | 
| 18 | 
            +
              ATTACK_ADAPTERS_GLOB_PATTERN = ATTACK_ADAPTERS_DIR + '/*.rb'
         | 
| 19 19 |  | 
| 20 20 | 
             
              class << self
         | 
| 21 | 
            -
                def  | 
| 22 | 
            -
                  Dir.glob( | 
| 21 | 
            +
                def attack_adapters
         | 
| 22 | 
            +
                  Dir.glob(ATTACK_ADAPTERS_GLOB_PATTERN)
         | 
| 23 23 | 
             
                end
         | 
| 24 24 |  | 
| 25 25 | 
             
                def attacks
         | 
| 26 | 
            -
                   | 
| 26 | 
            +
                  attack_adapters.map do |full_path|
         | 
| 27 27 | 
             
                    File.basename(full_path, '.rb')
         | 
| 28 28 | 
             
                  end.sort
         | 
| 29 29 | 
             
                end
         | 
| 30 30 |  | 
| 31 | 
            -
                def  | 
| 32 | 
            -
                   | 
| 33 | 
            -
                end
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                def attack(name, options={})
         | 
| 36 | 
            -
                  Attack.new(name, options).run
         | 
| 31 | 
            +
                def attack(path, tags=[])
         | 
| 32 | 
            +
                  Attack.new(path, tags).run
         | 
| 37 33 | 
             
                end
         | 
| 38 34 | 
             
              end
         | 
| 39 35 | 
             
            end
         | 
    
        data/lib/gauntlt/attack.rb
    CHANGED
    
    | @@ -3,39 +3,43 @@ require 'cucumber/cli/main' | |
| 3 3 |  | 
| 4 4 | 
             
            module Gauntlt
         | 
| 5 5 | 
             
              class Attack
         | 
| 6 | 
            -
                class  | 
| 7 | 
            -
                class ExecutionFailed <  | 
| 8 | 
            -
             | 
| 9 | 
            -
                attr_accessor :name, :opts, :attack_file
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                def initialize(name, opts={})
         | 
| 12 | 
            -
                  if opts[:attack_file] && File.exists?( opts[:attack_file] )
         | 
| 13 | 
            -
                    self.name = name
         | 
| 14 | 
            -
                    self.opts = opts
         | 
| 15 | 
            -
                    self.attack_file = opts[:attack_file]
         | 
| 16 | 
            -
                  else
         | 
| 17 | 
            -
                    raise NotFound.new("No '#{opts[:attack_file]}' attack found")
         | 
| 18 | 
            -
                  end
         | 
| 19 | 
            -
                end
         | 
| 6 | 
            +
                class NoFilesFound < StandardError; end
         | 
| 7 | 
            +
                class ExecutionFailed < StandardError; end
         | 
| 20 8 |  | 
| 21 | 
            -
                 | 
| 22 | 
            -
                  File.expand_path( File.dirname(__FILE__) )
         | 
| 23 | 
            -
                end
         | 
| 9 | 
            +
                attr_accessor :path, :attack_files, :tags
         | 
| 24 10 |  | 
| 25 | 
            -
                def  | 
| 26 | 
            -
                   | 
| 11 | 
            +
                def initialize(path, tags=[])
         | 
| 12 | 
            +
                  self.path         = path
         | 
| 13 | 
            +
                  self.attack_files = attack_files_for(path)
         | 
| 14 | 
            +
                  self.tags         = tags
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  raise NoFilesFound.new("No files found in path: #{path}") if attack_files.empty?
         | 
| 27 17 | 
             
                end
         | 
| 28 18 |  | 
| 29 19 | 
             
                def run
         | 
| 30 | 
            -
                   | 
| 20 | 
            +
                  args =  attack_files + ['--strict', '--require', adapters_dir]
         | 
| 21 | 
            +
                  args += ['--tags', tags] unless tags.empty?
         | 
| 31 22 |  | 
| 32 | 
            -
                  cli = Cucumber::Cli::Main.new( | 
| 23 | 
            +
                  cli = Cucumber::Cli::Main.new(args)
         | 
| 33 24 |  | 
| 34 25 | 
             
                  if cli.execute! # cucumber failed, returning true
         | 
| 35 26 | 
             
                    raise ExecutionFailed.new("Bad or undefined attack!")
         | 
| 36 27 | 
             
                  else            # cucumber executed successfully, returning false
         | 
| 37 | 
            -
                     | 
| 28 | 
            +
                    true
         | 
| 38 29 | 
             
                  end
         | 
| 39 30 | 
             
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                private
         | 
| 33 | 
            +
                def attack_files_for(path)
         | 
| 34 | 
            +
                  path.split(' ').map{|p| Dir.glob(p)}.flatten
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def base_dir
         | 
| 38 | 
            +
                  File.expand_path( File.dirname(__FILE__) )
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def adapters_dir
         | 
| 42 | 
            +
                  File.join(base_dir, "attack_adapters")
         | 
| 43 | 
            +
                end
         | 
| 40 44 | 
             
              end
         | 
| 41 45 | 
             
            end
         | 
| @@ -1,3 +1,37 @@ | |
| 1 | 
            +
            When /^"curl" is installed$/ do
         | 
| 2 | 
            +
              ensure_cli_installed("curl")
         | 
| 3 | 
            +
            end
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            When /^I launch a "curl" attack$/ do
         | 
| 6 | 
            +
              # curl custom output
         | 
| 7 | 
            +
              # from:
         | 
| 8 | 
            +
              #   http://beerpla.net/2010/06/10/how-to-display-just-the-http-response-code-in-cli-curl/
         | 
| 9 | 
            +
              #
         | 
| 10 | 
            +
              # for more output variables, see:
         | 
| 11 | 
            +
              #   http://man.he.net/man1/curl
         | 
| 12 | 
            +
              @raw_response = `curl --silent --output /dev/null --write-out "%{http_code}" "#{hostname}"`
         | 
| 13 | 
            +
              @response = {
         | 
| 14 | 
            +
                :code => @raw_response
         | 
| 15 | 
            +
              }
         | 
| 16 | 
            +
            end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            When /^I launch a "curl" attack with:$/ do |command|
         | 
| 19 | 
            +
              command.gsub!('<hostname>', hostname)
         | 
| 20 | 
            +
              run command
         | 
| 21 | 
            +
            end
         | 
| 22 | 
            +
             | 
| 1 23 | 
             
            Then /^the response code should be "(.*?)"$/ do |http_code|
         | 
| 2 | 
            -
              @response. | 
| 24 | 
            +
              @response[:code].should == http_code
         | 
| 25 | 
            +
            end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            When /^I launch a "cookies" attack$/ do
         | 
| 28 | 
            +
              set_cookies( cookies_for(hostname) )
         | 
| 29 | 
            +
            end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            Then /^the following cookies should be received:$/ do |table|
         | 
| 32 | 
            +
              names = table.hashes.map{|h| h['name'] }
         | 
| 33 | 
            +
              names.each do |name|
         | 
| 34 | 
            +
                cookies.any?{|s| s =~ /^#{name}/}.should be_true
         | 
| 35 | 
            +
                # TODO: check other values in table
         | 
| 36 | 
            +
              end
         | 
| 3 37 | 
             
            end
         | 
| @@ -1,18 +1,11 @@ | |
| 1 | 
            -
            require 'curb'
         | 
| 2 | 
            -
             | 
| 3 1 | 
             
            module Gauntlt
         | 
| 4 2 | 
             
              module Support
         | 
| 5 3 | 
             
                module CookieHelper
         | 
| 6 4 | 
             
                  def cookies_for(url)
         | 
| 7 | 
            -
                     | 
| 8 | 
            -
                      c = Curl::Easy.perform(url) do |curl|
         | 
| 9 | 
            -
                        curl.follow_location = true
         | 
| 10 | 
            -
                        curl.enable_cookies = true
         | 
| 5 | 
            +
                    output = `curl --include --location --head --silent "#{url}"`
         | 
| 11 6 |  | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
                        end
         | 
| 15 | 
            -
                      end
         | 
| 7 | 
            +
                    output.scan(/^Set-Cookie:.+$/).map do |header|
         | 
| 8 | 
            +
                      "#{$1}=#{$2}" if header =~ /^Set-Cookie: ([^=]+)=([^;]+;)/
         | 
| 16 9 | 
             
                    end
         | 
| 17 10 | 
             
                  end
         | 
| 18 11 |  | 
    
        data/lib/gauntlt/version.rb
    CHANGED
    
    
    
        data/spec/gauntlt/attack_spec.rb
    CHANGED
    
    | @@ -2,64 +2,42 @@ require 'spec_helper' | |
| 2 2 |  | 
| 3 3 | 
             
            describe Gauntlt::Attack do
         | 
| 4 4 | 
             
              before do
         | 
| 5 | 
            -
                 | 
| 5 | 
            +
                Gauntlt::Attack.any_instance.stub(:attack_files_for).with(:foo).and_return([:bar])
         | 
| 6 6 | 
             
              end
         | 
| 7 7 |  | 
| 8 8 | 
             
              subject{
         | 
| 9 | 
            -
                Gauntlt::Attack.new(:foo | 
| 9 | 
            +
                Gauntlt::Attack.new(:foo)
         | 
| 10 10 | 
             
              }
         | 
| 11 11 |  | 
| 12 12 | 
             
              describe :initialize do
         | 
| 13 13 | 
             
                context "attack file exists for passed name" do
         | 
| 14 | 
            -
                  it "sets  | 
| 15 | 
            -
                    subject. | 
| 16 | 
            -
                    subject. | 
| 14 | 
            +
                  it "sets path and attack_files" do
         | 
| 15 | 
            +
                    subject.path.should == :foo
         | 
| 16 | 
            +
                    subject.attack_files.should == [:bar]
         | 
| 17 17 | 
             
                  end
         | 
| 18 18 | 
             
                end
         | 
| 19 19 |  | 
| 20 | 
            -
                context " | 
| 20 | 
            +
                context "attack_files_for returns an empty array" do
         | 
| 21 21 | 
             
                  it "raises an error if the attack file does not exist" do
         | 
| 22 | 
            -
                     | 
| 22 | 
            +
                    Gauntlt::Attack.any_instance.stub(:attack_files_for).with(:foo).and_return([])
         | 
| 23 23 |  | 
| 24 24 | 
             
                    expect {
         | 
| 25 | 
            -
                      Gauntlt::Attack.new(:foo | 
| 26 | 
            -
                    }.to raise_error Gauntlt::Attack:: | 
| 25 | 
            +
                      Gauntlt::Attack.new(:foo)
         | 
| 26 | 
            +
                    }.to raise_error Gauntlt::Attack::NoFilesFound
         | 
| 27 27 | 
             
                  end
         | 
| 28 28 | 
             
                end
         | 
| 29 29 | 
             
              end
         | 
| 30 30 |  | 
| 31 | 
            -
              describe :base_dir do
         | 
| 32 | 
            -
                it "returns the full path for the attack.rb file" do
         | 
| 33 | 
            -
                  File.should_receive(:dirname).and_return(:foo)
         | 
| 34 | 
            -
                  File.should_receive(:expand_path).with(:foo)
         | 
| 35 | 
            -
             | 
| 36 | 
            -
                  subject.base_dir
         | 
| 37 | 
            -
                end
         | 
| 38 | 
            -
              end
         | 
| 39 | 
            -
             | 
| 40 | 
            -
              describe :attacks_dir do
         | 
| 41 | 
            -
                it "joins attacks to base_dir" do
         | 
| 42 | 
            -
                  subject.should_receive(:base_dir).and_return(:bar)
         | 
| 43 | 
            -
                  File.should_receive(:join).with(:bar, 'attack_adapters')
         | 
| 44 | 
            -
             | 
| 45 | 
            -
                  subject.attacks_dir
         | 
| 46 | 
            -
                end
         | 
| 47 | 
            -
              end
         | 
| 48 | 
            -
             | 
| 49 31 | 
             
              describe :run do
         | 
| 50 32 | 
             
                it "executes the attack file, specifies failure for undefined steps and specifies the attacks_dir" do
         | 
| 51 | 
            -
                  subject.should_receive(: | 
| 52 | 
            -
                  subject.should_receive(: | 
| 53 | 
            -
             | 
| 54 | 
            -
                  mock_io = mock('io')
         | 
| 55 | 
            -
                  mock_io.stub(:string)
         | 
| 56 | 
            -
                  StringIO.stub(:new).and_return(mock_io)
         | 
| 33 | 
            +
                  subject.should_receive(:adapters_dir).and_return('/bar')
         | 
| 34 | 
            +
                  subject.should_receive(:attack_files).and_return(['/bar/baz.attack'])
         | 
| 57 35 |  | 
| 58 36 | 
             
                  mock_cli = mock(Cucumber::Cli::Main)
         | 
| 59 37 | 
             
                  mock_cli.should_receive(:execute!)
         | 
| 60 | 
            -
                  Cucumber::Cli::Main.should_receive(:new).with(['/bar/baz.attack', '--strict', '--require', '/bar'] | 
| 38 | 
            +
                  Cucumber::Cli::Main.should_receive(:new).with(['/bar/baz.attack', '--strict', '--require', '/bar']).and_return(mock_cli)
         | 
| 61 39 |  | 
| 62 | 
            -
                  subject.run
         | 
| 40 | 
            +
                  subject.run.should be_true
         | 
| 63 41 | 
             
                end
         | 
| 64 42 |  | 
| 65 43 | 
             
                it "returns nil if if Cucumber::Cli::Main.execute succeeds (i.e. returns nil)" do
         |