contrast-agent 6.8.0 → 6.9.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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/lib/contrast/agent/assess/policy/trigger_method.rb +1 -1
  3. data/lib/contrast/agent/assess/property/evented.rb +11 -11
  4. data/lib/contrast/agent/assess.rb +0 -1
  5. data/lib/contrast/agent/excluder.rb +1 -1
  6. data/lib/contrast/agent/middleware.rb +8 -2
  7. data/lib/contrast/agent/protect/input_analyzer/worth_watching_analyzer.rb +116 -0
  8. data/lib/contrast/agent/protect/rule/base.rb +2 -2
  9. data/lib/contrast/agent/protect/rule/bot_blocker.rb +1 -1
  10. data/lib/contrast/agent/protect/rule/cmd_injection.rb +8 -7
  11. data/lib/contrast/agent/protect/rule/cmdi/cmdi_chained_command.rb +0 -5
  12. data/lib/contrast/agent/protect/rule/cmdi/cmdi_dangerous_path.rb +0 -5
  13. data/lib/contrast/agent/protect/rule/path_traversal.rb +4 -3
  14. data/lib/contrast/agent/protect/rule/sqli.rb +4 -3
  15. data/lib/contrast/agent/protect/rule/xss.rb +1 -0
  16. data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +1 -1
  17. data/lib/contrast/agent/reporting/report.rb +1 -0
  18. data/lib/contrast/agent/reporting/reporter.rb +34 -0
  19. data/lib/contrast/agent/reporting/reporter_heartbeat.rb +3 -9
  20. data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +1 -1
  21. data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +12 -7
  22. data/lib/contrast/agent/reporting/reporting_events/application_inventory_activity.rb +6 -1
  23. data/lib/contrast/agent/reporting/reporting_events/finding.rb +2 -2
  24. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +239 -93
  25. data/lib/contrast/agent/reporting/reporting_events/finding_event_signature.rb +10 -23
  26. data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +10 -9
  27. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +12 -0
  28. data/lib/contrast/agent/reporting/reporting_events/server_reporting_event.rb +8 -0
  29. data/lib/contrast/agent/reporting/reporting_events/server_settings.rb +40 -0
  30. data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +6 -0
  31. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +43 -1
  32. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +8 -4
  33. data/lib/contrast/agent/reporting/reporting_utilities/response_extractor.rb +58 -4
  34. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +4 -3
  35. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +76 -16
  36. data/lib/contrast/agent/reporting/server_settings_worker.rb +44 -0
  37. data/lib/contrast/agent/reporting/settings/assess_server_feature.rb +14 -2
  38. data/lib/contrast/agent/reporting/settings/helpers.rb +7 -0
  39. data/lib/contrast/agent/reporting/settings/protect_server_feature.rb +39 -2
  40. data/lib/contrast/agent/reporting/settings/rule_definition.rb +3 -0
  41. data/lib/contrast/agent/reporting/settings/security_logger.rb +77 -0
  42. data/lib/contrast/agent/reporting/settings/server_features.rb +9 -0
  43. data/lib/contrast/agent/reporting/settings/syslog.rb +34 -5
  44. data/lib/contrast/agent/request.rb +1 -0
  45. data/lib/contrast/agent/request_handler.rb +5 -10
  46. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_event.rb +1 -1
  47. data/lib/contrast/agent/thread_watcher.rb +35 -1
  48. data/lib/contrast/agent/version.rb +1 -1
  49. data/lib/contrast/agent.rb +6 -0
  50. data/lib/contrast/api/communication/connection_status.rb +15 -0
  51. data/lib/contrast/components/agent.rb +34 -0
  52. data/lib/contrast/components/api.rb +23 -0
  53. data/lib/contrast/components/app_context.rb +23 -3
  54. data/lib/contrast/components/assess.rb +34 -4
  55. data/lib/contrast/components/assess_rules.rb +18 -0
  56. data/lib/contrast/components/base.rb +40 -0
  57. data/lib/contrast/components/config/sources.rb +95 -0
  58. data/lib/contrast/components/config.rb +18 -1
  59. data/lib/contrast/components/heap_dump.rb +10 -0
  60. data/lib/contrast/components/inventory.rb +15 -2
  61. data/lib/contrast/components/logger.rb +18 -0
  62. data/lib/contrast/components/polling.rb +36 -0
  63. data/lib/contrast/components/protect.rb +48 -1
  64. data/lib/contrast/components/ruby_component.rb +15 -0
  65. data/lib/contrast/components/sampling.rb +70 -13
  66. data/lib/contrast/components/security_logger.rb +13 -0
  67. data/lib/contrast/components/settings.rb +74 -7
  68. data/lib/contrast/config/certification_configuration.rb +14 -0
  69. data/lib/contrast/config/config.rb +46 -0
  70. data/lib/contrast/config/diagnostics.rb +114 -0
  71. data/lib/contrast/config/diagnostics_tools.rb +98 -0
  72. data/lib/contrast/config/effective_config.rb +65 -0
  73. data/lib/contrast/config/effective_config_value.rb +32 -0
  74. data/lib/contrast/config/exception_configuration.rb +12 -0
  75. data/lib/contrast/config/protect_rule_configuration.rb +1 -1
  76. data/lib/contrast/config/protect_rules_configuration.rb +8 -7
  77. data/lib/contrast/config/request_audit_configuration.rb +13 -0
  78. data/lib/contrast/config/server_configuration.rb +41 -2
  79. data/lib/contrast/configuration.rb +28 -2
  80. data/lib/contrast/extension/assess/erb.rb +1 -1
  81. data/lib/contrast/utils/assess/event_limit_utils.rb +31 -9
  82. data/lib/contrast/utils/assess/trigger_method_utils.rb +5 -4
  83. data/lib/contrast/utils/hash_digest.rb +2 -2
  84. data/lib/contrast/utils/input_classification_base.rb +1 -2
  85. data/lib/contrast/utils/reporting/application_activity_batch_utils.rb +81 -0
  86. data/lib/contrast/utils/routes_sent.rb +60 -0
  87. data/lib/contrast/utils/telemetry_client.rb +1 -2
  88. data/lib/contrast/utils/timer.rb +16 -0
  89. data/lib/contrast.rb +3 -1
  90. data/ruby-agent.gemspec +5 -1
  91. metadata +29 -20
  92. data/lib/contrast/agent/assess/contrast_event.rb +0 -157
  93. data/lib/contrast/agent/assess/events/event_factory.rb +0 -34
  94. data/lib/contrast/agent/assess/events/source_event.rb +0 -46
  95. data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +0 -36
