tcell_agent 1.1.12 → 2.0.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.
Files changed (163) hide show
  1. checksums.yaml +5 -5
  2. data/bin/tcell_agent +26 -14
  3. data/lib/tcell_agent.rb +16 -10
  4. data/lib/tcell_agent/agent.rb +78 -97
  5. data/lib/tcell_agent/agent/route_manager.rb +0 -16
  6. data/lib/tcell_agent/agent/static_agent.rb +9 -30
  7. data/lib/tcell_agent/authlogic.rb +3 -6
  8. data/lib/tcell_agent/config/unknown_options.rb +4 -8
  9. data/lib/tcell_agent/configuration.rb +38 -119
  10. data/lib/tcell_agent/devise.rb +25 -27
  11. data/lib/tcell_agent/hooks/login_fraud.rb +30 -33
  12. data/lib/tcell_agent/instrument_servers.rb +25 -0
  13. data/lib/tcell_agent/instrumentation.rb +12 -10
  14. data/lib/tcell_agent/instrumentation/cmdi.rb +19 -15
  15. data/lib/tcell_agent/instrumentation/lfi.rb +73 -0
  16. data/lib/tcell_agent/instrumentation/monkey_patches/file.rb +25 -0
  17. data/lib/tcell_agent/instrumentation/monkey_patches/io.rb +123 -0
  18. data/lib/tcell_agent/instrumentation/monkey_patches/kernel.rb +159 -0
  19. data/lib/tcell_agent/logger.rb +50 -114
  20. data/lib/tcell_agent/patches.rb +6 -7
  21. data/lib/tcell_agent/policies/appfirewall_policy.rb +26 -0
  22. data/lib/tcell_agent/policies/command_injection_policy.rb +28 -0
  23. data/lib/tcell_agent/policies/dataloss_policy.rb +44 -44
  24. data/lib/tcell_agent/policies/headers_policy.rb +25 -0
  25. data/lib/tcell_agent/policies/http_redirect_policy.rb +13 -79
  26. data/lib/tcell_agent/policies/js_agent_policy.rb +27 -0
  27. data/lib/tcell_agent/policies/local_file_access.rb +28 -0
  28. data/lib/tcell_agent/policies/login_policy.rb +43 -0
  29. data/lib/tcell_agent/policies/patches_policy.rb +27 -0
  30. data/lib/tcell_agent/policies/policies_manager.rb +68 -0
  31. data/lib/tcell_agent/policies/policy_polling.rb +58 -0
  32. data/lib/tcell_agent/policies/policy_types.rb +14 -0
  33. data/lib/tcell_agent/policies/system_enablements.rb +27 -0
  34. data/lib/tcell_agent/rails/auth/authlogic.rb +43 -68
  35. data/lib/tcell_agent/rails/auth/devise.rb +20 -23
  36. data/lib/tcell_agent/rails/auth/doorkeeper.rb +63 -74
  37. data/lib/tcell_agent/rails/csrf_exception.rb +2 -2
  38. data/lib/tcell_agent/rails/dlp.rb +25 -15
  39. data/lib/tcell_agent/rails/dlp_handler.rb +1 -2
  40. data/lib/tcell_agent/rails/js_agent_insert.rb +12 -13
  41. data/lib/tcell_agent/rails/middleware/body_filter_middleware.rb +4 -25
  42. data/lib/tcell_agent/rails/middleware/context_middleware.rb +2 -12
  43. data/lib/tcell_agent/rails/middleware/global_middleware.rb +0 -1
  44. data/lib/tcell_agent/rails/middleware/headers_middleware.rb +14 -34
  45. data/lib/tcell_agent/rails/on_start.rb +32 -31
  46. data/lib/tcell_agent/rails/routes.rb +7 -6
  47. data/lib/tcell_agent/rails/routes/grape.rb +1 -3
  48. data/lib/tcell_agent/rails/routes/route_id.rb +3 -1
  49. data/lib/tcell_agent/rails/settings_reporter.rb +23 -36
  50. data/lib/tcell_agent/rails/start_agent_after_initializers.rb +12 -0
  51. data/lib/tcell_agent/rails/tcell_body_proxy.rb +6 -4
  52. data/lib/tcell_agent/rust/agent_config.rb +49 -0
  53. data/lib/tcell_agent/rust/{libtcellagent-alpine-1.3.2.so → libtcellagent-4.14.0.dylib} +0 -0
  54. data/lib/tcell_agent/rust/libtcellagent-4.14.0.so +0 -0
  55. data/lib/tcell_agent/rust/{libtcellagent-1.3.2.so → libtcellagent-alpine-4.14.0.so} +0 -0
  56. data/lib/tcell_agent/rust/models.rb +0 -55
  57. data/lib/tcell_agent/rust/native_agent.rb +531 -0
  58. data/lib/tcell_agent/rust/native_agent_response.rb +42 -0
  59. data/lib/tcell_agent/rust/native_library.rb +68 -0
  60. data/lib/tcell_agent/rust/tcellagent-4.14.0.dll +0 -0
  61. data/lib/tcell_agent/sensor_events/agent_setting_event.rb +12 -0
  62. data/lib/tcell_agent/sensor_events/{app_config.rb → app_config_setting_event.rb} +0 -6
  63. data/lib/tcell_agent/sensor_events/dlp.rb +2 -6
  64. data/lib/tcell_agent/sensor_events/sensor.rb +0 -62
  65. data/lib/tcell_agent/sensor_events/server_agent.rb +13 -18
  66. data/lib/tcell_agent/sensor_events/util/sanitizer_utilities.rb +0 -108
  67. data/lib/tcell_agent/sensor_events/util/utils.rb +0 -2
  68. data/lib/tcell_agent/servers/passenger.rb +1 -28
  69. data/lib/tcell_agent/servers/puma.rb +3 -21
  70. data/lib/tcell_agent/servers/rails_server.rb +1 -1
  71. data/lib/tcell_agent/servers/thin.rb +2 -2
  72. data/lib/tcell_agent/servers/unicorn.rb +19 -80
  73. data/lib/tcell_agent/servers/webrick.rb +1 -1
  74. data/lib/tcell_agent/settings_reporter.rb +24 -24
  75. data/lib/tcell_agent/sinatra.rb +14 -16
  76. data/lib/tcell_agent/tcell_context.rb +40 -14
  77. data/lib/tcell_agent/utils/headers.rb +14 -0
  78. data/lib/tcell_agent/version.rb +1 -1
  79. data/spec/lib/tcell_agent/cmdi_spec.rb +0 -585
  80. data/spec/lib/tcell_agent/config/unknown_options_spec.rb +0 -18
  81. data/spec/lib/tcell_agent/configuration_spec.rb +4 -140
  82. data/spec/lib/tcell_agent/hooks/login_fraud_spec.rb +46 -173
  83. data/spec/lib/tcell_agent/instrumentation/cmdi/io_cmdi_spec.rb +504 -0
  84. data/spec/lib/tcell_agent/instrumentation/cmdi/kernel_cmdi_spec.rb +435 -0
  85. data/spec/lib/tcell_agent/instrumentation/lfi/file_lfi_spec.rb +326 -0
  86. data/spec/lib/tcell_agent/instrumentation/lfi/io_lfi_spec.rb +556 -0
  87. data/spec/lib/tcell_agent/instrumentation/lfi/kernel_lfi_spec.rb +249 -0
  88. data/spec/lib/tcell_agent/instrumentation/lfi_spec.rb +105 -0
  89. data/spec/lib/tcell_agent/patches_spec.rb +25 -43
  90. data/spec/lib/tcell_agent/policies/appfirewall_policy_spec.rb +183 -0
  91. data/spec/lib/tcell_agent/policies/clickjacking_policy_spec.rb +57 -0
  92. data/spec/lib/tcell_agent/policies/command_injection_policy_spec.rb +84 -773
  93. data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +161 -0
  94. data/spec/lib/tcell_agent/policies/dataloss_policy_spec.rb +9 -9
  95. data/spec/lib/tcell_agent/policies/http_redirect_policy_spec.rb +243 -198
  96. data/spec/lib/tcell_agent/policies/js_agent_policy_spec.rb +75 -0
  97. data/spec/lib/tcell_agent/policies/login_policy_spec.rb +165 -33
  98. data/spec/lib/tcell_agent/policies/patches_policy_spec.rb +84 -277
  99. data/spec/lib/tcell_agent/policies/policies_manager_spec.rb +104 -0
  100. data/spec/lib/tcell_agent/policies/policy_polling_spec.rb +6 -0
  101. data/spec/lib/tcell_agent/policies/secure_headers_policy_spec.rb +56 -0
  102. data/spec/lib/tcell_agent/rails/csrf_exception_spec.rb +9 -18
  103. data/spec/lib/tcell_agent/rails/js_agent_insert_spec.rb +13 -30
  104. data/spec/lib/tcell_agent/rails/logger_spec.rb +27 -7
  105. data/spec/lib/tcell_agent/rails/middleware/tcell_body_proxy_spec.rb +17 -12
  106. data/spec/lib/tcell_agent/rails/routes/routes_spec.rb +14 -14
  107. data/spec/lib/tcell_agent/sensor_events/util/sanitizer_utilities_spec.rb +0 -35
  108. data/spec/lib/tcell_agent/settings_reporter_spec.rb +127 -153
  109. data/spec/spec_helper.rb +1 -1
  110. data/spec/support/builders.rb +104 -0
  111. data/spec/support/force_logger_mocking.rb +38 -0
  112. data/spec/support/resources/lfi_sample_file.txt +2 -0
  113. data/spec/support/static_agent_overrides.rb +0 -15
  114. metadata +63 -74
  115. data/lib/tcell_agent/agent/event_processor.rb +0 -326
  116. data/lib/tcell_agent/agent/fork_pipe_manager.rb +0 -113
  117. data/lib/tcell_agent/agent/policy_manager.rb +0 -219
  118. data/lib/tcell_agent/agent/policy_types.rb +0 -30
  119. data/lib/tcell_agent/api.rb +0 -91
  120. data/lib/tcell_agent/appsensor/injections_reporter.rb +0 -24
  121. data/lib/tcell_agent/config/child_process_events.rb +0 -8
  122. data/lib/tcell_agent/instrumentation/cmdi/backtick.rb +0 -10
  123. data/lib/tcell_agent/instrumentation/cmdi/exec.rb +0 -14
  124. data/lib/tcell_agent/instrumentation/cmdi/popen.rb +0 -28
  125. data/lib/tcell_agent/instrumentation/cmdi/spawn.rb +0 -11
  126. data/lib/tcell_agent/instrumentation/cmdi/system.rb +0 -11
  127. data/lib/tcell_agent/policies/http_tx_policy.rb +0 -60
  128. data/lib/tcell_agent/policies/login_fraud_policy.rb +0 -45
  129. data/lib/tcell_agent/policies/rust_policies.rb +0 -110
  130. data/lib/tcell_agent/rails.rb +0 -40
  131. data/lib/tcell_agent/rust/libtcellagent-1.3.2.dylib +0 -0
  132. data/lib/tcell_agent/rust/tcellagent-1.3.2.dll +0 -0
  133. data/lib/tcell_agent/rust/whisperer.rb +0 -308
  134. data/lib/tcell_agent/sensor_events/appsensor_event.rb +0 -52
  135. data/lib/tcell_agent/sensor_events/appsensor_meta_event.rb +0 -45
  136. data/lib/tcell_agent/sensor_events/command_injection.rb +0 -75
  137. data/lib/tcell_agent/sensor_events/honeytokens.rb +0 -16
  138. data/lib/tcell_agent/sensor_events/login_fraud.rb +0 -60
  139. data/lib/tcell_agent/sensor_events/metrics.rb +0 -123
  140. data/lib/tcell_agent/sensor_events/patches.rb +0 -21
  141. data/lib/tcell_agent/start_background_thread.rb +0 -55
  142. data/lib/tcell_agent/system_info.rb +0 -11
  143. data/lib/tcell_agent/utils/io.rb +0 -38
  144. data/lib/tcell_agent/utils/passwords.rb +0 -28
  145. data/lib/tcell_agent/utils/queue_with_timeout.rb +0 -142
  146. data/spec/lib/tcell_agent/agent/fork_pipe_manager_spec.rb +0 -100
  147. data/spec/lib/tcell_agent/agent/policy_manager_spec.rb +0 -535
  148. data/spec/lib/tcell_agent/agent/static_agent_spec.rb +0 -133
  149. data/spec/lib/tcell_agent/api/api_spec.rb +0 -39
  150. data/spec/lib/tcell_agent/appsensor/injections_reporter_spec.rb +0 -187
  151. data/spec/lib/tcell_agent/instrumentation_spec.rb +0 -225
  152. data/spec/lib/tcell_agent/policies/appsensor_policy_spec.rb +0 -517
  153. data/spec/lib/tcell_agent/policies/http_tx_policy_spec.rb +0 -22
  154. data/spec/lib/tcell_agent/rails/middleware/appsensor_middleware_spec.rb +0 -293
  155. data/spec/lib/tcell_agent/rails/middleware/dlp_middleware_spec.rb +0 -198
  156. data/spec/lib/tcell_agent/rails/middleware/global_middleware_spec.rb +0 -180
  157. data/spec/lib/tcell_agent/rails/middleware/redirect_middleware_spec.rb +0 -116
  158. data/spec/lib/tcell_agent/rust/models_spec.rb +0 -120
  159. data/spec/lib/tcell_agent/rust/whisperer_spec.rb +0 -704
  160. data/spec/lib/tcell_agent/sensor_events/appsensor_meta_event_spec.rb +0 -45
  161. data/spec/lib/tcell_agent/sensor_events/sessions_metric_spec.rb +0 -272
  162. data/spec/lib/tcell_agent/utils/bounded_queue_spec.rb +0 -52
  163. data/spec/lib/tcell_agent/utils/passwords_spec.rb +0 -143
