appmap 0.33.0 → 0.34.5
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 +1 -1
- data/.rbenv-gemsets +1 -0
- data/CHANGELOG.md +27 -0
- data/README.md +17 -2
- data/Rakefile +10 -3
- data/appmap.gemspec +5 -0
- data/ext/appmap/appmap.c +95 -0
- data/ext/appmap/extconf.rb +6 -0
- data/lib/appmap.rb +3 -0
- data/lib/appmap/class_map.rb +11 -6
- data/lib/appmap/config.rb +51 -25
- data/lib/appmap/cucumber.rb +19 -2
- data/lib/appmap/hook.rb +44 -16
- data/lib/appmap/hook/method.rb +53 -25
- data/lib/appmap/rails/sql_handler.rb +5 -10
- data/lib/appmap/rspec.rb +1 -1
- data/lib/appmap/util.rb +18 -1
- data/lib/appmap/version.rb +1 -1
- data/spec/fixtures/hook/instance_method.rb +4 -0
- data/spec/fixtures/hook/singleton_method.rb +21 -12
- data/spec/hook_spec.rb +148 -13
- data/test/cli_test.rb +10 -0
- data/test/fixtures/openssl_recorder/Gemfile +3 -0
- data/test/fixtures/openssl_recorder/appmap.yml +3 -0
- data/test/fixtures/openssl_recorder/lib/openssl_cert_sign.rb +94 -0
- data/test/fixtures/openssl_recorder/lib/openssl_encrypt.rb +34 -0
- data/test/fixtures/openssl_recorder/lib/openssl_key_sign.rb +28 -0
- data/test/openssl_test.rb +203 -0
- metadata +55 -3
data/test/cli_test.rb
CHANGED
@@ -56,10 +56,12 @@ class CLITest < Minitest::Test
|
|
56
56
|
Class frequency:
|
57
57
|
----------------
|
58
58
|
1 Main
|
59
|
+
1 IO
|
59
60
|
|
60
61
|
Method frequency:
|
61
62
|
----------------
|
62
63
|
1 Main.say_hello
|
64
|
+
1 IO#write
|
63
65
|
OUTPUT
|
64
66
|
end
|
65
67
|
|
@@ -80,12 +82,20 @@ class CLITest < Minitest::Test
|
|
80
82
|
{
|
81
83
|
"name": "Main",
|
82
84
|
"count": 1
|
85
|
+
},
|
86
|
+
{
|
87
|
+
"name": "IO",
|
88
|
+
"count": 1
|
83
89
|
}
|
84
90
|
],
|
85
91
|
"method_frequency": [
|
86
92
|
{
|
87
93
|
"name": "Main.say_hello",
|
88
94
|
"count": 1
|
95
|
+
},
|
96
|
+
{
|
97
|
+
"name": "IO#write",
|
98
|
+
"count": 1
|
89
99
|
}
|
90
100
|
]
|
91
101
|
}
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# From the manual page https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL.html
|
4
|
+
|
5
|
+
require 'openssl'
|
6
|
+
|
7
|
+
module Example
|
8
|
+
def Example.sign
|
9
|
+
ca_key = OpenSSL::PKey::RSA.new 2048
|
10
|
+
pass_phrase = 'my secure pass phrase goes here'
|
11
|
+
|
12
|
+
cipher = OpenSSL::Cipher.new 'AES-256-CBC'
|
13
|
+
|
14
|
+
open 'tmp/ca_key.pem', 'w', 0644 do |io|
|
15
|
+
io.write ca_key.export(cipher, pass_phrase)
|
16
|
+
end
|
17
|
+
|
18
|
+
ca_name = OpenSSL::X509::Name.parse '/CN=ca/DC=example'
|
19
|
+
|
20
|
+
ca_cert = OpenSSL::X509::Certificate.new
|
21
|
+
ca_cert.serial = 0
|
22
|
+
ca_cert.version = 2
|
23
|
+
ca_cert.not_before = Time.now
|
24
|
+
ca_cert.not_after = Time.now + 86400
|
25
|
+
|
26
|
+
ca_cert.public_key = ca_key.public_key
|
27
|
+
ca_cert.subject = ca_name
|
28
|
+
ca_cert.issuer = ca_name
|
29
|
+
|
30
|
+
extension_factory = OpenSSL::X509::ExtensionFactory.new
|
31
|
+
extension_factory.subject_certificate = ca_cert
|
32
|
+
extension_factory.issuer_certificate = ca_cert
|
33
|
+
|
34
|
+
ca_cert.add_extension extension_factory.create_extension('subjectKeyIdentifier', 'hash')
|
35
|
+
ca_cert.add_extension extension_factory.create_extension('basicConstraints', 'CA:TRUE', true)
|
36
|
+
|
37
|
+
ca_cert.add_extension extension_factory.create_extension(
|
38
|
+
'keyUsage', 'cRLSign,keyCertSign', true)
|
39
|
+
|
40
|
+
ca_cert.sign ca_key, OpenSSL::Digest::SHA1.new
|
41
|
+
|
42
|
+
open 'tmp/ca_cert.pem', 'w' do |io|
|
43
|
+
io.write ca_cert.to_pem
|
44
|
+
end
|
45
|
+
|
46
|
+
csr = OpenSSL::X509::Request.new
|
47
|
+
csr.version = 0
|
48
|
+
csr.subject = OpenSSL::X509::Name.new([ ['CN', 'the name to sign', OpenSSL::ASN1::UTF8STRING] ])
|
49
|
+
csr.public_key = ca_key.public_key
|
50
|
+
csr.sign ca_key, OpenSSL::Digest::SHA1.new
|
51
|
+
|
52
|
+
open 'tmp/csr.pem', 'w' do |io|
|
53
|
+
io.write csr.to_pem
|
54
|
+
end
|
55
|
+
|
56
|
+
csr = OpenSSL::X509::Request.new File.read 'tmp/csr.pem'
|
57
|
+
|
58
|
+
raise 'CSR can not be verified' unless csr.verify csr.public_key
|
59
|
+
|
60
|
+
csr_cert = OpenSSL::X509::Certificate.new
|
61
|
+
csr_cert.serial = 0
|
62
|
+
csr_cert.version = 2
|
63
|
+
csr_cert.not_before = Time.now
|
64
|
+
csr_cert.not_after = Time.now + 600
|
65
|
+
|
66
|
+
csr_cert.subject = csr.subject
|
67
|
+
csr_cert.public_key = csr.public_key
|
68
|
+
csr_cert.issuer = ca_cert.subject
|
69
|
+
|
70
|
+
extension_factory = OpenSSL::X509::ExtensionFactory.new
|
71
|
+
extension_factory.subject_certificate = csr_cert
|
72
|
+
extension_factory.issuer_certificate = ca_cert
|
73
|
+
|
74
|
+
csr_cert.add_extension extension_factory.create_extension('basicConstraints', 'CA:FALSE')
|
75
|
+
|
76
|
+
csr_cert.add_extension extension_factory.create_extension(
|
77
|
+
'keyUsage', 'keyEncipherment,dataEncipherment,digitalSignature')
|
78
|
+
|
79
|
+
csr_cert.add_extension extension_factory.create_extension('subjectKeyIdentifier', 'hash')
|
80
|
+
|
81
|
+
csr_cert.sign ca_key, OpenSSL::Digest::SHA1.new
|
82
|
+
|
83
|
+
'tmp/csr_cert.pem'.tap do |fname|
|
84
|
+
open fname, 'w' do |io|
|
85
|
+
io.write csr_cert.to_pem
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
if __FILE__ == $0
|
92
|
+
cert_file = Example.sign
|
93
|
+
puts "Wrote cert file #{cert_file}"
|
94
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# From the manual page https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL.html
|
4
|
+
|
5
|
+
require 'openssl'
|
6
|
+
|
7
|
+
module Example
|
8
|
+
def Example.encrypt
|
9
|
+
cipher = OpenSSL::Cipher.new 'AES-256-CBC'
|
10
|
+
cipher.encrypt
|
11
|
+
iv = cipher.random_iv
|
12
|
+
|
13
|
+
pwd = 'some hopefully not to easily guessable password'
|
14
|
+
salt = OpenSSL::Random.random_bytes 16
|
15
|
+
iter = 20000
|
16
|
+
key_len = cipher.key_len
|
17
|
+
digest = OpenSSL::Digest::SHA256.new
|
18
|
+
|
19
|
+
key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest)
|
20
|
+
cipher.key = key
|
21
|
+
|
22
|
+
document = 'the document'
|
23
|
+
|
24
|
+
encrypted = cipher.update document
|
25
|
+
encrypted << cipher.final
|
26
|
+
encrypted
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if __FILE__ == $0
|
31
|
+
ciphertext = Example.encrypt
|
32
|
+
require 'base64'
|
33
|
+
puts "Computed ciphertext #{Base64.urlsafe_encode64(ciphertext)}"
|
34
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# From the manual page https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL.html
|
4
|
+
|
5
|
+
require 'appmap'
|
6
|
+
require 'openssl'
|
7
|
+
require 'openssl/digest'
|
8
|
+
|
9
|
+
module Example
|
10
|
+
def Example.sign
|
11
|
+
key = OpenSSL::PKey::RSA.new 2048
|
12
|
+
|
13
|
+
document = 'the document'
|
14
|
+
|
15
|
+
digest = OpenSSL::Digest::SHA256.new
|
16
|
+
key.sign digest, document
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
if __FILE__ == $0
|
21
|
+
appmap = AppMap.record do
|
22
|
+
Example.sign
|
23
|
+
puts 'Computed signature'
|
24
|
+
end
|
25
|
+
appmap['metadata'] = [ 'recorder' => __FILE__ ]
|
26
|
+
|
27
|
+
File.write('appmap.json', JSON.generate(appmap))
|
28
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'test_helper'
|
5
|
+
require 'English'
|
6
|
+
|
7
|
+
class OpenSSLTest < Minitest::Test
|
8
|
+
def perform_test(test_name)
|
9
|
+
Bundler.with_clean_env do
|
10
|
+
Dir.chdir 'test/fixtures/openssl_recorder' do
|
11
|
+
FileUtils.rm_rf 'tmp'
|
12
|
+
system 'bundle config --local local.appmap ../../..'
|
13
|
+
system 'bundle'
|
14
|
+
system({ 'APPMAP' => 'true', 'DEBUG' => 'true' }, %(bundle exec ruby lib/openssl_#{test_name}.rb))
|
15
|
+
|
16
|
+
yield
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_key_sign
|
22
|
+
perform_test 'key_sign' do
|
23
|
+
appmap_file = 'appmap.json'
|
24
|
+
|
25
|
+
assert File.file?(appmap_file), 'appmap output file does not exist'
|
26
|
+
appmap = JSON.parse(File.read(appmap_file))
|
27
|
+
assert_equal AppMap::APPMAP_FORMAT_VERSION, appmap['version']
|
28
|
+
assert_equal [ { 'recorder' => 'lib/openssl_key_sign.rb' } ], appmap['metadata']
|
29
|
+
assert_equal JSON.parse(<<~JSON), appmap['classMap']
|
30
|
+
[
|
31
|
+
{
|
32
|
+
"name": "lib",
|
33
|
+
"type": "package",
|
34
|
+
"children": [
|
35
|
+
{
|
36
|
+
"name": "Example",
|
37
|
+
"type": "class",
|
38
|
+
"children": [
|
39
|
+
{
|
40
|
+
"name": "sign",
|
41
|
+
"type": "function",
|
42
|
+
"location": "lib/openssl_key_sign.rb:10",
|
43
|
+
"static": true
|
44
|
+
}
|
45
|
+
]
|
46
|
+
}
|
47
|
+
]
|
48
|
+
},
|
49
|
+
{
|
50
|
+
"name": "openssl",
|
51
|
+
"type": "package",
|
52
|
+
"children": [
|
53
|
+
{
|
54
|
+
"name": "OpenSSL",
|
55
|
+
"type": "class",
|
56
|
+
"children": [
|
57
|
+
{
|
58
|
+
"name": "PKey",
|
59
|
+
"type": "class",
|
60
|
+
"children": [
|
61
|
+
{
|
62
|
+
"name": "PKey",
|
63
|
+
"type": "class",
|
64
|
+
"children": [
|
65
|
+
{
|
66
|
+
"name": "sign",
|
67
|
+
"type": "function",
|
68
|
+
"location": "OpenSSL::PKey::PKey#sign",
|
69
|
+
"static": false,
|
70
|
+
"labels": [
|
71
|
+
"security",
|
72
|
+
"crypto"
|
73
|
+
]
|
74
|
+
}
|
75
|
+
]
|
76
|
+
}
|
77
|
+
]
|
78
|
+
}
|
79
|
+
]
|
80
|
+
}
|
81
|
+
]
|
82
|
+
},
|
83
|
+
{
|
84
|
+
"name": "io",
|
85
|
+
"type": "package",
|
86
|
+
"children": [
|
87
|
+
{
|
88
|
+
"name": "IO",
|
89
|
+
"type": "class",
|
90
|
+
"children": [
|
91
|
+
{
|
92
|
+
"name": "write",
|
93
|
+
"type": "function",
|
94
|
+
"location": "IO#write",
|
95
|
+
"static": false,
|
96
|
+
"labels": [
|
97
|
+
"io"
|
98
|
+
]
|
99
|
+
}
|
100
|
+
]
|
101
|
+
}
|
102
|
+
]
|
103
|
+
}
|
104
|
+
]
|
105
|
+
JSON
|
106
|
+
sanitized_events = appmap['events'].map(&:deep_symbolize_keys).map(&AppMap::Util.method(:sanitize_event)).map do |event|
|
107
|
+
delete_value = ->(obj) { (obj || {}).delete(:value) }
|
108
|
+
delete_value.call(event[:receiver])
|
109
|
+
delete_value.call(event[:return_value])
|
110
|
+
event
|
111
|
+
end
|
112
|
+
|
113
|
+
diff = Diffy::Diff.new(<<~JSON.strip, JSON.pretty_generate(sanitized_events).strip)
|
114
|
+
[
|
115
|
+
{
|
116
|
+
"id": 1,
|
117
|
+
"event": "call",
|
118
|
+
"defined_class": "Example",
|
119
|
+
"method_id": "sign",
|
120
|
+
"path": "lib/openssl_key_sign.rb",
|
121
|
+
"lineno": 10,
|
122
|
+
"static": true,
|
123
|
+
"parameters": [
|
124
|
+
|
125
|
+
],
|
126
|
+
"receiver": {
|
127
|
+
"class": "Module"
|
128
|
+
}
|
129
|
+
},
|
130
|
+
{
|
131
|
+
"id": 2,
|
132
|
+
"event": "call",
|
133
|
+
"defined_class": "OpenSSL::PKey::PKey",
|
134
|
+
"method_id": "sign",
|
135
|
+
"path": "OpenSSL::PKey::PKey#sign",
|
136
|
+
"static": false,
|
137
|
+
"parameters": [
|
138
|
+
{
|
139
|
+
"name": "arg",
|
140
|
+
"class": "OpenSSL::Digest::SHA256",
|
141
|
+
"value": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
142
|
+
"kind": "req"
|
143
|
+
},
|
144
|
+
{
|
145
|
+
"name": "arg",
|
146
|
+
"class": "String",
|
147
|
+
"value": "the document",
|
148
|
+
"kind": "req"
|
149
|
+
}
|
150
|
+
],
|
151
|
+
"receiver": {
|
152
|
+
"class": "OpenSSL::PKey::RSA"
|
153
|
+
}
|
154
|
+
},
|
155
|
+
{
|
156
|
+
"id": 3,
|
157
|
+
"event": "return",
|
158
|
+
"parent_id": 2,
|
159
|
+
"return_value": {
|
160
|
+
"class": "String"
|
161
|
+
}
|
162
|
+
},
|
163
|
+
{
|
164
|
+
"id": 4,
|
165
|
+
"event": "return",
|
166
|
+
"parent_id": 1,
|
167
|
+
"return_value": {
|
168
|
+
"class": "String"
|
169
|
+
}
|
170
|
+
},
|
171
|
+
{
|
172
|
+
"id": 5,
|
173
|
+
"event": "call",
|
174
|
+
"defined_class": "IO",
|
175
|
+
"method_id": "write",
|
176
|
+
"path": "IO#write",
|
177
|
+
"static": false,
|
178
|
+
"parameters": [
|
179
|
+
{
|
180
|
+
"name": "arg",
|
181
|
+
"class": "String",
|
182
|
+
"value": "Computed signature",
|
183
|
+
"kind": "rest"
|
184
|
+
}
|
185
|
+
],
|
186
|
+
"receiver": {
|
187
|
+
"class": "IO"
|
188
|
+
}
|
189
|
+
},
|
190
|
+
{
|
191
|
+
"id": 6,
|
192
|
+
"event": "return",
|
193
|
+
"parent_id": 5,
|
194
|
+
"return_value": {
|
195
|
+
"class": "Integer"
|
196
|
+
}
|
197
|
+
}
|
198
|
+
]
|
199
|
+
JSON
|
200
|
+
assert_equal '', diff.to_s
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: appmap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.34.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Gilpin
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -164,6 +164,20 @@ dependencies:
|
|
164
164
|
- - ">="
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: rake-compiler
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
167
181
|
- !ruby/object:Gem::Dependency
|
168
182
|
name: climate_control
|
169
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -248,16 +262,46 @@ dependencies:
|
|
248
262
|
- - "~>"
|
249
263
|
- !ruby/object:Gem::Version
|
250
264
|
version: '4.0'
|
265
|
+
- !ruby/object:Gem::Dependency
|
266
|
+
name: timecop
|
267
|
+
requirement: !ruby/object:Gem::Requirement
|
268
|
+
requirements:
|
269
|
+
- - ">="
|
270
|
+
- !ruby/object:Gem::Version
|
271
|
+
version: '0'
|
272
|
+
type: :development
|
273
|
+
prerelease: false
|
274
|
+
version_requirements: !ruby/object:Gem::Requirement
|
275
|
+
requirements:
|
276
|
+
- - ">="
|
277
|
+
- !ruby/object:Gem::Version
|
278
|
+
version: '0'
|
279
|
+
- !ruby/object:Gem::Dependency
|
280
|
+
name: hashie
|
281
|
+
requirement: !ruby/object:Gem::Requirement
|
282
|
+
requirements:
|
283
|
+
- - ">="
|
284
|
+
- !ruby/object:Gem::Version
|
285
|
+
version: '0'
|
286
|
+
type: :development
|
287
|
+
prerelease: false
|
288
|
+
version_requirements: !ruby/object:Gem::Requirement
|
289
|
+
requirements:
|
290
|
+
- - ">="
|
291
|
+
- !ruby/object:Gem::Version
|
292
|
+
version: '0'
|
251
293
|
description:
|
252
294
|
email:
|
253
295
|
- kgilpin@gmail.com
|
254
296
|
executables:
|
255
297
|
- appmap
|
256
|
-
extensions:
|
298
|
+
extensions:
|
299
|
+
- ext/appmap/extconf.rb
|
257
300
|
extra_rdoc_files: []
|
258
301
|
files:
|
259
302
|
- ".dockerignore"
|
260
303
|
- ".gitignore"
|
304
|
+
- ".rbenv-gemsets"
|
261
305
|
- ".rubocop.yml"
|
262
306
|
- ".ruby-version"
|
263
307
|
- ".travis.yml"
|
@@ -277,6 +321,8 @@ files:
|
|
277
321
|
- examples/mock_webapp/lib/mock_webapp/request.rb
|
278
322
|
- examples/mock_webapp/lib/mock_webapp/user.rb
|
279
323
|
- exe/appmap
|
324
|
+
- ext/appmap/appmap.c
|
325
|
+
- ext/appmap/extconf.rb
|
280
326
|
- lib/appmap.rb
|
281
327
|
- lib/appmap/algorithm/prune_class_map.rb
|
282
328
|
- lib/appmap/algorithm/stats.rb
|
@@ -503,6 +549,11 @@ files:
|
|
503
549
|
- test/fixtures/minitest_recorder/appmap.yml
|
504
550
|
- test/fixtures/minitest_recorder/lib/hello.rb
|
505
551
|
- test/fixtures/minitest_recorder/test/hello_test.rb
|
552
|
+
- test/fixtures/openssl_recorder/Gemfile
|
553
|
+
- test/fixtures/openssl_recorder/appmap.yml
|
554
|
+
- test/fixtures/openssl_recorder/lib/openssl_cert_sign.rb
|
555
|
+
- test/fixtures/openssl_recorder/lib/openssl_encrypt.rb
|
556
|
+
- test/fixtures/openssl_recorder/lib/openssl_key_sign.rb
|
506
557
|
- test/fixtures/process_recorder/appmap.yml
|
507
558
|
- test/fixtures/process_recorder/hello.rb
|
508
559
|
- test/fixtures/rspec_recorder/Gemfile
|
@@ -512,6 +563,7 @@ files:
|
|
512
563
|
- test/fixtures/rspec_recorder/spec/labeled_hello_spec.rb
|
513
564
|
- test/fixtures/rspec_recorder/spec/plain_hello_spec.rb
|
514
565
|
- test/minitest_test.rb
|
566
|
+
- test/openssl_test.rb
|
515
567
|
- test/record_process_test.rb
|
516
568
|
- test/rspec_test.rb
|
517
569
|
- test/test_helper.rb
|