@@ -1,12 +1,18 @@
1
1
  # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'contrast/config/base_configuration'
5
+
4
6
  module Contrast
5
7
  module Config
6
8
  # Common Configuration settings. Those in this section pertain to the server identification functionality of the
7
9
  # Agent.
8
10
  class ServerConfiguration
9
11
  include Contrast::Config::BaseConfiguration
12
+ include Contrast::Components::ComponentBase
13
+
14
+ CANON_NAME = 'server'
15
+ CONFIG_VALUES = %w[tags environment version].cs__freeze
10
16
 
11
17
  # @return [String, nil]
12
18
  attr_reader :name
@@ -14,14 +20,19 @@ module Contrast
14
20
  attr_accessor :path
15
21
  # @return [String, nil]
16
22
  attr_accessor :type
17
- # @return [Array, nil]
18
- attr_accessor :tags
23
+ attr_writer :tags
19
24
  # @return [String, nil]
20
25
  attr_accessor :environment
21
26
  # @return [String, nil]
22
27
  attr_accessor :version
28
+ # @return [String]
29
+ attr_reader :canon_name
30
+ # @return [Array]
31
+ attr_reader :config_values
23
32
 
24
33
  def initialize hsh = {}
34
+ @config_values = CONFIG_VALUES
35
+ @canon_name = CANON_NAME
25
36
  return unless hsh
26
37
 
27
38
  @path = hsh[:path]
@@ -31,6 +42,34 @@ module Contrast
31
42
  @environment = hsh[:environment]
32
43
  @version = hsh[:version]
33
44
  end
45
+
46
+ # @return [String, nil]
47
+ def tags
48
+ stringify_array(@tags)
49
+ end
50
+
51
+ # Converts current configuration to effective config values class and appends them to
52
+ # EffectiveConfig class.
53
+ #
54
+ # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
55
+ def to_effective_config effective_config
56
+ super
57
+ add_single_effective_value(effective_config,
58
+ 'type',
59
+ Contrast::APP_CONTEXT.server_type,
60
+ CANON_NAME,
61
+ "#{ CONTRAST }.#{ CANON_NAME }")
62
+ add_single_effective_value(effective_config,
63
+ 'name',
64
+ Contrast::APP_CONTEXT.server_name,
65
+ CANON_NAME,
66
+ "#{ CONTRAST }.#{ CANON_NAME }")
67
+ add_single_effective_value(effective_config,
68
+ 'path',
69
+ Contrast::APP_CONTEXT.server_path,
70
+ CANON_NAME,
71
+ "#{ CONTRAST }.#{ CANON_NAME }")
72
+ end
34
73
  end