@@ -1,11 +0,0 @@
1
- module TCellAgent
2
- module SystemInfo
3
- def self.get_language_version
4
- RUBY_VERSION
5
- end
6
-
7
- def self.get_language
8
- 'Ruby'
9
- end
10
- end
11
- end
@@ -1,38 +0,0 @@
1
- require 'pathname'
2
- require 'tcell_agent/instrumentation'
3
- require 'tcell_agent/utils/strings'
4
-
5
- module TCellAgent
6
- module Utils
7
- module IO
8
- def self.create_directory(dir, owner = nil)
9
- return if File.directory?(dir)
10
-
11
- directories = Pathname(dir).each_filename.to_a
12
-
13
- return if directories.empty?
14
-
15
- memoized_path = File::SEPARATOR
16
-
17
- directories.each do |directory|
18
- memoized_path = File.join(memoized_path, directory)
19
- next if File.directory?(memoized_path)
20
- FileUtils.mkdir(memoized_path)
21
-
22
- next unless TCellAgent::Utils::Strings.present?(owner)
23
- TCellAgent::Instrumentation.safe_block('Ignoring agent_home_owner value, insufficient privileges') do
24
- FileUtils.chown(owner, nil, memoized_path)
25
- end
26
- end
27
- end
28
-
29
- def self.set_owner(filename, owner = nil)
30
- TCellAgent::Instrumentation.safe_block('Ignoring agent_home_owner value, insufficient privileges') do
31
- if TCellAgent::Utils::Strings.present?(owner) && File.exist?(filename)
32
- FileUtils.chown(owner, nil, filename)
33
- end
34
- end
35
- end
36
- end
37
- end
38
- end
@@ -1,28 +0,0 @@
1
- module TCellAgent
2
- module Utils
3
- module Passwords
4
- def self.fingerprint_password(password, user_id)
5
- digest = nil
6
-
7
- app_id = TCellAgent.configuration.app_id
8
- password_hmac_key = TCellAgent.configuration.password_hmac_key
9
- if app_id &&
10
- TCellAgent::Utils::Strings.present?(password_hmac_key) &&
11
- TCellAgent::Utils::Strings.present?(password)
12
- string_builder = [app_id, ':', password, ':']
13
- string_builder.push(user_id) if user_id
14
-
15
- digest = OpenSSL::HMAC.hexdigest(
16
- OpenSSL::Digest.new('sha256'),
17
- password_hmac_key.to_s,
18
- string_builder.join('')
19
- )
20
-
21
- digest = digest[0...8]
22
- end
23
-
24
- digest
25
- end
26
- end
27
- end
28
- end
@@ -1,142 +0,0 @@
1
- # See the file "LICENSE" for the full license governing this code.
2
-
3
- require 'tcell_agent/logger'
4
- require 'thread'
5
- require 'logger'
6
-
7
- module TCellAgent
8
- class BoundedQueue
9
- def initialize(max_size = :infinite)
10
- @lock = Mutex.new
11
- @items = []
12
- @item_available = ConditionVariable.new
13
- @max_size = max_size
14
- @space_available = ConditionVariable.new
15
- end
16
-
17
- def push(obj, timeout = :never, &timeout_policy)
18
- timeout_policy ||= lambda do
19
- raise 'Push timed out'
20
- end
21
-
22
- wait_for_condition(
23
- @space_available,
24
- -> { !full? },
25
- timeout,
26
- timeout_policy
27
- ) do
28
-
29
- @items.push(obj)
30
- @item_available.signal
31
- end
32
- end
33
-
34
- def pop(timeout = :never, &timeout_policy)
35
- timeout_policy ||= -> { nil }
36
- wait_for_condition(
37
- @item_available,
38
- -> { @items.any? },
39
- timeout,
40
- timeout_policy
41
- ) do
42
-
43
- item = @items.shift
44
- @space_available.signal
45
-
46
- item
47
- end
48
- end
49
-
50
- def full?
51
- return false if @max_size == :infinite
52
- @max_size <= @items.size
53
- end
54
-
55
- def size
56
- @items.size
57
- end
58
-
59
- private
60
-
61
- def wait_for_condition(condition_variable, condition_predicate, timeout = :never, timeout_policy = -> { nil })
62
- deadline = timeout == :never ? :never : Time.now + timeout
63
-
64
- @lock.synchronize do
65
- loop do
66
- cv_timeout = timeout == :never ? nil : deadline - Time.now
67
-
68
- if !condition_predicate.call && cv_timeout.to_f >= 0
69
- condition_variable.wait(@lock, cv_timeout)
70
- end
71
-
72
- if condition_predicate.call # rubocop:disable Style/GuardClause
73
- return yield
74
-
75
- elsif :never == deadline || deadline > Time.now # rubocop:disable Style/YodaCondition
76
- next
77
-
78
- else
79
- return timeout_policy.call
80
- end
81
- end
82
- end
83
- end
84
- end
85
-
86
- class QueueWithTimeout
87
- def initialize
88
- @mutex = Mutex.new
89
- @queue = []
90
- @response_time_table = {}
91
- @recieved = ConditionVariable.new
92
- end
93
-
94
- def <<(x) # rubocop:disable Naming/UncommunicativeMethodParamName
95
- @mutex.synchronize do
96
- @queue << x
97
- @recieved.signal
98
- end
99
- end
100
-
101
- def add_response_time(route_id, response_time)
102
- @mutex.synchronize do
103
- route_id = '?' if route_id.nil? || route_id == ''
104
- @response_time_table[route_id] = @response_time_table.fetch(route_id, {})
105
- @response_time_table[route_id]['c'] = @response_time_table[route_id].fetch('c', 0) + 1
106
- @response_time_table[route_id]['mx'] = [@response_time_table[route_id].fetch('mx', 0), response_time].max
107
- @response_time_table[route_id]['mn'] = [@response_time_table[route_id].fetch('mn', response_time), response_time].min
108
- @response_time_table[route_id]['t'] = ((@response_time_table[route_id].fetch('t', 0) * (@response_time_table[route_id]['c'] - 1)) + response_time) / @response_time_table[route_id]['c']
109
- end
110
- end
111
-
112
- def length
113
- @queue.length
114
- end
115
-
116
- def get_response_time_table
117
- @response_time_table
118
- end
119
-
120
- def reset_response_time_table
121
- @mutex.synchronize do
122
- @response_time_table = {}
123
- end
124
- end
125
-
126
- def pop(non_block = false)
127
- pop_with_timeout(non_block ? 0 : nil)
128
- end
129
-
130
- def pop_with_timeout(timeout = nil)
131
- @mutex.synchronize do
132
- if @queue.empty?
133
- @recieved.wait(@mutex, timeout) if timeout != 0
134
- # if we're still empty after the timeout, raise exception
135
- return nil if @queue.empty?
136
- # raise ThreadError, "queue empty" if @queue.empty?
137
- end
138
- @queue.shift
139
- end
140
- end
141
- end
142
- end
@@ -1,100 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module TCellAgent
4
- describe Agent::ForkPipeManager do
5
- describe '.send_to_metrics_pipe' do
6
- context 'incrementing a route' do
7
- it 'should call increment_route on the agent' do
8
- expect(TCellAgent).to receive(:increment_route).with('/ma_route', 50)
9
- expect(TCellAgent).to_not receive(:discover_database_fields)
10
- expect(TCellAgent).to_not receive(:increment_session_info)
11
-
12
- child_process = ForkBreak::Process.new do |_breakpoints|
13
- TCellAgent::Agent.send_to_metrics_pipe(
14
- '_type' => 'increment_route',
15
- 'route_id' => '/ma_route',
16
- 'response_time' => 50
17
- )
18
- end
19
-
20
- child_process.finish.wait
21
- end
22
- end
23
-
24
- context 'discover database fields' do
25
- it 'should call discover_database_fields on the agent' do
26
- expect(TCellAgent).to_not receive(:increment_route)
27
- expect(TCellAgent).to receive(:discover_database_fields).with(
28
- 'route_id', 'database', 'schema', 'table', 'fields'
29
- )
30
- expect(TCellAgent).to_not receive(:increment_session_info)
31
-
32
- child_process = ForkBreak::Process.new do |_breakpoints|
33
- TCellAgent::Agent.send_to_metrics_pipe(
34
- {
35
- '_type' => 'discover_database_fields',
36
- 'route_id' => 'route_id',
37
- 'database' => 'database',
38
- 'schema' => 'schema',
39
- 'table' => 'table',
40
- 'fields' => 'fields'
41
- }
42
- )
43
- end
44
-
45
- child_process.finish.wait
46
- end
47
- end
48
-
49
- context 'increment session info' do
50
- it 'should call increment_session_info on the agent' do
51
- expect(TCellAgent).to_not receive(:increment_route)
52
- expect(TCellAgent).to_not receive(:discover_database_fields)
53
- expect(TCellAgent).to receive(:increment_session_info).with(
54
- 'hmac_session_id', 'user_id', 'ip_address', 'user_agent'
55
- )
56
-
57
- child_process = ForkBreak::Process.new do |_breakpoints|
58
- TCellAgent::Agent.send_to_metrics_pipe(
59
- {
60
- '_type' => 'increment_session_info',
61
- 'hmac_session_id' => 'hmac_session_id',
62
- 'user_id' => 'user_id',
63
- 'ip_address' => 'ip_address',
64
- 'user_agent' => 'user_agent'
65
- }
66
- )
67
- end
68
-
69
- child_process.finish.wait
70
- end
71
- end
72
-
73
- context 'unknown metric' do
74
- it 'should raise an exception' do
75
- expect(TCellAgent).to_not receive(:increment_route)
76
- expect(TCellAgent).to_not receive(:discover_database_fields)
77
- expect(TCellAgent).to_not receive(:increment_session_info)
78
-
79
- logger = double('logger')
80
- expect(TCellAgent).to receive(:logger).and_return(logger)
81
- expect(TCellAgent).to receive(:logger).and_return(logger)
82
-
83
- expect(logger).to receive(:debug).with(
84
- 'Exception in safe_block Handling metrics_pipe_block: StandardError happened, message' \
85
- ' is Metrics Pipe Manager received unknown metric: dunno_what_this_is'
86
- )
87
- expect(logger).to receive(:debug).with(anything)
88
-
89
- child_process = ForkBreak::Process.new do |_breakpoints|
90
- TCellAgent::Agent.send_to_metrics_pipe(
91
- { '_type' => 'dunno_what_this_is' }
92
- )
93
- end
94
-
95
- child_process.finish.wait
96
- end
97
- end
98
- end
99
- end
100
- end
@@ -1,535 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module TCellAgent
4
- module SensorEvents
5
- describe Agent do
6
- describe '#start_policy_polling_loop' do
7
- context 'should_start_policy_poll disabled' do
8
- it 'should not start the policy polling loop' do
9
- configuration = double(
10
- 'configuration',
11
- {
12
- :should_start_policy_poll? => false,
13
- :event_time_limit_seconds => nil,
14
- :event_batch_size_limit => nil,
15
- :preload_policy_filename => nil,
16
- :cache_filename_with_app_id => 'cache-file.app_id'
17
- }
18
- )
19
-
20
- expect(TCellAgent).to receive(:configuration).and_return(configuration).at_least(:once)
21
- expect(TCellAgent::Policies::RustPolicies).to receive(:new).and_return(nil)
22
- agent = TCellAgent::Agent.new
23
-
24
- expect(Thread).to_not receive(:new)
25
- agent.start_policy_polling_loop
26
- end
27
- end
28
-
29
- context 'should_start_policy_poll enabled' do
30
- context 'tcell_api_url' do
31
- context 'is nil ' do
32
- it 'should not start the policy polling loop' do
33
- configuration = double(
34
- 'configuration',
35
- {
36
- :tcell_api_url => nil,
37
- :should_start_policy_poll? => true,
38
- :event_time_limit_seconds => nil,
39
- :event_batch_size_limit => nil,
40
- :preload_policy_filename => nil,
41
- :cache_filename_with_app_id => 'cache-file.app_id'
42
- }
43
- )
44
-
45
- expect(TCellAgent::Policies::RustPolicies).to receive(:new).and_return(nil)
46
- expect(TCellAgent).to receive(:configuration).and_return(configuration).at_least(:once)
47
- agent = TCellAgent::Agent.new
48
-
49
- logger = double('logger')
50
-
51
- expect(TCellAgent).to receive(:logger).and_return(logger)
52
- expect(logger).to receive(:error).with('tCell.io tcell_api_url is missing. Disabling policy polling.')
53
- expect(Thread).to_not receive(:new)
54
- agent.start_policy_polling_loop
55
- end
56
- end
57
-
58
- context 'is empty' do
59
- it 'should not start the policy polling loop' do
60
- configuration = double(
61
- 'configuration',
62
- {
63
- :tcell_api_url => '',
64
- :should_start_policy_poll? => true,
65
- :event_time_limit_seconds => nil,
66
- :event_batch_size_limit => nil,
67
- :preload_policy_filename => nil,
68
- :cache_filename_with_app_id => 'cache-file.app_id'
69
- }
70
- )
71
-
72
- expect(TCellAgent::Policies::RustPolicies).to receive(:new).and_return(nil)
73
- expect(TCellAgent).to receive(:configuration).and_return(configuration).at_least(:once)
74
- agent = TCellAgent::Agent.new
75
-
76
- logger = double('logger')
77
-
78
- expect(TCellAgent).to receive(:logger).and_return(logger)
79
- expect(logger).to receive(:error).with('tCell.io tcell_api_url is missing. Disabling policy polling.')
80
- expect(Thread).to_not receive(:new)
81
- agent.start_policy_polling_loop
82
- end
83
- end
84
-
85
- context 'is blank space' do
86
- it 'should not start the policy polling loop' do
87
- configuration = double(
88
- 'configuration',
89
- {
90
- :tcell_api_url => ' ',
91
- :should_start_policy_poll? => true,
92
- :event_time_limit_seconds => nil,
93
- :event_batch_size_limit => nil,
94
- :preload_policy_filename => nil,
95
- :cache_filename_with_app_id => 'cache-file.app_id'
96
- }
97
- )
98
-
99
- expect(TCellAgent::Policies::RustPolicies).to receive(:new).and_return(nil)
100
- expect(TCellAgent).to receive(:configuration).and_return(configuration).at_least(:once)
101
- agent = TCellAgent::Agent.new
102
-
103
- logger = double('logger')
104
-
105
- expect(TCellAgent).to receive(:logger).and_return(logger)
106
- expect(logger).to receive(:error).with('tCell.io tcell_api_url is missing. Disabling policy polling.')
107
- expect(Thread).to_not receive(:new)
108
- agent.start_policy_polling_loop
109
- end
110
- end
111
- end
112
-
113
- context 'app_id' do
114
- context 'is nil ' do
115
- it 'should not start the policy polling loop' do
116
- configuration = double(
117
- 'configuration',
118
- {
119
- :tcell_api_url => 'present',
120
- :app_id => nil,
121
- :should_start_policy_poll? => true,
122
- :event_time_limit_seconds => nil,
123
- :event_batch_size_limit => nil,
124
- :preload_policy_filename => nil,
125
- :cache_filename_with_app_id => 'cache-file.app_id'
126
- }
127
- )
128
-
129
- expect(TCellAgent::Policies::RustPolicies).to receive(:new).and_return(nil)
130
- expect(TCellAgent).to receive(:configuration).and_return(configuration).at_least(:once)
131
- agent = TCellAgent::Agent.new
132
-
133
- logger = double('logger')
134
-
135
- expect(TCellAgent).to receive(:logger).and_return(logger)
136
- expect(logger).to receive(:error).with('tCell.io app_id is missing. Disabling policy polling.')
137
- expect(Thread).to_not receive(:new)
138
- agent.start_policy_polling_loop
139
- end
140
- end
141
-
142
- context 'is empty' do
143
- it 'should not start the policy polling loop' do
144
- configuration = double(
145
- 'configuration',
146
- {
147
- :tcell_api_url => 'present',
148
- :app_id => '',
149
- :should_start_policy_poll? => true,
150
- :event_time_limit_seconds => nil,
151
- :event_batch_size_limit => nil,
152
- :preload_policy_filename => nil,
153
- :cache_filename_with_app_id => 'cache-file.app_id'
154
- }
155
- )
156
-
157
- expect(TCellAgent::Policies::RustPolicies).to receive(:new).and_return(nil)
158
- expect(TCellAgent).to receive(:configuration).and_return(configuration).at_least(:once)
159
- agent = TCellAgent::Agent.new
160
-
161
- logger = double('logger')
162
-
163
- expect(TCellAgent).to receive(:logger).and_return(logger)
164
- expect(logger).to receive(:error).with('tCell.io app_id is missing. Disabling policy polling.')
165
- expect(Thread).to_not receive(:new)
166
- agent.start_policy_polling_loop
167
- end
168
- end
169
-
170
- context 'is blank space' do
171
- it 'should not start the policy polling loop' do
172
- configuration = double(
173
- 'configuration',
174
- {
175
- :tcell_api_url => 'present',
176
- :app_id => ' ',
177
- :should_start_policy_poll? => true,
178
- :event_time_limit_seconds => nil,
179
- :event_batch_size_limit => nil,
180
- :preload_policy_filename => nil,
181
- :cache_filename_with_app_id => 'cache-file.app_id'
182
- }
183
- )
184
-
185
- expect(TCellAgent::Policies::RustPolicies).to receive(:new).and_return(nil)
186
- expect(TCellAgent).to receive(:configuration).and_return(configuration).at_least(:once)
187
- agent = TCellAgent::Agent.new
188
-
189
- logger = double('logger')
190
-
191
- expect(TCellAgent).to receive(:logger).and_return(logger)
192
- expect(logger).to receive(:error).with('tCell.io app_id is missing. Disabling policy polling.')
193
- expect(Thread).to_not receive(:new)
194
- agent.start_policy_polling_loop
195
- end
196
- end
197
- end
198
- end
199
- end
200
-
201
- describe '#cache' do
202
- context 'with an existing cached file' do
203
- context 'with two processes' do
204
- context 'while one process is writing to the cached file' do
205
- before(:each) do
206
- configuration = double(
207
- 'configuration',
208
- {
209
- 'app_id' => 'app_id',
210
- 'api_key' => 'api_key',
211
- 'allow_payloads' => true,
212
- 'js_agent_api_base_url' => 'http://api.tcell.com/',
213
- 'js_agent_url' => 'https://jsagent.tcell.io/tcellagent.min.js',
214
- 'max_csp_header_bytes' => nil,
215
- 'event_time_limit_seconds' => 15,
216
- 'event_batch_size_limit' => 50,
217
- 'preload_policy_filename' => nil,
218
- 'cache_filename_with_app_id' => '/tcellagent_src/tcell/cache/tcell_agent.cache',
219
- 'agent_home_owner' => nil
220
- }
221
- )
222
- expect(TCellAgent).to receive(:configuration).and_return(configuration).at_least(:once)
223
- TCellAgent.thread_agent.cache(
224
- 'http-redirect',
225
- {
226
- 'app_id' => 'raftest-EyJZR',
227
- 'policy_id' => '363b8b60-a9a8-11e5-bb10-a9372a56b8a7',
228
- 'data' => {
229
- 'enabled' => true,
230
- 'block' => false,
231
- 'whitelist' => []
232
- }
233
- }
234
- )
235
- end
236
-
237
- it 'should raise a timeout exception when the other process tries to write to it' do
238
- file_lock_holder = ForkBreak::Process.new do |breakpoints|
239
- original_dump = JSON.method(:dump)
240
- JSON.stub(:dump) do |*args|
241
- breakpoints << :before_dump
242
- original_dump.call(*args)
243
- end
244
-
245
- TCellAgent.thread_agent.cache(
246
- 'http-redirect',
247
- {
248
- 'app_id' => 'raftest-EyJZR',
249
- 'policy_id' => '363b8b60-a9a8-11e5-bb10-a9372a56b8a7',
250
- 'data' => {
251
- 'enabled' => true,
252
- 'block' => false,
253
- 'whitelist' => []
254
- }
255
- }
256
- )
257
- end
258
-
259
- file_lock_holder.run_until(:before_dump).wait
260
-
261
- logger = double('logger')
262
- expect(TCellAgent).to receive(:logger).and_return(logger)
263
- expect(logger).to receive(:warn).with('execution expired')
264
-
265
- TCellAgent.thread_agent.cache(
266
- 'http-redirect',
267
- {
268
- 'app_id' => 'raftest-EyJZR',
269
- 'policy_id' => '363b8b60-a9a8-11e5-bb10-a9372a56b8a7',
270
- 'data' => {
271
- 'enabled' => true,
272
- 'block' => false,
273
- 'whitelist' => []
274
- }
275
- }
276
- )
277
-
278
- file_lock_holder.finish.wait
279
- end
280
-
281
- after(:each) do
282
- File.delete(TCellAgent.configuration.cache_filename_with_app_id)
283
- end
284
- end
285
- end
286
- end
287
-
288
- context 'with 10 processes updating the cached file' do
289
- xit 'should update the cached file with all updates' do
290
- processes = Array.new(5).each do |process_number|
291
- ForkBreak::Process.new do |breakpoints|
292
- original_dump = JSON.method(:dump)
293
- JSON.stub(:dump) do |*args|
294
- breakpoints << :before_dump
295
- original_dump.call(*args)
296
- end
297
-
298
- TCellAgent.thread_agent.cache(
299
- "process_#{process_number}",
300
- {
301
- 'app_id' => 'raftest-EyJZR',
302
- 'policy_id' => 'policy_id',
303
- 'data' => { 'enabled' => true }
304
- }
305
- )
306
- end
307
- end
308
-
309
- processes.map(&:finish).map(&:wait)
310
-
311
- policies = JSON.parse(File.open(TCellAgent.configuration.cache_filename_with_app_id).read)
312
-
313
- File.delete(TCellAgent.configuration.cache_filename_with_app_id)
314
-
315
- expect(policies).to eq(
316
- {
317
- 'process_0' => { 'app_id' => 'raftest-EyJZR', 'policy_id' => 'policy_id', 'data' => { 'enabled' => true } },
318
- 'process_1' => { 'app_id' => 'raftest-EyJZR', 'policy_id' => 'policy_id', 'data' => { 'enabled' => true } },
319
- 'process_2' => { 'app_id' => 'raftest-EyJZR', 'policy_id' => 'policy_id', 'data' => { 'enabled' => true } },
320
- 'process_3' => { 'app_id' => 'raftest-EyJZR', 'policy_id' => 'policy_id', 'data' => { 'enabled' => true } },
321
- 'process_4' => { 'app_id' => 'raftest-EyJZR', 'policy_id' => 'policy_id', 'data' => { 'enabled' => true } }
322
- }
323
- )
324
- end
325
- end
326
- end
327
-
328
- describe '#policies_from_cachefile' do
329
- context 'with no cache file' do
330
- it 'should return nil' do
331
- rust_policies = double('rust_policies')
332
-
333
- expect(TCellAgent::Policies::RustPolicies).to receive(:new).and_return(rust_policies)
334
- expect(File).to receive(:exist?).with(%r{tcell/cache/tcell_agent.cache}).and_return(false)
335
- expect_any_instance_of(TCellAgent::Agent).to_not receive(:process_policy_json)
336
- agent = TCellAgent::Agent.new(Process.pid)
337
-
338
- expect(agent.policies).to eq({ 'rust' => rust_policies })
339
- end
340
- end
341
-
342
- context 'with a cache file present' do
343
- context 'that is empty' do
344
- it 'should raise a json error' do
345
- cache_file = double('cache_file')
346
- expect(File).to receive(:exist?).with(%r{tcell/cache/tcell_agent.cache}).and_return(true)
347
- expect(File).to receive(:open).and_return(cache_file)
348
- expect(cache_file).to receive(:flock).and_return(true)
349
- expect(cache_file).to receive(:read).and_return('')
350
- expect(cache_file).to receive(:close)
351
-
352
- logger = double('logger')
353
- expect(TCellAgent).to receive(:logger).and_return(logger)
354
- expect(logger).to receive(:warn).with('A JSON text must at least contain two octets!')
355
-
356
- rust_policies = double('rust_policies')
357
- expect(TCellAgent::Policies::RustPolicies).to receive(:new).and_return(rust_policies)
358
-
359
- expect_any_instance_of(TCellAgent::Agent).to_not receive(:process_policy_json)
360
-
361
- agent = TCellAgent::Agent.new(Process.pid)
362
-
363
- expect(agent.policies).to eq({ 'rust' => rust_policies })
364
- end
365
- end
366
-
367
- context 'that has content' do
368
- context 'that is malformed' do
369
- it 'should raise a json error' do
370
- cache_file = double('cache_file')
371
- expect(File).to receive(:exist?).with(%r{tcell/cache/tcell_agent.cache}).and_return(true)
372
- expect(File).to receive(:open).and_return(cache_file)
373
- expect(cache_file).to receive(:flock).and_return(true)
374
- expect(cache_file).to receive(:read).and_return('bad_json')
375
- expect(cache_file).to receive(:close)
376
-
377
- logger = double('logger')
378
- expect(TCellAgent).to receive(:logger).and_return(logger)
379
- expect(logger).to receive(:warn).with(/unexpected token at 'bad_json'/)
380
- expect_any_instance_of(TCellAgent::Agent).to_not receive(:process_policy_json)
381
-
382
- rust_policies = double('rust_policies')
383
- expect(TCellAgent::Policies::RustPolicies).to receive(:new).and_return(rust_policies)
384
-
385
- agent = TCellAgent::Agent.new(Process.pid)
386
-
387
- expect(agent.policies).to eq({ 'rust' => rust_policies })
388
- end
389
- end
390
-
391
- context 'that is an empty json object' do
392
- it 'should raise a json error' do
393
- cache_file = double('cache_file')
394
- expect(File).to receive(:exist?).with(%r{tcell/cache/tcell_agent.cache}).and_return(true)
395
- expect(File).to receive(:open).and_return(cache_file)
396
- expect(cache_file).to receive(:flock).and_return(true)
397
- expect(cache_file).to receive(:read).and_return('{}')
398
- expect(cache_file).to receive(:close)
399
-
400
- expect(TCellAgent).to_not receive(:logger)
401
-
402
- expect(TCellAgent::Policies::RustPolicies).to receive(:new).and_return(nil)
403
- expect_any_instance_of(TCellAgent::Agent).to receive(:process_policy_json).with({}, false)
404
-
405
- TCellAgent::Agent.new(Process.pid)
406
- end
407
- end
408
-
409
- context 'that is a valid policy' do
410
- it 'should set the policies' do
411
- cache_file = double('cache_file')
412
- expect(File).to receive(:exist?).with(%r{tcell/cache/tcell_agent.cache}).and_return(true)
413
- expect(File).to receive(:open).and_return(cache_file)
414
- expect(cache_file).to receive(:flock).and_return(true)
415
- expect(cache_file).to receive(:read).and_return(
416
- {
417
- :process_0 => {
418
- :app_id => 'raftest-EyJZR',
419
- :policy_id => 'policy_id',
420
- :data => { :enabled => true }
421
- }
422
- }.to_json
423
- )
424
- expect(cache_file).to receive(:close)
425
- expect_any_instance_of(TCellAgent::Agent).to receive(:process_policy_json).with(
426
- {
427
- 'process_0' => {
428
- 'app_id' => 'raftest-EyJZR',
429
- 'policy_id' => 'policy_id',
430
- 'data' => { 'enabled' => true }
431
- }
432
- },
433
- false
434
- )
435
- expect(TCellAgent::Policies::RustPolicies).to receive(:new).and_return(nil)
436
-
437
- TCellAgent::Agent.new(Process.pid)
438
- end
439
- end
440
- end
441
- end
442
- end
443
-
444
- describe '#policy_polling_iteration' do
445
- context 'with policy polling errors' do
446
- it 'should extend failure sleep time after each failure' do
447
- configuration = double(
448
- 'configuration',
449
- {
450
- :should_start_policy_poll? => false,
451
- :event_time_limit_seconds => nil,
452
- :event_batch_size_limit => nil,
453
- :preload_policy_filename => nil,
454
- :cache_filename_with_app_id => 'cache-file.app_id'
455
- }
456
- )
457
-
458
- api = double('api')
459
- logger = double('logger')
460
-
461
- expect(TCellAgent).to receive(:configuration).and_return(configuration).at_least(:once)
462
- expect(TCellAgent::TCellApi).to receive(:new).and_return(api)
463
- expect(TCellAgent::Policies::RustPolicies).to receive(:new).and_return(nil)
464
- agent = TCellAgent::Agent.new
465
-
466
- # failure sleep time should double after each failed attempt to retrieve policies
467
- # until it reaches 480 seconds
468
- failure_sleep_time = 30
469
- last_poll_time = 0
470
-
471
- # 1st attempt
472
- expect(api).to receive(:poll_api).with(0).and_return(nil)
473
- expect(TCellAgent).to receive(:logger).and_return(logger)
474
- expect(logger).to receive(:error).with(
475
- "Policy was nil. Sleeping for #{failure_sleep_time}"
476
- )
477
- expect(agent).to receive(:sleep).with(failure_sleep_time)
478
- failure_sleep_time, last_poll_time = agent.policy_polling_iteration(failure_sleep_time, last_poll_time)
479
-
480
- expect(failure_sleep_time).to eq(60)
481
- expect(last_poll_time).to eq(0)
482
-
483
- # 2nd attempt
484
- expect(api).to receive(:poll_api).with(0).and_return(nil)
485
- expect(TCellAgent).to receive(:logger).and_return(logger)
486
- expect(logger).to receive(:error).with(
487
- "Policy was nil. Sleeping for #{failure_sleep_time}"
488
- )
489
- expect(agent).to receive(:sleep).with(failure_sleep_time)
490
- failure_sleep_time, last_poll_time = agent.policy_polling_iteration(failure_sleep_time, last_poll_time)
491
-
492
- expect(failure_sleep_time).to eq(120)
493
- expect(last_poll_time).to eq(0)
494
-
495
- # 3rd attempt
496
- expect(api).to receive(:poll_api).with(0).and_return(nil)
497
- expect(TCellAgent).to receive(:logger).and_return(logger)
498
- expect(logger).to receive(:error).with(
499
- "Policy was nil. Sleeping for #{failure_sleep_time}"
500
- )
501
- expect(agent).to receive(:sleep).with(failure_sleep_time)
502
- failure_sleep_time, last_poll_time = agent.policy_polling_iteration(failure_sleep_time, last_poll_time)
503
-
504
- expect(failure_sleep_time).to eq(240)
505
- expect(last_poll_time).to eq(0)
506
-
507
- # 4th attempt
508
- expect(api).to receive(:poll_api).with(0).and_return(nil)
509
- expect(TCellAgent).to receive(:logger).and_return(logger)
510
- expect(logger).to receive(:error).with(
511
- "Policy was nil. Sleeping for #{failure_sleep_time}"
512
- )
513
- expect(agent).to receive(:sleep).with(failure_sleep_time)
514
- failure_sleep_time, last_poll_time = agent.policy_polling_iteration(failure_sleep_time, last_poll_time)
515
-
516
- expect(failure_sleep_time).to eq(480)
517
- expect(last_poll_time).to eq(0)
518
-
519
- # 5th attempt
520
- expect(api).to receive(:poll_api).with(0).and_return(nil)
521
- expect(TCellAgent).to receive(:logger).and_return(logger)
522
- expect(logger).to receive(:error).with(
523
- "Policy was nil. Sleeping for #{failure_sleep_time}"
524
- )
525
- expect(agent).to receive(:sleep).with(failure_sleep_time)
526
- failure_sleep_time, last_poll_time = agent.policy_polling_iteration(failure_sleep_time, last_poll_time)
527
-
528
- expect(failure_sleep_time).to eq(480)
529
- expect(last_poll_time).to eq(0)
530
- end
531
- end
532
- end
533
- end
534
- end
535
- end