contrast-agent 5.1.0 → 5.2.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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/ext/cs__assess_kernel/cs__assess_kernel.c +7 -4
  3. data/ext/cs__assess_module/cs__assess_module.c +7 -7
  4. data/ext/cs__common/cs__common.c +4 -0
  5. data/ext/cs__common/cs__common.h +1 -0
  6. data/ext/cs__contrast_patch/cs__contrast_patch.c +52 -27
  7. data/ext/cs__contrast_patch/cs__contrast_patch.h +2 -0
  8. data/ext/cs__scope/cs__scope.c +747 -0
  9. data/ext/cs__scope/cs__scope.h +88 -0
  10. data/ext/cs__scope/extconf.rb +5 -0
  11. data/lib/contrast/agent/assess/contrast_event.rb +20 -13
  12. data/lib/contrast/agent/assess/contrast_object.rb +4 -1
  13. data/lib/contrast/agent/assess/policy/propagation_node.rb +2 -5
  14. data/lib/contrast/agent/assess/policy/propagator/match_data.rb +2 -0
  15. data/lib/contrast/agent/assess/policy/trigger_method.rb +4 -1
  16. data/lib/contrast/agent/assess/rule/response/{autocomplete_rule.rb → auto_complete_rule.rb} +4 -3
  17. data/lib/contrast/agent/assess/rule/response/base_rule.rb +12 -79
  18. data/lib/contrast/agent/assess/rule/response/body_rule.rb +109 -0
  19. data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +157 -0
  20. data/lib/contrast/agent/assess/rule/response/click_jacking_header_rule.rb +26 -0
  21. data/lib/contrast/agent/assess/rule/response/csp_header_insecure_rule.rb +14 -15
  22. data/lib/contrast/agent/assess/rule/response/csp_header_missing_rule.rb +5 -25
  23. data/lib/contrast/agent/assess/rule/response/framework/rails_support.rb +29 -0
  24. data/lib/contrast/agent/assess/rule/response/header_rule.rb +70 -0
  25. data/lib/contrast/agent/assess/rule/response/hsts_header_rule.rb +12 -36
  26. data/lib/contrast/agent/assess/rule/response/parameters_pollution_rule.rb +2 -1
  27. data/lib/contrast/agent/assess/rule/response/x_content_type_header_rule.rb +26 -0
  28. data/lib/contrast/agent/assess/rule/response/x_xss_protection_header_rule.rb +36 -0
  29. data/lib/contrast/agent/middleware.rb +1 -0
  30. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +1 -3
  31. data/lib/contrast/agent/patching/policy/patch.rb +2 -6
  32. data/lib/contrast/agent/patching/policy/patcher.rb +1 -1
  33. data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +94 -0
  34. data/lib/contrast/agent/protect/rule/base.rb +28 -1
  35. data/lib/contrast/agent/protect/rule/base_service.rb +10 -1
  36. data/lib/contrast/agent/protect/rule/cmd_injection.rb +2 -0
  37. data/lib/contrast/agent/protect/rule/deserialization.rb +6 -0
  38. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +5 -1
  39. data/lib/contrast/agent/protect/rule/no_sqli.rb +1 -0
  40. data/lib/contrast/agent/protect/rule/path_traversal.rb +1 -0
  41. data/lib/contrast/agent/protect/rule/sqli/sqli_input_classification.rb +124 -0
  42. data/lib/contrast/agent/protect/rule/sqli/sqli_worth_watching.rb +121 -0
  43. data/lib/contrast/agent/protect/rule/sqli.rb +33 -0
  44. data/lib/contrast/agent/protect/rule/xxe.rb +4 -0
  45. data/lib/contrast/agent/reporting/input_analysis/input_analysis.rb +44 -0
  46. data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +115 -0
  47. data/lib/contrast/agent/reporting/input_analysis/input_type.rb +44 -0
  48. data/lib/contrast/agent/reporting/input_analysis/score_level.rb +21 -0
  49. data/lib/contrast/agent/reporting/report.rb +1 -0
  50. data/lib/contrast/agent/reporting/reporter.rb +8 -1
  51. data/lib/contrast/agent/reporting/reporting_events/finding.rb +69 -36
  52. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +88 -59
  53. data/lib/contrast/agent/reporting/reporting_events/{finding_object.rb → finding_event_object.rb} +24 -20
  54. data/lib/contrast/agent/reporting/reporting_events/finding_event_parent_object.rb +39 -0
  55. data/lib/contrast/agent/reporting/reporting_events/finding_event_property.rb +40 -0
  56. data/lib/contrast/agent/reporting/reporting_events/{finding_signature.rb → finding_event_signature.rb} +29 -24
  57. data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +12 -8
  58. data/lib/contrast/agent/reporting/reporting_events/{finding_stack.rb → finding_event_stack.rb} +23 -19
  59. data/lib/contrast/agent/reporting/reporting_events/{finding_taint_range.rb → finding_event_taint_range.rb} +17 -15
  60. data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +26 -53
  61. data/lib/contrast/agent/reporting/reporting_events/poll.rb +29 -0
  62. data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +5 -4
  63. data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +1 -0
  64. data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +1 -1
  65. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +10 -3
  66. data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +0 -1
  67. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -0
  68. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +28 -20
  69. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +1 -1
  70. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +13 -1
  71. data/lib/contrast/agent/request_context.rb +6 -1
  72. data/lib/contrast/agent/request_context_extend.rb +85 -21
  73. data/lib/contrast/agent/scope.rb +102 -107
  74. data/lib/contrast/agent/service_heartbeat.rb +45 -2
  75. data/lib/contrast/agent/version.rb +1 -1
  76. data/lib/contrast/api/decorators/bot_blocker.rb +37 -0
  77. data/lib/contrast/api/decorators/ip_denylist.rb +37 -0
  78. data/lib/contrast/api/decorators/rasp_rule_sample.rb +29 -0
  79. data/lib/contrast/api/decorators/user_input.rb +11 -1
  80. data/lib/contrast/api/decorators/virtual_patch.rb +34 -0
  81. data/lib/contrast/components/logger.rb +5 -0
  82. data/lib/contrast/components/protect.rb +4 -2
  83. data/lib/contrast/components/scope.rb +98 -91
  84. data/lib/contrast/config/agent_configuration.rb +58 -12
  85. data/lib/contrast/config/api_configuration.rb +100 -12
  86. data/lib/contrast/config/api_proxy_configuration.rb +55 -3
  87. data/lib/contrast/config/application_configuration.rb +114 -15
  88. data/lib/contrast/config/assess_configuration.rb +106 -12
  89. data/lib/contrast/config/assess_rules_configuration.rb +44 -3
  90. data/lib/contrast/config/base_configuration.rb +1 -0
  91. data/lib/contrast/config/certification_configuration.rb +74 -3
  92. data/lib/contrast/config/exception_configuration.rb +61 -3
  93. data/lib/contrast/config/heap_dump_configuration.rb +101 -17
  94. data/lib/contrast/config/inventory_configuration.rb +64 -3
  95. data/lib/contrast/config/logger_configuration.rb +46 -3
  96. data/lib/contrast/config/protect_rule_configuration.rb +36 -9
  97. data/lib/contrast/config/protect_rules_configuration.rb +120 -17
  98. data/lib/contrast/config/request_audit_configuration.rb +68 -3
  99. data/lib/contrast/config/ruby_configuration.rb +96 -22
  100. data/lib/contrast/config/sampling_configuration.rb +76 -10
  101. data/lib/contrast/config/server_configuration.rb +56 -11
  102. data/lib/contrast/configuration.rb +6 -3
  103. data/lib/contrast/logger/cef_log.rb +151 -0
  104. data/lib/contrast/utils/hash_digest.rb +14 -6
  105. data/lib/contrast/utils/log_utils.rb +114 -0
  106. data/lib/contrast/utils/middleware_utils.rb +6 -7
  107. data/lib/contrast/utils/net_http_base.rb +12 -9
  108. data/lib/contrast/utils/patching/policy/patch_utils.rb +0 -4
  109. data/lib/contrast.rb +4 -3
  110. data/ruby-agent.gemspec +1 -1
  111. data/service_executables/VERSION +1 -1
  112. data/service_executables/linux/contrast-service +0 -0
  113. data/service_executables/mac/contrast-service +0 -0
  114. metadata +41 -21
  115. data/lib/contrast/agent/assess/rule/response/cachecontrol_rule.rb +0 -184
  116. data/lib/contrast/agent/assess/rule/response/clickjacking_rule.rb +0 -66
  117. data/lib/contrast/agent/assess/rule/response/x_content_type_rule.rb +0 -52
  118. data/lib/contrast/agent/assess/rule/response/x_xss_protection_rule.rb +0 -53
  119. data/lib/contrast/extension/kernel.rb +0 -54
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/logger/log'
5
+ require 'contrast/logger/cef_log'
5
6
  require 'contrast/components/base'