35
74
  end
36
75
  end
@@ -13,6 +13,7 @@ require 'contrast/components/scope'
13
13
  require 'contrast/components/inventory'
14
14
  require 'contrast/components/protect'
15
15
  require 'contrast/components/assess'
16
+ require 'contrast/components/config/sources'
16
17
  require 'contrast/config/server_configuration'
17
18
 
18
19
  module Contrast
@@ -45,6 +46,12 @@ module Contrast
45
46
  attr_writer :protect
46
47
  # @return [Boolean, nil]
47
48
  attr_accessor :enable
49
+ # @return [Hash]
50
+ attr_accessor :loaded_config
51
+ # @return [Contrast::Config::Sources]
52
+ attr_accessor :sources
53
+ # @return [String,nil]
54
+ attr_reader :config_file
48
55
 
49
56
  DEFAULT_YAML_PATH = 'contrast_security.yaml'
50
57
  MILLISECOND_MARKER = '_ms'
@@ -53,18 +60,26 @@ module Contrast
53
60
  KEYS_TO_REDACT = %i[api_key url service_key user_name].cs__freeze
54
61
  REDACTED = '**REDACTED**'
55
62
 
56
- def initialize cli_options = nil, default_name = DEFAULT_YAML_PATH
63
+ def initialize cli_options = nil, default_name = DEFAULT_YAML_PATH # rubocop:disable Metrics/AbcSize
57
64
  @default_name = default_name
58
65
 
59
66
  # Load config_kv from file
60
67
  config_kv = deep_symbolize_all_keys(load_config)
68
+ config_sources = assign_source_to(config_kv, Contrast::Components::Config::Sources::YAML)
61
69
 
62
70
  # Overlay CLI options - they take precedence over config file
63
71
  cli_options = deep_symbolize_all_keys(cli_options)
64
- config_kv = deep_merge(cli_options, config_kv) if cli_options
72
+ if cli_options
73
+ config_kv = deep_merge(cli_options, config_kv)
74
+ config_sources = deep_merge(assign_source_to(cli_options, Contrast::Components::Config::Sources::CLI),
75
+ config_sources)
76
+ end
65
77
 
66
78
  # Some in-flight rewrites to maintain backwards compatibility
67
79
  config_kv = update_prop_keys(config_kv)
80
+ @loaded_config = config_kv
81
+
82
+ @sources = Contrast::Components::Config::Sources.new(config_sources)
68
83
 
69
84
  @api = Contrast::Components::Api::Interface.new(config_kv[:api])
70
85
  @enable = config_kv[:enable]
@@ -132,6 +147,7 @@ module Contrast
132
147
  next
133
148
  end
134
149
  config = yaml_to_hash(path) || {}
150
+ @config_file = path
135
151
  break
136
152
  end
137
153
 
@@ -307,5 +323,15 @@ module Contrast
307
323
  def redactable? key
308
324
  KEYS_TO_REDACT.include?(key.to_sym)
309
325
  end
326
+
327
+ def assign_source_to hash, source = Contrast::Components::Config::Sources::YAML
328
+ hash.transform_values do |value|
329
+ if value.is_a?(Hash)
330
+ assign_source_to(value, source)
331
+ else
332
+ source
333
+ end
334
+ end
335
+ end
310
336
  end
311
337
  end
@@ -39,7 +39,7 @@ module ERBPropagator
39
39
  # @param used_binding [Binding] the binding in of the current event, saved as preshift argument
40
40
  # @param erb_pre_result [String] the source saved in the preshift
41
41
  # @param properties [Contrast::Agent::Assess::Properties] properties of the target if none create new
42
- # @param parent_events [Array<Contrast::Agent::Assess::ContrastEvent>] parents event extracted from the source
42
+ # @param parent_events [Array<Contrast::Agent::Reporting::FindingEvent>] parents event extracted from the source
43
43
  # properties
44
44
  # @param ret [String] the Return of the invoked method
45
45
  # @return [Array<Symbol>]
@@ -12,18 +12,19 @@ module Contrast
12
12
  module EventLimitUtils
13
13
  include Contrast::Components::Logger::InstanceMethods
14
14
  # Checks to see if the event limit for the policy type has been met or exceeded
15
- # @param method_policy [Contrast::Agent::Patching::Policy::MethodPolicy] method to check for event limit
16
- def event_limit? method_policy
15
+ # @param policy [Contrast::Agent::Patching::Policy::MethodPolicy,
16
+ # Contrast::Agent::Patching::Policy::TriggerNode] method to check for event limit
17
+ def event_limit? policy
17
18
  return false unless (context = Contrast::Agent::REQUEST_TRACKER.current)
