tcell_agent 0.2.29.rc2 → 0.2.29

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/bin/tcell_agent +16 -4
  3. data/lib/tcell_agent/agent/event_processor.rb +2 -8
  4. data/lib/tcell_agent/agent/fork_pipe_manager.rb +0 -2
  5. data/lib/tcell_agent/agent/policy_manager.rb +12 -18
  6. data/lib/tcell_agent/api.rb +50 -27
  7. data/lib/tcell_agent/appsensor/injections_reporter.rb +7 -5
  8. data/lib/tcell_agent/appsensor/sensor.rb +8 -4
  9. data/lib/tcell_agent/config/unknown_options.rb +116 -0
  10. data/lib/tcell_agent/configuration.rb +17 -20
  11. data/lib/tcell_agent/instrumentation.rb +0 -1
  12. data/lib/tcell_agent/logger.rb +17 -21
  13. data/lib/tcell_agent/patches/block_rule.rb +43 -8
  14. data/lib/tcell_agent/patches/meta_data.rb +2 -1
  15. data/lib/tcell_agent/patches/sensors_matcher.rb +2 -1
  16. data/lib/tcell_agent/policies/appsensor/database_sensor.rb +5 -2
  17. data/lib/tcell_agent/policies/appsensor/misc_sensor.rb +10 -3
  18. data/lib/tcell_agent/policies/appsensor/payloads_policy.rb +8 -3
  19. data/lib/tcell_agent/policies/appsensor/request_size_sensor.rb +1 -1
  20. data/lib/tcell_agent/policies/appsensor/response_codes_sensor.rb +7 -2
  21. data/lib/tcell_agent/policies/appsensor/size_sensor.rb +7 -3
  22. data/lib/tcell_agent/policies/appsensor/sqli_sensor.rb +3 -5
  23. data/lib/tcell_agent/policies/appsensor/user_agent_sensor.rb +6 -2
  24. data/lib/tcell_agent/policies/appsensor/xss_sensor.rb +3 -5
  25. data/lib/tcell_agent/policies/appsensor_policy.rb +11 -6
  26. data/lib/tcell_agent/policies/content_security_policy.rb +19 -14
  27. data/lib/tcell_agent/rails/dlp.rb +1 -1
  28. data/lib/tcell_agent/rails/middleware/headers_middleware.rb +10 -7
  29. data/lib/tcell_agent/rails/on_start.rb +0 -1
  30. data/lib/tcell_agent/sensor_events/appsensor_event.rb +7 -5
  31. data/lib/tcell_agent/sinatra.rb +3 -6
  32. data/lib/tcell_agent/start_background_thread.rb +0 -7
  33. data/lib/tcell_agent/utils/strings.rb +18 -0
  34. data/lib/tcell_agent/version.rb +1 -1
  35. data/spec/lib/tcell_agent/api/api_spec.rb +1 -1
  36. data/spec/lib/tcell_agent/appsensor/injections_reporter_spec.rb +1 -1
  37. data/spec/lib/tcell_agent/config/unknown_options_spec.rb +188 -0
  38. data/spec/lib/tcell_agent/configuration_spec.rb +56 -0
  39. data/spec/lib/tcell_agent/patches/block_rule_spec.rb +110 -16
  40. data/spec/lib/tcell_agent/policies/appsensor/payloads_policy_log_spec.rb +226 -293
  41. data/spec/lib/tcell_agent/policies/appsensor/response_codes_sensor_spec.rb +32 -4
  42. data/spec/lib/tcell_agent/policies/appsensor_policy_spec.rb +11 -0
  43. data/spec/lib/tcell_agent/utils/strings_spec.rb +50 -0
  44. data/spec/support/static_agent_overrides.rb +1 -1
  45. data/tcell_agent.gemspec +1 -3
  46. metadata +9 -37
  47. data/lib/tcell_agent/rails/tracing.rb +0 -22
  48. data/spec/integration/puma.rb +0 -195
@@ -1,3 +1,4 @@
1
+ require 'libinjection/libinjection'
1
2
  require 'tcell_agent/policies/appsensor/injection_sensor'
