tcell_agent 2.0.0 → 2.5.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/LICENSE +2 -2
- data/bin/tcell_agent +41 -150
- data/lib/tcell_agent/agent.rb +87 -52
- data/lib/tcell_agent/config_initializer.rb +63 -0
- data/lib/tcell_agent/configuration.rb +72 -267
- data/lib/tcell_agent/hooks/login_fraud.rb +1 -1
- data/lib/tcell_agent/instrument_servers.rb +14 -18
- data/lib/tcell_agent/instrumentation/cmdi.rb +47 -15
- data/lib/tcell_agent/instrumentation/lfi.rb +72 -15
- data/lib/tcell_agent/instrumentation/monkey_patches/ruby_2/file.rb +21 -0
- data/lib/tcell_agent/instrumentation/monkey_patches/ruby_2/io.rb +75 -0
- data/lib/tcell_agent/instrumentation/monkey_patches/ruby_2/kernel.rb +80 -0
- data/lib/tcell_agent/instrumentation/monkey_patches/ruby_3/file.rb +21 -0
- data/lib/tcell_agent/instrumentation/monkey_patches/ruby_3/io.rb +75 -0
- data/lib/tcell_agent/instrumentation/monkey_patches/ruby_3/kernel.rb +80 -0
- data/lib/tcell_agent/instrumentation.rb +14 -6
- data/lib/tcell_agent/logger.rb +3 -4
- data/lib/tcell_agent/policies/command_injection_policy.rb +1 -1
- data/lib/tcell_agent/policies/dataloss_policy.rb +15 -8
- data/lib/tcell_agent/policies/headers_policy.rb +2 -2
- data/lib/tcell_agent/policies/patches_policy.rb +8 -4
- data/lib/tcell_agent/policies/policies_manager.rb +1 -0
- data/lib/tcell_agent/policies/policy_polling.rb +4 -3
- data/lib/tcell_agent/rails/auth/authlogic.rb +49 -44
- data/lib/tcell_agent/rails/auth/authlogic_helper.rb +20 -0
- data/lib/tcell_agent/rails/auth/devise.rb +103 -102
- data/lib/tcell_agent/rails/auth/devise_helper.rb +29 -0
- data/lib/tcell_agent/rails/auth/doorkeeper.rb +54 -57
- data/lib/tcell_agent/{userinfo.rb → rails/auth/userinfo.rb} +0 -0
- data/lib/tcell_agent/rails/better_ip.rb +7 -19
- data/lib/tcell_agent/rails/csrf_exception.rb +0 -8
- data/lib/tcell_agent/rails/dlp/process_request.rb +5 -0
- data/lib/tcell_agent/rails/dlp.rb +58 -56
- data/lib/tcell_agent/rails/dlp_handler.rb +9 -10
- data/lib/tcell_agent/rails/js_agent_insert.rb +2 -3
- data/lib/tcell_agent/rails/middleware/context_middleware.rb +2 -1
- data/lib/tcell_agent/rails/middleware/global_middleware.rb +3 -4
- data/lib/tcell_agent/rails/middleware/headers_middleware.rb +1 -0
- data/lib/tcell_agent/rails/{on_start.rb → railties/tcell_agent_railties.rb} +9 -16
- data/lib/tcell_agent/rails/railties/tcell_agent_unicorn_railties.rb +8 -0
- data/lib/tcell_agent/rails/routes/grape.rb +5 -12
- data/lib/tcell_agent/rails/routes.rb +6 -9
- data/lib/tcell_agent/rails/settings_reporter.rb +3 -6
- data/lib/tcell_agent/rails/tcell_body_proxy.rb +4 -7
- data/lib/tcell_agent/routes/table.rb +3 -0
- data/lib/tcell_agent/rust/agent_config.rb +62 -33
- data/lib/tcell_agent/rust/{libtcellagent-4.14.0.so → libtcellagent-alpine.so} +0 -0
- data/lib/tcell_agent/rust/{libtcellagent-4.14.0.dylib → libtcellagent-x64.dll} +0 -0
- data/lib/tcell_agent/rust/{libtcellagent-alpine-4.14.0.so → libtcellagent.dylib} +0 -0
- data/lib/tcell_agent/rust/libtcellagent.so +0 -0
- data/lib/tcell_agent/rust/models.rb +9 -0
- data/lib/tcell_agent/rust/native_agent.rb +61 -51
- data/lib/tcell_agent/rust/native_library.rb +8 -10
- data/lib/tcell_agent/sensor_events/server_agent.rb +3 -100
- data/lib/tcell_agent/sensor_events/util/sanitizer_utilities.rb +1 -0
- data/lib/tcell_agent/servers/puma.rb +30 -13
- data/lib/tcell_agent/servers/rack_puma_handler.rb +33 -0
- data/lib/tcell_agent/servers/rails_server.rb +4 -4
- data/lib/tcell_agent/servers/unicorn.rb +1 -1
- data/lib/tcell_agent/servers/webrick.rb +12 -3
- data/lib/tcell_agent/settings_reporter.rb +0 -93
- data/lib/tcell_agent/sinatra.rb +1 -0
- data/lib/tcell_agent/tcell_context.rb +16 -7
- data/lib/tcell_agent/utils/headers.rb +0 -1
- data/lib/tcell_agent/utils/strings.rb +2 -2
- data/lib/tcell_agent/version.rb +1 -1
- data/lib/tcell_agent.rb +8 -16
- data/spec/cruby_spec_helper.rb +26 -0
- data/spec/lib/tcell_agent/configuration_spec.rb +62 -212
- data/spec/lib/tcell_agent/instrument_servers_spec.rb +95 -0
- data/spec/lib/tcell_agent/instrumentation/cmdi/io_cmdi_spec.rb +2 -2
- data/spec/lib/tcell_agent/{cmdi_spec.rb → instrumentation/cmdi_spec.rb} +50 -0
- data/spec/lib/tcell_agent/instrumentation/lfi/file_lfi_spec.rb +211 -272
- data/spec/lib/tcell_agent/instrumentation/lfi/io_lfi_spec.rb +213 -223
- data/spec/lib/tcell_agent/instrumentation/lfi/kernel_lfi_spec.rb +95 -61
- data/spec/lib/tcell_agent/instrumentation/lfi_spec.rb +120 -2
- data/spec/lib/tcell_agent/patches_spec.rb +2 -1
- data/spec/lib/tcell_agent/policies/clickjacking_policy_spec.rb +1 -2
- data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +5 -6
- data/spec/lib/tcell_agent/policies/patches_policy_spec.rb +21 -2
- data/spec/lib/tcell_agent/policies/policies_manager_spec.rb +1 -1
- data/spec/lib/tcell_agent/policies/secure_headers_policy_spec.rb +13 -8
- data/spec/lib/tcell_agent/rails/better_ip_spec.rb +9 -11
- data/spec/lib/tcell_agent/rails/csrf_exception_spec.rb +6 -6
- data/spec/lib/tcell_agent/rails/dlp_spec.rb +1 -0
- data/spec/lib/tcell_agent/rails/js_agent_insert_spec.rb +10 -2
- data/spec/lib/tcell_agent/rails/middleware/tcell_body_proxy_spec.rb +2 -1
- data/spec/lib/tcell_agent/rails/routes/route_id_spec.rb +4 -4
- data/spec/lib/tcell_agent/rust/agent_config_spec.rb +27 -0
- data/spec/lib/tcell_agent/settings_reporter_spec.rb +2 -89
- data/spec/lib/tcell_agent/tcell_context_spec.rb +6 -5
- data/spec/spec_helper.rb +9 -1
- data/spec/support/builders.rb +8 -7
- data/spec/support/server_mocks/passenger_mock.rb +7 -0
- data/spec/support/server_mocks/puma_mock.rb +21 -0
- data/spec/support/server_mocks/rails_mock.rb +7 -0
- data/spec/support/server_mocks/thin_mock.rb +7 -0
- data/spec/support/server_mocks/unicorn_mock.rb +11 -0
- data/spec/support/shared_spec.rb +29 -0
- data/tcell_agent.gemspec +14 -14
- metadata +46 -29
- data/Rakefile +0 -18
- data/lib/tcell_agent/authlogic.rb +0 -23
- data/lib/tcell_agent/config/unknown_options.rb +0 -119
- data/lib/tcell_agent/devise.rb +0 -33
- data/lib/tcell_agent/instrumentation/monkey_patches/file.rb +0 -25
- data/lib/tcell_agent/instrumentation/monkey_patches/io.rb +0 -123
- data/lib/tcell_agent/instrumentation/monkey_patches/kernel.rb +0 -159
- data/lib/tcell_agent/rails/start_agent_after_initializers.rb +0 -12
- data/lib/tcell_agent/rust/tcellagent-4.14.0.dll +0 -0
- data/spec/lib/tcell_agent/config/unknown_options_spec.rb +0 -195
data/lib/tcell_agent/sinatra.rb
CHANGED
|
@@ -16,6 +16,7 @@ module TCellAgent
|
|
|
16
16
|
TCellAgent::Instrumentation.safe_block('Setting Headers') do
|
|
17
17
|
headers_policy = TCellAgent.policy(TCellAgent::PolicyTypes::HEADERS)
|
|
18
18
|
policy_headers = headers_policy.get_headers(
|
|
19
|
+
headers['Content-Type'],
|
|
19
20
|
request.env[TCellAgent::Instrumentation::TCELL_ID]
|
|
20
21
|
)
|
|
21
22
|
policy_headers.each do |header_info|
|
|
@@ -40,10 +40,11 @@ module TCellAgent
|
|
|
40
40
|
tcell_context.request_method,
|
|
41
41
|
tcell_context.remote_address,
|
|
42
42
|
tcell_context.route_id,
|
|
43
|
-
tcell_context.
|
|
43
|
+
tcell_context.session_id,
|
|
44
44
|
tcell_context.user_id,
|
|
45
45
|
tcell_context.transaction_id,
|
|
46
|
-
tcell_context.uri
|
|
46
|
+
tcell_context.uri,
|
|
47
|
+
tcell_context.reverse_proxy_header_value
|
|
47
48
|
)
|
|
48
49
|
meta_data.path = tcell_context.path
|
|
49
50
|
|
|
@@ -70,7 +71,8 @@ module TCellAgent
|
|
|
70
71
|
:response_headers,
|
|
71
72
|
:csrf_exception_name,
|
|
72
73
|
:sql_exceptions,
|
|
73
|
-
:database_result_sizes
|
|
74
|
+
:database_result_sizes,
|
|
75
|
+
:reverse_proxy_header_value
|
|
74
76
|
|
|
75
77
|
attr_reader :flattened_get_dict,
|
|
76
78
|
:flattened_cookie_dict,
|
|
@@ -85,7 +87,8 @@ module TCellAgent
|
|
|
85
87
|
session_id,
|
|
86
88
|
user_id,
|
|
87
89
|
transaction_id,
|
|
88
|
-
location
|
|
90
|
+
location,
|
|
91
|
+
reverse_proxy_header_value)
|
|
89
92
|
@method = method
|
|
90
93
|
@remote_address = remote_address
|
|
91
94
|
@route_id = route_id
|
|
@@ -93,7 +96,7 @@ module TCellAgent
|
|
|
93
96
|
@user_id = user_id
|
|
94
97
|
@transaction_id = transaction_id
|
|
95
98
|
@location = location
|
|
96
|
-
@
|
|
99
|
+
@reverse_proxy_header_value = reverse_proxy_header_value
|
|
97
100
|
|
|
98
101
|
@flattened_get_dict = {}
|
|
99
102
|
@flattened_cookie_dict = {}
|
|
@@ -148,6 +151,7 @@ module TCellAgent
|
|
|
148
151
|
if !content_length.nil? && content_length > TCELL_MAX_BODY_LENGTH || request.content_type.nil?
|
|
149
152
|
return nil
|
|
150
153
|
end
|
|
154
|
+
|
|
151
155
|
raw_post_data = nil
|
|
152
156
|
# Positions strio to the beginning of input, resetting lineno to zero.
|
|
153
157
|
# rails 4.1 seems to read the stringIO directly and so body.gets is empty
|
|
@@ -171,10 +175,15 @@ module TCellAgent
|
|
|
171
175
|
self.get_dict = request.GET
|
|
172
176
|
self.cookie_dict = request.cookies
|
|
173
177
|
|
|
174
|
-
self.post_dict = if @content_type.start_with?('application/json', 'application/xml')
|
|
178
|
+
self.post_dict = if @content_type.start_with?('application/json', 'application/xml') ||
|
|
179
|
+
(@content_type.start_with?('multipart/form-data') && @request_content_bytes_len == 0)
|
|
175
180
|
{}
|
|
176
181
|
else
|
|
177
|
-
|
|
182
|
+
begin
|
|
183
|
+
request.POST
|
|
184
|
+
rescue EOFError
|
|
185
|
+
{}
|
|
186
|
+
end
|
|
178
187
|
end
|
|
179
188
|
|
|
180
189
|
self.headers_dict = request.env
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
module TCellAgent
|
|
2
2
|
module Utils
|
|
3
3
|
module Strings
|
|
4
|
-
BLANK_RE = /\A[[:space:]]*\z
|
|
4
|
+
BLANK_RE = /\A[[:space:]]*\z/.freeze
|
|
5
5
|
|
|
6
6
|
def self.blank?(str)
|
|
7
|
-
str.nil? || str.empty? || BLANK_RE === str
|
|
7
|
+
str.nil? || str.empty? || BLANK_RE === str
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def self.present?(str)
|
data/lib/tcell_agent/version.rb
CHANGED
data/lib/tcell_agent.rb
CHANGED
|
@@ -1,26 +1,18 @@
|
|
|
1
1
|
# See the file "LICENSE" for the full license governing this code.
|
|
2
|
-
|
|
3
|
-
require 'tcell_agent/logger'
|
|
4
|
-
require 'tcell_agent/utils/strings'
|
|
5
2
|
require 'tcell_agent/configuration'
|
|
6
3
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
require 'tcell_agent/
|
|
10
|
-
|
|
11
|
-
require 'tcell_agent/instrumentation'
|
|
4
|
+
unless TCellAgent.configuration.disable_all
|
|
5
|
+
require 'tcell_agent/logger'
|
|
6
|
+
require 'tcell_agent/utils/strings'
|
|
7
|
+
require 'tcell_agent/agent'
|
|
12
8
|
|
|
13
|
-
require 'tcell_agent/
|
|
9
|
+
require 'tcell_agent/sensor_events/util/sanitizer_utilities'
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
require 'tcell_agent/instrumentation/cmdi'
|
|
17
|
-
require 'tcell_agent/instrumentation/lfi'
|
|
18
|
-
require 'tcell_agent/instrumentation/monkey_patches/io'
|
|
19
|
-
require 'tcell_agent/instrumentation/monkey_patches/file'
|
|
20
|
-
require 'tcell_agent/instrumentation/monkey_patches/kernel'
|
|
11
|
+
require 'tcell_agent/instrumentation'
|
|
21
12
|
|
|
13
|
+
require 'tcell_agent/instrument_servers'
|
|
22
14
|
require 'tcell_agent/hooks/login_fraud'
|
|
23
|
-
require 'tcell_agent/rails/
|
|
15
|
+
require 'tcell_agent/rails/railties/tcell_agent_railties' if defined?(Rails)
|
|
24
16
|
# sinatra used to be supported, but dropped support due to no customers using it
|
|
25
17
|
# require 'tcell_agent/sinatra' if defined?(Sinatra)
|
|
26
18
|
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'tcell_agent'
|
|
2
|
+
|
|
3
|
+
TCellAgent.configuration.enabled = true
|
|
4
|
+
TCellAgent.configuration.instrument = true
|
|
5
|
+
TCellAgent.configuration.enable_intercept_requests = true
|
|
6
|
+
TCellAgent.configuration.disabled_instrumentation = []
|
|
7
|
+
TCellAgent.thread_agent.instrument_built_ins
|
|
8
|
+
|
|
9
|
+
# This monkey patch turns off blocking for LFI/CMDI when run in CRuby specs/
|
|
10
|
+
# test suite. The original method also depends on a Rails installation,
|
|
11
|
+
# which CRuby does not have installed.
|
|
12
|
+
module TCellAgent
|
|
13
|
+
module Instrumentation
|
|
14
|
+
module Lfi
|
|
15
|
+
def self.block_file_access?(_path, _mode)
|
|
16
|
+
false
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
module Cmdi
|
|
22
|
+
def self.block_command?(_cmd)
|
|
23
|
+
false
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -2,228 +2,78 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
module TCellAgent
|
|
4
4
|
describe Configuration do
|
|
5
|
-
describe '
|
|
6
|
-
context '
|
|
7
|
-
it 'should
|
|
8
|
-
|
|
5
|
+
describe 'should_instrument?' do
|
|
6
|
+
context 'with the agent disabled' do
|
|
7
|
+
it 'should return false' do
|
|
8
|
+
config = Configuration.new
|
|
9
|
+
config.enabled = false
|
|
9
10
|
|
|
10
|
-
expect(
|
|
11
|
-
File.join(Dir.getwd, 'tcell/logs/tcell_agent.log')
|
|
12
|
-
)
|
|
13
|
-
expect(configuration.config_filename).to eq(
|
|
14
|
-
File.join(Dir.getwd, 'config/tcell_agent.config')
|
|
15
|
-
)
|
|
11
|
+
expect(config.should_instrument?).to be_falsey
|
|
16
12
|
end
|
|
17
13
|
end
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
it 'should set config filename to default, cache file and log file are updated' do
|
|
40
|
-
old_tcell_agent_home = ENV['TCELL_AGENT_HOME']
|
|
41
|
-
old_tcell_agent_log_dir = ENV['TCELL_AGENT_LOG_DIR']
|
|
42
|
-
|
|
43
|
-
ENV['TCELL_AGENT_HOME'] = 'spec_tcell_home'
|
|
44
|
-
ENV['TCELL_AGENT_LOG_DIR'] = 'spec_tcell_log_dir'
|
|
45
|
-
|
|
46
|
-
configuration = Configuration.new
|
|
47
|
-
|
|
48
|
-
expect(configuration.log_filename).to eq(
|
|
49
|
-
'spec_tcell_log_dir/tcell_agent.log'
|
|
50
|
-
)
|
|
51
|
-
expect(configuration.config_filename).to eq(
|
|
52
|
-
File.join(Dir.getwd, 'config/tcell_agent.config')
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
ENV['TCELL_AGENT_HOME'] = old_tcell_agent_home
|
|
56
|
-
ENV['TCELL_AGENT_LOG_DIR'] = old_tcell_agent_log_dir
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
context 'TCELL_AGENT_HOME, TCELL_AGENT_LOG_DIR, and TCELL_AGENT_CONFIG defined ' do
|
|
61
|
-
it 'should update config filename, cache file, and log file' do
|
|
62
|
-
old_tcell_agent_home = ENV['TCELL_AGENT_HOME']
|
|
63
|
-
old_tcell_agent_log_dir = ENV['TCELL_AGENT_LOG_DIR']
|
|
64
|
-
old_config_filename = ENV['TCELL_AGENT_CONFIG']
|
|
65
|
-
|
|
66
|
-
ENV['TCELL_AGENT_HOME'] = 'spec_tcell_home'
|
|
67
|
-
ENV['TCELL_AGENT_LOG_DIR'] = 'spec_tcell_log_dir'
|
|
68
|
-
ENV['TCELL_AGENT_CONFIG'] = 'spec_config/tcell_agent.config'
|
|
69
|
-
|
|
70
|
-
configuration = Configuration.new
|
|
71
|
-
|
|
72
|
-
expect(configuration.log_filename).to eq(
|
|
73
|
-
'spec_tcell_log_dir/tcell_agent.log'
|
|
74
|
-
)
|
|
75
|
-
expect(configuration.config_filename).to eq(
|
|
76
|
-
'spec_config/tcell_agent.config'
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
ENV['TCELL_AGENT_HOME'] = old_tcell_agent_home
|
|
80
|
-
ENV['TCELL_AGENT_LOG_DIR'] = old_tcell_agent_log_dir
|
|
81
|
-
ENV['TCELL_AGENT_CONFIG'] = old_config_filename
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
describe '#data_exposure' do
|
|
87
|
-
context 'no data_exposure defined' do
|
|
88
|
-
it 'should set max_data_ex_db_records_per_request to default' do
|
|
89
|
-
no_data_ex = double(
|
|
90
|
-
'no_data_ex',
|
|
91
|
-
:read => {
|
|
92
|
-
:version => 1,
|
|
93
|
-
:applications => [
|
|
94
|
-
:app_id => 'app_id',
|
|
95
|
-
:name => 'test',
|
|
96
|
-
:api_key => 'api_key'
|
|
97
|
-
]
|
|
98
|
-
}.to_json
|
|
99
|
-
)
|
|
100
|
-
expect(File).to receive(:file?).with(
|
|
101
|
-
File.join(Dir.getwd, 'no_data_ex.config')
|
|
102
|
-
).and_return(true)
|
|
103
|
-
expect(File).to receive(:open).with(
|
|
104
|
-
File.join(Dir.getwd, 'no_data_ex.config')
|
|
105
|
-
).and_return(no_data_ex)
|
|
106
|
-
configuration = Configuration.new('no_data_ex.config')
|
|
107
|
-
|
|
108
|
-
expect(configuration.max_data_ex_db_records_per_request).to eq(1000)
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
context 'data_exposure is empty' do
|
|
113
|
-
it 'should set max_data_ex_db_records_per_request to default' do
|
|
114
|
-
no_data_ex = double(
|
|
115
|
-
'no_data_ex',
|
|
116
|
-
:read => {
|
|
117
|
-
:version => 1,
|
|
118
|
-
:applications => [
|
|
119
|
-
:app_id => 'app_id',
|
|
120
|
-
:name => 'test',
|
|
121
|
-
:api_key => 'api_key',
|
|
122
|
-
:data_exposure => {}
|
|
123
|
-
]
|
|
124
|
-
}.to_json
|
|
125
|
-
)
|
|
126
|
-
expect(File).to receive(:file?).with(
|
|
127
|
-
File.join(Dir.getwd, 'no_data_ex.config')
|
|
128
|
-
).and_return(true)
|
|
129
|
-
expect(File).to receive(:open).with(
|
|
130
|
-
File.join(Dir.getwd, 'no_data_ex.config')
|
|
131
|
-
).and_return(no_data_ex)
|
|
132
|
-
configuration = Configuration.new('no_data_ex.config')
|
|
133
|
-
|
|
134
|
-
expect(configuration.max_data_ex_db_records_per_request).to eq(1000)
|
|
14
|
+
context 'with the agent enabled' do
|
|
15
|
+
context 'with all instrumentation enabled' do
|
|
16
|
+
context 'with no parameters' do
|
|
17
|
+
it 'should return true' do
|
|
18
|
+
config = Configuration.new
|
|
19
|
+
config.enabled = true
|
|
20
|
+
config.instrument = true
|
|
21
|
+
|
|
22
|
+
expect(config.should_instrument?).to be_truthy
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
context 'with parameters' do
|
|
26
|
+
it 'should return true' do
|
|
27
|
+
config = Configuration.new
|
|
28
|
+
config.enabled = true
|
|
29
|
+
config.instrument = true
|
|
30
|
+
config.disabled_instrumentation = Set.new
|
|
31
|
+
|
|
32
|
+
expect(config.should_instrument?('devise')).to be_truthy
|
|
33
|
+
end
|
|
34
|
+
end
|
|
135
35
|
end
|
|
136
|
-
|
|
36
|
+
context 'with auth frameworks disabled' do
|
|
37
|
+
it 'should return false' do
|
|
38
|
+
config = Configuration.new
|
|
39
|
+
config.disabled_instrumentation = Set.new(%w[authlogic devise doorkeeper])
|
|
137
40
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
no_data_ex = double(
|
|
141
|
-
'no_data_ex',
|
|
142
|
-
:read => {
|
|
143
|
-
:version => 1,
|
|
144
|
-
:applications => [
|
|
145
|
-
:app_id => 'app_id',
|
|
146
|
-
:name => 'test',
|
|
147
|
-
:api_key => 'api_key',
|
|
148
|
-
:data_exposure => {
|
|
149
|
-
:max_data_ex_db_records_per_request => 5000
|
|
150
|
-
}
|
|
151
|
-
]
|
|
152
|
-
}.to_json
|
|
153
|
-
)
|
|
154
|
-
expect(File).to receive(:file?).with(
|
|
155
|
-
File.join(Dir.getwd, 'no_data_ex.config')
|
|
156
|
-
).and_return(true)
|
|
157
|
-
expect(File).to receive(:open).with(
|
|
158
|
-
File.join(Dir.getwd, 'no_data_ex.config')
|
|
159
|
-
).and_return(no_data_ex)
|
|
160
|
-
configuration = Configuration.new('no_data_ex.config')
|
|
161
|
-
|
|
162
|
-
expect(configuration.max_data_ex_db_records_per_request).to eq(5000)
|
|
41
|
+
expect(config.should_instrument?('devise')).to be_falsey
|
|
42
|
+
end
|
|
163
43
|
end
|
|
164
44
|
end
|
|
165
45
|
end
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
:applications => [
|
|
176
|
-
:app_id => 'app_id',
|
|
177
|
-
:api_key => 'api_key',
|
|
178
|
-
:allow_payloads => false
|
|
179
|
-
]
|
|
180
|
-
}.to_json
|
|
181
|
-
)
|
|
182
|
-
expect(File).to receive(:file?).with(
|
|
183
|
-
File.join(Dir.getwd, 'config/tcell_agent.config')
|
|
184
|
-
).and_return(true)
|
|
185
|
-
expect(File).to receive(:open).with(
|
|
186
|
-
File.join(Dir.getwd, 'config/tcell_agent.config')
|
|
187
|
-
).and_return(allow_payloads_enabled)
|
|
188
|
-
|
|
189
|
-
configuration = Configuration.new
|
|
190
|
-
|
|
191
|
-
expect(configuration.allow_payloads).to eq(false)
|
|
192
|
-
end
|
|
46
|
+
describe 'populate_configuration' do
|
|
47
|
+
context 'with a poor native_agent_config_response' do
|
|
48
|
+
it 'should not throw an error' do
|
|
49
|
+
native_agent_config_response = {}
|
|
50
|
+
|
|
51
|
+
config = Configuration.new
|
|
52
|
+
expect do
|
|
53
|
+
config.populate_configuration(native_agent_config_response)
|
|
54
|
+
end.not_to raise_error
|
|
193
55
|
end
|
|
194
56
|
end
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
File.join(Dir.getwd, 'config/tcell_agent.config')
|
|
216
|
-
).and_return(true)
|
|
217
|
-
expect(File).to receive(:open).with(
|
|
218
|
-
File.join(Dir.getwd, 'config/tcell_agent.config')
|
|
219
|
-
).and_return(allow_payloads_enabled)
|
|
220
|
-
|
|
221
|
-
configuration = Configuration.new
|
|
222
|
-
|
|
223
|
-
ENV['TCELL_AGENT_ALLOW_PAYLOADS'] = old_tcell_agent_allow_payloads
|
|
224
|
-
|
|
225
|
-
expect(configuration.allow_payloads).to eq(false)
|
|
226
|
-
end
|
|
57
|
+
context 'with an elaborate native_agent_config_response' do
|
|
58
|
+
it 'should set all the correct configurations' do
|
|
59
|
+
native_agent_config_response = { 'enabled' => true,
|
|
60
|
+
'disabled_instrumentation' => %w[devise doorkeeper],
|
|
61
|
+
'update_policy' => 'true',
|
|
62
|
+
'applications' => { 'first' => { 'app_id' => 'app_id_placeholder',
|
|
63
|
+
'api_key' => 'api_key_paceholder',
|
|
64
|
+
'hmac_key' => 'hmac_key_placeholder',
|
|
65
|
+
'password_hmac_key' => 'password_hmac_key_placeholder',
|
|
66
|
+
'proxy_config' => { 'reverse_proxy' => true,
|
|
67
|
+
'reverse_proxy_ip_address_header' => 'X-Forwarded-For' } } },
|
|
68
|
+
'endpoint_config' => { 'api_url' => 'https://us.agent.tcell.insight.rapid7.com/api/v1' },
|
|
69
|
+
'ruby_config' => { 'enable_policy_polling' => true } }
|
|
70
|
+
|
|
71
|
+
config = Configuration.new
|
|
72
|
+
config.populate_configuration(native_agent_config_response)
|
|
73
|
+
|
|
74
|
+
expect(config.disabled_instrumentation).to be_a(Set)
|
|
75
|
+
expect(config.disabled_instrumentation).to include('devise', 'doorkeeper')
|
|
76
|
+
expect(config.enable_intercept_requests).to be_truthy
|
|
227
77
|
end
|
|
228
78
|
end
|
|
229
79
|
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
def test_rails
|
|
4
|
+
expect(Rails::Server.instance_methods.include?(:tcell_build_app)).to be_truthy
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def test_thin
|
|
8
|
+
expect(Thin::Server.instance_methods.include?(:original_start)).to be_truthy
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def test_unicorn
|
|
12
|
+
expect(Unicorn::HttpServer::START_CTX[0]).to be_falsy
|
|
13
|
+
expect(Unicorn::HttpServer.instance_methods.include?(:tcell_init_worker_process)).to be_truthy
|
|
14
|
+
expect(Unicorn::HttpServer.instance_methods.include?(:tcell_load_config!)).to be_truthy
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_passenger
|
|
18
|
+
expect(PhusionPassenger::LoaderSharedHelpers.instance_methods.include?(:tcell_before_handling_requests))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_puma
|
|
22
|
+
expect(Puma.cli_config.options[:preload_app]).to be_falsey
|
|
23
|
+
expect(Puma::Server.instance_methods.include?(:tcell_original_run)).to be_truthy
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_server(filenames, funcs)
|
|
27
|
+
fork do
|
|
28
|
+
filenames.each do |file|
|
|
29
|
+
load file
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
load 'tcell_agent/instrument_servers.rb'
|
|
33
|
+
|
|
34
|
+
funcs.each do |func|
|
|
35
|
+
method(func).call
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe 'instrument_servers' do
|
|
41
|
+
context 'with single server dependency' do
|
|
42
|
+
context 'with webrick server' do
|
|
43
|
+
it 'should instrument Webrick' do
|
|
44
|
+
mocks = ['spec/support/server_mocks/rails_mock.rb']
|
|
45
|
+
tests = [:test_rails]
|
|
46
|
+
test_server(mocks, tests)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
context 'with Thin server' do
|
|
51
|
+
it 'should instrument Thin' do
|
|
52
|
+
mocks = ['spec/support/server_mocks/thin_mock.rb']
|
|
53
|
+
tests = [:test_thin]
|
|
54
|
+
test_server(mocks, tests)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
context 'with Puma server' do
|
|
59
|
+
it 'should instrument Puma' do
|
|
60
|
+
mocks = ['spec/support/server_mocks/puma_mock.rb']
|
|
61
|
+
tests = [:test_puma]
|
|
62
|
+
test_server(mocks, tests)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
context 'with Unicorn server' do
|
|
67
|
+
it 'should instrument Unicorn' do
|
|
68
|
+
mocks = ['spec/support/server_mocks/unicorn_mock.rb']
|
|
69
|
+
tests = [:test_unicorn]
|
|
70
|
+
test_server(mocks, tests)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
context 'with Passenger server' do
|
|
75
|
+
it 'should instrument Unicorn' do
|
|
76
|
+
mocks = ['spec/support/server_mocks/passenger_mock.rb']
|
|
77
|
+
tests = [:test_passenger]
|
|
78
|
+
test_server(mocks, tests)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
context 'with multiple server dependencies' do
|
|
83
|
+
it 'should instrument all servers available' do
|
|
84
|
+
mocks = ['spec/support/server_mocks/rails_mock.rb',
|
|
85
|
+
'spec/support/server_mocks/thin_mock.rb',
|
|
86
|
+
'spec/support/server_mocks/puma_mock.rb',
|
|
87
|
+
'spec/support/server_mocks/unicorn_mock.rb',
|
|
88
|
+
'spec/support/server_mocks/passenger_mock.rb']
|
|
89
|
+
|
|
90
|
+
tests = %i[test_rails test_thin test_puma test_unicorn test_passenger]
|
|
91
|
+
|
|
92
|
+
test_server(mocks, tests)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -262,10 +262,10 @@ describe IO do
|
|
|
262
262
|
IO.popen(@env, %w[echo test], 'w+', :unsetenv_others => true)
|
|
263
263
|
|
|
264
264
|
expect(TCellAgent::Cmdi).to receive(:block_command?).with('echo test')
|
|
265
|
-
IO.popen([@env, 'echo', 'test', :unsetenv_others => true], 'w+')
|
|
265
|
+
IO.popen([@env, 'echo', 'test', { :unsetenv_others => true }], 'w+')
|
|
266
266
|
|
|
267
267
|
expect(TCellAgent::Cmdi).to receive(:block_command?).with('echo test')
|
|
268
|
-
IO.popen(@env, [@env, 'echo', 'test', :unsetenv_others => true], 'w+', :err => %i[child out])
|
|
268
|
+
IO.popen(@env, [@env, 'echo', 'test', { :unsetenv_others => true }], 'w+', :err => %i[child out])
|
|
269
269
|
end
|
|
270
270
|
end
|
|
271
271
|
end
|
|
@@ -147,5 +147,55 @@ module TCellAgent
|
|
|
147
147
|
end
|
|
148
148
|
end
|
|
149
149
|
end
|
|
150
|
+
describe '.parse_command_from_open' do
|
|
151
|
+
context 'with empty parameters' do
|
|
152
|
+
it 'should not return a command' do
|
|
153
|
+
cmd = TCellAgent::Cmdi.parse_command_from_open
|
|
154
|
+
expect(cmd).to eq('')
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
context 'with empty array' do
|
|
158
|
+
it 'should not return a command' do
|
|
159
|
+
args = []
|
|
160
|
+
cmd = TCellAgent::Cmdi.parse_command_from_open(*args)
|
|
161
|
+
expect(cmd).to eq('')
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
context 'with a string command' do
|
|
165
|
+
context 'with an empty string' do
|
|
166
|
+
it 'should return an empty string' do
|
|
167
|
+
cmd = TCellAgent::Cmdi.parse_command_from_open('')
|
|
168
|
+
expect(cmd).to eq('')
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
context 'with an empty command' do
|
|
172
|
+
it 'should return an empty string' do
|
|
173
|
+
cmd = TCellAgent::Cmdi.parse_command_from_open('|')
|
|
174
|
+
expect(cmd).to eq('')
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
context 'with a non-empty command' do
|
|
178
|
+
it 'should parse the command properly' do
|
|
179
|
+
cmd = TCellAgent::Cmdi.parse_command_from_open('|echo')
|
|
180
|
+
expect(cmd).to eq('echo')
|
|
181
|
+
|
|
182
|
+
cmd = TCellAgent::Cmdi.parse_command_from_open('|ls -l /tmp')
|
|
183
|
+
expect(cmd).to eq('ls -l /tmp')
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
context 'with a filename argument' do
|
|
188
|
+
it 'should not return a command' do
|
|
189
|
+
cmd = TCellAgent::Cmdi.parse_command_from_open('/tmp')
|
|
190
|
+
expect(cmd).to eq('')
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
context 'with a non-string first argument' do
|
|
194
|
+
it 'should return an empty string' do
|
|
195
|
+
cmd = TCellAgent::Cmdi.parse_command_from_open({})
|
|
196
|
+
expect(cmd).to eq('')
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
150
200
|
end
|
|
151
201
|
end
|