18
19
 
19
- if method_policy.source_node
20
+ if policy.source_node
20
21
  max = ::Contrast::ASSESS.max_context_source_events
21
- return at_limit?(method_policy, context.source_event_count, max)
22
-
22
+ return at_limit?(policy, context.source_event_count, max, context)
23
23
  end
24
- if method_policy.propagation_node
24
+
25
+ if policy.propagation_node
25
26
  max = ::Contrast::ASSESS.max_propagation_events
26
- return at_limit?(method_policy, context.propagation_event_count, max)
27
+ return at_limit?(policy, context.propagation_event_count, max, context)
27
28
  end
28
29
 
29
30
  false # policy does not have limit
@@ -65,8 +66,10 @@ module Contrast
65
66
  private
66
67
 
67
68
  # helper method to check limit and log when necessary
68
- def at_limit? method_policy, current_count, event_max
69
+ def at_limit? method_policy, current_count, event_max, context
69
70
  if current_count == event_max
71
+ return if event_limit_counts.key?(get_event_limit_key(method_policy, context))
72
+
70
73
  logger.warn('Event Limit Reached:',
71
74
  {
72
75
  count: current_count,
@@ -76,16 +79,21 @@ module Contrast
76
79
  })
77
80
  # increment to be over count for logging purposes
78
81
  increment_event_count(method_policy)
82
+ increment_event_limit_logs(method_policy, context)
83
+
79
84
  return true
80
85
  elsif current_count > event_max
81
- # increment to be over count for logging purposes
82
86
  increment_event_count(method_policy)
87
+ return if event_limit_counts.key?(get_event_limit_key(method_policy, context))
88
+
89
+ # increment to be over count for logging purposes
83
90
  logger.warn('Event Limit Exceeded:',
84
91
  {
85
92
  count: current_count,
86
93
  policy: method_policy.method_name,
87
94
  node: method_policy
88
95
  })
96
+ increment_event_limit_logs(method_policy, context)
89
97
  return true
90
98
  end
91
99
  false
@@ -95,6 +103,20 @@ module Contrast
95
103
  @_rule_counts ||= Hash.new { |h, k| h[k] = 0 }
96
104
  end
97
105
 
106
+ def event_limit_counts
107
+ @_event_limit_counts ||= Hash.new { |h, k| h[k] = 0 }
108
+ end
109
+
110
+ def get_event_limit_key method_policy, context
111
+ "#{ method_policy.method_name }_#{ context.request.__id__ }"
112
+ end
113
+
114
+ def increment_event_limit_logs method_policy, context
115
+ event_limit_counter = get_event_limit_key(method_policy, context)
116
+
117
+ event_limit_counts[event_limit_counter] += 1
118
+ end
119
+
98
120
  # the time threshold for which to track rule counts resets when now >= threshold_time_limit
99
121
  # @return [Integer]
100
122
  def threshold_time_limit
@@ -1,12 +1,15 @@
1
1
  # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'contrast/utils/assess/event_limit_utils'
5
+
4
6
  module Contrast
5
7
  module Utils
6
8
  module Assess
7
9
  # This module will include all methods for some internal validations/appliers in the TriggerMethod module
8
10
  # and some other module methods from the same place, so we can ease the main module
9
11
  module TriggerMethodUtils
12
+ extend Contrast::Utils::Assess::EventLimitUtils
10
13
  # A request is reportable if it is not from ActionController::Live
11
14
  #
12
15
  # @param env [Hash] the env of the Request
@@ -33,10 +36,10 @@ module Contrast
33
36
 
34
37
  # Finds the first request along the left most tree of parent events
35
38
  #
36
- # @param event [Contrast::Agent::Assess::ContrastEvent|Contrast::Agent::Assess::Events::SourceEvent]
39
+ # @param event [Contrast::Agent::Reporting::FindingEvent]
37
40
  # @return [Contrast::Agent::Request, nil]
38
41
  def find_event_request event
39
- return event.request if event.cs__is_a?(Contrast::Agent::Assess::Events::SourceEvent)
42
+ return event.request if event&.source_type
40
43
 
41
44
  idx = 0
42
45
  while idx <= event.parent_events.length
@@ -44,9 +47,7 @@ module Contrast
44
47
  return found if found
45
48
 
46
49
  idx += 1
47
- return event.request if event.request
48
50
  end
49
- return unless event.cs__is_a?(Contrast::Agent::Assess::Events::SourceEvent)
50
51
 
51
52
  event.request
