tcell_agent 2.0.0 → 2.2.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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/bin/tcell_agent +42 -146
  3. data/lib/tcell_agent.rb +8 -16
  4. data/lib/tcell_agent/agent.rb +76 -46
  5. data/lib/tcell_agent/config_initializer.rb +66 -0
  6. data/lib/tcell_agent/configuration.rb +72 -267
  7. data/lib/tcell_agent/instrument_servers.rb +14 -18
  8. data/lib/tcell_agent/instrumentation/cmdi.rb +15 -15
  9. data/lib/tcell_agent/instrumentation/lfi.rb +21 -10
  10. data/lib/tcell_agent/instrumentation/monkey_patches/io.rb +20 -12
  11. data/lib/tcell_agent/instrumentation/monkey_patches/kernel.rb +45 -102
  12. data/lib/tcell_agent/logger.rb +1 -2
  13. data/lib/tcell_agent/policies/command_injection_policy.rb +1 -1
  14. data/lib/tcell_agent/rails/auth/authlogic.rb +49 -44
  15. data/lib/tcell_agent/rails/auth/authlogic_helper.rb +20 -0
  16. data/lib/tcell_agent/rails/auth/devise.rb +103 -102
  17. data/lib/tcell_agent/rails/auth/devise_helper.rb +29 -0
  18. data/lib/tcell_agent/rails/auth/doorkeeper.rb +54 -58
  19. data/lib/tcell_agent/{userinfo.rb → rails/auth/userinfo.rb} +0 -0
  20. data/lib/tcell_agent/rails/csrf_exception.rb +0 -8
  21. data/lib/tcell_agent/rails/dlp.rb +10 -8
  22. data/lib/tcell_agent/rails/middleware/global_middleware.rb +4 -1
  23. data/lib/tcell_agent/rails/{on_start.rb → railties/tcell_agent_railties.rb} +9 -16
  24. data/lib/tcell_agent/rails/railties/tcell_agent_unicorn_railties.rb +8 -0
  25. data/lib/tcell_agent/rails/routes.rb +6 -9
  26. data/lib/tcell_agent/rails/routes/grape.rb +4 -12
  27. data/lib/tcell_agent/rails/tcell_body_proxy.rb +0 -1
  28. data/lib/tcell_agent/rust/agent_config.rb +43 -32
  29. data/lib/tcell_agent/rust/{libtcellagent-4.14.0.dylib → libtcellagent-5.0.2.dylib} +0 -0
  30. data/lib/tcell_agent/rust/{libtcellagent-4.14.0.so → libtcellagent-5.0.2.so} +0 -0
  31. data/lib/tcell_agent/rust/{libtcellagent-alpine-4.14.0.so → libtcellagent-alpine-5.0.2.so} +0 -0
  32. data/lib/tcell_agent/rust/models.rb +9 -0
  33. data/lib/tcell_agent/rust/native_agent.rb +18 -0
  34. data/lib/tcell_agent/rust/native_library.rb +2 -1
  35. data/lib/tcell_agent/rust/{tcellagent-4.14.0.dll → tcellagent-5.0.2.dll} +0 -0
  36. data/lib/tcell_agent/servers/puma.rb +7 -7
  37. data/lib/tcell_agent/servers/rack_puma_handler.rb +23 -0
  38. data/lib/tcell_agent/servers/rails_server.rb +4 -4
  39. data/lib/tcell_agent/servers/unicorn.rb +1 -1
  40. data/lib/tcell_agent/servers/webrick.rb +0 -1
  41. data/lib/tcell_agent/settings_reporter.rb +0 -79
  42. data/lib/tcell_agent/tcell_context.rb +1 -1
  43. data/lib/tcell_agent/version.rb +1 -1
  44. data/spec/lib/tcell_agent/configuration_spec.rb +62 -212
  45. data/spec/lib/tcell_agent/instrument_servers_spec.rb +95 -0
  46. data/spec/lib/tcell_agent/{cmdi_spec.rb → instrumentation/cmdi_spec.rb} +50 -0
  47. data/spec/lib/tcell_agent/instrumentation/lfi/io_lfi_spec.rb +6 -0
  48. data/spec/lib/tcell_agent/instrumentation/lfi/kernel_lfi_spec.rb +19 -4
  49. data/spec/lib/tcell_agent/instrumentation/lfi_spec.rb +47 -2
  50. data/spec/lib/tcell_agent/rust/agent_config_spec.rb +27 -0
  51. data/spec/lib/tcell_agent/settings_reporter_spec.rb +0 -73
  52. data/spec/spec_helper.rb +6 -0
  53. data/spec/support/builders.rb +6 -6
  54. data/spec/support/server_mocks/passenger_mock.rb +7 -0
  55. data/spec/support/server_mocks/puma_mock.rb +17 -0
  56. data/spec/support/server_mocks/rails_mock.rb +7 -0
  57. data/spec/support/server_mocks/thin_mock.rb +7 -0
  58. data/spec/support/server_mocks/unicorn_mock.rb +11 -0
  59. metadata +29 -16
  60. data/lib/tcell_agent/authlogic.rb +0 -23
  61. data/lib/tcell_agent/config/unknown_options.rb +0 -119
  62. data/lib/tcell_agent/devise.rb +0 -33
  63. data/lib/tcell_agent/rails/start_agent_after_initializers.rb +0 -12
  64. data/spec/lib/tcell_agent/config/unknown_options_spec.rb +0 -195