2
3
 
3
4
  module TCellAgent
@@ -21,11 +22,8 @@ module TCellAgent
21
22
  end
22
23
 
23
24
  def find_vulnerability(param_name, param_value)
24
- if @libinjection
25
- require 'libinjection/libinjection'
26
- if Libinjection.is_sqli(param_value) == 1
27
- return {"param" => param_name, "value" => param_value, "pattern" => "li"}
28
- end
25
+ if @libinjection && Libinjection.is_sqli(param_value) == 1
26
+ return {"param" => param_name, "value" => param_value, "pattern" => "li"}
29
27
  end
30
28
 
31
29
  super(param_name, param_value)
@@ -6,16 +6,18 @@ module TCellAgent
6
6
  class UserAgentSensor
7
7
  DP_CODE = "uaempty"
8
8
 
9
- attr_accessor :enabled, :empty_enabled, :excluded_route_ids
9
+ attr_accessor :enabled, :empty_enabled, :excluded_route_ids, :collect_full_uri
10
10
 
11
11
  def initialize(policy_json=nil)
12
12
  @enabled = false
13
13
  @empty_enabled = false
14
14
  @excluded_route_ids = {}
15
+ @collect_full_uri = false
15
16
 
16
17
  if policy_json
17
18
  @enabled = policy_json.fetch("enabled", false)
18
19
  @empty_enabled = policy_json.fetch("empty_enabled", false)
20
+ @collect_full_uri = policy_json.fetch("collect_full_uri", @collect_full_uri)
19
21
 
20
22
  policy_json.fetch("exclude_routes", []).each do |excluded_route|
21
23
  @excluded_route_ids[excluded_route] = true
@@ -30,7 +32,9 @@ module TCellAgent
30
32
 
31
33
  user_agent = appsensor_meta.user_agent
32
34
  if !user_agent || user_agent.strip == ""
33
- TCellAgent::AppSensor::Sensor.send_event(appsensor_meta, DP_CODE, nil, nil, nil, nil)
35
+ TCellAgent::AppSensor::Sensor.send_event(
36
+ appsensor_meta, DP_CODE, nil, nil, nil, nil, @collect_full_uri
37
+ )
34
38
  end
35
39
  end
36
40
 
@@ -1,3 +1,4 @@
1
+ require 'libinjection/libinjection'
1
2
  require 'tcell_agent/policies/appsensor/injection_sensor'
2
3
 
3
4
  module TCellAgent
@@ -21,11 +22,8 @@ module TCellAgent
21
22
  end
22
23
 
23
24
  def find_vulnerability(param_name, param_value)
24
- if @libinjection
25
- require 'libinjection/libinjection'
26
- if Libinjection.is_xss(param_value) == 1
27
- return {"param" => param_name, "value" => param_value, "pattern" => "li"}
28
- end
25
+ if @libinjection && Libinjection.is_xss(param_value) == 1
26
+ return {"param" => param_name, "value" => param_value, "pattern" => "li"}
29
27
  end
30
28
 
31
29
  super(param_name, param_value)
@@ -149,26 +149,31 @@ module TCellAgent
149
149
  if policy_json["version"] && policy_json["version"] == 2
150
150
  if data_json
151
151
  sensors_json = data_json.fetch("sensors", {})
152
+
152
153
  if sensors_json.empty?
153
154
  sensor_policy.enabled = false
154
155
 
155
156
  else
156
157
  sensor_policy.enabled = true
157
158
 
159
+ options_hash = data_json.fetch("options", {})
160
+ collect_full_uri = options_hash.fetch("uri_options", {}).fetch("collect_full_uri", false)
161
+
158
162
  DETECTION_POINTS_V2_NON_INJECTION.each do |sensor_name, sensor_class|
159
163
  settings = sensors_json.fetch(sensor_name, {})
160
164
  updated_settings = {
161
- "enabled" => sensors_json.has_key?(sensor_name)
165
+ "enabled" => sensors_json.has_key?(sensor_name),
166
+ "collect_full_uri" => collect_full_uri
162
167
  }.merge(settings)