52
53
  end
@@ -61,8 +61,8 @@ module Contrast
61
61
  def update_on_sources events
62
62
  events.each do |event|
63
63
  event.event_sources.each do |source|
64
- update(source.type)
65
- update(source.name) # rubocop:disable Security/Module/Name
64
+ update(source.source_type)
65
+ update(source.source_name)
66
66
  end
67
67
  end
68
68
  end
@@ -133,8 +133,7 @@ module Contrast
133
133
  input_eval = Contrast::AGENT_LIB.eval_input(value,
134
134
  convert_input_type(input_type),
135
135
  Contrast::AGENT_LIB.rule_set[rule_id],
136
- Contrast::AGENT_LIB.
137
- eval_option[:WORTHWATCHING])
136
+ Contrast::AGENT_LIB.eval_option[:WORTHWATCHING])
138
137
 
139
138
  ia_result = new_ia_result(rule_id, input_type, request.path, value)
140
139
  score = input_eval&.score || 0
@@ -0,0 +1,81 @@
1
+ # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ require 'contrast/agent/reporting/reporting_events/application_activity'
5
+
6
+ module Contrast
7
+ module Utils
8
+ module Reporting
9
+ # ApplicationActivityBatchUtils handles batching and reporting of ApplicationActivity events to TeamServer at a
10
+ # set interval
11
+ module ApplicationActivityBatchUtils
12
+ DEFAULT_REPORTING_INTERVAL_MS = 30_000.cs__freeze
13
+
14
+ # @return [Integer] time when activity batch was created in ms
15
+ attr_reader :batch_age
16
+
17
+ # Merge a ApplicationActivity into the ApplicationActivityBatch
18
+ # @param activity [Contrast::Agent::Reporting::ApplicationActivity] from a RequestContext
19
+ def add_activity_to_batch activity
20
+ return unless activity
21
+
22
+ activity_batch.query_count += activity.query_count
23
+ activity_batch.routes << activity.routes
24
+ activity_batch.routes.flatten!
25
+ merge_attackers(activity)
26
+ activity_batch.attach_inventory(activity.inventory) unless activity.inventory.empty?
27
+ end
28
+
29
+ # If the batch can be reported, mask the data and add it to the reporting queue, then reset the activity_batch
30
+ def report_batch
31
+ return unless report_batch?
32
+ return unless (reporter = Contrast::Agent.reporter)
33
+
34
+ Contrast::Agent::Reporting::Masker.mask(activity_batch)
35
+ reporter&.send_event(activity_batch)
36
+ reset_activity_batch
37
+ end
38
+
39
+ # @return Contrast::Agent::Reporting::ApplicationActivity
40
+ def activity_batch
41
+ return @activity_batch unless @activity_batch.nil?
42
+
43
+ reset_activity_batch
44
+ @activity_batch
45
+ end
46
+
47
+ private
48
+
49
+ def merge_attackers activity
50
+ return if activity.defend.attackers.empty?
51
+
52
+ activity.defend.attackers.each do |attacker|
53
+ if (existing = activity_batch.defend.find_existing_attacker_activity(attacker))
54
+ attacker.protection_rules.each_key do |key|
55
+ activity_batch.defend.attach_existing(existing, attacker, key)
56
+ end
57
+ else
58
+ activity_batch.defend.attackers << attacker
59
+ end
60
+ end
61
+ end
62
+
63
+ # resets the activity_batch object and it's batch_age
64
+ def reset_activity_batch
65
+ @batch_age = Contrast::Utils::Timer.now_ms
66
+ @activity_batch = Contrast::Agent::Reporting::ApplicationActivity.new
67
+ end
68
+
69
+ # @return [Boolean] if the age of the batch is outside the reporting interval
70
+ def report_batch?
71
+ reporting_interval <= (Contrast::Utils::Timer.now_ms - batch_age)
72
+ end
73
+
74
+ # @return [Integer] interval to report to TeamServer in seconds
75
+ def reporting_interval
76
+ Contrast::AGENT.polling.batch_reporting_interval_ms.to_i || DEFAULT_REPORTING_INTERVAL_MS
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,60 @@
1
+ # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ # require 'contrast/components/logger'
5
+ # require 'contrast/agent/telemetry/events/exceptions/telemetry_exception_event'
6
+
7
+ module Contrast
8
+ module Utils
9
+ # This is the RoutesSent class, which determines whether observed routes can be sent to TeamServer.
10
+ # Routes that have not been seen (according to the cache) can be sent, as well as any route that
11
+ # # has been seen but not within the time limit.
12
+ class RoutesSent
13
+ # include Contrast::Components::Logger::InstanceMethods
14
+ ROUTES_LIMIT = 500
15
+ TIME_LIMIT_IN_SECONDS = 3600
16
+
17
+ attr_accessor :cache
18
+
19
+ def initialize
20
+ @cache = {}
21
+ end
22
+
23
+ # Determine whether the provided route can be sent to TeamServer.
24
+ #
25
+ # @param [Contrast::Agent::Reporting::ObservedRoute] the route
26
+ # @return [boolean]
27
+ def sendable? route
28
+ route_hash = route.hash_id
29
+
30
+ # If hash doesn't exist in @cache...
31
+ # - Add hash to @cache (with Time.now)
32
+ # - Clear oldest entries (if more than ROUTES_LIMIT)
33
+ # - Return *true*
34
+ unless cache.key?(route_hash)
35
+ cache[route_hash] = Time.now
36
+ remove_oldest_entries!
37
+ return true
38
+ end
39
+
40
+ # If hash exists in @cache...
41
+ # - Return *true* if more than a minute since time recorded for hash
42
+ # - Return *false* if not than a minute since time recorded for hash
43
+ return false unless Time.now.to_i - cache.fetch(route_hash, 0).to_i > TIME_LIMIT_IN_SECONDS
44
+
45
+ cache[route_hash] = Time.now
46
+ true
47
+ end
48
+
49
+ private
50
+
51
+ def remove_oldest_entries!
52
+ return if cache.size < ROUTES_LIMIT
53
+
54
+ route_hashes = cache.sort_by { |_, v| -v.tv_nsec }.
55
+ to_h.keys.slice(0, ROUTES_LIMIT)
56
+ @cache = cache.slice(*route_hashes)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -97,8 +97,7 @@ module Contrast
97
97
  # @param event [Contrast::Agent::Telemetry::Event, Array<Contrast::Agent::Telemetry::TelemetryException::Event>]
