stratagem 0.2.3 → 0.2.4

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 (65) hide show
  1. data/Manifest +16 -6
  2. data/Rakefile +8 -1
  3. data/lib/generators/stratagem/install/install_base.rb +13 -3
  4. data/lib/generators/stratagem/install/install_generator.rb +1 -1
  5. data/lib/stratagem.rb +42 -18
  6. data/lib/stratagem/authentication.rb +2 -5
  7. data/lib/stratagem/auto_mock.rb +1 -0
  8. data/lib/stratagem/auto_mock/aquifer.rb +49 -26
  9. data/lib/stratagem/auto_mock/factory.rb +1 -6
  10. data/lib/stratagem/auto_mock/user_loader.rb +38 -0
  11. data/lib/stratagem/client.rb +15 -4
  12. data/lib/stratagem/configuration/auth_auth.rb +19 -0
  13. data/lib/stratagem/configuration/core.rb +20 -0
  14. data/lib/stratagem/crawler/authentication.rb +17 -12
  15. data/lib/stratagem/crawler/authentication/automated.rb +40 -0
  16. data/lib/stratagem/crawler/authentication/base.rb +140 -0
  17. data/lib/stratagem/crawler/authentication/configured.rb +27 -0
  18. data/lib/stratagem/crawler/parameter_resolver.rb +12 -8
  19. data/lib/stratagem/crawler/route_invoker.rb +10 -13
  20. data/lib/stratagem/crawler/session.rb +14 -2
  21. data/lib/stratagem/crawler/site_model.rb +4 -173
  22. data/lib/stratagem/crawler/site_model/edge.rb +20 -0
  23. data/lib/stratagem/crawler/site_model/page.rb +121 -0
  24. data/lib/stratagem/crawler/site_model/page_set.rb +58 -0
  25. data/lib/stratagem/instrumentation/models.rb +3 -14
  26. data/lib/stratagem/instrumentation/models/annotations.rb +39 -5
  27. data/lib/stratagem/instrumentation/models/authentication.rb +0 -1
  28. data/lib/stratagem/instrumentation/models/authentication/authlogic/detect.rb +1 -0
  29. data/lib/stratagem/instrumentation/models/authentication/devise/detect.rb +1 -1
  30. data/lib/stratagem/instrumentation/models/authentication/devise/instrumentation.rb +0 -4
  31. data/lib/stratagem/instrumentation/models/metadata.rb +23 -1
  32. data/lib/stratagem/instrumentation/models/persistence.rb +3 -4
  33. data/lib/stratagem/instrumentation/models/persistence/active_record/metadata.rb +2 -2
  34. data/lib/stratagem/interface/browser.rb +9 -3
  35. data/lib/stratagem/interface/public/javascripts/stratagem.js +14 -12
  36. data/lib/stratagem/interface/views/index.haml +3 -3
  37. data/lib/stratagem/logger.rb +28 -2
  38. data/lib/stratagem/model.rb +6 -0
  39. data/lib/stratagem/model/application.rb +21 -134
  40. data/lib/stratagem/model/components/base.rb +1 -4
  41. data/lib/stratagem/model/components/controller.rb +1 -2
  42. data/lib/stratagem/model/components/model.rb +15 -15
  43. data/lib/stratagem/model/components/route.rb +3 -2
  44. data/lib/stratagem/model/components/view.rb +0 -1
  45. data/lib/stratagem/model/containers/base.rb +60 -0
  46. data/lib/stratagem/model/containers/gem.rb +25 -0
  47. data/lib/stratagem/model/containers/plugin.rb +11 -0
  48. data/lib/stratagem/model/containers/route.rb +19 -0
  49. data/lib/stratagem/model/parse_util.rb +3 -3
  50. data/lib/stratagem/model_builder.rb +1 -4
  51. data/lib/stratagem/rack_hack.rb +15 -0
  52. data/lib/stratagem/site_crawler.rb +5 -4
  53. data/lib/stratagem/snapshot.rb +5 -7
  54. data/spec/stratagem/configuration_spec.rb +32 -0
  55. data/stratagem.gemspec +5 -8
  56. data/templates/install/environments/stratagem.rb.erb +31 -2
  57. data/templates/install/script/stratagem +16 -0
  58. data/templates/install/tasks/stratagem.rake +2 -2
  59. metadata +36 -65
  60. data/bin/stratagem +0 -58
  61. data/lib/stratagem/scan.rb +0 -19
  62. data/lib/stratagem/scan/checks/email_address.rb +0 -15
  63. data/lib/stratagem/scan/checks/error_pages.rb +0 -25
  64. data/lib/stratagem/scan/result.rb +0 -45
  65. data/lib/stratagem/scanner.rb +0 -32