6
7
 
7
8
  module Contrast
@@ -12,6 +13,10 @@ module Contrast
12
13
  Contrast::Logger::Log.instance.logger
13
14
  end
14
15
 
16
+ def cef_logger
17
+ @_cef_logger ||= Contrast::Logger::CEFLog.instance.tap(&:build_logger)
18
+ end
19
+
15
20
  def add_trace_perf_logging_for sym, custom_message = nil
16
21
  logger.add_trace_perf_logging(self, sym, custom_message)
17
22
  end
@@ -28,7 +28,8 @@ module Contrast
28
28
  end
29
29
 
30
30
  def rule_mode rule_id
31
- ::Contrast::CONFIG.root.protect.rules[rule_id]&.applicable_mode ||
31
+ str = rule_id.tr('-', '_')
32
+ ::Contrast::CONFIG.root.protect.rules[str]&.applicable_mode ||
32
33
  ::Contrast::SETTINGS.application_state.modes_by_id[rule_id] ||
33
34
  Contrast::Api::Settings::ProtectionRule::Mode::NO_ACTION
34
35
  end
@@ -47,7 +48,8 @@ module Contrast
47
48
 
48
49
  def report_custom_code_sysfile_access?
49
50
  if @_report_custom_code_sysfile_access.nil?
50
- ctrl = rule_config[Contrast::Agent::Protect::Rule::PathTraversal::NAME]
51
+ name_changed = Contrast::Agent::Protect::Rule::PathTraversal::NAME.tr('-', '_')
52
+ ctrl = rule_config[name_changed]
51
53
  @_report_custom_code_sysfile_access = true?(ctrl.detect_custom_code_accessing_system_files)
