contrast-agent 7.3.2 → 7.4.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/lib/contrast/agent/protect/rule/base.rb +5 -1
  3. data/lib/contrast/agent/protect/rule/cmdi/cmd_injection.rb +17 -5
  4. data/lib/contrast/agent/protect/rule/input_classification/base.rb +7 -2
  5. data/lib/contrast/agent/protect/rule/input_classification/encoding.rb +1 -1
  6. data/lib/contrast/agent/protect/rule/path_traversal/path_traversal.rb +8 -1
  7. data/lib/contrast/agent/protect/rule/sqli/sqli.rb +8 -1
  8. data/lib/contrast/agent/protect/state.rb +110 -0
  9. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +2 -0
  10. data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +2 -0
  11. data/lib/contrast/agent/reporting/reporting_events/finding.rb +1 -0
  12. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +4 -0
  13. data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +2 -0
  14. data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +2 -0
  15. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +9 -5
  16. data/lib/contrast/agent/reporting/reporting_events/reportable_hash.rb +30 -6
  17. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -1
  18. data/lib/contrast/agent/reporting/reporting_utilities/resend.rb +1 -1
  19. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +1 -5
  20. data/lib/contrast/agent/reporting/settings/protect.rb +3 -3
  21. data/lib/contrast/agent/reporting/settings/sampling.rb +5 -4
  22. data/lib/contrast/agent/version.rb +1 -1
  23. data/lib/contrast/components/agent.rb +3 -5
  24. data/lib/contrast/components/api.rb +3 -3
  25. data/lib/contrast/components/assess_rules.rb +1 -2
  26. data/lib/contrast/components/base.rb +1 -2
  27. data/lib/contrast/components/config/sources.rb +23 -0
  28. data/lib/contrast/components/logger.rb +19 -0
  29. data/lib/contrast/components/protect.rb +55 -14
  30. data/lib/contrast/components/sampling.rb +5 -12
  31. data/lib/contrast/components/security_logger.rb +17 -0
  32. data/lib/contrast/components/settings.rb +110 -76
  33. data/lib/contrast/config/certification_configuration.rb +1 -1
  34. data/lib/contrast/config/configuration_files.rb +0 -2
  35. data/lib/contrast/config/diagnostics/config.rb +3 -3
  36. data/lib/contrast/config/diagnostics/effective_config.rb +1 -1
  37. data/lib/contrast/config/diagnostics/environment_variables.rb +21 -11
  38. data/lib/contrast/config/diagnostics/monitor.rb +1 -1
  39. data/lib/contrast/config/diagnostics/singleton_tools.rb +170 -0
  40. data/lib/contrast/config/diagnostics/source_config_value.rb +14 -9
  41. data/lib/contrast/config/diagnostics/tools.rb +23 -84
  42. data/lib/contrast/config/request_audit_configuration.rb +1 -1
  43. data/lib/contrast/config/server_configuration.rb +3 -15
  44. data/lib/contrast/configuration.rb +5 -2
  45. data/lib/contrast/framework/manager.rb +4 -3
  46. data/lib/contrast/framework/manager_extend.rb +3 -1
  47. data/lib/contrast/framework/rack/support.rb +11 -2
  48. data/lib/contrast/utils/log_utils.rb +1 -1
  49. data/lib/contrast/utils/request_utils.rb +1 -1
  50. data/lib/contrast/utils/timer.rb +1 -1
  51. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a4ed370d3625c9e07c5966fb4e091e96cc37a6a2fce8376d63a547e655b27173
4
- data.tar.gz: 601a4767e4317af72e2c610df6ba19bb68df2c42f128bb873539204c93801019
3
+ metadata.gz: 1266effb11fb78123e8461ce7295f9b4a67a88b7dda632bc57da5d70cb39f87d
4
+ data.tar.gz: e553aa33bd73ab712585b774578c10ff6f19ae925fdea8adb89c3b6ac253e399
5
5
  SHA512:
6
- metadata.gz: 597307a8f3521cd9783c07ccc8b2f54d6bf2cf1631db84bd29fba683fbd93fc4f5eff47bbbc2ed50c37c02fd3c59d5df987526c839c5e731299cdb6e02e30c6f
7
- data.tar.gz: 95898f87cbabbcc24d9ce3f0d5ba1397b4399f9ca35f4c4a1290c7e3d9c7cd26d6bf13c99affc013dea2456260aeb918349a97905863ba790ba869a272faccfc
6
+ metadata.gz: 7abce257d4092010babc21cff242307343ea2fc83bdbd040b8cd95e64be9b2e640963a06ae017053989be17e98442bbc528987c2da5b8f7bc8688b776022c783
7
+ data.tar.gz: f85de50b08e0eaa5f5d8c6a571fe4d04a03cbbcaab1f9c7f2431dac6b4373b00e04f63be94b5f02d56e222248c5fe256b61fb43ba123d041e1ce585b80e63a5f
@@ -45,7 +45,6 @@ module Contrast
45
45
  #
46
46
  # @return mode [Symbol]
47
47
  def initialize
48
- ::Contrast::PROTECT.defend_rules[rule_name] = self
49
48
  @mode = mode_from_settings
50
49
  end
51
50
 
@@ -63,6 +62,11 @@ module Contrast
63
62
  RULE_NAME
64
63
  end
65
64
 
65
+ # Update state form Settings or Configuration.
66
+ def update
67
+ @mode = mode_from_settings
68
+ end
69
+
66
70
  # Should return the short name.
67
71
  #
68
72
  # @return [String]
@@ -31,15 +31,27 @@ module Contrast
31
31
  NAME
32
32
  end
33
33
 
34
+ # Sub-rules forwarders:
35
+
36
+ # @return [Contrast::Agent::Protect::Rule::CmdiBackdoors]
37
+ def command_backdoors
38
+ @_command_backdoors ||= Contrast::Agent::Protect::Rule::CmdiBackdoors.new
39
+ end
40
+
41
+ # @return [Contrast::Agent::Protect::Rule::CmdiChainedCommand]
42
+ def semantic_chained_commands
43
+ @_semantic_chained_commands ||= Contrast::Agent::Protect::Rule::CmdiChainedCommand.new
44
+ end
45
+
46
+ def semantic_dangerous_paths
47
+ @_semantic_dangerous_paths ||= Contrast::Agent::Protect::Rule::CmdiDangerousPath.new
48
+ end
49
+
34
50
  # Array of sub_rules:
35
51
  #
36
52
  # @return [Array]
37
53
  def sub_rules
38
- @_sub_rules ||= [
39
- Contrast::Agent::Protect::Rule::CmdiBackdoors.new,
40
- Contrast::Agent::Protect::Rule::CmdiChainedCommand.new,
41
- Contrast::Agent::Protect::Rule::CmdiDangerousPath.new
42
- ].cs__freeze
54
+ @_sub_rules ||= [command_backdoors, semantic_chained_commands, semantic_dangerous_paths].cs__freeze
43
55
  end
44
56
 
45
57
  def applicable_user_inputs
@@ -24,7 +24,7 @@ module Contrast
24
24
  COOKIE_VALUE, PARAMETER_VALUE, HEADER, JSON_VALUE, MULTIPART_VALUE, XML_VALUE, DWR_VALUE
25
25
  ].cs__freeze
26
26
 
27
- BASE64_INPUT_TYPES = [BODY, COOKIE_VALUE, HEADER, PARAMETER_VALUE, MULTIPART_VALUE, XML_VALUE].cs__freeze
27
+ BASE64_INPUT_TYPES = [BODY, COOKIE_VALUE, PARAMETER_VALUE, MULTIPART_VALUE, XML_VALUE].cs__freeze
28
28
 
29
29
  class << self
30
30
  include Contrast::Components::Logger::InstanceMethods
@@ -172,7 +172,9 @@ module Contrast
172
172
  end
173
173
 
174
174
  # Decodes the value for the given input type.
175
- # Applies to BODY, COOKIE_VALUE, HEADER, PARAMETER_VALUE, MULTIPART_VALUE, XML_VALUE
175
+ #
176
+ # This applies to Values sources only:
177
+ # BODY, COOKIE_VALUE, HEADER, PARAMETER_VALUE, MULTIPART_VALUE, XML_VALUE
176
178
  #
177
179
  # @param value [String]
178
180
  # @param input_type [Symbol]
@@ -181,6 +183,9 @@ module Contrast
181
183
  return value unless Contrast::PROTECT.normalize_base64?
182
184
  return value unless BASE64_INPUT_TYPES.include?(input_type)
183
185
 
186
+ # TODO: RUBY-2110 Update the HEADER handling if possible.
187
+ # We need only the Header values.
188
+
184
189
  cs__decode64(value, input_type)