98
98
  # @return [String] - JSON
99
99
  def get_event_json event
100
- hsh = [event.to_controlled_hash]
101
- hsh.to_json
100
+ Array(event.to_controlled_hash).to_json
102
101
  rescue Exception => e # rubocop:disable Lint/RescueException
103
102
  logger.error('Unable to convert TelemetryEvent to JSON string', e, hsh)
104
103
  raise(e)
@@ -22,6 +22,22 @@ module Contrast
22
22
  def self.now_ms
23
23
  (Time.now.to_f * 1000).to_i
24
24
  end
25
+
26
+ # Return current time in iso8601 format.
27
+ #
28
+ # @return[String]
29
+ def self.time_now
30
+ Time.now.utc.iso8601(7)
31
+ end
32
+
33
+ # Converts time given in ms format form TS to HttpDate.
34
+ # Returns time format for If-Modified-Since: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
35
+ # Note: The Time class treats GMT (Greenwich Mean Time) and UTC (Coordinated Universal Time) as equivalent.
36
+ #
37
+ # @param time [Integer] time in ms.
38
+ def self.ms_to_httpdate time
39
+ Time.at(time / 1000).httpdate unless time.nil?
40
+ end
25
41
  end
26
42
  end
27
43
  end
data/lib/contrast.rb CHANGED
@@ -60,12 +60,13 @@ require 'contrast/components/protect'
60
60
  require 'contrast/components/sampling'
61
61
  require 'contrast/components/scope'
62
62
  require 'contrast/components/settings'
63
+ require 'contrast/utils/routes_sent'
63
64
  require 'contrast/utils/telemetry_hash'
64
65
  require 'contrast/utils/telemetry'
65
66
  require 'contrast/agent/telemetry/events/exceptions/telemetry_exception_event'
66
67
  require 'contrast/agent_lib/interface'
67
68
 
68
- module Contrast
69
+ module Contrast # :nodoc:
69
70
  CONFIG = Contrast::Components::Config::Interface.new
70
71
  SCOPE = Contrast::Components::Scope::Interface.new
71
72
  API = CONFIG.api
@@ -81,6 +82,7 @@ end
81
82
 
82
83
  module Contrast
83
84
  TELEMETRY_EXCEPTIONS = (Contrast::Utils::TelemetryHash.new if Contrast::Utils::Telemetry.exceptions_enabled?)
85
+ ROUTES_SENT = Contrast::Utils::RoutesSent.new
84
86
  end
85
87
 
86
88
  # This needs to be required very early, after component interfaces, and before instrumentation attempts
data/ruby-agent.gemspec CHANGED
@@ -101,7 +101,11 @@ end
101
101
 