52
54
  end
53
55
  @_report_custom_code_sysfile_access
@@ -2,8 +2,8 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'fiber'
5
- require 'monitor'
6
5
  require 'contrast/agent/scope'
6
+ require 'cs__scope/cs__scope'
7
7
 
8
8
  # This is the Scope component.
9
9
  #
@@ -12,85 +12,99 @@ require 'contrast/agent/scope'
12
12
  # execution context for which we need to special case?".
13
13
  module Contrast
14
14
  module Components
15
- module Scope # :nodoc:
16
- MONITOR = Monitor.new
17
- EXECUTION_CONTEXT = {} # rubocop:disable Style/MutableConstant
18
-
19
- class Interface # :nodoc:
20
- def initialize
21
- # This is probably redundant with #scope_for_current_ec's nil check.
22
- EXECUTION_CONTEXT[Fiber.current] = Contrast::Agent::Scope.new
23
- end
24
-
25
- # This returns the scope governing the current execution context. Use this sparingly, preferring the instance
26
- # & class methods to access and query scope, rather than interacting with the scope object directly.
27
- def scope_for_current_ec
28
- MONITOR.synchronize do
29
- return EXECUTION_CONTEXT[Fiber.current] ||= Contrast::Agent::Scope.new
30
- end
31
- end
32
- end
33
-
34
- module InstanceMethods # :nodoc:
35
- # For each instance method on a scope, define a forwarder to the scope on the current execution context's scope.
36
- def scope_for_current_ec
37
- MONITOR.synchronize do
38
- return EXECUTION_CONTEXT[Fiber.current] ||= Contrast::Agent::Scope.new
39
- end
40
- end
41
-
42
- def enter_contrast_scope!
43
- scope_for_current_ec.enter_contrast_scope!
44
- end
45
-
46
- def enter_deserialization_scope!
47
- scope_for_current_ec.enter_deserialization_scope!
48
- end
49
-
50
- def enter_split_scope!
51
- scope_for_current_ec.enter_split_scope!
52
- end
53
-
54
- def enter_scope! name
55
- scope_for_current_ec.enter_scope! name
56
- end
57
-
58
- def exit_contrast_scope!
59
- scope_for_current_ec.exit_contrast_scope!
60
- end
61
-
62
- def exit_deserialization_scope!
63
- scope_for_current_ec.exit_deserialization_scope!
64
- end
65
-
66
- def exit_split_scope!
67
- scope_for_current_ec.exit_split_scope!
68
- end
69
-
70
- def exit_scope! name
71
- scope_for_current_ec.exit_scope! name
72
- end
73
-
74
- def in_contrast_scope?
75
- scope_for_current_ec.in_contrast_scope?
76
- end
77
-
78
- def in_deserialization_scope?
79
- scope_for_current_ec.in_deserialization_scope?
80
- end
81
-
82
- def in_split_scope?
83
- scope_for_current_ec.in_split_scope?
84
- end
85
-
86
- def split_scope_depth
87
- scope_for_current_ec.split_scope_depth
88
- end
89
-
90
- def in_scope? name
91
- scope_for_current_ec.in_scope? name
92
- end
93
-
15
+ # Constants defined in C:
16
+ #
17
+ # MONITOR = Mutex.new This was replaced from Monitor to Mutex.
18
+ # EXECUTION_CONTEXT = {} Hash containing all of the current ecs as keys pointing to their scope instances.
19
+ # EC_KEYS = [] set while we get the current ec, and used for sweeping the dead fibers in C.
20
+ #
21
+ # Methods defined in C:
22
+ #
23
+ # class Interface
24
+ # initializes the scope for the current fiber context.
25
+ # def initialize end;
26
+ #
27
+ # This returns the scope governing the current execution context. Use this sparingly, preferring the instance
28
+ # & class methods to access and query scope, rather than interacting with the scope object directly.
29
+ # def scope_for_current_ec end;
30
+ # end
31
+ #
32
+ # module Scope
33
+ # Singleton method for cleaning the dead fibers and unused scope instances, scope GC.
34
+ # def self.sweep_dead_ecs end;
35
+ # end
36
+ module Scope
37
+ # Methods defined in C:
38
+ #
39
+ # For each instance method on a scope, define a forwarder to the scope on the
40
+ # current execution context's scope.
41
+ # def scope_for_current_ec end;
42
+ #
43
+ # all the methods bellow are used as forwarders to be executed in the current ec.
44
+ # exp: in_contrast_scope? => scope_for_current_ec.enter_contrast_scope!
45
+ #
46
+ # Check if we are in contrast scope.
47
+ # def in_contrast_scope? end;
48
+ # @return [Boolean] check if we are in contrast scope
49
+ # if the scope is above 0 return true.
50
+ #
51
+ # check if we are in deserialization scope.
52
+ # def in_deserialization_scope? end;
53
+ # @return [Boolean] check if we are in contrast scope
54
+ # if the scope is above 0 return true.
55
+ #
56
+ # check if we are in split scope.
57
+ # def in_split_scope? end;
58
+ # @return [Boolean] check if we are in contrast scope
59
+ # if the scope is above 0 return true.
60
+ #
61
+ # enter contrast scope.
62
+ # def enter_contrast_scope! end;
63
+ # @return @contrast_scope [Integer] contrast scope increased.
64
+ #
65
+ # enter deserialization scope.
66
+ # def enter_deserialization_scope! end;
67
+ # @return @deserialization_scope [Integer] deserialization scope increased.
68
+ #
69
+ # enter split scope.
70
+ # def enter_split_scope! end;
71
+ # @return @split_scope [Integer] split scope increased.
72
+ #
73
+ # check split scope depth.
74
+ # def split_scope_depth end;
75
+ # @return @split_scope [Integer] split scope depth.
76
+ #
77
+ # exit contrast scope.
78
+ # def exit_contrast_scope! end;
79
+ # @return @contrast_scope [Integer] contrast scope decreased.
80
+ #
81
+ # exit deserialization scope.
82
+ # def exit_deserialization_scope! end;
83
+ # @return @deserialization_scope [Integer] deserialization scope decreased.
84
+ #
85
+ # exit split scope.
86
+ # def exit_split_scope! end;
87
+ # @return @split_scope [Integer] split scope decreased.
88
+ #
89
+ # Static methods to be used, the cases are defined by the usage from the above methods
90
+ #
91
+ # check if are in specific scope.
92
+ # def in_scope? name end;
93
+ # @param name [Symbol] scope symbol representing scope to check.
94
+ # @return [Boolean] check if we are in passed scope.
95
+ #
96
+ # enter specific scope.
97
+ # def enter_scope! name end;
98
+ # @param name [Symbol] scope symbol representing scope to enter.
99
+ # @return scope [Integer] entered scope value increased.
100
+ #
101
+ # exit specific scope.
102
+ # def exit_cope! name end;
103
+ # @param name [Symbol] scope symbol representing scope to exit.
104
+ # @return scope [Integer] entered scope value decreased.
105
+ module InstanceMethods
106
+ # Forwarder to execute block in contrast scope under current
107
+ # method execution context. On completion exits scope.
94
108
  def with_contrast_scope