163
168
 
164
- sensor_policy.options[sensor_name] = sensor_class.new(updated_settings)
169
+ sensor_policy.options[sensor_name] =
170
+ sensor_class.new(updated_settings)
165
171
  end
166
172
 
167
- payloads_policy = PayloadsPolicy.from_json(
168
- data_json.fetch("options", {})
169
- )
173
+ payloads_policy = PayloadsPolicy.from_json(options_hash)
170
174
  sensor_policy.injections_reporter =
171
- TCellAgent::AppSensor::InjectionsReporter.from_json(2, sensors_json, payloads_policy)
175
+ TCellAgent::AppSensor::InjectionsReporter.from_json(
176
+ 2, sensors_json, payloads_policy, collect_full_uri)
172
177
  end
173
178
  end
174
179
 
@@ -40,11 +40,6 @@ module TCellAgent
40
40
  self.raw_value = value
41
41
  self.report_uri = report_uri
42
42
  end
43
- def self.jhash(str)
44
- str.each_char.reduce(0) do |result, char|
45
- [((result << 5) - result) + char.ord].pack('L').unpack('l').first
46
- end
47
- end
48
43
  def value(transaction_id=nil, route_id=nil, session_id=nil, user_id=nil)
49
44
  if !self.report_uri
50
45
  return self.raw_value
@@ -66,7 +61,7 @@ module TCellAgent
66
61
  end
67
62
  report_uri = uri.to_s
68
63
  if self.policy_id
69
- checksum = ContentSecurityPolicyHeader.jhash(self.policy_id + report_uri)
64
+ checksum = TCellAgent::Utils::Strings.java_hashcode(self.policy_id + report_uri)
70
65
  if new_query_ar != []
71
66
  report_uri = report_uri + "&"
72
67
  else
@@ -85,17 +80,27 @@ module TCellAgent
85
80
  attr_accessor :policy_id
86
81
  attr_accessor :js_agent_api_key
87
82
 
88
- def each(transaction_id=nil, route_id=nil, hmac_session_id=nil, user_id=nil, &block)
89
- result = []
90
- headers.each do | header |
83
+ def each_header_pair(transaction_id=nil, route_id=nil, hmac_session_id=nil, user_id=nil, path=nil)
84
+ max_csp_header_bytes = TCellAgent.configuration.max_csp_header_bytes
85
+
86
+ headers.each do |header|
91
87
  header_value = header.value(transaction_id, route_id, hmac_session_id)
92
- header_names = ContentSecurityPolicy.cspHeadersForType(header.type)
93
- header_names.each do | header_name |
94
- result.push( {"name"=>header_name, "value"=>header_value} )
95
- end #doloop
88
+
89
+ if !max_csp_header_bytes || header_value.bytesize <= max_csp_header_bytes
90
+ header_names = ContentSecurityPolicy.cspHeadersForType(header.type)
91
+ header_names.each do | header_name |
92
+ yield(header_name, header_value)
93
+ end
94
+
95
+ else
96
+ TCellAgent.logger.warn(
97
+ "[RouteID=#{route_id},Path=#{path}] CSP header(#{header_value.bytesize}) " +
98
+ "is bigger than configured max_csp_header_bytes(#{max_csp_header_bytes})"
99
+ )
100
+ end
96
101
  end
97
- result.each(&block)
98
102
  end
103
+
99
104
  def self.from_json(policy_json)
100
105
  if (!policy_json)
101
106
  return nil
@@ -127,7 +127,7 @@ module TCellAgent
127
127
  if appsensor_policy
128
128
  request_env = TCellAgent::Instrumentation::Rails::Middleware::ContextMiddleware::THREADS.fetch(Thread.current.object_id, {})
129
129
  tcell_data = request_env[TCellAgent::Instrumentation::TCELL_ID]
130
- if tcell_data && e.is_a?(ActiveRecord::StatementInvalid)
130
+ if tcell_data && result.is_a?(ActiveRecord::StatementInvalid)
131
131
  appsensor_policy.sql_exception_detected(tcell_data, result)