@@ -37,85 +37,6 @@ module TCellAgent
37
37
  )
38
38
  end
39
39
 
40
- TCellAgent::Instrumentation.safe_block('Instrumenting Initial Config') do
41
- TCellAgent.send_event(
42
- TCellAgent::SensorEvents::AgentSettingEvent.new(
43
- 'allow_payloads',
44
- (!!TCellAgent.configuration.allow_payloads).to_s # rubocop:disable Style/DoubleNegation
45
- )
46
- )
47
-
48
- TCellAgent.send_event(
49
- TCellAgent::SensorEvents::AgentSettingEvent.new(
50
- 'reverse_proxy',
51
- (!!TCellAgent.configuration.reverse_proxy).to_s # rubocop:disable Style/DoubleNegation
52
- )
53
- )
54
-
55
- # Because of all the diff ways to initialize the agent
56
- # some some of the following vars might not be set until
57
- # we call this method, so call this method to set all
58
- # the variables
59
- TCellAgent.configuration.log_filename
60
-
61
- TCellAgent.send_event(
62
- TCellAgent::SensorEvents::AgentSettingEvent.new(
63
- 'config_filename',
64
- TCellAgent.configuration.config_filename
65
- )
66
- )
67
- TCellAgent.send_event(
68
- TCellAgent::SensorEvents::AgentSettingEvent.new(
69
- 'logging_directory',
70
- TCellAgent.configuration.agent_log_dir
71
- )
72
- )
73
-
74
- TCellAgent.send_event(
75
- TCellAgent::SensorEvents::AgentSettingEvent.new(
76
- 'agent_home_directory',
77
- TCellAgent.configuration.agent_home_dir
78
- )
79
- )
80
-
81
- logging_options = TCellAgent.configuration.logging_options || {}
82
- use_default_setting = !logging_options.key?(:enabled) && !logging_options.key?('enabled')
83
- if use_default_setting || logging_options[:enabled] || logging_options['enabled']
84
- TCellAgent.send_event(
85
- TCellAgent::SensorEvents::AgentSettingEvent.new('logging_enabled', 'true')
86
- )
87
-
88
- TCellAgent.send_event(
89
- TCellAgent::SensorEvents::AgentSettingEvent.new(
90
- 'logging_level',
91
- logging_options[:level] || logging_options['level'] || 'INFO'
92
- )
93
- )
94
- else
95
- TCellAgent.send_event(
96
- TCellAgent::SensorEvents::AgentSettingEvent.new('logging_enabled', 'false')
97
- )
98
- end
99
-
100
- if TCellAgent.configuration.hmac_key
101
- TCellAgent.send_event(
102
- TCellAgent::SensorEvents::AgentSettingEvent.new(
103
- 'hmac_key_present',
104
- (!!TCellAgent.configuration.hmac_key).to_s # rubocop:disable Style/DoubleNegation
105
- )
106
- )
107
- end
108
-
109
- if TCellAgent.configuration.reverse_proxy
110
- TCellAgent.send_event(
111
- TCellAgent::SensorEvents::AgentSettingEvent.new(
112
- 'reverse_proxy_ip_address_header',
113
- TCellAgent.configuration.reverse_proxy_ip_address_header
114
- )
115
- )
116
- end
117
- end
118
-
119
40
  if defined?(::Rails)