185
190
  end
186
191
  end
@@ -16,7 +16,7 @@ module Contrast
16
16
 
17
17
  # Still a list is needed for this one, as it is not possible to determine if the value is encoded or not.
18
18
  # As long as the list is short the method has a good percentage of success.
19
- KNOWN_DECODING_EXCEPTIONS = %w[cmd].cs__freeze
19
+ KNOWN_DECODING_EXCEPTIONS = %w[cmd version if_modified_since].cs__freeze
20
20
 
21
21
  # This methods is not performant, but is more safe for false positive.
22
22
  # Base64 check is no trivial task. For example if one passes a value like 'stringdw' it will return true,
@@ -30,11 +30,18 @@ module Contrast
30
30
  NAME
31
31
  end
32
32
 
33
+ # Sub-rules forwarders:
34
+
35
+ # @return [Contrast::Agent::Protect::Rule::PathTraversalSemanticBypass]
36
+ def semantic_file_security_bypass
37
+ @_semantic_file_security_bypass ||= Contrast::Agent::Protect::Rule::PathTraversalSemanticBypass.new
38
+ end
39
+
33
40
  # Array of sub_rules
34
41
  #
35
42
  # @return [Array]
36
43
  def sub_rules
37
- @_sub_rules ||= [Contrast::Agent::Protect::Rule::PathTraversalSemanticBypass.new].cs__freeze
44
+ @_sub_rules ||= [semantic_file_security_bypass].cs__freeze
38
45
  end
39
46
 
40
47
  def applicable_user_inputs
@@ -35,11 +35,18 @@ module Contrast
35
35
  BLOCK_MESSAGE
36
36
  end
37
37
 
38
+ # Sub-rules forwarders:
39
+
40
+ # @return [Contrast::Agent::Protect::Rule::SqliDangerousFunctions]
41
+ def semantic_dangerous_functions
42
+ @_semantic_dangerous_functions ||= Contrast::Agent::Protect::Rule::SqliDangerousFunctions.new
43
+ end
44
+
38
45
  # Array of sub_rules
39
46
  #
40
47
  # @return [Array]
41
48
  def sub_rules
42
- @_sub_rules ||= [Contrast::Agent::Protect::Rule::SqliDangerousFunctions.new].cs__freeze
49
+ @_sub_rules ||= [semantic_dangerous_functions].cs__freeze
43
50
  end
44
51
 
45
52
  def applicable_user_inputs
