contrast-agent 7.3.2 → 7.4.0

Sign up to get free protection for your applications and to get access to all the features.
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