132
132
  end
133
133
  end
@@ -57,12 +57,15 @@ module TCellAgent
57
57
  content_security_policy = TCellAgent.policy(TCellAgent::PolicyTypes::CSP)
58
58
 
59
59
  if content_security_policy
60
- content_security_policy.each(
61
- request.env[TCellAgent::Instrumentation::TCELL_ID].transaction_id,
62
- request.env[TCellAgent::Instrumentation::TCELL_ID].route_id,
63
- request.env[TCellAgent::Instrumentation::TCELL_ID].hmac_session_id,
64
- request.env[TCellAgent::Instrumentation::TCELL_ID].user_id) do | header_pair |
65
- headers[header_pair["name"]] = header_pair["value"]
60
+ tcell_context = request.env[TCellAgent::Instrumentation::TCELL_ID]
61
+ content_security_policy.each_header_pair(
62
+ tcell_context.transaction_id,
63
+ tcell_context.route_id,
64
+ tcell_context.hmac_session_id,
65
+ tcell_context.user_id,
66
+ tcell_context.path
67
+ ) do |header_name, header_value|
68
+ headers[header_name] = header_value
66
69
  end
67
70
  end
68
71
  response = [status, headers, active_response]
@@ -187,7 +190,7 @@ module TCellAgent
187
190
  appsensor_policy = TCellAgent.policy(TCellAgent::PolicyTypes::AppSensor)
188
191
  if appsensor_policy
189
192
  event = TCellAgent::SensorEvents::AppSensorMetaEvent.build(
190
- request, content_length, status_code.to_i, response_headers
193
+ request, content_length, status_code, response_headers
191
194
  )
192
195
  TCellAgent.send_event(event)
193
196
 
@@ -8,7 +8,6 @@ require 'tcell_agent/configuration'
8
8
 
9
9
  require 'tcell_agent/rails/routes'
10
10
  require 'tcell_agent/rails/dlp/process_request'
11
- require 'tcell_agent/rails/tracing'
12
11
 
13
12
  TCellAgent::Instrumentation::Rails.send_language_info
14
13
  TCellAgent::Instrumentation::Rails.send_framework_info
@@ -12,11 +12,12 @@ module TCellAgent
12
12
  remote_addr,
13
13
  param,
14
14
  route_id,
15
- meta=nil,
16
- hmac_session_id=nil,
17
- user_id=nil,
18
- payload=nil,
19
- pattern=nil)
15
+ meta,
16
+ hmac_session_id,
17
+ user_id,
18
+ payload,
19
+ pattern,
20
+ collect_full_uri)
20
21
  super("as")
21
22
  self["dp"] = detection_point
22
23
  self["param"] = param.to_s if param
@@ -30,6 +31,7 @@ module TCellAgent
30
31
  self["pattern"] = pattern if pattern
31
32
  self["meta"] = meta if meta
32
33
  self["rid"] = route_id if route_id
34
+ self["full_uri"] = location if collect_full_uri && location
33
35
  end
34
36
 
35
37
  def post_process
@@ -8,18 +8,15 @@ require 'tcell_agent/instrumentation'
8
8
  module TCellAgent
9
9
  class Sinatra::Response
10
10
  include Sinatra
11
+
11
12
  alias_method :original_finish, :finish
12
13
  def finish
13
14
  status, headers, response = original_finish
14
-
15
15
  TCellAgent::Instrumentation.safe_block("Setting CSP Headers") {
16
16
  content_security_policy = TCellAgent.policy(TCellAgent::PolicyTypes::CSP)
17
17
  if content_security_policy
18
- content_security_policy.each(
19
- nil,
20
- nil,
21
- nil) do | header_pair |
22
- headers[header_pair["name"]] = header_pair["value"]
18
+ content_security_policy.each_header_pair do |header_name, header_value|
19
+ headers[header_name] = header_value
23
20
  end
24
21
  end
25
22
  }
@@ -2,12 +2,6 @@
2
2
  require 'tcell_agent/configuration'
3
3
 
