codez-tarantula 0.5.0

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.
Files changed (88) hide show
  1. data/.autotest +14 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG +64 -0
  5. data/DSL_EXAMPLES.md +120 -0
  6. data/Gemfile +2 -0
  7. data/LICENSE +20 -0
  8. data/README.rdoc +136 -0
  9. data/Rakefile +36 -0
  10. data/ci/rails2.gemfile +4 -0
  11. data/ci/rails3.gemfile +4 -0
  12. data/laf/images/header_bg.jpg +0 -0
  13. data/laf/images/logo.png +0 -0
  14. data/laf/images/tagline.png +0 -0
  15. data/laf/javascripts/jquery-1.2.3.js +3408 -0
  16. data/laf/javascripts/jquery-ui-tabs.js +890 -0
  17. data/laf/javascripts/jquery.tablesorter.js +861 -0
  18. data/laf/javascripts/tarantula.js +10 -0
  19. data/laf/stylesheets/tarantula.css +346 -0
  20. data/lib/relevance/core_extensions/ellipsize.rb +38 -0
  21. data/lib/relevance/core_extensions/file.rb +15 -0
  22. data/lib/relevance/core_extensions/metaclass.rb +78 -0
  23. data/lib/relevance/core_extensions/response.rb +14 -0
  24. data/lib/relevance/core_extensions/test_case.rb +21 -0
  25. data/lib/relevance/tarantula.rb +55 -0
  26. data/lib/relevance/tarantula/attack.rb +22 -0
  27. data/lib/relevance/tarantula/attack_handler.rb +43 -0
  28. data/lib/relevance/tarantula/basic_attack.rb +44 -0
  29. data/lib/relevance/tarantula/crawler.rb +271 -0
  30. data/lib/relevance/tarantula/detail.html.erb +81 -0
  31. data/lib/relevance/tarantula/form.rb +29 -0
  32. data/lib/relevance/tarantula/form_submission.rb +98 -0
  33. data/lib/relevance/tarantula/html_document_handler.rb +42 -0
  34. data/lib/relevance/tarantula/html_report_helper.rb +46 -0
  35. data/lib/relevance/tarantula/html_reporter.rb +111 -0
  36. data/lib/relevance/tarantula/index.html.erb +37 -0
  37. data/lib/relevance/tarantula/invalid_html_handler.rb +27 -0
  38. data/lib/relevance/tarantula/io_reporter.rb +40 -0
  39. data/lib/relevance/tarantula/link.rb +105 -0
  40. data/lib/relevance/tarantula/log_grabber.rb +22 -0
  41. data/lib/relevance/tarantula/rails_integration_proxy.rb +90 -0
  42. data/lib/relevance/tarantula/recording.rb +12 -0
  43. data/lib/relevance/tarantula/response.rb +19 -0
  44. data/lib/relevance/tarantula/result.rb +83 -0
  45. data/lib/relevance/tarantula/test_report.html.erb +32 -0
  46. data/lib/relevance/tarantula/tidy_handler.rb +35 -0
  47. data/lib/relevance/tarantula/transform.rb +21 -0
  48. data/lib/relevance/tarantula/version.rb +5 -0
  49. data/lib/relevance/tasks/tarantula_tasks.rake +42 -0
  50. data/lib/tarantula-rails3.rb +9 -0
  51. data/spec/relevance/core_extensions/ellipsize_spec.rb +19 -0
  52. data/spec/relevance/core_extensions/file_spec.rb +7 -0
  53. data/spec/relevance/core_extensions/response_spec.rb +48 -0
  54. data/spec/relevance/core_extensions/test_case_spec.rb +19 -0
  55. data/spec/relevance/tarantula/attack_handler_spec.rb +29 -0
  56. data/spec/relevance/tarantula/basic_attack_spec.rb +12 -0
  57. data/spec/relevance/tarantula/crawler_spec.rb +409 -0
  58. data/spec/relevance/tarantula/form_spec.rb +50 -0
  59. data/spec/relevance/tarantula/form_submission_spec.rb +171 -0
  60. data/spec/relevance/tarantula/html_document_handler_spec.rb +43 -0
  61. data/spec/relevance/tarantula/html_report_helper_spec.rb +46 -0
  62. data/spec/relevance/tarantula/html_reporter_spec.rb +82 -0
  63. data/spec/relevance/tarantula/invalid_html_handler_spec.rb +33 -0
  64. data/spec/relevance/tarantula/io_reporter_spec.rb +11 -0
  65. data/spec/relevance/tarantula/link_spec.rb +132 -0
  66. data/spec/relevance/tarantula/log_grabber_spec.rb +26 -0
  67. data/spec/relevance/tarantula/rails_integration_proxy_spec.rb +100 -0
  68. data/spec/relevance/tarantula/result_spec.rb +85 -0
  69. data/spec/relevance/tarantula/tidy_handler_spec.rb +58 -0
  70. data/spec/relevance/tarantula/transform_spec.rb +20 -0
  71. data/spec/relevance/tarantula_spec.rb +23 -0
  72. data/spec/spec_helper.rb +43 -0
  73. data/tarantula.gemspec +25 -0
  74. data/template/tarantula_test.rb +22 -0
  75. data/vendor/xss-shield/MIT-LICENSE +20 -0
  76. data/vendor/xss-shield/README +76 -0
  77. data/vendor/xss-shield/init.rb +16 -0
  78. data/vendor/xss-shield/lib/xss_shield.rb +6 -0
  79. data/vendor/xss-shield/lib/xss_shield/erb_hacks.rb +111 -0
  80. data/vendor/xss-shield/lib/xss_shield/haml_hacks.rb +42 -0
  81. data/vendor/xss-shield/lib/xss_shield/safe_string.rb +47 -0
  82. data/vendor/xss-shield/lib/xss_shield/secure_helpers.rb +40 -0
  83. data/vendor/xss-shield/test/test_actionview_integration.rb +40 -0
  84. data/vendor/xss-shield/test/test_erb.rb +44 -0
  85. data/vendor/xss-shield/test/test_haml.rb +43 -0
  86. data/vendor/xss-shield/test/test_helpers.rb +25 -0
  87. data/vendor/xss-shield/test/test_safe_string.rb +55 -0
  88. metadata +247 -0