@@ -0,0 +1,110 @@
1
+ # Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ require 'contrast/utils/object_share'
5
+ require 'contrast/components/logger'
6
+
7
+ module Contrast
8
+ module Agent
9
+ module Protect
10
+ # Master class for each protect rule. This class will hold all the rules references.
11
+ # Any access to the rules should be done through this class. and new rules should be
12
+ # added here. Each main rule should require and include and initialize it's sub-rules.
13
+ class State
14
+ include Contrast::Components::Logger::InstanceMethods
15
+
16
+ # @return [boolean] State dictated by local or server settings
17
+ attr_accessor :enabled
18
+ # @return [Contrast::Agent::Protect::Rule::BotBlocker] the bot blocker rule
19
+ attr_reader :bot_blocker
20
+ # @return [Contrast::Agent::Protect::Rule::CmdInjection] the command injection rule
21
+ attr_reader :cmd_injection
22
+ # @return [Contrast::Agent::Protect::Rule::CmdiBackdoors]
23
+ attr_reader :cmd_injection_command_backdoors
24
+ # @return [Contrast::Agent::Protect::Rule::CmdiChainedCommand]
25
+ attr_reader :cmd_injection_semantic_chained_commands
26
+ # @return [Contrast::Agent::Protect::Rule::CmdiDangerousPath]
27
+ attr_reader :cmd_injection_semantic_dangerous_paths
28
+ # @return [Contrast::Agent::Protect::Rule::Deserialization]
29
+ attr_reader :untrusted_deserialization
30
+ # @return [Contrast::Agent::Protect::Rule::NoSqli]
31
+ attr_reader :nosql_injection
32
+ # @return [Contrast::Agent::Protect::Rule::PathTraversal]
33
+ attr_reader :path_traversal
34
+ # @return [Contrast::Agent::Protect::Rule::PathTraversalSemanticBypass]
35
+ attr_reader :path_traversal_semantic_file_security_bypass
36
+ # @return [Contrast::Agent::Protect::Rule::Sqli]
37
+ attr_reader :sql_injection
38
+ # @return [Contrast::Agent::Protect::Rule::SqliDangerousFunctions]
39
+ attr_reader :sql_injection_semantic_dangerous_functions
40
+ # @return [Contrast::Agent::Protect::Rule::UnsafeFileUpload] the unsafe file upload rule
41
+ attr_reader :unsafe_file_upload
42
+ # @return [Contrast::Agent::Protect::Rule::Xss] the reflected xss rule
43
+ attr_reader :reflected_xss
44
+ # @return [Contrast::Agent::Protect::Rule::Xxe] the xxe rule
45
+ attr_reader :xxe
46
+
47
+ # Initialize all the protect rules. This should be the one place to access each live
48
+ # rule reference.
49
+ def initialize
50
+ @bot_blocker = Contrast::Agent::Protect::Rule::BotBlocker.new
51
+ @cmd_injection = Contrast::Agent::Protect::Rule::CmdInjection.new
52
+ @cmd_injection_command_backdoors = @cmd_injection.command_backdoors
53
+ @cmd_injection_semantic_chained_commands = @cmd_injection.semantic_chained_commands
54
+ @cmd_injection_semantic_dangerous_paths = @cmd_injection.semantic_dangerous_paths
55
+ @untrusted_deserialization = Contrast::Agent::Protect::Rule::Deserialization.new
56
+ @nosql_injection = Contrast::Agent::Protect::Rule::NoSqli.new
57
+ @path_traversal = Contrast::Agent::Protect::Rule::PathTraversal.new
58
+ @path_traversal_semantic_file_security_bypass = @path_traversal.semantic_file_security_bypass
59
+ @sql_injection = Contrast::Agent::Protect::Rule::Sqli.new
60
+ @sql_injection_semantic_dangerous_functions = @sql_injection.semantic_dangerous_functions
61
+ @unsafe_file_upload = Contrast::Agent::Protect::Rule::UnsafeFileUpload.new
62
+ @reflected_xss = Contrast::Agent::Protect::Rule::Xss.new
63
+ @xxe = Contrast::Agent::Protect::Rule::Xxe.new
64
+ end
65
+
66
+ # Return the Rules in Hash form {rule_id => rule_class }.
67
+ # This is used to traverse for each rule and update it's settings.
68
+ # Also is the way a rule is retrieved given the ID is known.
69
+ #
70
+ # @return [Hash<String, Contrast::Agent::Protect::Rule::Base>]
71
+ def rules
72
+ @_rules ||= {
73
+ @bot_blocker.rule_name => @bot_blocker,
74
+ @cmd_injection.rule_name => @cmd_injection,
75
+ @cmd_injection_command_backdoors.rule_name => @cmd_injection_command_backdoors,
76
+ @cmd_injection_semantic_chained_commands.rule_name => @cmd_injection_semantic_chained_commands,
77
+ @cmd_injection_semantic_dangerous_paths.rule_name => @cmd_injection_semantic_dangerous_paths,
78
+ @untrusted_deserialization.rule_name => @untrusted_deserialization,
79
+ @nosql_injection.rule_name => @nosql_injection,
80
+ @path_traversal.rule_name => @path_traversal,
81
+ @path_traversal_semantic_file_security_bypass.rule_name => @path_traversal_semantic_file_security_bypass,
82
+ @sql_injection.rule_name => @sql_injection,
83
+ @sql_injection_semantic_dangerous_functions.rule_name => @sql_injection_semantic_dangerous_functions,
84
+ @unsafe_file_upload.rule_name => @unsafe_file_upload,
85
+ @reflected_xss.rule_name => @reflected_xss,
86
+ @xxe.rule_name => @xxe
87
+ }
88
+ end
89
+
90
+ # Update all settings from configuration.
91
+ def update
92
+ rules.values.each(&:update)
93
+ logger.info('Current rule settings:')
94
+ rules.each { |k, v| logger.info('Protect Rule mode set', rule: k, mode: v.mode) }
95
+ end
96
+
97
+ # Check the local configurations first then the server settings.
98
+ def enabled?
99
+ Contrast::PROTECT.enable || Contrast::SETTINGS.protect_state.enabled
100
+ end
101
+
102
+ # @param [String] rule_id
103
+ # @return [Contrast::Agent::Protect::Rule::Base]
104
+ def [] rule_id
105
+ rules[rule_id]
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -32,6 +32,8 @@ module Contrast
32
32
 