4
4
  if (TCellAgent.configuration.disable_all == false)
5
- require 'objspace'
6
-
7
- if ObjectSpace.respond_to?(:trace_object_allocations_start)
8
- ObjectSpace.trace_object_allocations_start
9
- end
10
-
11
5
  require 'tcell_agent/logger'
12
6
  require 'tcell_agent/agent'
13
7
  require 'thread'
@@ -18,7 +12,6 @@ if (TCellAgent.configuration.disable_all == false)
18
12
  def self.run_instrumentation(server_name, send_startup_events=true)
19
13
 
20
14
  require 'tcell_agent/rails/on_start' if defined?(Rails)
21
- require 'rbtrace'
22
15
 
23
16
  TCellAgent::Instrumentation.safe_block("Starting thread agent") do
24
17
  TCellAgent.logger.debug("Instrumenting: #{server_name}")
@@ -10,6 +10,24 @@ module TCellAgent
10
10
  def self.present?(str)
11
11
  !self.blank?(str)
12
12
  end
13
+
14
+ def self.remove_trailing_slash(path)
15
+ if path && path != "/"
16
+ return path.chomp("/")
17
+ end
18
+
19
+ return path
20
+ end
21
+
22
+ # emulate the java String.hashcode() without upcasting to BigInt
23
+ def self.java_hashcode(str)
24
+ result = 0
25
+ str.each_codepoint do |cp|
26
+ # prevent overflow into BigInt which would cause heap allocs + emulate c-style int32 signed add overflow
27
+ result = ((((((result & 0x07FFFFFF) << 5) - result) + cp) + 0x80000000) & 0xFFFFFFFF) - 0x80000000
28
+ end
29
+ result
30
+ end
13
31
  end
14
32
  end
15
33
  end
@@ -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 = "0.2.29.rc2"
4
+ VERSION = "0.2.29"
5
5
  end
@@ -26,7 +26,7 @@ module TCellAgent
26
26
  } })
27
27
 
28
28
  # to_return(:body => resbody,
29
- result = tapi.pollAPI
29
+ result = tapi.poll_api()
30
30
  TCellAgent.configuration.app_id = nil
31
31
  TCellAgent.configuration.api_key = nil
32
32
  expect(result["csp-headers"]["app_id"]).to eq("testapp-Becwu")
@@ -9,7 +9,7 @@ module TCellAgent
9
9
  before(:each) do
10
10
  @payloads_policy = double("payloads_policy")
11
11
  @injections_matcher = double("injections_matcher")
12
- @injections_reporter = InjectionsReporter.new(@injections_matcher, @payloads_policy)
12
+ @injections_reporter = InjectionsReporter.new(@injections_matcher, @payloads_policy, false)
13
13
 
14
14
  @appsensor_meta = TCellAgent::SensorEvents::AppSensorMetaEvent.new
15
15
  @appsensor_meta.remote_address = "remote_address"