95
109
  scope_for_current_ec.enter_contrast_scope!
96
110
  yield
@@ -98,6 +112,8 @@ module Contrast
98
112
  scope_for_current_ec.exit_contrast_scope!
99
113
  end
100
114
 
115
+ # Forwarder to execute block in deserialization scope under current
116
+ # method execution context. On completion exits scope.
101
117
  def with_deserialization_scope
102
118
  scope_for_current_ec.enter_deserialization_scope!
103
119
  yield
@@ -105,6 +121,8 @@ module Contrast
105
121
  scope_for_current_ec.exit_deserialization_scope!
106
122
  end
107
123
 
124
+ # Forwarder to execute block in split scope under current
125
+ # method execution context. On completion exits scope.
108
126
  def with_split_scope
109
127
  scope_for_current_ec.enter_split_scope!
110
128
  yield
@@ -113,17 +131,6 @@ module Contrast
113
131
  end
114
132
  end
115
133
 
116
- def self.sweep_dead_ecs
117
- # TODO: RUBY-534, #sweep_dead_ecs compensates for a lack of weak tables. when we can use WeakRef, we should
118
- # investigate removing this call and instead use the WeakRef for the Execution Context's Keys or using our
119
- # Finalizers Hash for Fibers
120
- MONITOR.synchronize do
121
- EXECUTION_CONTEXT.delete_if do |ec, _scope|
122
- !ec.alive?
123
- end
124
- end
125
- end
126
-
127
134
  ClassMethods = InstanceMethods