33
33
  def validate
34
34
  raise(ArgumentError, 'Start Time is not presented') unless @start_time
35
+
36
+ nil
35
37
  end
36
38
 
37
39
  # @param attack_result [Contrast::Agent::Reporting::AttackResult]
@@ -59,6 +59,8 @@ module Contrast
59
59
  raise(ArgumentError, "#{ self } did not have a proper type - '#{ type }'. Unable to continue.")
60
60
  end
61
61
  raise(ArgumentError, "#{ self } did not have a proper URL. Unable to continue.") unless url
62
+
63
+ nil
62
64
  end
63
65
  end
64
66
  end
@@ -125,6 +125,7 @@ module Contrast
125
125
  # @raise [ArgumentError]
126
126
  def validate
127
127
  raise(ArgumentError, "#{ self } did not have a proper rule. Unable to continue.") unless @rule_id
128
+
128
129
  unless ::Contrast::ASSESS.session_id
129
130
  raise(ArgumentError, "#{ self } did not have a proper session id. Unable to continue.")
130
131
  end
@@ -422,6 +422,8 @@ module Contrast
422
422
  raise(ArgumentError, "#{ self } did not have a proper thread. Unable to continue.") unless thread
423
423
  raise(ArgumentError, "#{ self } did not have a proper time. Unable to continue.") unless time
424
424
  raise(ArgumentError, "#{ self } did not have a proper type. Unable to continue.") unless type
425
+
426
+ nil
425
427
  end
426
428
 
427
429
  # @raise [ArgumentError]
@@ -435,6 +437,8 @@ module Contrast
435
437
  raise(ArgumentError, "#{ self } did not have a proper signature. Unable to continue.") unless signature
436
438
  raise(ArgumentError, "#{ self } did not have a proper stack. Unable to continue.") unless stack
437
439
  raise(ArgumentError, "#{ self } did not have a proper tags. Unable to continue.") unless reportable_tags
440
+
441
+ nil
438
442
  end
439
443
  end
440
444
  end
@@ -108,6 +108,8 @@ module Contrast
108
108
  raise(ArgumentError, "#{ self } did not have a proper method. Unable to continue.")
109
109
  end
110
110
  raise(ArgumentError, "#{ self } did not have a proper uri. Unable to continue.") unless uri && !uri.empty?
111
+
112
+ nil
111
113
  end
112
114
 
113
115
  # @param request [Contrast::Agent::Request]
@@ -30,6 +30,8 @@ module Contrast
30
30
 
31
31
  def validate
32
32
  raise(ArgumentError, "#{ self } did not have observations. Unable to continue.") if observations.empty?
33
+
34
+ nil
33
35
  end
34
36
  end
35
37
  end
@@ -38,14 +38,15 @@ module Contrast
38
38
  def to_controlled_hash
39
39
  validate
40
40
  {
41
+ appLanguage: Contrast::Utils::ObjectShare::RUBY,
42
+ appName: ::Contrast::APP_CONTEXT.name, # rubocop:disable Security/Module/Name
43
+ appPath: ::Contrast::APP_CONTEXT.name, # rubocop:disable Security/Module/Name
44
+ appVersion: ::Contrast::APP_CONTEXT.version,
41
45
  code: CODE,
42
- app_language: Contrast::Utils::ObjectShare::RUBY,
43
- app_name: ::Contrast::APP_CONTEXT.name, # rubocop:disable Security/Module/Name
44
- app_version: ::Contrast::APP_CONTEXT.version,
45
46
  data: '',
46
47
  key: 0,
47
- routes: @routes.map(&:to_controlled_hash),
48
- session_id: ::Contrast::ASSESS.session_id
48
+ session_id: ::Contrast::ASSESS.session_id,
49
+ routes: @routes.map(&:to_controlled_hash)
49
50
  }
50
51
  end
51
52
 
@@ -57,6 +58,9 @@ module Contrast
57
58
  unless ::Contrast::ASSESS.session_id
58
59
  raise(ArgumentError, "#{ cs__class } did not have a proper session id. Unable to continue.")
59
60
  end
61
+ unless Contrast::APP_CONTEXT.name # rubocop:disable Security/Module/Name
62
+ raise(ArgumentError, "#{ cs__class } did not have a proper Application Name. Unable to continue.")
63
+ end
60
64
 
61
65
  nil
62
66
  end