@@ -15,9 +15,7 @@ module Stratagem::Crawler
15
15
  begin
16
16
  call_route!(route_info, track_invocations)
17
17
  rescue Exception
18
- # TODO - add exception as a response page
19
- puts "ERROR: #{$!.message}"
20
- puts $!.backtrace
18
+ Stratagem.logger.error($!)
21
19
  end
22
20
  end
23
21
 
@@ -31,8 +29,8 @@ module Stratagem::Crawler
31
29
  invocations = model_invocations_for_request do
32
30
  case verb
33
31
  when 'get'
32
+ puts "\t#{route_info[:path].to_s == '/connections'} - #{route_info[:path]}"
34
33
  do_get(route_info)
35
- puts "\tresponse code: #{response.code}" if response
36
34
  when 'post'
37
35
  do_post(route_info)
38
36
  when 'put'
@@ -43,20 +41,20 @@ module Stratagem::Crawler
43
41
  end
44
42
  end
45
43
 
46
- if (response)
47
- if (track_invocations)
48
- changes = detect_attribute_changes_in_models(invocations)
44
+ if (response && track_invocations)
45
+ changes = detect_attribute_changes_in_models(invocations)
46
+ if (![500].include?(response.code) || (changes.size > 0) || (invocations.size > 0))
49
47
  puts "\tfound #{invocations.size} invocations"
50
48
  invocations.each do |i|
51
49
  puts "\t\t#{i.controller_action} -> #{i.model_class}"
52
50
  end
53
-
54
- puts "\tchanges values: #{changes.values.inspect}" if changes.size > 0
55
- site_model.add(route_info[:route_container], controller, request, response, invocations, changes) {|redirect_url| redirect_proc.call(redirect_url) }
51
+ puts "\tchanges values: #{changes.values.inspect}"
52
+ page = site_model.add(route_info[:route_container], controller, request, response, invocations, changes) {|redirect_url| redirect_proc.call(redirect_url) }
53
+ puts "\tresponse code: #{response.code} - body size: #{page.response_body.size}"
56
54
  puts "\tadded to site model"
57
55
  end
58
56
  else
59
- puts "ERROR: did not call #{route_info.inspect}"
57
+ puts "ERROR: did not call #{route_info[:path]}"
60
58
  end
61
59
  end
62
60
 
@@ -169,7 +167,6 @@ module Stratagem::Crawler
169
167
 
170
168
  def guess_form_for_route(route_info)
171
169
  forms = []
172
- pages = site_models.map {|sm| sm.pages }.flatten
173
170
  site_models.each do |site_model|
174
171
  site_model.pages.each do |page|
175
172
  page.forms.each do |form|
@@ -178,7 +175,7 @@ module Stratagem::Crawler
178
175
  (route_info[:path].sub(/\.\(\:format\)*/, '') == form.action) &&
179
176
  ((form.implied_method || form.method).to_s.downcase == route_info[:verb].to_s.downcase)
180
177
  end
181
- puts "\tform: #{form.action} - #{form.implied_method || form.method} - #{usable}"
178
+ puts "\tpageset: #{site_model.name} - form: #{form.action} - #{form.implied_method || form.method} - #{usable} - #{form.inputs.map{|i| i.name}}"
182
179
  forms << form if (usable)
183
180
  end
184
181
  end
@@ -56,6 +56,7 @@ module Stratagem::Crawler::Session
56
56
  end
57
57
 
58
58
  def crawler_session(application_model=nil)
59
+ aquifer # force fill
59
60
  @application_model = application_model if application_model
60
61
  open_session do |session|
61
62
  @session = session
@@ -68,7 +69,16 @@ module Stratagem::Crawler::Session
68
69
  end
69
70
 
70
71
  def aquifer(initial_capacity=6)