128
135
  end
129
136
  end
@@ -1,23 +1,69 @@
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/service_configuration'
5
+ require 'contrast/config/logger_configuration'
6
+ require 'contrast/config/ruby_configuration'
7
+ require 'contrast/config/heap_dump_configuration'
8
+ require 'contrast/config/api_configuration'
9
+
4
10
  module Contrast
5
11
  module Config
6
12
  # Common Configuration settings. Those in this section pertain to the
7
13
  # core functionality of the Agent.
8
14
  class AgentConfiguration < BaseConfiguration
9
- KEYS = {
10
- enable: EMPTY_VALUE,
11
- start_bundled_service: true,
12
- omit_body: EMPTY_VALUE,
13
- service: Contrast::Config::ServiceConfiguration,
14
- logger: Contrast::Config::LoggerConfiguration,
15
- ruby: Contrast::Config::RubyConfiguration,
16
- heap_dump: Contrast::Config::HeapDumpConfiguration
17
- }.cs__freeze
18
-
19
- def initialize hsh
20
- super(hsh, KEYS)
15
+ attr_accessor :enable, :omit_body, :start_bundled_service, :api
16
+ attr_writer :ruby, :service, :logger, :heap_dump
17
+
18
+ def initialize hsh = {}
19
+ @enable = traverse_config(hsh, :enable)
20
+ @start_bundled_service = traverse_config(hsh, :start_bundled_service)
21
+ @omit_body = traverse_config(hsh, :omit_body)
22
+ @service = Contrast::Config::ServiceConfiguration.new(traverse_config(hsh, :service))
23
+ @logger = Contrast::Config::LoggerConfiguration.new(traverse_config(hsh, :logger))
24
+ @ruby = Contrast::Config::RubyConfiguration.new(traverse_config(hsh, :ruby))
25
+ @heap_dump = Contrast::Config::HeapDumpConfiguration.new(traverse_config(hsh, :heap_dump))
26
+ @configuration_map = {}
27
+ build_configuration_map
28
+ end
29
+
30
+ def service
31
+ @service ||= Contrast::Config::ServiceConfiguration.new({})
32
+ end
33
+
34
+ def logger
35
+ @logger ||= Contrast::Config::LoggerConfiguration.new({})
36
+ end
37
+
38
+ def ruby
39
+ @ruby ||= Contrast::Config::RubyConfiguration.new({})
40
+ end
41
+
42
+ def heap_dump
43
+ @heap_dump ||= Contrast::Config::HeapDumpConfiguration.new({})
44
+ end
45
+
46
+ # Traverse the given entity to build out the configuration graph.
47
+ #
48
+ # The values will be either a hash, indicating internal nodes to
49
+ # traverse, or a value to set or the EMPTY_VALUE symbol, indicating a
50
+ # leaf node.
51
+ #
52
+ # The spec_key are the Contrast defined keys based on the instance variables of
53
+ # a given configuration.
54
+ def traverse_config values, spec_key
55
+ internal_nodes = values.cs__respond_to?(:has_key?)
56
+ val = internal_nodes ? value_from_key_config(spec_key, values) : nil
57
+ val == EMPTY_VALUE ? nil : val
58
+ end
59
+
60
+ def build_configuration_map
61
+ instance_variables.each do |key|
62
+ str_key = key.to_s.tr('@', '')
63
+ next if str_key == 'configuration_map'
64
+
65
+ @configuration_map[str_key] = send(str_key.to_sym)
66
+ end
21
67
  end