102
102
  # Dependencies not mocked out during RSpec that we test real code of, beyond just frameworks.
103
103
  def self.add_tested_gems spec
104
- spec.add_development_dependency 'async'
104
+ if RUBY_VERSION < '3.0.0'
105
+ spec.add_development_dependency 'async', '~> 1.30.3'
106
+ else
107
+ spec.add_development_dependency 'async'
108
+ end
105
109
  spec.add_development_dependency 'execjs'
106
110
  spec.add_development_dependency 'rhino'
107
111
  spec.add_development_dependency 'sqlite3'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contrast-agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.8.0
4
+ version: 6.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - galen.palmer@contrastsecurity.com
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: exe
15
15
  cert_chain: []
16
- date: 2022-09-08 00:00:00.000000000 Z
16
+ date: 2022-10-07 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: bundler
@@ -305,16 +305,16 @@ dependencies:
305
305
  name: async
306
306
  requirement: !ruby/object:Gem::Requirement
307
307
  requirements:
308
- - - ">="
308
+ - - "~>"
309
309
  - !ruby/object:Gem::Version
310
- version: '0'
310
+ version: 1.30.3
311
311
  type: :development
312
312
  prerelease: false
313
313
  version_requirements: !ruby/object:Gem::Requirement
314
314
  requirements:
315
- - - ">="
315
+ - - "~>"
316
316
  - !ruby/object:Gem::Version
317
- version: '0'
317
+ version: 1.30.3
318
318
  - !ruby/object:Gem::Dependency
319
319
  name: execjs
320
320
  requirement: !ruby/object:Gem::Requirement
@@ -678,22 +678,22 @@ email:
678
678
  executables: []
679
679
  extensions:
680
680
  - ext/cs__common/extconf.rb
681
- - ext/cs__assess_hash/extconf.rb
682
- - ext/cs__assess_basic_object/extconf.rb
683
- - ext/cs__assess_string/extconf.rb
681
+ - ext/cs__assess_module/extconf.rb
682
+ - ext/cs__assess_marshal_module/extconf.rb
683
+ - ext/cs__assess_array/extconf.rb
684
+ - ext/cs__os_information/extconf.rb
685
+ - ext/cs__assess_string_interpolation/extconf.rb
684
686
  - ext/cs__assess_regexp/extconf.rb
687
+ - ext/cs__assess_string/extconf.rb
688
+ - ext/cs__assess_hash/extconf.rb
685
689
  - ext/cs__assess_yield_track/extconf.rb
686
- - ext/cs__assess_string_interpolation/extconf.rb
687
- - ext/cs__scope/extconf.rb
688
690
  - ext/cs__contrast_patch/extconf.rb
689
- - ext/cs__assess_module/extconf.rb
690
691
  - ext/cs__assess_kernel/extconf.rb
691
- - ext/cs__assess_marshal_module/extconf.rb
692
692
  - ext/cs__assess_test/extconf.rb
693
- - ext/cs__os_information/extconf.rb
694
- - ext/cs__assess_array/extconf.rb
695
- - ext/cs__tests/extconf.rb
693
+ - ext/cs__scope/extconf.rb
696
694
  - ext/cs__assess_fiber_track/extconf.rb
695
+ - ext/cs__tests/extconf.rb
696
+ - ext/cs__assess_basic_object/extconf.rb
697
697
  extra_rdoc_files: []
698
698
  files:
699
699
  - ".clang-format"
@@ -895,11 +895,8 @@ files:
895
895
  - lib/contrast.rb
896
896
  - lib/contrast/agent.rb
897
897
  - lib/contrast/agent/assess.rb
898
- - lib/contrast/agent/assess/contrast_event.rb
899
898
  - lib/contrast/agent/assess/contrast_object.rb
900
899
  - lib/contrast/agent/assess/events/event_data.rb
901
- - lib/contrast/agent/assess/events/event_factory.rb
902
- - lib/contrast/agent/assess/events/source_event.rb
903
900
  - lib/contrast/agent/assess/finalizers/freeze.rb
904
901
  - lib/contrast/agent/assess/finalizers/hash.rb
905
902
  - lib/contrast/agent/assess/policy/dynamic_source_factory.rb
@@ -997,6 +994,7 @@ files:
997
994
  - lib/contrast/agent/patching/policy/trigger_node.rb
998
995
  - lib/contrast/agent/protect/exploitable_collection.rb
999
996
  - lib/contrast/agent/protect/input_analyzer/input_analyzer.rb
997
+ - lib/contrast/agent/protect/input_analyzer/worth_watching_analyzer.rb
1000
998
  - lib/contrast/agent/protect/policy/applies_command_injection_rule.rb