71
- @aquifer ||= Stratagem::AutoMock::Aquifer.init(application_model).fill(initial_capacity)
72
+ @aquifer ||= begin
73
+ Stratagem.logger.phase "mocking_models"
74
+
75
+ if Stratagem.configuration.use_automatic_mocking
76
+ Stratagem::AutoMock::Aquifer.init(application_model).fill_by_automock(initial_capacity)
77
+ else
78
+ # TODO - refactor out into another method
79
+ Stratagem::AutoMock::Aquifer.init(application_model).fill_by_configuration(Stratagem.configuration.credentials)
80
+ end
81
+ end
72
82
  end
73
83
 
74
84
  def site_models
@@ -81,11 +91,13 @@ module Stratagem::Crawler::Session
81
91
  end
82
92
 
83
93
  def page_set(name, &block)
94
+ Stratagem.logger.phase "traversing_site"
95
+
84
96
  log "---------------------------------------"
85
97
  log "Crawling page set #{name}"
86
98
  log "---------------------------------------"
87
99
  reset!
88
- site_models << Stratagem::Crawler::SiteModel.new(name)
100
+ site_models << Stratagem::Crawler::SiteModel::PageSet.new(name)
89
101
  yield site_model
90
102
  end
91
103
 
@@ -1,174 +1,5 @@
1
- module Stratagem::Crawler
2
- class SiteModel
3
- include Stratagem::Crawler::HtmlUtils
1
+ module Stratagem::Crawler::SiteModel; end
4
2
 