@@ -0,0 +1,81 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
7
+ <link rel="stylesheet" href="../stylesheets/tarantula.css" type="text/css" media="screen" title="no title" charset="utf-8" />
8
+ <title>Detail</title>
9
+ </head>
10
+ <body>
11
+ <div id="container">
12
+ <div id="header">
13
+ <h1>Tarantula by Relevance</h1>
14
+ <h2>Eight legs, two fangs ... and an attitude</h2>
15
+ <p>Tarantula is an open source tool for testing Rails web
16
+ applications. Tarantula is developed by <a href="http://thinkrelevance.com">Relevance, Inc.</a>
17
+ and lives at <a href="http://github.com/relevance/tarantula">http://github.com/relevance/tarantula</a>.</p>
18
+ <hr/>
19
+ </div>
20
+ <div id="page">
21
+ <ul class="tabs">
22
+ <li><a href="../index.html">&laquo; Back</a></li>
23
+ <li><a href="#fragment-1" class="active">Body</a></li>
24
+ <li><a href="#fragment-2" class="active">Log</a></li>
25
+ </ul>
26
+
27
+ <div id="report">
28
+ <h3>Detail of <%= result.short_description %> <em>Generated on <%= Time.now %></em></h3>
29
+ <p><b>Resource</b> <a href="<%= result.full_url %>"><%= result.full_url %></a></p>
30
+ <p><b>Response</b> <span class="r<%= result.code.first %>"><%= result.code %></span></p>
31
+ <p><b>Referrer</b> <%= result.referrer || "" %></p>
32
+
33
+ <table class="output">
34
+ <tbody>
35
+ <tr>
36
+ <th colspan="2">#&nbsp;&nbsp;Data</th>
37
+ </tr>
38
+ <% if result.data %>
39
+ <%= result.wrap_in_line_number_table_row(result.data) %>
40
+ <% else %>
41
+ <tr>
42
+ <td colspan="2">No Data</td>
43
+ </tr>
44
+ <% end %>
45
+ </tbody>
46
+ </table>
47
+
48
+ <table class="output" id="fragment-1">
49
+ <tbody>
50
+ <tr>
51
+ <th colspan="2">#&nbsp;&nbsp;Body</th>
52
+ </tr>
53
+ <% if result.body %>
54
+ <%= result.wrap_in_line_number_table_row(result.body) %>
55
+ <% else %>
56
+ <tr>
57
+ <td colspan="2">No Body</td>
58
+ </tr>
59
+ <% end %>
60
+ </tbody>
61
+ </table>
62
+
63
+ <table class="output" id="fragment-2">
64
+ <tbody>
65
+ <tr>
66
+ <th colspan="2">#&nbsp;&nbsp;Log</th>
67
+ </tr>
68
+ <% if result.log %>
69
+ <%= result.wrap_in_line_number_table_row(result.log) {|line| wrap_stack_trace_line(line)} %>
70
+ <% else %>
71
+ <tr>
72
+ <td colspan="2">No Log</td>
73
+ </tr>
74
+ <% end %>
75
+ </tbody>
76
+ </table>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ </body>
81
+ </html>
@@ -0,0 +1,29 @@
1
+ module Relevance
2
+ module Tarantula
3
+
4
+ class Form
5
+ extend Forwardable
6
+ def_delegators("@tag", :search)
7
+
8
+ attr_accessor :crawler, :referrer
9
+
10
+ def initialize(tag, crawler, referrer)
11
+ @tag, @crawler, @referrer = tag, crawler, referrer
12
+ end
13
+
14
+ def action
15
+ @tag['action']
16
+ end
17
+
18
+ def meth
19
+ (rails_method_hack or @tag['method'] or 'get').downcase
20
+ end
21
+
22
+ def rails_method_hack
23
+ (tag = @tag.at('input[@name="_method"]')) && tag["value"]
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,98 @@
1
+ module Relevance
2
+ module Tarantula
3
+
4
+ class FormSubmission
5
+ include Relevance::Tarantula
6
+ attr_accessor :meth, :action, :data, :attack, :form
7
+
8
+ class << self
9
+ def attacks
10
+ # normalize from hash input to Attack
11
+ @attacks = @attacks.map do |val|
12
+ Hash === val ? Relevance::Tarantula::Attack.new(val) : val
13
+ end
14
+ @attacks
15
+ end
16
+ def attacks=(atts)
17
+ # normalize from hash input to Attack
18
+ @attacks = atts.map do |val|
19
+ Hash === val ? Relevance::Tarantula::Attack.new(val) : val
20
+ end
21
+ end
22
+ end
23
+ @attacks = [Relevance::Tarantula::BasicAttack.new]
24
+
25
+ def initialize(form, attack = Relevance::Tarantula::BasicAttack.new)
26
+ @form = form
27
+ @meth = form.meth
28
+ @action = form.action
29
+ @attack = attack
30
+ @data = mutate_selects(form).merge(mutate_text_areas(form)).merge(mutate_inputs(form))
31
+ end
32
+
33
+ def crawl
34
+ begin
35
+ response = form.crawler.submit(meth, action, data)
36
+ log "Response #{response.code} for #{self}"
37
+ rescue ActiveRecord::RecordNotFound => e
38
+ log "Skipping #{action}, presumed ok that record is missing"
39
+ response = Relevance::Tarantula::Response.new(:code => "404", :body => e.message, :content_type => "text/plain")
40
+ end
41
+ form.crawler.handle_form_results(self, response)
42
+ response
43
+ end
44
+
45
+ def self.mutate(form)
46
+ attacks.map{|attack| new(form, attack)} if attacks
47
+ end
48
+
49
+ def url
50
+ action
51
+ end
52
+
53
+ def to_s
54
+ "#{action} #{meth} #{data.inspect} #{attack.inspect}"
55
+ end
56
+
57
+ # a form's signature is what makes it unique (e.g. action + fields)
58
+ # used to keep track of which forms we have submitted already
59
+ def signature
60
+ [action, data.keys.sort, attack.name]
61
+ end
62
+
63
+ def create_random_data_for(form, tag_selector)
64
+ form.search(tag_selector).inject({}) do |form_args, input|
65
+ # TODO: test
66
+ form_args[input['name']] = random_data(input) if input['name']
67
+ form_args
68
+ end
69
+ end
70
+
71
+ def mutate_inputs(form)
72
+ create_random_data_for(form, 'input')
73
+ end
74
+
75
+ def mutate_text_areas(form)
76
+ create_random_data_for(form, 'textarea')
77
+ end
78
+
79
+ def mutate_selects(form)
80
+ form.search('select').inject({}) do |form_args, select|
81
+ options = select.search('option')
82
+ option = options.sample
83
+ form_args[select['name']] = option && option['value']
84
+ form_args
85
+ end
86
+ end
87
+
88
+ def random_data(input)
89
+ case input['name']
90
+ when /^_method$/ then input['value']
91
+ else
92
+ attack.input(input)
93
+ end
94
+ end
95
+ end
96
+
97
+ end
98
+ end
@@ -0,0 +1,42 @@
1
+ require 'hpricot'
2
+
3
+ module Relevance
4
+ module Tarantula
5
+
6
+ class HtmlDocumentHandler
7
+ extend Forwardable
8
+ def_delegators("@crawler", :queue_link, :queue_form)
9
+
10
+ def initialize(crawler)
11
+ @crawler = crawler
12
+ end
13
+ # HTML::Document shouts to stderr when it sees ugly HTML
14
+ # We don't want this -- the InvalidHtmlHandler will deal with it
15
+ def html_doc_without_stderr_noise(html)
16
+ body = nil
17
+ Recording.stderr do
18
+ body = Hpricot html
19
+ end
20
+ body
21
+ end
22
+ def handle(result)
23
+ response = result.response
24
+ url = result.url
25
+ return unless response.html?
26
+ body = html_doc_without_stderr_noise(response.body)
27
+ body.search('a').each do |tag|
28
+ queue_link(tag, url)
29
+ end
30
+ body.search('link').each do |tag|
31
+ queue_link(tag, url)
32
+ end
33
+ body.search('form').each do |form|
34
+ form['action'] = url unless form['action']
35
+ queue_form(form, url)
36
+ end
37
+ nil
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,46 @@
1
+ require "erb"
2
+ require "active_support/builder" unless defined?(Builder)
3
+ module Relevance
4
+ module Tarantula
5
+
6
+ module HtmlReportHelper
7
+ include ERB::Util
8
+ include Relevance::Tarantula
9
+ def wrap_in_line_number_table_row(text, &blk)
10
+ x = Builder::XmlMarkup.new
11
+
12
+ x.tr do
13
+ lines = text.split("\n")
14
+ x.td(:class => "numbers") do
15
+ lines.size.times do |index|
16
+ x.span(index+1, :class => "line number")
17
+ end
18
+ end
19
+ x.td(:class => "lines") do
20
+ lines.each do |line|
21
+ x.span(line, :class => "line")
22
+ end
23
+ end
24
+ end
25
+
26
+ x.target!
27
+ end
28
+
29
+ def textmate_url(file, line_no)
30
+ "txmt://open?url=file://#{File.expand_path(File.join(rails_root,file))}&line_no=#{line_no}"
31
+ end
32
+
33
+ def wrap_stack_trace_line(text)
34
+ if text =~ %r{^\s*(/[^:]+):(\d+):([^:]+)$}
35
+ file = h($1) # .to_s_xss_protected
36
+ line_number = $2
37
+ message = h($3) # .to_s_xss_protected
38
+ "<a href='#{textmate_url(file, line_number)}'>#{file}:#{line_number}</a>:#{message}" # .mark_as_xss_protected
39
+ else
40
+ h(text) # .to_s_xss_protected
41
+ end
42
+ end
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,111 @@
1
+ module Relevance
2
+ module Tarantula
3
+
4
+ class HtmlReporter
5
+
6
+ include Relevance::Tarantula
7
+ attr_accessor :basedir, :results
8
+ delegate :successes, :failures, :to => :results
9
+
10
+ HtmlResultOverview = Struct.new(:code, :url, :description, :method, :referrer, :file_name)
11
+
12
+ def initialize(basedir)
13
+ @basedir = basedir
14
+ @results = Struct.new(:successes, :failures).new([], [])
15
+ FileUtils.mkdir_p(@basedir)
16
+ end
17
+
18
+ def report(result)
19
+ return if result.nil?
20
+
21
+ create_detail_report(result)
22
+
23
+ collection = result.success ? results.successes : results.failures
24
+ collection << HtmlResultOverview.new(
25
+ result.code, result.url, result.description, result.method, result.referrer, result.file_name
26
+ )
27
+ end
28
+
29
+ def finish_report(test_name)
30
+ puts "Writing results to #{basedir}"
31
+ copy_styles unless styles_exist?
32
+ create_index unless index_exists?
33
+ update_index(test_name)
34
+ end
35
+
36
+ def create_detail_report(result)
37
+ template = ERB.new(template("detail.html.erb"))
38
+ output(result.file_name, template.result(result.send(:binding)), result.test_name)
39
+ end
40
+
41
+ def copy_styles
42
+ # not using cp_r because it picks up .svn crap
43
+ FileUtils.mkdir_p(File.join(basedir, "stylesheets"))
44
+ Dir.glob("#{tarantula_home}/laf/stylesheets/*.css").each do |file|
45
+ FileUtils.cp(file, File.join(basedir, "stylesheets"))
46
+ end
47
+ FileUtils.mkdir_p(File.join(basedir, "images"))
48
+ Dir.glob("#{tarantula_home}/laf/images/*.{jpg,gif,png}").each do |file|
49
+ FileUtils.cp(file, File.join(basedir, "images"))
50
+ end
51
+ FileUtils.mkdir_p(File.join(basedir, "javascripts"))
52
+ Dir.glob("#{tarantula_home}/laf/javascripts/*.js").each do |file|
53
+ FileUtils.cp(file, File.join(basedir, "javascripts"))
54
+ end
55
+ end
56
+
57
+ def create_index
58
+ template = ERB.new(template("index.html.erb"))
59
+ output("index.html", template.result(binding))
60
+ end
61
+
62
+ def update_index(test_name)
63
+ File.open(File.join(basedir, "index.html"), "r+") do |file|
64
+ doc = Hpricot file.read
65
+ tabs_container = doc.search "#tabs-container ul"
66
+ results_container = doc.search "#results-container"
67
+ tabs_container.append tab_html(test_name)
68
+ results_container.append results_html(test_name)
69
+ file.rewind
70
+ file.write doc.to_s
71
+ end
72
+ end
73
+
74
+ def index_exists?
75
+ File.exists?(File.join(basedir, "index.html"))
76
+ end
77
+
78
+ def styles_exist?
79
+ File.exists?(File.join(basedir, "stylesheets", "tarantula.css"))
80
+ end
81
+
82
+ def tab_html(test_name)
83
+ "<li><a href='##{test_name}'><span>#{test_name}</span></a></li>"
84
+ end
85
+
86
+ def results_html(test_name)
87
+ template = ERB.new(template("test_report.html.erb"))
88
+ template.result(binding)
89
+ end
90
+
91
+ def template(name)
92
+ File.read(File.join(File.dirname(__FILE__), name))
93
+ end
94
+
95
+ def output(name, body, subdir = '')
96
+ FileUtils.mkdir_p(File.join(basedir, subdir)) unless subdir.empty?
97
+ File.open(File.join(basedir, subdir, name), "w") do |file|
98
+ file.write body
99
+ end
100
+ end
101
+
102
+ # CSS class for HTML status codes
103
+ def class_for_code(code)
104
+ "r#{Integer(code)/100}"
105
+ end
106
+
107
+
108
+ end
109
+
110
+ end
111
+ end
@@ -0,0 +1,37 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
7
+ <link rel="stylesheet" href="stylesheets/tarantula.css" type="text/css" media="screen" title="no title" charset="utf-8">
8
+ <script type="text/javascript" src="javascripts/jquery-1.2.3.js"></script>
9
+ <script type="text/javascript" src="javascripts/jquery.tablesorter.js"></script>
10
+ <script type="text/javascript" src="javascripts/jquery-ui-tabs.js"></script>
11
+ <script type="text/javascript" src="javascripts/tarantula.js"></script>
12
+
13
+ <title>Tarantula</title>
14
+ </head>
15
+
16
+ <body>
17
+ <div id="container">
18
+ <div id="header">
19
+ <h1>Tarantula by Relevance</h1>
20
+ <h2>Eight legs, two fangs ... and an attitude</h2>
21
+ <p>Tarantula is an open source tool for testing Rails web
22
+ applications. Tarantula is developed by <a href="http://thinkrelevance.com">Relevance, Inc.</a>
23
+ and lives at <a href="http://github.com/relevance/tarantula">http://github.com/relevance/tarantula</a>.</p>
24
+ <hr/>
25
+ </div>
26
+ <div id="page">
27
+ <div id="tabs-container">
28
+ <ul class="tabs"> </ul>
29
+ </div>
30
+
31
+ <div id="results-container">
32
+
33
+ </div>
34
+ </div>
35
+ </div>
36
+ </body>
37
+ </html>