22
68
  end
23
69
  end
@@ -9,18 +9,106 @@ module Contrast
9
9
  module Config
10
10
  # Api keys configuration
11
11
  class ApiConfiguration < BaseConfiguration
12
- URL = 'https://app.contrastsecurity.com/Contrast'
13
- KEYS = {
14
- api_key: EMPTY_VALUE,
15
- url: URL,
16
- user_name: EMPTY_VALUE,
17
- service_key: EMPTY_VALUE,
18
- proxy: Contrast::Config::ApiProxyConfiguration,
19
- request_audit: Contrast::Config::RequestAuditConfiguration,
20
- certificate: Contrast::Config::CertificationConfiguration
21
- }.cs__freeze
22
- def initialize hsh
23
- super(hsh, KEYS)
12
+ # @return [String]
13
+ attr_reader :api_key
14
+ # @return [String]
15
+ attr_reader :user_name
16
+ # @return [String]
17
+ attr_reader :service_key
18
+
19
+ DEFAULT_URL = 'https://app.contrastsecurity.com/Contrast'
20
+
21
+ def initialize hsh = {}
22
+ @api_key = traverse_config(hsh, :api_key)
23
+ @url = traverse_config(hsh, :url)
24
+ @user_name = traverse_config(hsh, :user_name)
25
+ @service_key = traverse_config(hsh, :service_key)
26
+ @proxy = Contrast::Config::ApiProxyConfiguration.new(traverse_config(hsh, :proxy))
27
+ @request_audit = Contrast::Config::RequestAuditConfiguration.new(traverse_config(hsh, :request_audit))
28
+ @certificate = Contrast::Config::CertificationConfiguration.new(traverse_config(hsh, :certificate))
29
+ @configuration_map = {}
30
+ build_configuration_map
31
+ end
32
+
33
+ def url
34
+ @url.nil? ? DEFAULT_URL : @url
35
+ end
36
+
37
+ # @return [Contrast::Config::ApiProxyConfiguration]
38
+ def proxy
39
+ @proxy ||= Contrast::Config::ApiProxyConfiguration.new
40
+ end
41
+
42
+ # @return [Contrast::Config::RequestAuditConfiguration]
43
+ def request_audit
44
+ @request_audit ||= Contrast::Config::RequestAuditConfiguration.new
45
+ end
46
+
47
+ # @return [Contrast::Config::CertificationConfiguration]
48
+ def certificate
49
+ @certificate ||= Contrast::Config::CertificationConfiguration.new
50
+ end
51
+
52
+ def api_key= value
53
+ self['api_key'] = value
54
+ end
55
+
56
+ def url= value
57
+ self['url'] = value
58
+ end
59
+
60
+ def user_name= value
61
+ self['user_name'] = value
62
+ end
63
+
64
+ def service_key= value
65
+ self['service_key'] = value
66
+ end
67
+
68
+ def proxy= value
69
+ self['proxy'] = value
70
+ end
71
+
72
+ def request_audit= value
73
+ self['request_audit'] = value
74
+ end
75
+
76
+ def certificate= value
77
+ self['certificate'] = value
78
+ end
79
+
80
+ # TODO: RUBY-1493 MOVE TO BASE CONFIG
81
+
82
+ def []= key, value
83
+ instance_variable_set("@#{ key }".to_sym, value)
84
+ @configuration_map[key] = value
85
+ end
86
+
87
+ def [] key
88
+ send(key.to_sym)
89
+ end
90
+
91
+ # Traverse the given entity to build out the configuration graph.
92
+ #
93
+ # The values will be either a hash, indicating internal nodes to
94
+ # traverse, or a value to set or the EMPTY_VALUE symbol, indicating a
95
+ # leaf node.
96
+ #
97
+ # The spec_key are the Contrast defined keys based on the instance variables of
98
+ # a given configuration.
99
+ def traverse_config values, spec_key
100
+ internal_nodes = values.cs__respond_to?(:has_key?)
101
+ val = internal_nodes ? value_from_key_config(spec_key, values) : nil
102
+ val == EMPTY_VALUE ? nil : val
103
+ end
104
+
105
+ def build_configuration_map
106
+ instance_variables.each do |key|
107
+ str_key = key.to_s.tr('@', '')
108
+ next if str_key == 'configuration_map'
109
+
110
+ @configuration_map[str_key] = send(str_key.to_sym)
111
+ end
24
112
  end
