appmap 0.34.5 → 0.37.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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +24 -0
- data/README.md +11 -8
- data/Rakefile +2 -1
- data/appmap.gemspec +2 -1
- data/appmap.yml +1 -7
- data/lib/appmap.rb +2 -2
- data/lib/appmap/class_map.rb +22 -9
- data/lib/appmap/config.rb +55 -25
- data/lib/appmap/event.rb +28 -10
- data/lib/appmap/hook.rb +9 -8
- data/lib/appmap/hook/method.rb +10 -6
- data/lib/appmap/rails/request_handler.rb +88 -0
- data/lib/appmap/rails/sql_handler.rb +10 -2
- data/lib/appmap/railtie.rb +4 -6
- data/lib/appmap/rspec.rb +11 -1
- data/lib/appmap/trace.rb +9 -7
- data/lib/appmap/version.rb +2 -2
- data/spec/abstract_controller4_base_spec.rb +1 -1
- data/spec/abstract_controller_base_spec.rb +6 -0
- data/spec/class_map_spec.rb +36 -0
- data/spec/fixtures/hook/exception_method.rb +44 -0
- data/spec/hook_spec.rb +145 -2
- data/test/cli_test.rb +0 -10
- data/test/expectations/openssl_test_key_sign1.json +55 -0
- data/test/expectations/openssl_test_key_sign2.json +58 -0
- data/test/fixtures/gem_test/Gemfile +6 -0
- data/test/fixtures/gem_test/appmap.yml +3 -0
- data/test/fixtures/gem_test/test/to_param_test.rb +14 -0
- data/test/gem_test.rb +34 -0
- data/test/minitest_test.rb +2 -2
- data/test/openssl_test.rb +10 -165
- metadata +30 -10
- data/.ruby-version +0 -1
- data/lib/appmap/rails/action_handler.rb +0 -91
data/lib/appmap/hook/method.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module AppMap
|
2
4
|
class Hook
|
3
5
|
class Method
|
4
|
-
attr_reader :hook_class, :hook_method
|
6
|
+
attr_reader :hook_package, :hook_class, :hook_method
|
5
7
|
|
6
8
|
# +method_display_name+ may be nil if name resolution gets
|
7
9
|
# deferred until runtime (e.g. for a singleton method on an
|
@@ -15,8 +17,9 @@ module AppMap
|
|
15
17
|
# with the method we're hooking.
|
16
18
|
TIME_NOW = Time.method(:now)
|
17
19
|
private_constant :TIME_NOW
|
18
|
-
|
19
|
-
def initialize(hook_class, hook_method)
|
20
|
+
|
21
|
+
def initialize(hook_package, hook_class, hook_method)
|
22
|
+
@hook_package = hook_package
|
20
23
|
@hook_class = hook_class
|
21
24
|
@hook_method = hook_method
|
22
25
|
|
@@ -67,23 +70,24 @@ module AppMap
|
|
67
70
|
raise
|
68
71
|
ensure
|
69
72
|
with_disabled_hook.() do
|
70
|
-
after_hook.(call_event, start_time, return_value, exception)
|
73
|
+
after_hook.(self, call_event, start_time, return_value, exception)
|
71
74
|
end
|
72
75
|
end
|
73
76
|
end
|
74
77
|
end
|
75
78
|
hook_class.define_method_with_arity(hook_method.name, hook_method.arity, hook_method_def)
|
76
79
|
end
|
80
|
+
|
77
81
|
protected
|
78
82
|
|
79
83
|
def before_hook(receiver, defined_class, args)
|
80
84
|
require 'appmap/event'
|
81
85
|
call_event = AppMap::Event::MethodCall.build_from_invocation(defined_class, hook_method, receiver, args)
|
82
|
-
AppMap.tracing.record_event call_event, defined_class: defined_class, method: hook_method
|
86
|
+
AppMap.tracing.record_event call_event, package: hook_package, defined_class: defined_class, method: hook_method
|
83
87
|
[ call_event, TIME_NOW.call ]
|
84
88
|
end
|
85
89
|
|
86
|
-
def after_hook(call_event, start_time, return_value, exception)
|
90
|
+
def after_hook(receiver, call_event, start_time, return_value, exception)
|
87
91
|
require 'appmap/event'
|
88
92
|
elapsed = TIME_NOW.call - start_time
|
89
93
|
return_event = \
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'appmap/event'
|
4
|
+
require 'appmap/hook'
|
5
|
+
|
6
|
+
module AppMap
|
7
|
+
module Rails
|
8
|
+
module RequestHandler
|
9
|
+
class HTTPServerRequest < AppMap::Event::MethodEvent
|
10
|
+
attr_accessor :request_method, :path_info, :params
|
11
|
+
|
12
|
+
def initialize(request)
|
13
|
+
super AppMap::Event.next_id_counter, :call, Thread.current.object_id
|
14
|
+
|
15
|
+
@request_method = request.request_method
|
16
|
+
@path_info = request.path_info.split('?')[0]
|
17
|
+
@params = ActionDispatch::Http::ParameterFilter.new(::Rails.application.config.filter_parameters).filter(request.params)
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_h
|
21
|
+
super.tap do |h|
|
22
|
+
h[:http_server_request] = {
|
23
|
+
request_method: request_method,
|
24
|
+
path_info: path_info
|
25
|
+
}
|
26
|
+
|
27
|
+
h[:message] = params.keys.map do |key|
|
28
|
+
val = params[key]
|
29
|
+
{
|
30
|
+
name: key,
|
31
|
+
class: val.class.name,
|
32
|
+
value: self.class.display_string(val),
|
33
|
+
object_id: val.__id__
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class HTTPServerResponse < AppMap::Event::MethodReturnIgnoreValue
|
41
|
+
attr_accessor :status, :mime_type
|
42
|
+
|
43
|
+
def initialize(response, parent_id, elapsed)
|
44
|
+
super AppMap::Event.next_id_counter, :return, Thread.current.object_id
|
45
|
+
|
46
|
+
self.status = response.status
|
47
|
+
self.mime_type = response.headers['Content-Type']
|
48
|
+
self.parent_id = parent_id
|
49
|
+
self.elapsed = elapsed
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_h
|
53
|
+
super.tap do |h|
|
54
|
+
h[:http_server_response] = {
|
55
|
+
status: status,
|
56
|
+
mime_type: mime_type
|
57
|
+
}.compact
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class HookMethod < AppMap::Hook::Method
|
63
|
+
def initialize
|
64
|
+
# ActionController::Instrumentation has issued start_processing.action_controller and
|
65
|
+
# process_action.action_controller since Rails 3. Therefore it's a stable place to hook
|
66
|
+
# the request. Rails controller notifications can't be used directly because they don't
|
67
|
+
# provide response headers, and we want the Content-Type.
|
68
|
+
super(nil, ActionController::Instrumentation, ActionController::Instrumentation.instance_method(:process_action))
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
|
73
|
+
def before_hook(receiver, defined_class, _) # args
|
74
|
+
call_event = HTTPServerRequest.new(receiver.request)
|
75
|
+
# http_server_request events are i/o and do not require a package name.
|
76
|
+
AppMap.tracing.record_event call_event, defined_class: defined_class, method: hook_method
|
77
|
+
[ call_event, TIME_NOW.call ]
|
78
|
+
end
|
79
|
+
|
80
|
+
def after_hook(receiver, call_event, start_time, _, _) # return_value, exception
|
81
|
+
elapsed = TIME_NOW.call - start_time
|
82
|
+
return_event = HTTPServerResponse.new receiver.response, call_event.id, elapsed
|
83
|
+
AppMap.tracing.record_event return_event
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -72,9 +72,17 @@ module AppMap
|
|
72
72
|
end
|
73
73
|
|
74
74
|
class ActiveRecordExaminer
|
75
|
+
@@db_version_warning_issued = {}
|
76
|
+
|
77
|
+
def issue_warning
|
78
|
+
db_type = database_type
|
79
|
+
return if @@db_version_warning_issued[db_type]
|
80
|
+
warn("AppMap: Unable to determine database version for #{db_type.inspect}")
|
81
|
+
@@db_version_warning_issued[db_type] = true
|
82
|
+
end
|
83
|
+
|
75
84
|
def server_version
|
76
|
-
ActiveRecord::Base.connection.try(:database_version)
|
77
|
-
warn("Unable to determine database version for #{database_type.inspect}")
|
85
|
+
ActiveRecord::Base.connection.try(:database_version) || issue_warning
|
78
86
|
end
|
79
87
|
|
80
88
|
def database_type
|
data/lib/appmap/railtie.rb
CHANGED
@@ -13,13 +13,11 @@ module AppMap
|
|
13
13
|
# AppMap events.
|
14
14
|
initializer 'appmap.subscribe', after: 'appmap.init' do |_| # params: app
|
15
15
|
require 'appmap/rails/sql_handler'
|
16
|
-
require 'appmap/rails/
|
16
|
+
require 'appmap/rails/request_handler'
|
17
17
|
ActiveSupport::Notifications.subscribe 'sql.sequel', AppMap::Rails::SQLHandler.new
|
18
18
|
ActiveSupport::Notifications.subscribe 'sql.active_record', AppMap::Rails::SQLHandler.new
|
19
|
-
|
20
|
-
|
21
|
-
ActiveSupport::Notifications.subscribe \
|
22
|
-
'process_action.action_controller', AppMap::Rails::ActionHandler::HTTPServerResponse.new
|
19
|
+
|
20
|
+
AppMap::Rails::RequestHandler::HookMethod.new.activate
|
23
21
|
end
|
24
22
|
|
25
23
|
# appmap.trace begins recording an AppMap trace and writes it to appmap.json.
|
@@ -42,4 +40,4 @@ module AppMap
|
|
42
40
|
end.call
|
43
41
|
end
|
44
42
|
end
|
45
|
-
end
|
43
|
+
end unless ENV['APPMAP_INITIALIZE'] == 'false'
|
data/lib/appmap/rspec.rb
CHANGED
@@ -124,8 +124,18 @@ module AppMap
|
|
124
124
|
def initialize(example)
|
125
125
|
super
|
126
126
|
|
127
|
+
webdriver_port = lambda do
|
128
|
+
return unless defined?(page) && page&.driver
|
129
|
+
|
130
|
+
# This is the ugliest thing ever but I don't want to lose it.
|
131
|
+
# All the WebDriver calls are getting app-mapped and it's really unclear
|
132
|
+
# what they are.
|
133
|
+
page.driver.options[:http_client].instance_variable_get('@server_url').port
|
134
|
+
end
|
135
|
+
|
127
136
|
warn "Starting recording of example #{example}" if AppMap::RSpec::LOG
|
128
137
|
@trace = AppMap.tracing.trace
|
138
|
+
@webdriver_port = webdriver_port.()
|
129
139
|
end
|
130
140
|
|
131
141
|
def finish
|
@@ -138,7 +148,7 @@ module AppMap
|
|
138
148
|
|
139
149
|
AppMap::RSpec.add_event_methods @trace.event_methods
|
140
150
|
|
141
|
-
class_map = AppMap.class_map(@trace.event_methods)
|
151
|
+
class_map = AppMap.class_map(@trace.event_methods, include_source: false)
|
142
152
|
|
143
153
|
description = []
|
144
154
|
scope = ScopeExample.new(example)
|
data/lib/appmap/trace.rb
CHANGED
@@ -3,9 +3,10 @@
|
|
3
3
|
module AppMap
|
4
4
|
module Trace
|
5
5
|
class ScopedMethod < SimpleDelegator
|
6
|
-
attr_reader :defined_class, :static
|
7
|
-
|
8
|
-
def initialize(defined_class, method, static)
|
6
|
+
attr_reader :package, :defined_class, :static
|
7
|
+
|
8
|
+
def initialize(package, defined_class, method, static)
|
9
|
+
@package = package
|
9
10
|
@defined_class = defined_class
|
10
11
|
@static = static
|
11
12
|
super(method)
|
@@ -32,9 +33,9 @@ module AppMap
|
|
32
33
|
@tracing.any?(&:enabled?)
|
33
34
|
end
|
34
35
|
|
35
|
-
def record_event(event, defined_class: nil, method: nil)
|
36
|
+
def record_event(event, package: nil, defined_class: nil, method: nil)
|
36
37
|
@tracing.each do |tracer|
|
37
|
-
tracer.record_event(event, defined_class: defined_class, method: method)
|
38
|
+
tracer.record_event(event, package: package, defined_class: defined_class, method: method)
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
@@ -71,11 +72,12 @@ module AppMap
|
|
71
72
|
# Record a program execution event.
|
72
73
|
#
|
73
74
|
# The event should be one of the MethodEvent subclasses.
|
74
|
-
def record_event(event, defined_class: nil, method: nil)
|
75
|
+
def record_event(event, package: nil, defined_class: nil, method: nil)
|
75
76
|
return unless @enabled
|
76
77
|
|
77
78
|
@events << event
|
78
|
-
@methods << Trace::ScopedMethod.new(defined_class, method, event.static)
|
79
|
+
@methods << Trace::ScopedMethod.new(package, defined_class, method, event.static) \
|
80
|
+
if package && defined_class && method && (event.event == :call)
|
79
81
|
end
|
80
82
|
|
81
83
|
# Gets a unique list of the methods that were invoked by the program.
|
data/lib/appmap/version.rb
CHANGED
@@ -39,7 +39,7 @@ describe 'AbstractControllerBase' do
|
|
39
39
|
expect(appmap).to include(<<-SERVER_REQUEST.strip)
|
40
40
|
http_server_request:
|
41
41
|
request_method: POST
|
42
|
-
path_info: "/api/users
|
42
|
+
path_info: "/api/users"
|
43
43
|
SERVER_REQUEST
|
44
44
|
end
|
45
45
|
it 'Properly captures method parameters in the appmap' do
|
@@ -45,6 +45,12 @@ describe 'AbstractControllerBase' do
|
|
45
45
|
request_method: POST
|
46
46
|
path_info: "/api/users"
|
47
47
|
SERVER_REQUEST
|
48
|
+
|
49
|
+
expect(appmap).to include(<<-SERVER_RESPONSE.strip)
|
50
|
+
http_server_response:
|
51
|
+
status: 201
|
52
|
+
mime_type: application/json; charset=utf-8
|
53
|
+
SERVER_RESPONSE
|
48
54
|
end
|
49
55
|
|
50
56
|
it 'properly captures method parameters in the appmap' do
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe 'AppMap::ClassMap' do
|
6
|
+
describe '.build_from_methods' do
|
7
|
+
it 'includes source code if available' do
|
8
|
+
map = AppMap.class_map([scoped_method(method(:test_method))])
|
9
|
+
function = dig_map(map, 5)[0]
|
10
|
+
expect(function[:source]).to include 'test method body'
|
11
|
+
expect(function[:comment]).to include 'test method comment'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'can omit source code even if available' do
|
15
|
+
map = AppMap.class_map([scoped_method((method :test_method))], include_source: false)
|
16
|
+
function = dig_map(map, 5)[0]
|
17
|
+
expect(function).to_not include(:source)
|
18
|
+
expect(function).to_not include(:comment)
|
19
|
+
end
|
20
|
+
|
21
|
+
# test method comment
|
22
|
+
def test_method
|
23
|
+
'test method body'
|
24
|
+
end
|
25
|
+
|
26
|
+
def scoped_method(method)
|
27
|
+
AppMap::Trace::ScopedMethod.new AppMap::Config::Package.new, method.receiver.class.name, method, false
|
28
|
+
end
|
29
|
+
|
30
|
+
def dig_map(map, depth)
|
31
|
+
return map if depth == 0
|
32
|
+
|
33
|
+
dig_map map[0][:children], depth - 1
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -9,3 +9,47 @@ class ExceptionMethod
|
|
9
9
|
raise 'Exception occurred in raise_exception'
|
10
10
|
end
|
11
11
|
end
|
12
|
+
|
13
|
+
# subclass from BasicObject so we don't get #to_s. Requires some
|
14
|
+
# hackery to implement the other methods normally provided by Object.
|
15
|
+
class NoToSMethod < BasicObject
|
16
|
+
def is_a?(*args)
|
17
|
+
return false
|
18
|
+
end
|
19
|
+
|
20
|
+
def class
|
21
|
+
return ::Class
|
22
|
+
end
|
23
|
+
|
24
|
+
def respond_to?(*args)
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
|
28
|
+
def inspect
|
29
|
+
"NoToSMethod"
|
30
|
+
end
|
31
|
+
|
32
|
+
def say_hello
|
33
|
+
"hello"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class InspectRaises < NoToSMethod
|
38
|
+
def inspect
|
39
|
+
::Kernel.raise "#to_s missing, #inspect raises"
|
40
|
+
end
|
41
|
+
|
42
|
+
def say_hello
|
43
|
+
"hello"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class ToSRaises
|
48
|
+
def to_s
|
49
|
+
raise "#to_s raises"
|
50
|
+
end
|
51
|
+
|
52
|
+
def say_hello
|
53
|
+
"hello"
|
54
|
+
end
|
55
|
+
end
|
data/spec/hook_spec.rb
CHANGED
@@ -27,7 +27,7 @@ describe 'AppMap class Hooking', docker: false do
|
|
27
27
|
|
28
28
|
def invoke_test_file(file, setup: nil, &block)
|
29
29
|
AppMap.configuration = nil
|
30
|
-
package = AppMap::Config::Package.
|
30
|
+
package = AppMap::Config::Package.build_from_path(file)
|
31
31
|
config = AppMap::Config.new('hook_spec', [ package ])
|
32
32
|
AppMap.configuration = config
|
33
33
|
tracer = nil
|
@@ -112,6 +112,10 @@ describe 'AppMap class Hooking', docker: false do
|
|
112
112
|
:type: function
|
113
113
|
:location: spec/fixtures/hook/instance_method.rb:8
|
114
114
|
:static: false
|
115
|
+
:source: |2
|
116
|
+
def say_default
|
117
|
+
'default'
|
118
|
+
end
|
115
119
|
YAML
|
116
120
|
end
|
117
121
|
|
@@ -465,6 +469,132 @@ describe 'AppMap class Hooking', docker: false do
|
|
465
469
|
end
|
466
470
|
end
|
467
471
|
|
472
|
+
context 'string conversions works for the receiver when' do
|
473
|
+
|
474
|
+
it 'is missing #to_s' do
|
475
|
+
events_yaml = <<~YAML
|
476
|
+
---
|
477
|
+
- :id: 1
|
478
|
+
:event: :call
|
479
|
+
:defined_class: NoToSMethod
|
480
|
+
:method_id: respond_to?
|
481
|
+
:path: spec/fixtures/hook/exception_method.rb
|
482
|
+
:lineno: 24
|
483
|
+
:static: false
|
484
|
+
:parameters:
|
485
|
+
- :name: :args
|
486
|
+
:class: Symbol
|
487
|
+
:value: to_s
|
488
|
+
:kind: :rest
|
489
|
+
:receiver:
|
490
|
+
:class: Class
|
491
|
+
:value: NoToSMethod
|
492
|
+
- :id: 2
|
493
|
+
:event: :return
|
494
|
+
:parent_id: 1
|
495
|
+
- :id: 3
|
496
|
+
:event: :call
|
497
|
+
:defined_class: NoToSMethod
|
498
|
+
:method_id: say_hello
|
499
|
+
:path: spec/fixtures/hook/exception_method.rb
|
500
|
+
:lineno: 32
|
501
|
+
:static: false
|
502
|
+
:parameters: []
|
503
|
+
:receiver:
|
504
|
+
:class: Class
|
505
|
+
:value: NoToSMethod
|
506
|
+
- :id: 4
|
507
|
+
:event: :return
|
508
|
+
:parent_id: 3
|
509
|
+
:return_value:
|
510
|
+
:class: String
|
511
|
+
:value: hello
|
512
|
+
YAML
|
513
|
+
|
514
|
+
test_hook_behavior 'spec/fixtures/hook/exception_method.rb', events_yaml do
|
515
|
+
inst = NoToSMethod.new
|
516
|
+
# sanity check
|
517
|
+
expect(inst).not_to respond_to(:to_s)
|
518
|
+
inst.say_hello
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
it 'it is missing #to_s and it raises an exception in #inspect' do
|
523
|
+
events_yaml = <<~YAML
|
524
|
+
---
|
525
|
+
- :id: 1
|
526
|
+
:event: :call
|
527
|
+
:defined_class: NoToSMethod
|
528
|
+
:method_id: respond_to?
|
529
|
+
:path: spec/fixtures/hook/exception_method.rb
|
530
|
+
:lineno: 24
|
531
|
+
:static: false
|
532
|
+
:parameters:
|
533
|
+
- :name: :args
|
534
|
+
:class: Symbol
|
535
|
+
:value: to_s
|
536
|
+
:kind: :rest
|
537
|
+
:receiver:
|
538
|
+
:class: Class
|
539
|
+
:value: "*Error inspecting variable*"
|
540
|
+
- :id: 2
|
541
|
+
:event: :return
|
542
|
+
:parent_id: 1
|
543
|
+
- :id: 3
|
544
|
+
:event: :call
|
545
|
+
:defined_class: InspectRaises
|
546
|
+
:method_id: say_hello
|
547
|
+
:path: spec/fixtures/hook/exception_method.rb
|
548
|
+
:lineno: 42
|
549
|
+
:static: false
|
550
|
+
:parameters: []
|
551
|
+
:receiver:
|
552
|
+
:class: Class
|
553
|
+
:value: "*Error inspecting variable*"
|
554
|
+
- :id: 4
|
555
|
+
:event: :return
|
556
|
+
:parent_id: 3
|
557
|
+
:return_value:
|
558
|
+
:class: String
|
559
|
+
:value: hello
|
560
|
+
YAML
|
561
|
+
|
562
|
+
test_hook_behavior 'spec/fixtures/hook/exception_method.rb', events_yaml do
|
563
|
+
inst = InspectRaises.new
|
564
|
+
# sanity check
|
565
|
+
expect(inst).not_to respond_to(:to_s)
|
566
|
+
inst.say_hello
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
it 'it raises an exception in #to_s' do
|
571
|
+
events_yaml = <<~YAML
|
572
|
+
---
|
573
|
+
- :id: 1
|
574
|
+
:event: :call
|
575
|
+
:defined_class: ToSRaises
|
576
|
+
:method_id: say_hello
|
577
|
+
:path: spec/fixtures/hook/exception_method.rb
|
578
|
+
:lineno: 52
|
579
|
+
:static: false
|
580
|
+
:parameters: []
|
581
|
+
:receiver:
|
582
|
+
:class: ToSRaises
|
583
|
+
:value: "*Error inspecting variable*"
|
584
|
+
- :id: 2
|
585
|
+
:event: :return
|
586
|
+
:parent_id: 1
|
587
|
+
:return_value:
|
588
|
+
:class: String
|
589
|
+
:value: hello
|
590
|
+
YAML
|
591
|
+
|
592
|
+
test_hook_behavior 'spec/fixtures/hook/exception_method.rb', events_yaml do
|
593
|
+
ToSRaises.new.say_hello
|
594
|
+
end
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
468
598
|
it 're-raises exceptions' do
|
469
599
|
RSpec::Expectations.configuration.on_potential_false_positives = :nothing
|
470
600
|
|
@@ -587,6 +717,10 @@ describe 'AppMap class Hooking', docker: false do
|
|
587
717
|
:type: function
|
588
718
|
:location: spec/fixtures/hook/compare.rb:4
|
589
719
|
:static: true
|
720
|
+
:source: |2
|
721
|
+
def self.compare(s1, s2)
|
722
|
+
ActiveSupport::SecurityUtils.secure_compare(s1, s2)
|
723
|
+
end
|
590
724
|
- :name: active_support
|
591
725
|
:type: package
|
592
726
|
:children:
|
@@ -603,6 +737,15 @@ describe 'AppMap class Hooking', docker: false do
|
|
603
737
|
:labels:
|
604
738
|
- security
|
605
739
|
- crypto
|
740
|
+
:comment: |
|
741
|
+
# Constant time string comparison, for variable length strings.
|
742
|
+
#
|
743
|
+
# The values are first processed by SHA256, so that we don't leak length info
|
744
|
+
# via timing attacks.
|
745
|
+
:source: |2
|
746
|
+
def secure_compare(a, b)
|
747
|
+
fixed_length_secure_compare(::Digest::SHA256.digest(a), ::Digest::SHA256.digest(b)) && a == b
|
748
|
+
end
|
606
749
|
- :name: openssl
|
607
750
|
:type: package
|
608
751
|
:children:
|
@@ -624,7 +767,7 @@ describe 'AppMap class Hooking', docker: false do
|
|
624
767
|
config, tracer = invoke_test_file 'spec/fixtures/hook/compare.rb' do
|
625
768
|
expect(Compare.compare('string', 'string')).to be_truthy
|
626
769
|
end
|
627
|
-
cm = AppMap::Util.sanitize_paths(AppMap::ClassMap.build_from_methods(
|
770
|
+
cm = AppMap::Util.sanitize_paths(AppMap::ClassMap.build_from_methods(tracer.event_methods))
|
628
771
|
entry = cm[1][:children][0][:children][0][:children][0]
|
629
772
|
# Sanity check, make sure we got the right one
|
630
773
|
expect(entry[:name]).to eq('secure_compare')
|