120
41
  TCellAgent::Instrumentation.safe_block('Instrumenting routes') do
121
42
  TCellAgent::Instrumentation::Rails.instrument_routes
@@ -40,7 +40,7 @@ module TCellAgent
40
40
  tcell_context.request_method,
41
41
  tcell_context.remote_address,
42
42
  tcell_context.route_id,
43
- tcell_context.hmac_session_id,
43
+ tcell_context.session_id,
44
44
  tcell_context.user_id,
45
45
  tcell_context.transaction_id,
46
46
  tcell_context.uri
@@ -1,5 +1,5 @@
1
1
  # See the file "LICENSE" for the full license governing this code.
2
2
 
3
3
  module TCellAgent
4
- VERSION = '2.0.0'.freeze
4
+ VERSION = '2.2.1'.freeze
5
5
  end
@@ -2,228 +2,78 @@ require 'spec_helper'
2
2
 
3
3
  module TCellAgent
4
4
  describe Configuration do
5
- describe '#agent_home_dir' do
6
- context 'no TCELL_AGENT_HOME defined' do
7
- it 'should set cache file, config, and log file to defaults' do
8
- configuration = Configuration.new
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(configuration.log_filename).to eq(
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
- context 'TCELL_AGENT_HOME defined' do
20
- it 'should set config filename to default, cache file and log file are updated' do
21
- old_tcell_agent_home = ENV['TCELL_AGENT_HOME']
22
-
23
- ENV['TCELL_AGENT_HOME'] = 'spec_tcell_home'
24
-
25
- configuration = Configuration.new
26
-
27
- expect(configuration.log_filename).to eq(
28
- 'spec_tcell_home/logs/tcell_agent.log'
29
- )
30
- expect(configuration.config_filename).to eq(
31
- File.join(Dir.getwd, 'config/tcell_agent.config')
32
- )
33
-
34
- ENV['TCELL_AGENT_HOME'] = old_tcell_agent_home
35
- end
36
- end
37
-
38
- context 'TCELL_AGENT_HOME and TCELL_AGENT_LOG_DIR defined' do
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
- end
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
- context 'data_exposure contains an override' do
139
- it 'should set max_data_ex_db_records_per_request to override' do
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
- describe '#allow_payloads' do
168
- context 'setting it via config' do
169
- context 'using allow_payloads' do
170
- it 'should be false' do
171
- allow_payloads_enabled = double(
172
- 'no_data_ex',
173
- :read => {
174
- :version => 1,
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
- context 'setting it via env var' do
197
- context 'TCELL_AGENT_ALLOW_PAYLOADS overrides everything else' do
198
- it 'should be false' do
199
- old_tcell_agent_allow_payloads = ENV['TCELL_AGENT_ALLOW_PAYLOADS']
200
-
201
- ENV['TCELL_AGENT_ALLOW_PAYLOADS'] = 'false'
202
-
203
- allow_payloads_enabled = double(
204
- 'no_data_ex',
205
- :read => {
206
- :version => 1,
207
- :applications => [
208
- :app_id => 'app_id',
209
- :api_key => 'api_key',
210
- :allow_payloads => true
211
- ]
212
- }.to_json
213
- )
214
- expect(File).to receive(:file?).with(
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?(: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