durable_decorator 0.1.0 → 0.1.1
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/README.md +17 -1
- data/durable_decorator.gemspec +0 -1
- data/lib/durable_decorator/base.rb +9 -8
- data/lib/durable_decorator/util.rb +9 -1
- data/lib/durable_decorator/validator.rb +12 -4
- data/lib/durable_decorator/version.rb +1 -1
- data/spec/durable_decorator_spec.rb +24 -12
- data/spec/spec_helper.rb +1 -0
- metadata +2 -2
data/README.md
CHANGED
|
@@ -64,7 +64,7 @@ DurableDecorator::Base.determine_sha('ExampleClass#no_param_method')
|
|
|
64
64
|
# => 'ba3114b2d46caa684b3f7ba38d6f74b2'
|
|
65
65
|
|
|
66
66
|
ExampleClass.class_eval do
|
|
67
|
-
durably_decorate :string_method, mode: 'strict', sha: '
|
|
67
|
+
durably_decorate :string_method, mode: 'strict', sha: 'WRONG-SHA-123456' do
|
|
68
68
|
string_method_original + " and new"
|
|
69
69
|
end
|
|
70
70
|
end
|
|
@@ -117,6 +117,22 @@ instance.string_method_ba3114b2d46caa684b3f7ba38d6f74b2
|
|
|
117
117
|
# => "original"
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
+
### Asking for history
|
|
121
|
+
|
|
122
|
+
You can inquire about the history of method [re]definitions like this:
|
|
123
|
+
```ruby
|
|
124
|
+
DurableDecorator::Base.definitions('ExampleClass#one_param_method')
|
|
125
|
+
# => [{:name=>:one_param_method, :sha=>"935888f04d9e132be458591d5755cb8131fec457", :body=>"def one_param_method param\n \"original: \#{param}\"\nend\n", :source=>["/home/denis/rails/durable_decorator/spec/example_class.rb", 6]}, {:name=>:one_param_method, :sha=>"3c39948e5e83c04fd4bf7a6ffab12c6828e0d959", :body=>"durably_decorate :one_param_method do |another_string|\n \"\#{one_param_method_935888f04d9e132be458591d5755cb8131fec457('check')} and \#{another_string}\"\nend\n", :source=>["/home/denis/rails/durable_decorator/spec/durable_decorator_spec.rb", 45]}]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
With any luck you can even get the specific [re]definition printed!
|
|
129
|
+
```ruby
|
|
130
|
+
puts DurableDecorator::Base.definitions('ExampleClass#one_param_method')[0][:body]
|
|
131
|
+
def one_param_method param
|
|
132
|
+
"original: #{param}"
|
|
133
|
+
end
|
|
134
|
+
```
|
|
135
|
+
|
|
120
136
|
### No more suprise monkey patching
|
|
121
137
|
Once you decorate the method and seal it with its SHA, if some gem tries to come in and overwrite your work **BEFORE** decorate-time, DurableDecorator will warn you. Similarly, expect to see an exception bubble up if the definition of the original method has changed and requires a review and a re-hash.
|
|
122
138
|
|
data/durable_decorator.gemspec
CHANGED
|
@@ -3,10 +3,10 @@ require 'digest/sha1'
|
|
|
3
3
|
module DurableDecorator
|
|
4
4
|
class Base
|
|
5
5
|
class << self
|
|
6
|
-
|
|
6
|
+
DEFINITIONS = {}
|
|
7
7
|
|
|
8
8
|
def reset!
|
|
9
|
-
|
|
9
|
+
DEFINITIONS.clear
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def redefine clazz, method_name, meta, &block
|
|
@@ -45,8 +45,8 @@ module DurableDecorator
|
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
def
|
|
49
|
-
|
|
48
|
+
def definitions
|
|
49
|
+
DEFINITIONS
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def alias_definitions clazz, method_name, old_sha
|
|
@@ -67,11 +67,12 @@ module DurableDecorator
|
|
|
67
67
|
|
|
68
68
|
|
|
69
69
|
def original_redefinition? clazz, method_name
|
|
70
|
-
|
|
70
|
+
defs = DEFINITIONS[Util.full_method_name(clazz, method_name)]
|
|
71
|
+
!defs || defs.empty?
|
|
71
72
|
end
|
|
72
73
|
|
|
73
74
|
def store_redefinition clazz, name, old_method, new_method
|
|
74
|
-
methods =
|
|
75
|
+
methods = (DEFINITIONS[Util.full_method_name(clazz, name)] ||= [])
|
|
75
76
|
|
|
76
77
|
to_store = [new_method]
|
|
77
78
|
to_store.unshift(old_method) if original_redefinition?(clazz, name)
|
|
@@ -86,7 +87,7 @@ module DurableDecorator
|
|
|
86
87
|
def redefined? clazz, method_name, &block
|
|
87
88
|
begin
|
|
88
89
|
result =
|
|
89
|
-
overrides =
|
|
90
|
+
overrides = DEFINITIONS[clazz][method_name] and
|
|
90
91
|
overrides.select{|o| o == Util.method_hash(method_name)}.first and
|
|
91
92
|
true
|
|
92
93
|
rescue
|
|
@@ -95,7 +96,7 @@ module DurableDecorator
|
|
|
95
96
|
end
|
|
96
97
|
|
|
97
98
|
def determine_sha target
|
|
98
|
-
raise "Please provide a fully qualified method name: Module::Clazz#instance_method or
|
|
99
|
+
raise "Please provide a fully qualified method name: Module::Clazz#instance_method or .clazz_method" unless target && target.match(/\.|#/)
|
|
99
100
|
|
|
100
101
|
class_name, separator, method_name = target.match(/(.*)(\.|#)(.*)/)[1..3]
|
|
101
102
|
clazz = Constantizer.constantize(class_name)
|
|
@@ -24,10 +24,18 @@ module DurableDecorator
|
|
|
24
24
|
def method_hash name, method
|
|
25
25
|
{
|
|
26
26
|
:name => name,
|
|
27
|
-
:sha => method_sha(method)
|
|
27
|
+
:sha => method_sha(method),
|
|
28
|
+
:body => outdented_method_body(method),
|
|
29
|
+
:source => method.source_location
|
|
28
30
|
}
|
|
29
31
|
end
|
|
30
32
|
|
|
33
|
+
def outdented_method_body method
|
|
34
|
+
body = method.source
|
|
35
|
+
indent = body.match(/^\W+/).to_s
|
|
36
|
+
body.lines.map{|l| l.sub(indent, '')}.join
|
|
37
|
+
end
|
|
38
|
+
|
|
31
39
|
def method_sha method
|
|
32
40
|
Digest::SHA1.hexdigest(method.source.gsub(/\s+/, ' '))
|
|
33
41
|
end
|
|
@@ -4,23 +4,31 @@ module DurableDecorator
|
|
|
4
4
|
DECORATION_MODES = ['strict', 'soft']
|
|
5
5
|
|
|
6
6
|
def validate_decoration_meta clazz, method_name, old_method, meta
|
|
7
|
-
|
|
7
|
+
expected_sha = Util.method_sha(old_method)
|
|
8
|
+
|
|
9
|
+
unless meta
|
|
10
|
+
log_sha_suggestion clazz, method_name, expected_sha
|
|
11
|
+
return
|
|
12
|
+
end
|
|
8
13
|
|
|
9
14
|
chill_meta = Util.symbolized_hash(meta)
|
|
10
15
|
provided_mode = chill_meta[:mode]
|
|
11
16
|
provided_sha = chill_meta[:sha]
|
|
12
|
-
expected_sha = Util.method_sha(old_method)
|
|
13
17
|
|
|
14
18
|
raise InvalidDecorationError, "The :mode provided is invalid. Possible modes are: #{DECORATION_MODES.join(", ")}" unless DECORATION_MODES.include? provided_mode
|
|
15
19
|
raise InvalidDecorationError, "The SHA provided appears to be empty" unless provided_sha and !provided_sha.empty?
|
|
16
20
|
send("handle_#{chill_meta[:mode]}_fault", clazz, method_name, expected_sha, provided_sha) unless expected_sha == provided_sha
|
|
17
21
|
end
|
|
18
22
|
|
|
19
|
-
def
|
|
23
|
+
def log_sha_suggestion clazz, method_name, expected_sha
|
|
24
|
+
Util.logger.warn "#{clazz}##{method_name} definition's SHA is currently: #{expected_sha}. Consider sealing it against tampering."
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def handle_strict_fault clazz, method_name, expected_sha, provided_sha
|
|
20
28
|
raise TamperedDefinitionError, "Method SHA mismatch, the definition has been tampered with. #{expected_sha} is expected but #{provided_sha} was provided."
|
|
21
29
|
end
|
|
22
30
|
|
|
23
|
-
def handle_soft_fault
|
|
31
|
+
def handle_soft_fault clazz, method_name, expected_sha, provided_sha
|
|
24
32
|
Util.logger.fatal "#{clazz}##{method_name} decoration uses an invalid SHA. The original method definition could have been tampered with!"
|
|
25
33
|
Util.logger.fatal "Expected SHA was #{expected_sha} but the provided SHA is #{provided_sha}"
|
|
26
34
|
end
|
|
@@ -74,6 +74,10 @@ describe DurableDecorator::Base do
|
|
|
74
74
|
instance.one_param_method_9358('').should == "original: "
|
|
75
75
|
instance.one_param_method_935888('').should == "original: "
|
|
76
76
|
end
|
|
77
|
+
|
|
78
|
+
it 'maintains history of decorations' do
|
|
79
|
+
DurableDecorator::Base.definitions['ExampleClass#one_param_method'].size.should == 2
|
|
80
|
+
end
|
|
77
81
|
end
|
|
78
82
|
|
|
79
83
|
context 'for strict definitions' do
|
|
@@ -146,19 +150,27 @@ describe DurableDecorator::Base do
|
|
|
146
150
|
|
|
147
151
|
context 'with the wrong SHA' do
|
|
148
152
|
it 'logs a warning but does not raise an error' do
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
153
|
+
ExampleClass.class_eval do
|
|
154
|
+
meta = {
|
|
155
|
+
:mode => 'soft',
|
|
156
|
+
:sha => '1234wrong'
|
|
157
|
+
}
|
|
158
|
+
durably_decorate :no_param_method, meta do
|
|
159
|
+
no_param_method_original + " and a new string"
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
@log_output.readline.should match(/invalid SHA/)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
context 'when lacking SHA' do
|
|
167
|
+
it 'prints the SHA suggestion' do
|
|
168
|
+
ExampleClass.class_eval do
|
|
169
|
+
durably_decorate :no_param_method do
|
|
170
|
+
no_param_method_original + " and a new string"
|
|
159
171
|
end
|
|
160
|
-
|
|
161
|
-
|
|
172
|
+
end
|
|
173
|
+
@log_output.readline.should match(/d54f9c7ea2038fac0ae2ff9af49c56f35761725d/)
|
|
162
174
|
end
|
|
163
175
|
end
|
|
164
176
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: durable_decorator
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2013-08-
|
|
12
|
+
date: 2013-08-16 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: method_source
|