1001
999
  - lib/contrast/agent/protect/policy/applies_deserialization_rule.rb
1002
1000
  - lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb
@@ -1113,8 +1111,8 @@ files:
1113
1111
  - lib/contrast/agent/reporting/reporting_events/route_coverage.rb
1114
1112
  - lib/contrast/agent/reporting/reporting_events/route_discovery.rb
1115
1113
  - lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb
1116
- - lib/contrast/agent/reporting/reporting_events/server_activity.rb
1117
1114
  - lib/contrast/agent/reporting/reporting_events/server_reporting_event.rb
1115
+ - lib/contrast/agent/reporting/reporting_events/server_settings.rb
1118
1116
  - lib/contrast/agent/reporting/reporting_utilities/audit.rb
1119
1117
  - lib/contrast/agent/reporting/reporting_utilities/build_preflight.rb
1120
1118
  - lib/contrast/agent/reporting/reporting_utilities/endpoints.rb
@@ -1127,6 +1125,7 @@ files:
1127
1125
  - lib/contrast/agent/reporting/reporting_utilities/response_handler.rb
1128
1126
  - lib/contrast/agent/reporting/reporting_utilities/response_handler_mode.rb
1129
1127
  - lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb
1128
+ - lib/contrast/agent/reporting/server_settings_worker.rb
1130
1129
  - lib/contrast/agent/reporting/settings/application_settings.rb
1131
1130
  - lib/contrast/agent/reporting/settings/assess.rb
1132
1131
  - lib/contrast/agent/reporting/settings/assess_server_feature.rb
@@ -1145,6 +1144,7 @@ files:
1145
1144
  - lib/contrast/agent/reporting/settings/rule_definition.rb
1146
1145
  - lib/contrast/agent/reporting/settings/sampling.rb
1147
1146
  - lib/contrast/agent/reporting/settings/sanitizer.rb
1147
+ - lib/contrast/agent/reporting/settings/security_logger.rb
1148
1148
  - lib/contrast/agent/reporting/settings/sensitive_data_masking.rb
1149
1149
  - lib/contrast/agent/reporting/settings/sensitive_data_masking_rule.rb
1150
1150
  - lib/contrast/agent/reporting/settings/server_features.rb
@@ -1195,9 +1195,11 @@ files:
1195
1195
  - lib/contrast/components/assess_rules.rb
1196
1196
  - lib/contrast/components/base.rb
1197
1197
  - lib/contrast/components/config.rb
1198
+ - lib/contrast/components/config/sources.rb
1198
1199
  - lib/contrast/components/heap_dump.rb
1199
1200
  - lib/contrast/components/inventory.rb
1200
1201
  - lib/contrast/components/logger.rb
1202
+ - lib/contrast/components/polling.rb
1201
1203
  - lib/contrast/components/protect.rb
1202
1204
  - lib/contrast/components/ruby_component.rb
1203
1205
  - lib/contrast/components/sampling.rb
@@ -1208,6 +1210,11 @@ files:
1208
1210
  - lib/contrast/config/api_proxy_configuration.rb
1209
1211
  - lib/contrast/config/base_configuration.rb
1210
1212
  - lib/contrast/config/certification_configuration.rb
1213
+ - lib/contrast/config/config.rb
1214
+ - lib/contrast/config/diagnostics.rb
1215
+ - lib/contrast/config/diagnostics_tools.rb
1216
+ - lib/contrast/config/effective_config.rb
1217
+ - lib/contrast/config/effective_config_value.rb
1211
1218
  - lib/contrast/config/env_variables.rb
1212
1219
  - lib/contrast/config/exception_configuration.rb
1213
1220
  - lib/contrast/config/protect_rule_configuration.rb
@@ -1288,9 +1295,11 @@ files:
1288
1295
  - lib/contrast/utils/os.rb
1289
1296
  - lib/contrast/utils/patching/policy/patch_utils.rb
1290
1297
  - lib/contrast/utils/patching/policy/patcher_utils.rb
1298
+ - lib/contrast/utils/reporting/application_activity_batch_utils.rb
1291
1299
  - lib/contrast/utils/request_utils.rb
1292
1300
  - lib/contrast/utils/resource_loader.rb
1293
1301
  - lib/contrast/utils/response_utils.rb
1302
+ - lib/contrast/utils/routes_sent.rb
1294
1303
  - lib/contrast/utils/sha256_builder.rb
1295
1304
  - lib/contrast/utils/stack_trace_utils.rb
1296
1305
  - lib/contrast/utils/string_utils.rb