5
- attr_reader :pages, :edges, :name
6
- attr_accessor :authentication
7
-
8
- def initialize(name)
9
- @name = name
10
- @pages = []
11
- @edges = []
12
- end
13
-
14
- def export
15
- {
16
- :name => name,
17
- :pages => @pages.map {|page| page.export },
18
- :edges => @edges.map {|edge| edge.export },
19
- :authentication => authentication.nil? ? nil : {
20
- :authenticated_user_id => authentication.authenticated_with.object_id,
21
- :success => authentication.success,
22
- :login_page_external_id => authentication.login_page.object_id,
23
- :response_page_external_id => authentication.response_page.object_id,
24
- :ssl => authentication.ssl
25
- },
26
- }
27
- end
28
-
29
- def add_edge(from,to,type)
30
- self.edges << Edge.new(from,to,type)
31
- end
32
-
33
- def add(route, controller, request, response, invocations=[], model_changes={}, &block)
34
- page = Page.new(self, controller, request, response, invocations, model_changes, &block)
35
- self.pages << page
36
- page
37
- end
38
-
39
- def pages_for(id)
40
- if (id.kind_of?(String))
41
- pages.select {|page| page.url == id }
42
- else
43
- pages.select {|page| page.route == id }
44
- end
45
- end
46
-
47
- end
48
-
49
- class Edge
50
- # type -> :link, :redirect,
51
- attr_accessor :from, :to, :type
52
-
53
- def initialize(from, to, type)
54
- @from = from
55
- @to = to
56
- @type = type
57
- end
58
-
59
- def export
60
- {
61
- :from => from.object_id,
62
- :to => to.object_id,
63
- :relation_type => type
64
- }
65
- end
66
- end
67
-
68
- class Page
69
- include Stratagem::Crawler::HtmlUtils
70
-
71
- attr_reader :response
72
-
73
- attr_accessor :url
74
- attr_accessor :path
75
- attr_accessor :method
76
- attr_accessor :redirected_to
77
- attr_accessor :document
78
- attr_accessor :response_body
79
-
80
- def initialize(site_model, controller, request, response, invocations, model_changes, &block)
81
- @site_model = site_model
82
- @invocations = invocations
83
- @model_changes = model_changes
84
- @authenticity_checked = (controller && controller.methods.include?(:authenticity_checked?)) ? controller.authenticity_checked? : true
85
- init(request, response, &block)
86
- end
87
-
88
- def route
89
- @route ||= Stratagem::Model::Application.instance.routes.recognize(self)
90
- end
91
-
92
- def export
93
- h = {
94
- :external_id => self.object_id,
95
- :url => url,
96
- :path => path,
97
- :request_method => method,
98
- :redirected_to_page_external_id => redirected_to ? redirected_to.object_id : nil,
99
- :route_external_id => route ? route.object_id : nil,
100
- :references => @invocations.map {|i| i.to_reference.export },
101
- :model_changes => Hash[@model_changes.map {|model,changes| [model.object_id, changes] }].to_json,
102
- :authenticity_checked => @authenticity_checked,
103
- :parameters => @request.parameters.to_json,
104
- :response_body => @response_body
105
- }
106
- h
107
- end
108
-
109
- def init(request, response, &block)
110
- @request = request.clone
111
- @response = response.clone
112
- @url = request.url
113
- @path = request.path
114
- @method = request.method
115
- begin
116
- @document = Nokogiri::HTML(response.body)
117
- rescue
118
- puts "ERROR: Could not parse html: #{$!.message} - #{response.body}"
119
- end
120
- @response_body = response.body
121
- self.redirected_to = block.call(response.redirect_url) if response.redirect?
122
- end
123
-
124
- def reload(&block)
125
- # TODO - should support all the verbs and params, but
126
- # hack together for now to reload the authenticity token
127
- request,response = yield url
128
- init(request, response) {|redirected_to| }
129
- end
130
-
131
- def redirected?
132
- !self.redirected_to.nil?
133
- end
134
-
135
- def forms
136
- @forms ||= begin
137
- if (@document)
138
- forms = self.parse_forms(@document)
139
- forms.each do |form|
140
- form.page = self
141
- end
142
- forms
143
- else
144
- []
145
- end
146
- end
147
- end
148
-
149
- def login_form
150
- self.find_login_form(@document)
151
- end
152
-
153
- def to_html
154
- @document.to_html
155
- end
156
-
157
- def outbound_edges(type=nil)
158
- @site_model.edges.select {|edge| edge.from == self && (type.nil? || (type == edge.type)) }
159
- end
160
-
161
- def inbound_edges(type=nil)
162
- @site_model.edges.select {|edge| (edge.to == self) && (type.nil? || (type == edge.type)) }
163
- end
164
-
165
- def title
166
- if ((@document) && !(@title))
167
- title = (@document/'head title').first
168
- @title = title.inner_html if title
169
- end
170
- @title
171
- end
172
- end
173
-
174
- end
3
+ require 'stratagem/crawler/site_model/page_set'
4
+ require 'stratagem/crawler/site_model/page'
5
+ require 'stratagem/crawler/site_model/edge'
@@ -0,0 +1,20 @@
1
+ module Stratagem::Crawler::SiteModel
2
+ class Edge
3
+ # type -> :link, :redirect,
4
+ attr_accessor :from, :to, :type
5
+
6
+ def initialize(from, to, type)
7
+ @from = from
8
+ @to = to
9
+ @type = type
10
+ end
11
+
12
+ def export
13
+ {
14
+ :from_page_external_id => from.object_id,
15
+ :to_page_external_id => to.object_id,
16
+ :relation_type => type
17
+ }
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,121 @@
1
+ module Stratagem::Crawler::SiteModel
2
+
3
+ class Page
4
+ include Stratagem::Crawler::HtmlUtils
5
+
6
+ attr_reader :response
7
+
8
+ attr_accessor :url
9
+ attr_accessor :path
10
+ attr_accessor :method
11
+ attr_accessor :redirected_to
12
+ attr_accessor :document
13
+ attr_accessor :response_body
14
+
15
+ def initialize(site_model, controller, request, response, invocations, model_changes, &block)
16
+ @site_model = site_model
17
+ @invocations = invocations
18
+ @model_changes = model_changes
19
+ @authenticity_checked = (controller && controller.methods.include?(:authenticity_checked?)) ? controller.authenticity_checked? : true
20
+ init(request, response, &block)
21
+ end
22
+
23
+ def route
24
+ @route ||= Stratagem::Model::Application.instance.routes.recognize(self)
25
+ end
26
+
27
+ def export
28
+ h = {
29
+ :external_id => self.object_id,
30
+ :url => url,
31
+ :path => path,
32
+ :request_method => method,
33
+ :redirected_to_page_external_id => redirected_to ? redirected_to.object_id : nil,
34
+ :route_external_id => route ? route.object_id : nil,
35
+ :references_attributes => @invocations.map {|i| i.to_reference.export },
36
+ :model_changes => Hash[@model_changes.map {|model,changes| [model.object_id, changes] }].to_json,
37
+ :authenticity_checked => @authenticity_checked,
38
+ :parameters => @request.parameters.to_json,
39
+ :response_body => @response_body,
40
+ :response_code => @response.code
41
+ }
42
+ h
43
+ end
44
+
45
+ def init(request, response, &block)
46
+ @request = request.clone
47
+ @response = response.clone
48
+ @url = request.url
49
+ @path = request.path
50
+ @method = request.method
51
+ body = response.body
52
+ begin
53
+ if [500, 400, 302].include?(response.code)
54
+ body = ''
55
+ elsif
56
+ body.kind_of?(Array)
57
+ body = body.join
58
+ body = body.slice(0,20000)
59
+ end
60
+
61
+ @document = Nokogiri::HTML(body)
62
+ rescue
63
+ puts "ERROR: Could not parse html: #{$!.message} - #{body}"
64
+ end
65
+
66
+ @response_body = body
67
+
68
+ self.redirected_to = block.call(response.redirect_url) if response.redirect?
69
+ end
70
+
71
+ def reload(&block)
72
+ # TODO - should support all the verbs and params, but
73
+ # hack together for now to reload the authenticity token
74
+ request,response = yield url
75
+ init(request, response) {|redirected_to| }
76
+ end
77
+
78
+ def redirected?
79
+ !self.redirected_to.nil?
80
+ end
81
+
82
+ def forms
83
+ @forms ||= begin
84
+ if (@document)
85
+ forms = self.parse_forms(@document)
86
+ forms.each do |form|
87
+ form.page = self
88
+ end
89
+ forms
90
+ else
91
+ []
92
+ end
93
+ end
94
+ end
95
+
96
+ def login_form
97
+ self.find_login_form(@document)
98
+ end
99
+
100
+ def to_html
101
+ @document.to_html
102
+ end
103
+
104
+ def outbound_edges(type=nil)
105
+ @site_model.edges.select {|edge| edge.from == self && (type.nil? || (type == edge.type)) }
106
+ end
107
+
108
+ def inbound_edges(type=nil)
109
+ @site_model.edges.select {|edge| (edge.to == self) && (type.nil? || (type == edge.type)) }
110
+ end
111
+
112
+ def title
113
+ if ((@document) && !(@title))
114
+ title = (@document/'head title').first
115
+ @title = title.inner_html if title
116
+ end
117
+ @title
118
+ end
119
+ end
120
+
121
+ end
@@ -0,0 +1,58 @@
1
+ module Stratagem::Crawler::SiteModel
2
+
3
+ class PageSet
4
+ include Stratagem::Crawler::HtmlUtils
5
+
6
+ attr_reader :pages, :edges, :name
7
+ attr_accessor :authentication
8
+
9
+ def initialize(name)
10
+ @name = name
11
+ @pages = []
12
+ @edges = []
13
+ end
14
+
15
+ def export
16
+ puts "Exporting page set #{name} with #{@pages.size} initial pages"
17
+ pages = @pages.select {|page| page.response_body && page.response_body.size > 0 }
18
+ puts "\t#{pages.size} filtered pages"
19
+ pages = pages.map {|page| page.export }
20
+
21
+ pages << authentication.login_page.export if authentication && authentication.login_page
22
+ pages << authentication.response_page.export if authentication && authentication.response_page
23
+
24
+ puts "\t#{pages.size} exported pages"
25
+ {
26
+ :name => name,
27
+ :pages_attributes => pages,
28
+ :edges_attributes => @edges.map {|edge| edge.export },
29
+ :authentication_attributes => authentication.nil? ? nil : {
30
+ :authenticated_user_id => authentication.authenticated_with.object_id,
31
+ :success => authentication.success,
32
+ :login_page_external_id => authentication.login_page ? authentication.login_page.object_id : nil,
33
+ :response_page_external_id => authentication.response_page ? authentication.response_page.object_id : nil,
34
+ :ssl => authentication.ssl
35
+ },
36
+ }
37
+ end
38
+
39
+ def add_edge(from,to,type)
40
+ self.edges << Edge.new(from,to,type)
41
+ end
42
+
43
+ def add(route, controller, request, response, invocations=[], model_changes={}, &block)
44
+ page = Page.new(self, controller, request, response, invocations, model_changes, &block)
45
+ self.pages << page
46
+ page
47
+ end
48
+
49
+ def pages_for(id)
50
+ if (id.kind_of?(String))
51
+ pages.select {|page| page.url == id }
52
+ else
53
+ pages.select {|page| page.route == id }
54
+ end
55
+ end
56
+
57
+ end
58
+ end