25
113
  end
26
114
  end
@@ -5,9 +5,61 @@ module Contrast
5
5
  module Config
6
6
  # Api Proxy keys configuration
7
7
  class ApiProxyConfiguration < BaseConfiguration
8
- KEYS = { enable: false, url: EMPTY_VALUE }.cs__freeze
9
- def initialize hsh
10
- super(hsh, KEYS)
8
+ # @return [String] proxy url
9
+ attr_reader :url
10
+
11
+ def initialize hsh = {}
12
+ @enable = traverse_config(hsh, :enable)
13
+ @url = traverse_config(hsh, :url)
14
+ @configuration_map = {}
15
+ build_configuration_map
16
+ end
17
+
18
+ # @return [Boolean, false]
19
+ def enable
20
+ @enable.nil? ? false : @enable
21
+ end
22
+
23
+ def enable= value
24
+ self['enable'] = value
25
+ end
26
+
27
+ def url= value
28
+ self['url'] = value
29
+ end
30
+
31
+ # TODO: RUBY-1493 MOVE TO BASE CONFIG
32
+
33
+ def []= key, value
34
+ instance_variable_set("@#{ key }".to_sym, value)
35
+ @configuration_map[key] = value
36
+ end
37
+
38
+ def [] key
39
+ send(key.to_sym)
40
+ end
41
+
42
+ # Traverse the given entity to build out the configuration graph.
43
+ #
44
+ # The values will be either a hash, indicating internal nodes to
45
+ # traverse, or a value to set or the EMPTY_VALUE symbol, indicating a
46
+ # leaf node.
47
+ #
48
+ # The spec_key are the Contrast defined keys based on the instance variables of
49
+ # a given configuration.
50
+ def traverse_config values, spec_key
51
+ internal_nodes = values.cs__respond_to?(:has_key?)
52
+ val = internal_nodes ? value_from_key_config(spec_key, values) : nil
53
+ val == EMPTY_VALUE ? nil : val
54
+ end
55
+
56
+ def build_configuration_map
57
+ instance_variables.each do |key|
58
+ str_key = key.to_s.tr('@', '')
59
+ next if str_key == 'configuration_map'
60
+
61
+ @configuration_map[str_key] = send(str_key.to_sym)
62
+ end
11
63
  end
12
64
  end
13
65
  end
@@ -8,21 +8,120 @@ module Contrast
8
8
  # Common Configuration settings. Those in this section pertain to the
9
9
  # application identification functionality of the Agent.
10
10
  class ApplicationConfiguration < BaseConfiguration