@@ -28,12 +28,31 @@ module Contrast
28
28
  #
29
29
  # @return [String, nil] - JSON
30
30
  def event_json
31
- hsh = to_controlled_hash
32
- hsh.to_json
33
- rescue ArgumentError => e
34
- # Log the error and raise it for the client to handle:
35
- logger.error(validation_error_message, e)
36
- raise(e)
31
+ return unless valid?
32
+
33
+ to_controlled_hash.to_json
34
+ end
35
+
36
+ # Check before building the json if the event is valid.
37
+ # This will also log the error if the event is invalid.
38
+ # This will save some object creation in the reporter
39
+ # in the case of an invalid event, and will stop the
40
+ # reporting of the event.
41
+ #
42
+ # @return [Boolean]
43
+ # @raise [ArgumentError]
44
+ def valid?
45
+ @_valid ||= begin
46
+ validate
47
+ # Some deeply nested validations only happens on
48
+ # the to_controlled_hash method, so we need to
49
+ # invoke it.
50
+ to_controlled_hash
51
+ true
52
+ rescue ArgumentError => e
53
+ handle_validation_error(e)
54
+ false
55
+ end
37
56
  end
38
57
 
39
58
  private
@@ -41,6 +60,11 @@ module Contrast
41
60
  def validation_error_message
42
61
  "#{ cs__class } failed validation with: "
43
62
  end
63
+
64
+ # @param error [ArgumentError]
65
+ def handle_validation_error error
66
+ logger.error(validation_error_message, error)
67
+ end
44
68
  end
45
69
  end
46
70
  end
@@ -72,8 +72,8 @@ module Contrast
72
72
  # @return response [Net::HTTP::Response, nil] response from TS if no response
73
73
  def send_event event, connection
74
74
  return unless connection
75
+ return unless event.valid?
75
76
 
76
- response = nil
77
77
  logger.debug('[Reporter] Preparing to send reporting event', event_class: event.cs__class)
78
78
  request = build_request(event)
79
79
  response = connection.request(request)
@@ -12,7 +12,7 @@ module Contrast
12
12
  RESCUE_ATTEMPTS = 3
13
13
  TIMEOUT = 5
