stratagem 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest +99 -0
- data/Rakefile +17 -0
- data/bin/stratagem +10 -0
- data/init.rb +2 -0
- data/lib/bootstrap.rb +31 -0
- data/lib/stratagem/authentication.rb +64 -0
- data/lib/stratagem/auto_mock/aquifer.rb +86 -0
- data/lib/stratagem/auto_mock/factory.rb +213 -0
- data/lib/stratagem/auto_mock/value_generator.rb +174 -0
- data/lib/stratagem/auto_mock.rb +6 -0
- data/lib/stratagem/blocker.rb +16 -0
- data/lib/stratagem/client.rb +32 -0
- data/lib/stratagem/command.rb +13 -0
- data/lib/stratagem/commands/analyze.rb +22 -0
- data/lib/stratagem/commands/base.rb +11 -0
- data/lib/stratagem/commands/devel_crawl.rb +27 -0
- data/lib/stratagem/commands/devel_mock.rb +10 -0
- data/lib/stratagem/commands.rb +7 -0
- data/lib/stratagem/crawler/authentication.rb +109 -0
- data/lib/stratagem/crawler/form.rb +101 -0
- data/lib/stratagem/crawler/html_utils.rb +92 -0
- data/lib/stratagem/crawler/session.rb +296 -0
- data/lib/stratagem/crawler/site_model.rb +138 -0
- data/lib/stratagem/crawler/trace_utils.rb +10 -0
- data/lib/stratagem/crawler.rb +9 -0
- data/lib/stratagem/extensions/class.rb +9 -0
- data/lib/stratagem/extensions/hash.rb +16 -0
- data/lib/stratagem/extensions/module.rb +11 -0
- data/lib/stratagem/extensions/object.rb +15 -0
- data/lib/stratagem/extensions/red_parse.rb +86 -0
- data/lib/stratagem/extensions/string.rb +20 -0
- data/lib/stratagem/extensions.rb +6 -0
- data/lib/stratagem/framework_extensions/controllers/action_controller.rb +10 -0
- data/lib/stratagem/framework_extensions/controllers/action_mailer.rb +12 -0
- data/lib/stratagem/framework_extensions/controllers.rb +5 -0
- data/lib/stratagem/framework_extensions/models/adapters/active_model/detect.rb +7 -0
- data/lib/stratagem/framework_extensions/models/adapters/active_model/extensions.rb +35 -0
- data/lib/stratagem/framework_extensions/models/adapters/active_model/metadata.rb +103 -0
- data/lib/stratagem/framework_extensions/models/adapters/active_model/tracing.rb +50 -0
- data/lib/stratagem/framework_extensions/models/adapters/authlogic/detect.rb +11 -0
- data/lib/stratagem/framework_extensions/models/adapters/authlogic/extensions.rb +10 -0
- data/lib/stratagem/framework_extensions/models/adapters/authlogic/metadata.rb +30 -0
- data/lib/stratagem/framework_extensions/models/adapters/authlogic/tracing.rb +4 -0
- data/lib/stratagem/framework_extensions/models/adapters/common/authentication_metadata.rb +21 -0
- data/lib/stratagem/framework_extensions/models/adapters/restful_authentication/detect.rb +13 -0
- data/lib/stratagem/framework_extensions/models/adapters/restful_authentication/extensions.rb +19 -0
- data/lib/stratagem/framework_extensions/models/adapters/restful_authentication/metadata.rb +30 -0
- data/lib/stratagem/framework_extensions/models/adapters/restful_authentication/tracing.rb +4 -0
- data/lib/stratagem/framework_extensions/models/annotations.rb +79 -0
- data/lib/stratagem/framework_extensions/models/detect.rb +7 -0
- data/lib/stratagem/framework_extensions/models/metadata.rb +85 -0
- data/lib/stratagem/framework_extensions/models/mocking.rb +23 -0
- data/lib/stratagem/framework_extensions/models/tracing.rb +71 -0
- data/lib/stratagem/framework_extensions/models.rb +21 -0
- data/lib/stratagem/framework_extensions/rails.rb +8 -0
- data/lib/stratagem/framework_extensions.rb +6 -0
- data/lib/stratagem/interface/browser.rb +37 -0
- data/lib/stratagem/interface/public/images/backgrounds/content.png +0 -0
- data/lib/stratagem/interface/public/images/backgrounds/shadow.png +0 -0
- data/lib/stratagem/interface/public/javascripts/jquery-1.4.2.min.js +154 -0
- data/lib/stratagem/interface/public/javascripts/stratagem.js +27 -0
- data/lib/stratagem/interface/public/javascripts/stratagem_debug.js +53 -0
- data/lib/stratagem/interface/public/stylesheets/960.css +1 -0
- data/lib/stratagem/interface/public/stylesheets/reset.css +10 -0
- data/lib/stratagem/interface/public/stylesheets/stratagem.css +20 -0
- data/lib/stratagem/interface/public/stylesheets/stratagem_debug.css +20 -0
- data/lib/stratagem/interface/views/debug.haml +43 -0
- data/lib/stratagem/interface/views/index.haml +35 -0
- data/lib/stratagem/labs/auto_mock.rb +7 -0
- data/lib/stratagem/labs/crawler.rb +0 -0
- data/lib/stratagem/logger.rb +46 -0
- data/lib/stratagem/model/application.rb +157 -0
- data/lib/stratagem/model/components/base.rb +55 -0
- data/lib/stratagem/model/components/controller.rb +118 -0
- data/lib/stratagem/model/components/model.rb +170 -0
- data/lib/stratagem/model/components/reference.rb +30 -0
- data/lib/stratagem/model/components/route.rb +53 -0
- data/lib/stratagem/model/components/static_file.rb +18 -0
- data/lib/stratagem/model/components/view.rb +186 -0
- data/lib/stratagem/model/parse_util.rb +61 -0
- data/lib/stratagem/model.rb +12 -0
- data/lib/stratagem/model_builder.rb +146 -0
- data/lib/stratagem/recipes/deploy.rb +30 -0
- data/lib/stratagem/scan/checks/capistrano/secure_deploy.rb +43 -0
- data/lib/stratagem/scan/checks/email_address.rb +15 -0
- data/lib/stratagem/scan/checks/error_pages.rb +25 -0
- data/lib/stratagem/scan/checks/filter_parameter_logging.rb +6 -0
- data/lib/stratagem/scan/checks/mongo_mapper/base.rb +19 -0
- data/lib/stratagem/scan/checks/mongo_mapper/foreign_keys_exposed.rb +32 -0
- data/lib/stratagem/scan/checks/routes.rb +16 -0
- data/lib/stratagem/scan/checks/ssl/secure_login_page.rb +19 -0
- data/lib/stratagem/scan/checks/ssl/secure_login_submit.rb +18 -0
- data/lib/stratagem/scan/result.rb +45 -0
- data/lib/stratagem/scan.rb +19 -0
- data/lib/stratagem/scanner.rb +32 -0
- data/lib/stratagem/site_crawler.rb +47 -0
- data/lib/stratagem/snapshot.rb +33 -0
- data/lib/stratagem.rb +77 -0
- data/lib/tasks/_old_stratagem.rake +99 -0
- data/stratagem.gemspec +56 -0
- metadata +380 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
module Stratagem::ApplicationExtensions::Models::Adapters::ActiveModel
|
2
|
+
|
3
|
+
# prefix method names with to avoid collision
|
4
|
+
class Metadata
|
5
|
+
|
6
|
+
attr_reader :model, :instance
|
7
|
+
|
8
|
+
def initialize(model)
|
9
|
+
@model = model
|
10
|
+
@instance = @model.new unless (@model == ActiveRecord::Base)
|
11
|
+
end
|
12
|
+
|
13
|
+
def relations(relation_type=nil) # :belongs_to, :has_many
|
14
|
+
@relations ||= {}
|
15
|
+
@relations[relation_type || :all] ||= model.reflect_on_all_associations(relation_type).map {|a|
|
16
|
+
Stratagem::ApplicationExtensions::Models::Metadata::StratagemAssociation.new(a.name.to_sym, a.association_foreign_key.to_sym, a.klass, a.macro)
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def unaccessible_attributes
|
21
|
+
attrs = []
|
22
|
+
if (model.accessible_attributes)
|
23
|
+
attrs = model.stratagem.attribute_names - model.accessible_attributes.map {|a| a.to_sym }
|
24
|
+
end
|
25
|
+
attrs += model.protected_attributes.map {|a| a.to_sym } if model.protected_attributes
|
26
|
+
attrs
|
27
|
+
end
|
28
|
+
|
29
|
+
# parses a database error and returns the columns that had problems
|
30
|
+
# this is typically a not null enforced by the database but not
|
31
|
+
# by the model
|
32
|
+
def column_from_error(database_error)
|
33
|
+
if (database_error.kind_of?(Mysql::Error) || database_error.kind_of?(::ActiveRecord::StatementInvalid))
|
34
|
+
database_error.message =~ /Column '(.*)?' cannot/
|
35
|
+
$1 ? $1.to_sym : nil
|
36
|
+
else
|
37
|
+
puts database_error.class.name
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def valid?
|
44
|
+
model.valid?
|
45
|
+
end
|
46
|
+
|
47
|
+
def whitelists_attributes?
|
48
|
+
!model.accessible_attributes.nil?
|
49
|
+
end
|
50
|
+
|
51
|
+
def blacklists_attributes?
|
52
|
+
!model.protected_attributes.nil?
|
53
|
+
end
|
54
|
+
|
55
|
+
def attribute_names
|
56
|
+
instance.attribute_names.map {|a| a.to_sym} - ignore_attributes
|
57
|
+
end
|
58
|
+
|
59
|
+
# junk attributes
|
60
|
+
def ignore_attributes
|
61
|
+
["!".to_sym, :[]]
|
62
|
+
end
|
63
|
+
|
64
|
+
# Attributes generally used by the persistence mechanism that should not be human writable
|
65
|
+
# accessible from the class
|
66
|
+
def internal_attributes
|
67
|
+
attrs = [:id, :created_at, :updated_at]
|
68
|
+
attrs += attribute_names.select {|a|
|
69
|
+
(a.to_s =~ /_count$/) ||
|
70
|
+
(a.to_s =~ /_salt$/) ||
|
71
|
+
(a.to_s =~ /_token$/) ||
|
72
|
+
(a.to_s == 'type')
|
73
|
+
}.map {|a| a.to_sym }
|
74
|
+
attrs
|
75
|
+
end
|
76
|
+
|
77
|
+
def attribute_type(name)
|
78
|
+
column = instance.column_for_attribute(name.to_s)
|
79
|
+
if (!column.nil?)
|
80
|
+
if (model.stratagem.foreign_keys.include?(name.to_sym))
|
81
|
+
:integer
|
82
|
+
else
|
83
|
+
column.type
|
84
|
+
end
|
85
|
+
else
|
86
|
+
if (name =~ /password/)
|
87
|
+
:string
|
88
|
+
else
|
89
|
+
types = [:string, :boolean, :integer]
|
90
|
+
types[rand(3)]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def invalid_columns(instance)
|
96
|
+
instance.valid?
|
97
|
+
errors = []
|
98
|
+
instance.errors.each {|error,i| errors << error.to_s.to_sym }
|
99
|
+
errors & attribute_names
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Stratagem::ApplicationExtensions::Models::Adapters::ActiveModel
|
2
|
+
module Tracing
|
3
|
+
def self.included(model)
|
4
|
+
model.class_eval do
|
5
|
+
# inject read tracing
|
6
|
+
@@removed_finder_methods = [:first, :last]+methods.select {|m| m =~ /^find/ }.map {|m| m.to_sym }.uniq
|
7
|
+
@@removed_methods = [:method_missing]+@@removed_finder_methods
|
8
|
+
class << self
|
9
|
+
@@removed_methods.each do |m|
|
10
|
+
alias_method "old_#{m}", m
|
11
|
+
undef_method m
|
12
|
+
end
|
13
|
+
end
|
14
|
+
model.removed_methods = @@removed_methods
|
15
|
+
|
16
|
+
# inject write tracing
|
17
|
+
[:create_or_update].each do |m|
|
18
|
+
alias_method "old_#{m}", m
|
19
|
+
undef_method m
|
20
|
+
end
|
21
|
+
|
22
|
+
# enhance method missing
|
23
|
+
class << self
|
24
|
+
def method_missing(method, *args, &block)
|
25
|
+
if (self.removed_methods.include?(method.to_sym))
|
26
|
+
# puts "read invocation: #{self.name} -> #{method} -> #{args.inspect}"
|
27
|
+
stratagem.read_invocation(method, args) if (@@removed_finder_methods.include?(method))
|
28
|
+
send("old_"+method.to_s, *args, &block)
|
29
|
+
elsif (self.removed_validators.include?(method.to_sym))
|
30
|
+
stratagem.validator_called(method, args)
|
31
|
+
puts "calling validator #{method.to_s} with #{args.inspect}"
|
32
|
+
send("old_"+method.to_s, *args, &block)
|
33
|
+
else
|
34
|
+
old_method_missing(method, *args, &block)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# add logging of save methods
|
40
|
+
|
41
|
+
def create_or_update(*args)
|
42
|
+
path,action,line = stratagem.controller_trace(/active_record\/base\.rb/)
|
43
|
+
stratagem.write_invocation(self, action.to_sym, args)
|
44
|
+
old_create_or_update(*args)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Stratagem::ApplicationExtensions::Models::Adapters::Authlogic
|
2
|
+
class Detect < Stratagem::ApplicationExtensions::Models::Detect
|
3
|
+
def self.supports?(model)
|
4
|
+
begin
|
5
|
+
model.ancestors.include?(::Authlogic::ActsAsAuthentic::MagicColumns::Methods)
|
6
|
+
rescue
|
7
|
+
false
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
if defined?(Authlogic)
|
2
|
+
module Authlogic::ActsAsAuthentic::MagicColumns::Methods
|
3
|
+
def self.included(model)
|
4
|
+
# automatically activate the account
|
5
|
+
model.class_eval do
|
6
|
+
before_save { |record| record.active = true if record.methods_include?(:active) }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Stratagem::ApplicationExtensions::Models::Adapters::Authlogic
|
2
|
+
|
3
|
+
# prefix method names with to avoid collision
|
4
|
+
class Metadata
|
5
|
+
include Stratagem::ApplicationExtensions::Models::Adapters::Common::AuthenticationMetadata
|
6
|
+
|
7
|
+
VIRTUAL_COLUMNS = [:password, :password_confirmation]
|
8
|
+
|
9
|
+
def authenticates?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(model)
|
14
|
+
@model = model
|
15
|
+
end
|
16
|
+
|
17
|
+
def attribute_names
|
18
|
+
VIRTUAL_COLUMNS
|
19
|
+
end
|
20
|
+
|
21
|
+
def internal_attributes
|
22
|
+
[:crypted_password, :password_salt]
|
23
|
+
end
|
24
|
+
|
25
|
+
def attribute_type(name)
|
26
|
+
:string
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Stratagem::ApplicationExtensions::Models::Adapters::Common
|
2
|
+
|
3
|
+
# prefix method names with to avoid collision
|
4
|
+
module AuthenticationMetadata
|
5
|
+
def exclude_attributes_for_mocking
|
6
|
+
# open id
|
7
|
+
attrs = @model.stratagem.attribute_names.select {|a|
|
8
|
+
(a =~ /open_id/ || a =~ /openid/ || a =~ /identity_url/)
|
9
|
+
}
|
10
|
+
attrs << :identity_url
|
11
|
+
attrs << :openid_identifier
|
12
|
+
|
13
|
+
# aasm
|
14
|
+
if (@model.methods_include?(:aasm_column))
|
15
|
+
attrs << @model.aasm_column
|
16
|
+
end
|
17
|
+
|
18
|
+
attrs.uniq
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Stratagem::ApplicationExtensions::Models::Adapters::RestfulAuthentication
|
4
|
+
class Detect < Stratagem::ApplicationExtensions::Models::Detect
|
5
|
+
def self.supports?(model)
|
6
|
+
begin
|
7
|
+
model.ancestors.include?(::Authentication::ByPassword)
|
8
|
+
rescue
|
9
|
+
false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
if (defined?(Authentication))
|
2
|
+
Authentication.subclasses.each do |model|
|
3
|
+
model.class_eval do
|
4
|
+
# add support for aasm models
|
5
|
+
before_save { |record|
|
6
|
+
begin
|
7
|
+
if (record.methods_include?(:active?) && !record.send(:active?))
|
8
|
+
Stratagem.logger.debug "Activating Restful Authentication model #{name}";
|
9
|
+
record.send("#{record.class.aasm_column}=", record.class.aasm_initial_state.values.first.to_s)
|
10
|
+
record.activate! unless record.active?
|
11
|
+
end
|
12
|
+
rescue
|
13
|
+
puts $!.message
|
14
|
+
puts $!.backtrace
|
15
|
+
end
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Stratagem::ApplicationExtensions::Models::Adapters::RestfulAuthentication
|
2
|
+
|
3
|
+
# prefix method names with to avoid collision
|
4
|
+
class Metadata
|
5
|
+
include Stratagem::ApplicationExtensions::Models::Adapters::Common::AuthenticationMetadata
|
6
|
+
|
7
|
+
VIRTUAL_COLUMNS = [:password, :password_confirmation]
|
8
|
+
|
9
|
+
def authenticates?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(model)
|
14
|
+
@model = model
|
15
|
+
end
|
16
|
+
|
17
|
+
def attribute_names
|
18
|
+
VIRTUAL_COLUMNS
|
19
|
+
end
|
20
|
+
|
21
|
+
def internal_attributes
|
22
|
+
[:crypted_password]
|
23
|
+
end
|
24
|
+
|
25
|
+
def attribute_type(name)
|
26
|
+
:string
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Defines the stratagem namespace attached to the model
|
2
|
+
module Stratagem::ApplicationExtensions::Models
|
3
|
+
MethodInvocation = Struct.new(:method, :controller_path, :controller_action, :line_number, :model_instance, :model_class, :stack_trace, :args)
|
4
|
+
ValidatorDefinition = Struct.new(:validation, :field, :args, :model_class)
|
5
|
+
|
6
|
+
class InstanceAnnotations
|
7
|
+
include Mocking
|
8
|
+
|
9
|
+
def initialize(object)
|
10
|
+
@object = object
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(method, *args, &block)
|
14
|
+
@object.class.stratagem.send(method, *args, &block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Annotations
|
19
|
+
include Metadata
|
20
|
+
include Tracing
|
21
|
+
|
22
|
+
attr_reader :model
|
23
|
+
|
24
|
+
AdapterDescriptor = Struct.new(:tracing, :metadata, :detector)
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def configure(model)
|
28
|
+
puts "configuring #{model.name}"
|
29
|
+
|
30
|
+
# add the stratagem namespace
|
31
|
+
model.class_eval do
|
32
|
+
def self.stratagem
|
33
|
+
# one stratagem instance per subclass
|
34
|
+
@@stratagem ||= {}
|
35
|
+
@@stratagem[self] ||= Stratagem::ApplicationExtensions::Models::Annotations.new(self)
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def stratagem
|
40
|
+
@stratagem ||= Stratagem::ApplicationExtensions::Models::InstanceAnnotations.new(self)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# connect the adapters
|
45
|
+
detect_adapters(model).each {|adapter|
|
46
|
+
if adapter.detector.supports?(model)
|
47
|
+
model.send(:include, adapter.tracing)
|
48
|
+
end
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def detect_adapters(model)
|
53
|
+
Detect.subclasses.map do |detector|
|
54
|
+
namespace = detector.name.split('::')
|
55
|
+
namespace.pop
|
56
|
+
namespace = namespace.join('::')
|
57
|
+
|
58
|
+
tracing = module_eval(namespace+"::Tracing")
|
59
|
+
metadata = module_eval(namespace+"::Metadata").new(model)
|
60
|
+
|
61
|
+
AdapterDescriptor.new(tracing, metadata, detector)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def initialize(model)
|
67
|
+
puts "initializing stratagem for #{model.name}"
|
68
|
+
@model = model
|
69
|
+
end
|
70
|
+
|
71
|
+
def adapters
|
72
|
+
# supported adapters may change throughout the lifecycle of a class / object
|
73
|
+
@adapters ||= self.class.detect_adapters(model)
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
|
2
|
+
module Stratagem::ApplicationExtensions::Models
|
3
|
+
module Metadata
|
4
|
+
StratagemAssociation = Struct.new(:name, :foreign_key, :klass, :macro)
|
5
|
+
|
6
|
+
INSTANCE_ENUMERATION_METHODS = [:relations, :attribute_names, :ignore_attributes, :internal_attributes, :unaccessible_attributes, :invalid_columns, :exclude_attributes_for_mocking]
|
7
|
+
INSTANCE_ENTITY_METHODS = [:attribute_type, :column_from_error, :authenticates?, :whitelists_attributes?, :blacklists_attributes?]
|
8
|
+
|
9
|
+
def Metadata.included(mod)
|
10
|
+
mod.class_eval do
|
11
|
+
INSTANCE_ENUMERATION_METHODS.each do |name|
|
12
|
+
define_method(name) do |*args|
|
13
|
+
run_callbacks(name, *args)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
INSTANCE_ENTITY_METHODS.each do |name|
|
18
|
+
define_method(name) do |*args|
|
19
|
+
val = run_callbacks(name, *args).first
|
20
|
+
val ||= false if (name.to_s.include?('?'))
|
21
|
+
val
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Convenience methods
|
29
|
+
|
30
|
+
def foreign_keys
|
31
|
+
relations(:belongs_to).map {|relation| relation.foreign_key }
|
32
|
+
end
|
33
|
+
|
34
|
+
def relation(name)
|
35
|
+
relations.find {|relation| relation.name == name }
|
36
|
+
end
|
37
|
+
|
38
|
+
def relation_names(relation_type=nil)
|
39
|
+
@relation_names ||= {}
|
40
|
+
@relation_names[relation_type || :all] ||= relations(relation_type).map {|relation| relation.name }
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
# Tracking of validates_xyz methods. Population of this data can be found in the tracing library
|
45
|
+
|
46
|
+
def validations(field=nil, validation=nil)
|
47
|
+
validators = self.validators
|
48
|
+
|
49
|
+
if (field || validation)
|
50
|
+
validators.select {|v|
|
51
|
+
conditions = []
|
52
|
+
conditions << (v.field == field) if field
|
53
|
+
conditions << (v.validation == validation) if validation
|
54
|
+
!conditions.include?(false)
|
55
|
+
}
|
56
|
+
else
|
57
|
+
validators
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def callbacks
|
62
|
+
adapters.select {|a| a.detector.supports?(model) }.map {|a| a.metadata }
|
63
|
+
end
|
64
|
+
|
65
|
+
def validators
|
66
|
+
@validators ||= []
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def run_callbacks(method, *args)
|
72
|
+
results = callbacks.inject([]) {|memory,callback|
|
73
|
+
begin
|
74
|
+
memory << callback.send(method, *args) if callback.methods_include?(method) || callback.methods_include?(method.to_s)
|
75
|
+
memory
|
76
|
+
rescue
|
77
|
+
puts $!.message
|
78
|
+
puts $!.backtrace
|
79
|
+
end
|
80
|
+
}
|
81
|
+
(results || []).flatten.compact
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Stratagem::ApplicationExtensions::Models
|
2
|
+
module Mocking
|
3
|
+
def mock_attributes
|
4
|
+
@attributes ||= {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def write_mock_attribute(name, value)
|
8
|
+
mock_attributes[name] = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def read_mock_attribute(name)
|
12
|
+
mock_attributes[name]
|
13
|
+
end
|
14
|
+
|
15
|
+
def used_in_mock_relation
|
16
|
+
@available_for_mock_relation = false
|
17
|
+
end
|
18
|
+
|
19
|
+
def used_in_mock_relation?
|
20
|
+
@available_for_mock_relation ||= true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Stratagem::ApplicationExtensions::Models
|
2
|
+
module Tracing
|
3
|
+
|
4
|
+
@@invocations_audit = []
|
5
|
+
|
6
|
+
def invocations_audit
|
7
|
+
@@invocations_audit
|
8
|
+
end
|
9
|
+
|
10
|
+
def read_invocations
|
11
|
+
@read_invocations ||= []
|
12
|
+
end
|
13
|
+
|
14
|
+
def write_invocations
|
15
|
+
@write_invocations ||= []
|
16
|
+
end
|
17
|
+
|
18
|
+
def validator_called(validation, args)
|
19
|
+
params = args.find {|a| a.kind_of?(Hash) } || {}
|
20
|
+
(args-[params]).each do |field|
|
21
|
+
self.validators << ValidatorDefinition.new(validation, field, params, model)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def clear_invocations
|
26
|
+
read_invocations.clear
|
27
|
+
write_invocations.clear
|
28
|
+
invocations_audit.clear
|
29
|
+
end
|
30
|
+
|
31
|
+
def write_invocation(model_instance, method, args)
|
32
|
+
invocation(method, args, write_invocations, model_instance)
|
33
|
+
end
|
34
|
+
|
35
|
+
def read_invocation(method, *args)
|
36
|
+
# ensure that the read did not stem from a write operation
|
37
|
+
path,action,line = controller_trace(/active_record\/base\.rb/)
|
38
|
+
invocation(method, args, read_invocations) unless (action =~ /create/) || (action =~ /update/) || (action =~ /save/)
|
39
|
+
end
|
40
|
+
|
41
|
+
def invocation(method, args, enumeration, model_instance=nil)
|
42
|
+
path,action,line = controller_trace
|
43
|
+
args = args.first if args && (args.size == 1) && (args.first.kind_of?(Array))
|
44
|
+
add_invocation enumeration, MethodInvocation.new(method, path, action, line, model_instance, model, caller, args) if (path)
|
45
|
+
end
|
46
|
+
|
47
|
+
def controller_trace(regex = /_controller\.rb/)
|
48
|
+
controller_trace = caller.select {|c| c =~ regex }.last
|
49
|
+
if controller_trace
|
50
|
+
path,line,action = controller_trace.split(':')
|
51
|
+
action.gsub!(/[`']/, '').gsub!('in ', '')
|
52
|
+
line = line.to_i
|
53
|
+
[path,action,line]
|
54
|
+
else
|
55
|
+
[]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_invocation(enumeration, invocation)
|
60
|
+
# puts "adding invocation: #{invocation.inspect}"
|
61
|
+
invocations = (enumeration ||= [])
|
62
|
+
existing = invocations.find {|i|
|
63
|
+
i.controller_path == invocation.controller_path &&
|
64
|
+
i.controller_action == invocation.controller_action &&
|
65
|
+
i.line_number == invocation.line_number
|
66
|
+
}
|
67
|
+
invocations << invocation unless existing
|
68
|
+
invocations_audit << invocation
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Stratagem::ApplicationExtensions::Models; end
|
2
|
+
module Stratagem::ApplicationExtensions::Models::Adapters; end
|
3
|
+
|
4
|
+
require 'stratagem/framework_extensions/models/mocking'
|
5
|
+
require 'stratagem/framework_extensions/models/metadata'
|
6
|
+
require 'stratagem/framework_extensions/models/tracing'
|
7
|
+
require 'stratagem/framework_extensions/models/annotations'
|
8
|
+
require 'stratagem/framework_extensions/models/detect'
|
9
|
+
|
10
|
+
base = File.join(File.dirname(__FILE__), 'models', 'adapters', 'common')
|
11
|
+
Dir.entries(base).select {|s| s =~ /\.rb$/}.each {|helper|
|
12
|
+
require File.join(base, helper.gsub(/\.rb/, ''))
|
13
|
+
}
|
14
|
+
|
15
|
+
base = File.join(File.dirname(__FILE__), 'models', 'adapters')
|
16
|
+
Dir.entries(base).select {|s| s !~ /^\./ && s != 'common' }.each {|adapter_dir|
|
17
|
+
require File.join(base, adapter_dir, 'detect')
|
18
|
+
require File.join(base, adapter_dir, 'tracing')
|
19
|
+
require File.join(base, adapter_dir, 'metadata')
|
20
|
+
require File.join(base, adapter_dir, 'extensions')
|
21
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sinatra'
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
set :run, false
|
6
|
+
enable :sessions
|
7
|
+
disable :logging
|
8
|
+
# log = File.new("log/sinatra.log", "a")
|
9
|
+
# STDOUT.reopen(log)
|
10
|
+
# STDERR.reopen(log)
|
11
|
+
|
12
|
+
get '/' do
|
13
|
+
session[:instance_id] = Stratagem.session_id
|
14
|
+
Stratagem.analyze
|
15
|
+
haml :index
|
16
|
+
end
|
17
|
+
|
18
|
+
get '/credentials' do
|
19
|
+
Stratagem::Authentication.instance.store_credentials(params[:account], params[:api_key], params[:project])
|
20
|
+
redirect '/'
|
21
|
+
end
|
22
|
+
|
23
|
+
get '/logs' do
|
24
|
+
if (session[:instance_id] == Stratagem.session_id)
|
25
|
+
logger = Stratagem.logger
|
26
|
+
logs = [logger.pop]
|
27
|
+
logs << logger.pop until logger.empty?
|
28
|
+
logs.to_json
|
29
|
+
else
|
30
|
+
""
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
Thread.new do
|
36
|
+
Sinatra::Application.run!
|
37
|
+
end
|
Binary file
|
Binary file
|