11
- KEYS = {
12
- name: EMPTY_VALUE,
13
- version: EMPTY_VALUE,
14
- language: EMPTY_VALUE,
15
- path: EMPTY_VALUE,
16
- group: EMPTY_VALUE,
17
- tags: EMPTY_VALUE,
18
- code: EMPTY_VALUE,
19
- metadata: EMPTY_VALUE,
20
- session_id: Contrast::Utils::ObjectShare::EMPTY_STRING,
21
- session_metadata: Contrast::Utils::ObjectShare::EMPTY_STRING
22
- }.cs__freeze
23
-
24
- def initialize hsh
25
- super(hsh, KEYS)
11
+ # @return [String]
12
+ attr_reader :name
13
+ # @return [String]
14
+ attr_reader :version
15
+ # @return [String]
16
+ attr_reader :language
17
+ # @return [String]
18
+ attr_reader :path
19
+ # @return [String]
20
+ attr_reader :group
21
+ # @return [String]
22
+ attr_reader :tags
23
+ # @return [String]
24
+ attr_reader :code
25
+ # @return [String]
26
+ attr_reader :metadata
27
+
28
+ def initialize hsh = {}
29
+ @name = traverse_config(hsh, :name)
30
+ @version = traverse_config(hsh, :version)
31
+ @language = traverse_config(hsh, :language)
32
+ @path = traverse_config(hsh, :path)
33
+ @group = traverse_config(hsh, :group)
34
+ @tags = traverse_config(hsh, :tags)
35
+ @code = traverse_config(hsh, :code)
36
+ @metadata = traverse_config(hsh, :metadata)
37
+ @session_id = traverse_config(hsh, :session_id)
38
+ @session_metadata = traverse_config(hsh, :session_metadata)
39
+ @configuration_map = {}
40
+ build_configuration_map
41
+ end
42
+
43
+ # @return [String, Contrast::Utils::ObjectShare::EMPTY_STRING]
44
+ def session_id
45
+ @session_id ||= Contrast::Utils::ObjectShare::EMPTY_STRING
46
+ end
47
+
48
+ # @return [String, Contrast::Utils::ObjectShare::EMPTY_STRING]
49
+ def session_metadata
50
+ @session_metadata ||= Contrast::Utils::ObjectShare::EMPTY_STRING
51
+ end
52
+
53
+ def name= value
54
+ self['name'] = value
55
+ end
56
+
57
+ def version= value
58
+ self['version'] = value
59
+ end
60
+
61
+ def language= value
62
+ self['language'] = value
63
+ end
64
+
65
+ def path= value
66
+ self['path'] = value
67
+ end
68
+
69
+ def group= value
70
+ self['group'] = value
71
+ end
72
+
73
+ def tags= value
74
+ self['tags'] = value
75
+ end
76
+
77
+ def code= value
78
+ self['code'] = value
79
+ end
80
+
81
+ def metadata= value
82
+ self['metadata'] = value
83
+ end
84
+
85
+ def session_id= value
86
+ self['session_id'] = value
87
+ end
88
+
89
+ def session_metadata= value
90
+ self['session_metadata'] = value
91
+ end
92
+
93
+ # TODO: RUBY-1493 MOVE TO BASE CONFIG
94
+
95
+ def []= key, value
96
+ instance_variable_set("@#{ key }".to_sym, value)
97
+ @configuration_map[key] = value
98
+ end
99
+
100
+ def [] key
101
+ send(key.to_sym)
102
+ end
103
+
104
+ # Traverse the given entity to build out the configuration graph.
105
+ #
106
+ # The values will be either a hash, indicating internal nodes to
107
+ # traverse, or a value to set or the EMPTY_VALUE symbol, indicating a
108
+ # leaf node.
109
+ #
110
+ # The spec_key are the Contrast defined keys based on the instance variables of
111
+ # a given configuration.
112
+ def traverse_config values, spec_key
113
+ internal_nodes = values.cs__respond_to?(:has_key?)
114
+ val = internal_nodes ? value_from_key_config(spec_key, values) : nil
115
+ val == EMPTY_VALUE ? nil : val
116
+ end
117
+
118
+ def build_configuration_map
119
+ instance_variables.each do |key|
120
+ str_key = key.to_s.tr('@', '')
121
+ next if str_key == 'configuration_map'
122
+
123
+ @configuration_map[str_key] = send(str_key.to_sym)
124
+ end
26
125
  end
27
126
  end
28
127
  end