14
14
  RETRY_ERRORS = [
15
- Net::OpenTimeout, Net::ReadTimeout, ArgumentError, EOFError, OpenSSL::SSL::SSLError, Resolv::ResolvError,
15
+ Net::OpenTimeout, Net::ReadTimeout, EOFError, OpenSSL::SSL::SSLError, Resolv::ResolvError,
16
16
  Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::ETIMEDOUT, Errno::ESHUTDOWN, Errno::EHOSTDOWN, NameError,
17
17
  Errno::EHOSTUNREACH, Errno::EISCONN, Errno::ECONNABORTED, Errno::ENETRESET, Errno::ENETUNREACH, SocketError,
18
18
  NameError, NoMethodError, Timeout::Error, RuntimeError
@@ -232,11 +232,7 @@ module Contrast
232
232
  return unless ::Contrast::AGENT.enabled?
233
233
 
234
234
  logger.trace_with_time('Rebuilding rule modes from TeamServer') do
235
- # TODO: RUBY-999999 Make sure when updating Protect rules to reflect the mode source (always DEFAULT_VALUE)
236
- ::Contrast::AGENT.reset_ruleset
237
- ::Contrast::SETTINGS.build_protect_rules if ::Contrast::PROTECT.enabled?
238
- logger.info('Current rule settings:')
239
- ::Contrast::PROTECT.defend_rules.each { |k, v| logger.info('Protect Rule mode set', rule: k, mode: v.mode) }
235
+ ::Contrast::PROTECT.state.update if ::Contrast::PROTECT.enabled?
240
236
  if ::Contrast::ASSESS.enabled?
241
237
  logger.info('Disabled Assess Rules', rules: ::Contrast::ASSESS.disabled_rules)
242
238
  end
@@ -121,10 +121,10 @@ module Contrast
121
121
  # Returns list of actively used protection rules to be updated, or default list.
122
122
  # This will be used to query the received settings for the ones used by the Agent.
123
123
  def active_defend_rules
124
- return ACTIVE_PROTECT_RULES_LIST unless defined?(Contrast::SETTINGS)
124
+ return ACTIVE_PROTECT_RULES_LIST unless defined?(Contrast::PROTECT)
125
125
 
126
- current_rules = (Contrast::PROTECT&.defend_rules&.keys if defined?(Contrast::PROTECT))
127
- return current_rules unless current_rules&.empty?
126
+ current_rules = Contrast::PROTECT.defend_rules.keys
127
+ return current_rules unless current_rules.empty?
128
128
 
129
129
  ACTIVE_PROTECT_RULES_LIST
130
130
  end
@@ -24,10 +24,11 @@ module Contrast
24
24
 
25
25
  def initialize hsh
26
26
  @baseline = hsh[:baseline]
27
- @enabled = hsh[:enabled]
28
- @request_frequency = hsh[:frequency]
29
- @response_frequency = hsh[:responseFrequency]
30
- @window_ms = hsh[:window]
27
+ # NG endpoints vs non-ng
28
+ @enabled = hsh[:enabled] || hsh[:enable]
29
+ @request_frequency = hsh[:frequency] || hsh[:request_frequency]
30
+ @response_frequency = hsh[:responseFrequency] || hsh[:response_frequency]
31
+ @window_ms = hsh[:window] || hsh[:window_ms]
31
32
  end
32
33
 
33
34
  def to_controlled_hash
@@ -3,6 +3,6 @@
3
3
 
4
4
  module Contrast
5
5
  module Agent
6
- VERSION = '7.3.2'
6
+ VERSION = '7.4.0'
7
7
  end
8
8
  end
@@ -26,6 +26,8 @@ module Contrast
26
26
  attr_reader :config_values
27
27
  # @return [Boolean]
28
28
  attr_accessor :enable
29
+ # @return [Boolean]
30
+ attr_accessor :omit_body
29
31
 
30
32
  CANON_NAME = 'agent'
31
33
  CONFIG_VALUES = %w[enabled? omit_body?].cs__freeze
@@ -95,16 +97,12 @@ module Contrast
95
97
  @_ruleset ||= Contrast::Agent::RuleSet.new(retrieve_protect_ruleset.values)
96
98
  end
97
99
 
98
- def reset_ruleset
99
- @_ruleset = nil
100
- end
101
-
102
100
  def patch_yield?
103
101
  !false?(ruby.propagate_yield)
104
102
  end
105
103
 
106
104
  def omit_body?
107
- @_omit_body
105
+ true?(@_omit_body)
108
106
  end
109
107
 
110
108
  def disable_agent!
@@ -129,7 +129,7 @@ module Contrast
129
129
  #
130
130
  # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
131
131
  def to_effective_config effective_config
132
- add_effective_config_values(effective_config, CONFIG_VALUES, CANON_NAME, CONTRAST)
132
+ add_effective_config_values(effective_config, CONFIG_VALUES, CANON_NAME, CANON_NAME)
133
133
  effective_proxy(effective_config)
134
134
  request_audit&.to_effective_config(effective_config)
135
135
  certificate&.to_effective_config(effective_config)
@@ -139,10 +139,10 @@ module Contrast
139
139
 
140
140
  # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
141
141
  def effective_proxy effective_config
142
- add_single_effective_value(effective_config, ENABLE, proxy_enable.to_s, PROXY_NAME, "#{ CONTRAST }.proxy")
142
+ add_single_effective_value(effective_config, ENABLE, proxy_enable.to_s, PROXY_NAME)
143
143
  return unless proxy_url && proxy_enable
144
144
 
145
- add_single_effective_value(effective_config, 'url', proxy_url, PROXY_NAME, "#{ CONTRAST }.proxy")
145
+ add_single_effective_value(effective_config, 'url', proxy_url, PROXY_NAME)
146
146
  end
147
147
 
148
148
  def certification_truly_enabled? config_path
@@ -16,7 +16,6 @@ module Contrast
16
16
 
17
17
  SPEC_KEY = :disabled_rules.cs__freeze
18
18
  CANON_NAME = 'assess.rules'
19
- NAME_PREFIX = "#{ CONTRAST }.#{ CANON_NAME }".cs__freeze
20
19
 
21
20
  # @return [Array, nil] list of disabled assess rules
22
21
  attr_accessor :disabled_rules
@@ -36,7 +35,7 @@ module Contrast
36
35
  #
37
36
  # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
38
37
  def to_effective_config effective_config
39
- add_single_effective_value(effective_config, SPEC_KEY.to_s, disabled_rules, canon_name, NAME_PREFIX)
38
+ add_single_effective_value(effective_config, SPEC_KEY.to_s, disabled_rules || [], canon_name)
40
39
  end
41
40
 
42
41
  private
@@ -12,7 +12,6 @@ module Contrast
12
12
  module ComponentBase
13
13
  include Contrast::Config::Diagnostics::Tools
14
14
 
15
- CONTRAST = 'contrast'
16
15
  ENABLE = 'enable'
17
16
 
18
17
  # Used for config diagnostics. Override per rule.
@@ -87,7 +86,7 @@ module Contrast
87
86
  #
88
87
  # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
89
88
  def to_effective_config effective_config
90
- add_effective_config_values(effective_config, config_values, canon_name, "#{ CONTRAST }.#{ canon_name }")
89
+ add_effective_config_values(effective_config, config_values, canon_name)
91
90
  end
92
91
 
93
92
  # attempts to stringify the config value if it is an array with the join char
@@ -11,6 +11,8 @@ module Contrast
11
11
  # This component encapsulates storing the source for each entry in the config,
12
12
  # so that we can report on where the value was set from.
13
13
  class Sources
14
+ # [ CORPORATE_RULE, COMMAND_LINE, JAVA_SYSTEM_PROPERTY, ENVIRONMENT_VARIABLE, APP_CONFIGURATION_FILE,
15
+ # USER_CONFIGURATION_FILE, CONTRAST_UI, DEFAULT_VALUE ]
14
16
  ENVIRONMENT_VARIABLE = 'ENVIRONMENT_VARIABLE'
15
17
  COMMAND_LINE = 'COMMAND_LINE'
16
18
  CONTRAST_UI = 'CONTRAST_UI'
@@ -57,6 +59,27 @@ module Contrast
57
59
  deep_select(data.dup, type, [])
58
60
  end
59
61
 
62
+ # @param path [String] the canonical name for the config entry (such as api.proxy.enable) or source
63
+ # if the source(CONTRAST_UI, ENVIRONMENT_VARIABLE...) flag is set true.
64
+ # @param source [Boolean] flag to specify we are passing in a source, no need to look for it.
65
+ # @return [Boolean] true if the entry is from a YAML file
66
+ def configuration_file_source? path, source: false
67
+ s = source ? path : Contrast::CONFIG.sources.get(path)
68
+ return true if s.include?(APP_CONFIGURATION_EXTENSIONS[0]) || s.include?(APP_CONFIGURATION_EXTENSIONS[1])
69
+
70
+ false
71
+ end
72
+
73
+ # Check to see whether the source has been overridden by local settings.
74
+ # @param path [String] the canonical name for the config entry (such as api.proxy.enable)
75
+ def source_overridden? path
76
+ source = Contrast::CONFIG.sources.get(path)
77
+ return true if [ENVIRONMENT_VARIABLE, COMMAND_LINE].include?(source)
78
+ return true if configuration_file_source?(source, source: true)
79
+
80
+ false
81
+ end
82
+
60
83
  private
61
84
 
62
85
  # @param path [String] the canonical name for a config entry (such as api.proxy.enable)
@@ -33,6 +33,8 @@ module Contrast
33
33
  include InstanceMethods
34
34
  include Contrast::Components::ComponentBase
35
35
 
36
+ DEFAULT_NAME = 'contrast.log'
37
+ DEFAULT_LEVEL = 'INFO'
36
38
  CANON_NAME = 'agent.logger'
37
39
  CONFIG_VALUES = %w[path level progname].cs__freeze
38
40
 
@@ -56,6 +58,23 @@ module Contrast
56
58
  @level = hsh[:level]
57
59
  @progname = hsh[:progname]
58
60
  end
61
+
62
+ def to_effective_config effective_config
63
+ path_setting = nil
64
+ level_setting = nil
65
+
66
+ if defined?(Contrast::SETTINGS)
67
+ path_setting = Contrast::SETTINGS.agent_state.logger_path
68
+ level_setting = Contrast::SETTINGS.agent_state.logger_level
69
+ end
70
+
71
+ path_setting ||= DEFAULT_NAME
72
+ level_setting ||= DEFAULT_LEVEL
73
+
74
+ add_single_effective_value(effective_config, config_values[0], path || path_setting, CANON_NAME)
75
+ add_single_effective_value(effective_config, config_values[1], level || level_setting, CANON_NAME)
76
+ add_single_effective_value(effective_config, config_values[2], progname, CANON_NAME)
77
+ end
59
78
  end
60
79
  end
61
80
  end