@@ -0,0 +1,188 @@
1
+ require 'spec_helper'
2
+
3
+ module TCellAgent
4
+ module Config
5
+
6
+ describe Validate do
7
+ describe ".get_unknown_options" do
8
+ context "with an unknown tcell environment variable set" do
9
+ it "should return a message about the unknown variable" do
10
+
11
+ orig_allow_uap = ENV.fetch("TCELL_AGENT_ALLOW_UNENCRYPTED_APPSENSOR_PAYLOADS", nil)
12
+ orig_allow_uafp = ENV.fetch("TCELL_AGENT_ALLOW_UNENCRYPTED_APPFIREWALL_PAYLOADS", nil)
13
+ orig_demomode = ENV.fetch("TCELL_DEMOMODE", nil)
14
+ orig_agent_home = ENV.fetch("TCELL_AGENT_HOME", nil)
15
+ orig_agent_log_dir = ENV.fetch("TCELL_AGENT_LOG_DIR", nil)
16
+ orig_agent_config = ENV.fetch("TCELL_AGENT_CONFIG", nil)
17
+ orig_agent_app_id = ENV.fetch("TCELL_AGENT_APP_ID", nil)
18
+ orig_agent_api_key = ENV.fetch("TCELL_AGENT_API_KEY", nil)
19
+ orig_agent_host_identifier = ENV.fetch("TCELL_AGENT_HOST_IDENTIFIER", nil)
20
+ orig_input_url = ENV.fetch("TCELL_INPUT_URL", nil)
21
+ orig_hmac_key = ENV.fetch("TCELL_HMAC_KEY", nil)
22
+ orig_api_url = ENV.fetch("TCELL_API_URL", nil)
23
+
24
+ ENV["TCELL_HACK"] = "hack the system"
25
+ ENV["TCELL_AGENT_ALLOW_UNENCRYPTED_APPSENSOR_PAYLOADS"] = "valid"
26
+ ENV["TCELL_AGENT_ALLOW_UNENCRYPTED_APPFIREWALL_PAYLOADS"] = "valid"
27
+ ENV["TCELL_DEMOMODE"] = "valid"
28
+ ENV["TCELL_AGENT_HOME"] = "valid"
29
+ ENV["TCELL_AGENT_LOG_DIR"] = "valid"
30
+ ENV["TCELL_AGENT_CONFIG"] = "valid"
31
+ ENV["TCELL_AGENT_APP_ID"] = "valid"
32
+ ENV["TCELL_AGENT_API_KEY"] = "valid"
33
+ ENV["TCELL_AGENT_HOST_IDENTIFIER"] = "valid"
34
+ ENV["TCELL_INPUT_URL"] = "valid"
35
+ ENV["TCELL_HMAC_KEY"] = "valid"
36
+ ENV["TCELL_API_URL"] = "valid"
37
+
38
+ messages = Validate.get_unknown_options(nil)
39
+
40
+ ENV.delete "TCELL_HACK"
41
+ if orig_allow_uap
42
+ ENV["TCELL_AGENT_ALLOW_UNENCRYPTED_APPSENSOR_PAYLOADS"] = orig_allow_uap
43
+ else
44
+ ENV.delete "TCELL_AGENT_ALLOW_UNENCRYPTED_APPSENSOR_PAYLOADS"
45
+ end
46
+
47
+ if orig_allow_uafp
48
+ ENV["TCELL_AGENT_ALLOW_UNENCRYPTED_APPFIREWALL_PAYLOADS"] = orig_allow_uafp
49
+ else
50
+ ENV.delete "TCELL_AGENT_ALLOW_UNENCRYPTED_APPFIREWALL_PAYLOADS"
51
+ end
52
+ if orig_demomode
53
+ ENV["TCELL_DEMOMODE"] = orig_demomode
54
+ else
55
+ ENV.delete "TCELL_DEMOMODE"
56
+ end
57
+ if orig_agent_home
58
+ ENV["TCELL_AGENT_HOME"] = orig_agent_home
59
+ else
60
+ ENV.delete "TCELL_AGENT_HOME"
61
+ end
62
+ if orig_agent_log_dir
63
+ ENV["TCELL_AGENT_LOG_DIR"] = orig_agent_log_dir
64
+ else
65
+ ENV.delete "TCELL_AGENT_LOG_DIR"
66
+ end
67
+ if orig_agent_config
68
+ ENV["TCELL_AGENT_CONFIG"] = orig_agent_config
69
+ else
70
+ ENV.delete "TCELL_AGENT_CONFIG"
71
+ end
72
+ if orig_agent_app_id
73
+ ENV["TCELL_AGENT_APP_ID"] = orig_agent_app_id
74
+ else
75
+ ENV.delete "TCELL_AGENT_APP_ID"
76
+ end
77
+ if orig_agent_api_key
78
+ ENV["TCELL_AGENT_API_KEY"] = orig_agent_api_key
79
+ else
80
+ ENV.delete "TCELL_AGENT_API_KEY"
81
+ end
82
+ if orig_agent_host_identifier
83
+ ENV["TCELL_AGENT_HOST_IDENTIFIER"] = orig_agent_host_identifier
84
+ else
85
+ ENV.delete "TCELL_AGENT_HOST_IDENTIFIER"
86
+ end
87
+ if orig_input_url
88
+ ENV["TCELL_INPUT_URL"] = orig_input_url
89
+ else
90
+ ENV.delete "TCELL_INPUT_URL"
91
+ end
92
+ if orig_hmac_key
93
+ ENV["TCELL_HMAC_KEY"] = orig_hmac_key
94
+ else
95
+ ENV.delete "TCELL_HMAC_KEY"
96
+ end
97
+ if orig_api_url
98
+ ENV["TCELL_API_URL"] = orig_api_url
99
+ else
100
+ ENV.delete "TCELL_API_URL"
101
+ end
102
+
103
+ expect(messages.sort).to eq([
104
+ "Unrecognized environment parameter (TCELL_*) found: TCELL_HACK"
105
+ ])
106
+ end
107
+ end
108
+
109
+ context "with a config json with all options including some extra ones" do
110
+ it "should report the extra options in messages" do
111
+ config_json = {
112
+ "first_level" => "boo",
113
+ "version" => 1,
114
+ "applications" => [{
115
+ "second_level" => "boo",
116
+ "name" => "name",
117
+ "app_id" => "app id",
118
+ "api_key" => "api key",
119
+ "fetch_policies_from_tcell" => true,
120
+ "preload_policy_filename" => "preload policy filename",
121
+ "log_dir" => "custom log dir",
122
+ "logging_options" => {
123
+ "logging_level" => "boo",
124
+ "enabled" => true,
125
+ "level" => "DEBUG",
126
+ "filename" => "filename"},
127
+ "tcell_api_url" => "tcell api url",
128
+ "tcell_input_url" => "tcell input url",
129
+ "host_identifier" => "host identifier",
130
+ "hipaaSafeMode" => "hipaa safe mode",
131
+ "hmac_key" => "hmac key",
132
+ "js_agent_api_base_url" => "js agent api base url",
133
+ "js_agent_url" => "js agent url",
134
+ "max_csp_header_bytes" => 512,
135
+ "event_batch_size_limit" => 50,
136
+ "allow_unencrypted_appsensor_payloads" => true,
137
+ "allow_unencrypted_appfirewall_payloads" => true,
138
+ "data_exposure" => {
139
+ "data_ex_level" => "boo",
140
+ "max_data_ex_db_records_per_request" => 10000},
141
+ "reverse_proxy" => true,
142
+ "reverse_proxy_ip_address_header" => "reverse proxy ip address header",
143
+ "demomode" => true,
144
+ # Ruby only
145
+ "disable_all" => false,
146
+ "enabled" => true,
147
+ "enable_event_manager" => true,
148
+ "enable_event_consumer" => true,
149
+ "enable_policy_polling" => true,
150
+ "enable_instrumentation" => true,
151
+ "enable_intercept_requests" => true,
152
+ "instrument_for_events" => true,
153
+ "agent_home_owner" => true,
154
+ "enabled_instrumentations" => {
155
+ "enabled_instrumentations_level" => "blah",
156
+ "doorkeeper" => true,
157
+ "devise" => true,
158
+ "authlogic" => true}}]}
159
+
160
+ messages = Validate.get_unknown_options(config_json)
161
+
162
+ expect(messages.sort).to eq([
163
+ "Unrecognized config setting key: data_ex_level",
164
+ "Unrecognized config setting key: enabled_instrumentations_level",
165
+ "Unrecognized config setting key: first_level",
166
+ "Unrecognized config setting key: logging_level",
167
+ "Unrecognized config setting key: second_level"
168
+ ])
169
+ end
170
+ end
171
+
172
+ context "with a config json that has more than one application" do
173
+ it "should report the misconfiguration" do
174
+ config_json = {"version" => 1, "applications" => [{}, {}]}
175
+
176
+ messages = Validate.get_unknown_options(config_json)
177
+
178
+ expect(messages.sort).to eq([
179
+ "Multiple applications detected in config file"
180
+ ])
181
+ end
182
+ end
183
+ end
184
+ end
185
+
186
+ end
187
+ end
188
+