contrast-agent 7.0.0 → 7.1.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.
- checksums.yaml +4 -4
- data/lib/contrast/agent/assess/policy/policy.rb +1 -1
- data/lib/contrast/agent/deadzone/policy/policy.rb +1 -1
- data/lib/contrast/agent/patching/policy/policy.rb +2 -2
- data/lib/contrast/agent/protect/input_analyzer/worth_watching_analyzer.rb +3 -0
- data/lib/contrast/agent/protect/rule/no_sqli/no_sqli.rb +1 -1
- data/lib/contrast/agent/reporting/reporter.rb +19 -4
- data/lib/contrast/agent/reporting/reporting_events/agent_effective_config.rb +32 -0
- data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +7 -0
- data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +3 -1
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +11 -7
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +15 -7
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +2 -1
- data/lib/contrast/agent/reporting/reporting_workers/application_server_worker.rb +3 -0
- data/lib/contrast/agent/reporting/reporting_workers/reporter_heartbeat.rb +3 -0
- data/lib/contrast/agent/reporting/reporting_workers/server_settings_worker.rb +3 -0
- data/lib/contrast/agent/telemetry/base.rb +37 -12
- data/lib/contrast/agent/telemetry/client.rb +1 -3
- data/lib/contrast/agent/telemetry/telemetry.rb +0 -7
- data/lib/contrast/agent/thread/thread_watcher.rb +2 -2
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/components/agent.rb +1 -1
- data/lib/contrast/components/api.rb +2 -2
- data/lib/contrast/components/app_context.rb +1 -1
- data/lib/contrast/components/assess.rb +1 -1
- data/lib/contrast/components/assess_rules.rb +1 -1
- data/lib/contrast/components/base.rb +3 -3
- data/lib/contrast/components/config/sources.rb +12 -9
- data/lib/contrast/components/config.rb +2 -2
- data/lib/contrast/components/protect.rb +2 -2
- data/lib/contrast/components/sampling.rb +6 -4
- data/lib/contrast/components/settings.rb +1 -1
- data/lib/contrast/config/certification_configuration.rb +1 -1
- data/lib/contrast/config/configuration_files.rb +47 -0
- data/lib/contrast/config/diagnostics/command_line.rb +24 -0
- data/lib/contrast/config/{config.rb → diagnostics/config.rb} +21 -6
- data/lib/contrast/config/diagnostics/contrast_ui.rb +24 -0
- data/lib/contrast/config/diagnostics/effective_config.rb +28 -0
- data/lib/contrast/config/diagnostics/effective_config_value.rb +14 -0
- data/lib/contrast/config/diagnostics/environment_variables.rb +51 -0
- data/lib/contrast/config/{diagnostics.rb → diagnostics/monitor.rb} +10 -10
- data/lib/contrast/config/diagnostics/source_config_value.rb +51 -0
- data/lib/contrast/config/diagnostics/tools.rb +188 -0
- data/lib/contrast/config/diagnostics/user_configuration_file.rb +44 -0
- data/lib/contrast/config/request_audit_configuration.rb +1 -1
- data/lib/contrast/config/server_configuration.rb +1 -1
- data/lib/contrast/configuration.rb +90 -57
- data/lib/contrast/utils/hash_utils.rb +43 -0
- data/lib/contrast/utils/json.rb +46 -0
- data/lib/contrast/utils/net_http_base.rb +75 -26
- metadata +16 -7
- data/lib/contrast/config/diagnostics_tools.rb +0 -99
- data/lib/contrast/config/effective_config.rb +0 -131
- data/lib/contrast/config/effective_config_value.rb +0 -32
@@ -4,7 +4,7 @@
|
|
4
4
|
require 'contrast/utils/env_configuration_item'
|
5
5
|
require 'ougai'
|
6
6
|
require 'contrast/configuration'
|
7
|
-
require 'contrast/config/diagnostics'
|
7
|
+
require 'contrast/config/diagnostics/monitor'
|
8
8
|
|
9
9
|
module Contrast
|
10
10
|
module Components
|
@@ -249,7 +249,7 @@ module Contrast
|
|
249
249
|
return unless current_level.nil? == false && current_level.cs__respond_to?(dot_path_array[-1])
|
250
250
|
|
251
251
|
current_level.send("#{ dot_path_array[-1] }=", value)
|
252
|
-
sources.set(dot_path_array.join('.'), Contrast::Components::Config::Sources::
|
252
|
+
sources.set(dot_path_array.join('.'), Contrast::Components::Config::Sources::ENVIRONMENT_VARIABLE)
|
253
253
|
end
|
254
254
|
end
|
255
255
|
end
|
@@ -130,7 +130,7 @@ module Contrast
|
|
130
130
|
# Converts current configuration to effective config values class and appends them to
|
131
131
|
# EffectiveConfig class.
|
132
132
|
#
|
133
|
-
# @param effective_config [Contrast::
|
133
|
+
# @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
|
134
134
|
def to_effective_config effective_config
|
135
135
|
super
|
136
136
|
protect_rules_to_effective_config(effective_config)
|
@@ -138,7 +138,7 @@ module Contrast
|
|
138
138
|
|
139
139
|
private
|
140
140
|
|
141
|
-
# @param effective_config [Contrast::
|
141
|
+
# @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
|
142
142
|
def protect_rules_to_effective_config effective_config
|
143
143
|
return unless defend_rules
|
144
144
|
|
@@ -136,7 +136,7 @@ module Contrast
|
|
136
136
|
# Converts current configuration to effective config values class and appends them to
|
137
137
|
# EffectiveConfig class.
|
138
138
|
#
|
139
|
-
# @param effective_config [Contrast::
|
139
|
+
# @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
|
140
140
|
def to_effective_config effective_config
|
141
141
|
confirm_sources
|
142
142
|
|
@@ -161,10 +161,11 @@ module Contrast
|
|
161
161
|
# back to the default values.
|
162
162
|
def confirm_sources
|
163
163
|
if sampling_control[:enabled] == DEFAULT_SAMPLING_ENABLED
|
164
|
-
Contrast::CONFIG.sources.set('assess.sampling.enable', Contrast::Components::Config::Sources::
|
164
|
+
Contrast::CONFIG.sources.set('assess.sampling.enable', Contrast::Components::Config::Sources::DEFAULT_VALUE)
|
165
165
|
end
|
166
166
|
if sampling_control[:window] == DEFAULT_SAMPLING_WINDOW_MS
|
167
|
-
Contrast::CONFIG.sources.set('assess.sampling.window_ms',
|
167
|
+
Contrast::CONFIG.sources.set('assess.sampling.window_ms',
|
168
|
+
Contrast::Components::Config::Sources::DEFAULT_VALUE)
|
168
169
|
end
|
169
170
|
{
|
170
171
|
'baseline' => :baseline,
|
@@ -172,7 +173,8 @@ module Contrast
|
|
172
173
|
'response_frequency' => :response_frequency
|
173
174
|
}.each do |k, v|
|
174
175
|
if sampling_control[v] == cs__class.cs__const_get("DEFAULT_SAMPLING_#{ v.upcase }")
|
175
|
-
Contrast::CONFIG.sources.set("assess.sampling.#{ k }",
|
176
|
+
Contrast::CONFIG.sources.set("assess.sampling.#{ k }",
|
177
|
+
Contrast::Components::Config::Sources::DEFAULT_VALUE)
|
176
178
|
end
|
177
179
|
end
|
178
180
|
end
|
@@ -283,7 +283,7 @@ module Contrast
|
|
283
283
|
return unless level.cs__is_a?(Hash)
|
284
284
|
|
285
285
|
level[parts[-1]] = value
|
286
|
-
Contrast::CONFIG.sources.set(parts.join('.'), Contrast::Components::Config::Sources::
|
286
|
+
Contrast::CONFIG.sources.set(parts.join('.'), Contrast::Components::Config::Sources::CONTRAST_UI)
|
287
287
|
end
|
288
288
|
end
|
289
289
|
end
|
@@ -38,7 +38,7 @@ module Contrast
|
|
38
38
|
# Converts current configuration to effective config values class and appends them to
|
39
39
|
# EffectiveConfig class.
|
40
40
|
#
|
41
|
-
# @param effective_config [Contrast::
|
41
|
+
# @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
|
42
42
|
def to_effective_config effective_config
|
43
43
|
add_effective_config_values(effective_config, CONFIG_VALUES, CANON_NAME, CONTRAST)
|
44
44
|
end
|
@@ -0,0 +1,47 @@
|
|
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/duck_utils'
|
5
|
+
require 'contrast/utils/object_share'
|
6
|
+
require 'contrast/components/config/sources'
|
7
|
+
require 'contrast/config/diagnostics/tools'
|
8
|
+
|
9
|
+
module Contrast
|
10
|
+
module Config
|
11
|
+
# This class will hold all the references for the configuration files. It will safe read values used to
|
12
|
+
# identify the source of configuration in Configuration Diagnostics reported to TS.
|
13
|
+
class ConfigurationFiles
|
14
|
+
# @return [String] path of the main configuration file.
|
15
|
+
attr_accessor :main_file
|
16
|
+
|
17
|
+
# @return [Array<Contrast::Config::LocalSourceValue>]
|
18
|
+
def source_files
|
19
|
+
@_source_files ||= []
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param path [String]
|
23
|
+
# @param values [Hash]
|
24
|
+
def add_source_file path, values
|
25
|
+
source_files << Contrast::Config::LocalSourceValue.new(path, values)
|
26
|
+
@main_file = path if source_files.length == 1
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# This class will hold all the info about the read file.
|
31
|
+
class LocalSourceValue
|
32
|
+
YML_EXT = '.yml'
|
33
|
+
YAML_EXT = '.yaml'
|
34
|
+
# @return [String]
|
35
|
+
attr_reader :path
|
36
|
+
# @return [Hash]
|
37
|
+
attr_reader :values
|
38
|
+
|
39
|
+
# @param path [String]
|
40
|
+
# @param values [Hash]
|
41
|
+
def initialize path = '', values = {}
|
42
|
+
@path = path unless Contrast::Utils::DuckUtils.empty_duck?(path)
|
43
|
+
@values = values
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,24 @@
|
|
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/config/diagnostics/effective_config_value'
|
5
|
+
require 'contrast/config/diagnostics/tools'
|
6
|
+
require 'contrast/utils/object_share'
|
7
|
+
|
8
|
+
module Contrast
|
9
|
+
module Config
|
10
|
+
module Diagnostics
|
11
|
+
# Reads All ENV variables.
|
12
|
+
module CommandLine
|
13
|
+
class << self
|
14
|
+
def command_line_settings
|
15
|
+
cli = Contrast::Config::Diagnostics::Tools.flatten_settings(Contrast::CONFIG.sources.
|
16
|
+
for(Contrast::Components::Config::Sources::COMMAND_LINE))
|
17
|
+
|
18
|
+
Contrast::Config::Diagnostics::Tools.to_config_values(cli, source: true)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -1,24 +1,32 @@
|
|
1
1
|
# Copyright (c) 2023 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/effective_config'
|
4
|
+
require 'contrast/config/diagnostics/effective_config'
|
5
|
+
require 'contrast/config/diagnostics/user_configuration_file'
|
6
|
+
require 'contrast/config/diagnostics/environment_variables'
|
7
|
+
require 'contrast/config/diagnostics/command_line'
|
8
|
+
require 'contrast/config/diagnostics/contrast_ui'
|
5
9
|
|
6
10
|
module Contrast
|
7
|
-
module
|
8
|
-
module
|
11
|
+
module Config
|
12
|
+
module Diagnostics
|
9
13
|
# This class is responsible for logging to file the effective Agent configurations after startup.
|
10
14
|
class Config
|
15
|
+
# @return [Contrast::Config::Diagnostics::EffectiveConfig]
|
11
16
|
attr_reader :effective_config
|
12
17
|
# @return [String] Status message of the connection with TS.
|
13
18
|
attr_accessor :config_status
|
19
|
+
# @return [Contrast::Config::Diagnostics::UserConfigurationFile]
|
20
|
+
attr_reader :user_configuration_file
|
14
21
|
|
15
22
|
MESSAGE_FAIL = 'Unable to connect to Contrast, configuration details from the Contrast UI will not be included.'
|
16
23
|
MESSAGE_SUCCESSFUL = 'Success'
|
17
24
|
CONN_STATUS_MSG_FAILURE = 'Unable to connect to Contrast, insufficient connection properties provided.'
|
18
25
|
|
19
26
|
def initialize
|
20
|
-
@effective_config = Contrast::
|
27
|
+
@effective_config = Contrast::Config::Diagnostics::EffectiveConfig.new
|
21
28
|
@config_status = Contrast::Utils::ObjectShare::EMPTY_STRING
|
29
|
+
@user_configuration_file = Contrast::Config::Diagnostics::UserConfigurationFile.new
|
22
30
|
end
|
23
31
|
|
24
32
|
# This method will set the status from the request/response cycles
|
@@ -31,7 +39,6 @@ module Contrast
|
|
31
39
|
else
|
32
40
|
MESSAGE_FAIL
|
33
41
|
end
|
34
|
-
true
|
35
42
|
end
|
36
43
|
|
37
44
|
# This method will set the status message from the config validation
|
@@ -40,7 +47,15 @@ module Contrast
|
|
40
47
|
end
|
41
48
|
|
42
49
|
def to_controlled_hash
|
43
|
-
|
50
|
+
{
|
51
|
+
status: @config_status,
|
52
|
+
effective_config: effective_config.to_controlled_hash,
|
53
|
+
user_configuration_file: user_configuration_file.to_controlled_hash,
|
54
|
+
environment_variable: Contrast::Config::Diagnostics::EnvironmentVariables.environment_settings(ENV).
|
55
|
+
map(&:to_controlled_hash),
|
56
|
+
command_line: Contrast::Config::Diagnostics::CommandLine.command_line_settings.map(&:to_controlled_hash),
|
57
|
+
contrast_ui: Contrast::Config::Diagnostics::ContrastUI.contrast_ui_settings.map(&:to_controlled_hash)
|
58
|
+
}.compact
|
44
59
|
end
|
45
60
|
end
|
46
61
|
end
|
@@ -0,0 +1,24 @@
|
|
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/config/diagnostics/effective_config_value'
|
5
|
+
require 'contrast/config/diagnostics/tools'
|
6
|
+
require 'contrast/utils/object_share'
|
7
|
+
|
8
|
+
module Contrast
|
9
|
+
module Config
|
10
|
+
module Diagnostics
|
11
|
+
# Reads All ENV variables.
|
12
|
+
module ContrastUI
|
13
|
+
class << self
|
14
|
+
def contrast_ui_settings
|
15
|
+
ui = Contrast::Config::Diagnostics::Tools.flatten_settings(Contrast::CONFIG.sources.
|
16
|
+
for(Contrast::Components::Config::Sources::CONTRAST_UI))
|
17
|
+
|
18
|
+
Contrast::Config::Diagnostics::Tools.to_config_values(ui, source: true)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
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/config/diagnostics/effective_config_value'
|
5
|
+
require 'contrast/config/diagnostics/tools'
|
6
|
+
require 'contrast/utils/object_share'
|
7
|
+
|
8
|
+
module Contrast
|
9
|
+
module Config
|
10
|
+
module Diagnostics
|
11
|
+
# The current effective config received from all authorized configuration channels.
|
12
|
+
class EffectiveConfig
|
13
|
+
# Value of effective agent configurations
|
14
|
+
#
|
15
|
+
# @return [Array]
|
16
|
+
attr_reader :values
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@values = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_controlled_hash
|
23
|
+
{ values: @values&.map(&:to_controlled_hash) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,14 @@
|
|
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/config/diagnostics/source_config_value'
|
5
|
+
|
6
|
+
module Contrast
|
7
|
+
module Config
|
8
|
+
module Diagnostics
|
9
|
+
# All In effect config values stored in a easy to write representation.
|
10
|
+
class EffectiveConfigValue < SourceConfigValue
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,51 @@
|
|
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/config/diagnostics/effective_config_value'
|
5
|
+
require 'contrast/config/diagnostics/tools'
|
6
|
+
require 'contrast/utils/object_share'
|
7
|
+
|
8
|
+
module Contrast
|
9
|
+
module Config
|
10
|
+
module Diagnostics
|
11
|
+
# Reads All ENV variables.
|
12
|
+
module EnvironmentVariables
|
13
|
+
class << self
|
14
|
+
NON_COMMON_ENV = %w[CONTRAST_CONFIG_PATH CONTRAST_AGENT_TELEMETRY_OPTOUT].cs__freeze
|
15
|
+
|
16
|
+
# This method will fill the canonical name for each env var and will check for any uncommon ones.
|
17
|
+
#
|
18
|
+
# @param env [Hash]
|
19
|
+
# @return [Array] array of all the values needed to be written.
|
20
|
+
def environment_settings env
|
21
|
+
env_hash = env.select do |e|
|
22
|
+
e.to_s.start_with?(Contrast::Components::Config::CONTRAST_ENV_MARKER) || NON_COMMON_ENV.include?(e.to_s)
|
23
|
+
end
|
24
|
+
environment_settings = []
|
25
|
+
env_hash.each do |key, value|
|
26
|
+
efc_value = Contrast::Config::Diagnostics::EffectiveConfigValue.new.tap do |effective_value|
|
27
|
+
next unless value
|
28
|
+
|
29
|
+
effective_value.canonical_name = if NON_COMMON_ENV.include?(key)
|
30
|
+
key.gsub(Contrast::Utils::ObjectShare::UNDERSCORE,
|
31
|
+
Contrast::Utils::ObjectShare::PERIOD).downcase
|
32
|
+
else
|
33
|
+
key.gsub(Contrast::Utils::ObjectShare::DOUBLE_UNDERSCORE,
|
34
|
+
Contrast::Utils::ObjectShare::PERIOD).downcase
|
35
|
+
end
|
36
|
+
if effective_value.canonical_name
|
37
|
+
effective_value.key =
|
38
|
+
effective_value.canonical_name.gsub(Contrast::Utils::ObjectShare::CONTRAST_DOT,
|
39
|
+
Contrast::Utils::ObjectShare::EMPTY_STRING)
|
40
|
+
end
|
41
|
+
effective_value.value = Contrast::Config::Diagnostics::Tools.value_to_s(value)
|
42
|
+
end
|
43
|
+
environment_settings << efc_value if efc_value
|
44
|
+
end
|
45
|
+
environment_settings
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -7,16 +7,16 @@ require 'contrast/utils/timer'
|
|
7
7
|
require 'contrast/utils/log_utils'
|
8
8
|
require 'contrast/components/logger'
|
9
9
|
require 'contrast/utils/object_share'
|
10
|
-
require 'contrast/config/config'
|
11
|
-
require 'contrast/config/effective_config'
|
12
|
-
require 'contrast/config/effective_config_value'
|
10
|
+
require 'contrast/config/diagnostics/config'
|
11
|
+
require 'contrast/config/diagnostics/effective_config'
|
12
|
+
require 'contrast/config/diagnostics/effective_config_value'
|
13
13
|
require 'contrast/utils/duck_utils'
|
14
14
|
|
15
15
|
module Contrast
|
16
|
-
module
|
17
|
-
module
|
16
|
+
module Config
|
17
|
+
module Diagnostics
|
18
18
|
# This class is responsible for logging to file the effective Agent configurations after startup.
|
19
|
-
class
|
19
|
+
class Monitor
|
20
20
|
include Contrast::Components::Logger::InstanceMethods
|
21
21
|
include Contrast::Utils::LogUtils
|
22
22
|
|
@@ -30,7 +30,7 @@ module Contrast
|
|
30
30
|
|
31
31
|
# @param path [String] path to write to file.
|
32
32
|
def initialize path
|
33
|
-
@path = path
|
33
|
+
@path = path unless Contrast::Utils::DuckUtils.empty_duck?(path)
|
34
34
|
end
|
35
35
|
|
36
36
|
# Write current settings to file.
|
@@ -71,9 +71,9 @@ module Contrast
|
|
71
71
|
|
72
72
|
# Returns effective configurations of the agent.
|
73
73
|
#
|
74
|
-
# @return [Contrast::
|
74
|
+
# @return [Contrast::Config::Diagnostics::Config]
|
75
75
|
def config
|
76
|
-
@_config ||= Contrast::
|
76
|
+
@_config ||= Contrast::Config::Diagnostics::Config.new
|
77
77
|
end
|
78
78
|
|
79
79
|
# Reset the state of the current effective config.
|
@@ -84,7 +84,7 @@ module Contrast
|
|
84
84
|
else
|
85
85
|
@_config.config_status
|
86
86
|
end
|
87
|
-
@_config = Contrast::
|
87
|
+
@_config = Contrast::Config::Diagnostics::Config.new
|
88
88
|
@_config.config_status = status if status
|
89
89
|
@_config
|
90
90
|
end
|
@@ -0,0 +1,51 @@
|
|
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
|
+
module Contrast
|
5
|
+
module Config
|
6
|
+
module Diagnostics
|
7
|
+
# All config values from all sources, stored in a easy to write representation.
|
8
|
+
class SourceConfigValue
|
9
|
+
# @return [String] Name of the config starting form root of yaml config.
|
10
|
+
attr_accessor :canonical_name
|
11
|
+
# @return [String] Name of the config.
|
12
|
+
attr_accessor :key
|
13
|
+
# @return [String, Boolean, array<String>] Value set for the config. Current Effective Value
|
14
|
+
attr_accessor :value
|
15
|
+
# @return [String] The source for the entry in the config.
|
16
|
+
attr_accessor :source
|
17
|
+
# @return [String,nil] The filename for the source of the config, if the source was "yaml".
|
18
|
+
attr_accessor :filename
|
19
|
+
|
20
|
+
def to_controlled_hash
|
21
|
+
{
|
22
|
+
canonical_name: canonical_name,
|
23
|
+
name: key,
|
24
|
+
value: value.cs__is_a?(Array) ? value.map(&:to_s) : value.to_s,
|
25
|
+
source: source,
|
26
|
+
filename: filename
|
27
|
+
}.compact
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_source_hash
|
31
|
+
{
|
32
|
+
canonical_name: canonical_name,
|
33
|
+
name: key,
|
34
|
+
value: value.cs__is_a?(Array) ? value.map(&:to_s) : value.to_s
|
35
|
+
}.compact
|
36
|
+
end
|
37
|
+
|
38
|
+
# Assigns file name of the config iv viable, Currently supported formats for config file are *.yaml
|
39
|
+
# and *.yml
|
40
|
+
#
|
41
|
+
# @param source [String] name of the source file yaml | yml
|
42
|
+
# @return [Array<String>, nil]
|
43
|
+
def assign_filename source
|
44
|
+
Contrast::Components::Config::Sources::APP_CONFIGURATION_FILE.each do |type|
|
45
|
+
instance_variable_set(:@filename, source) if source.include?(".#{ type.downcase }")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,188 @@
|
|
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/config/diagnostics/effective_config_value'
|
6
|
+
require 'contrast/utils/duck_utils'
|
7
|
+
|
8
|
+
module Contrast
|
9
|
+
module Config
|
10
|
+
module Diagnostics
|
11
|
+
# Diagnostics tools to be included in config components.
|
12
|
+
module Tools
|
13
|
+
CHECK = 'd'
|
14
|
+
class << self
|
15
|
+
# Creates new config instances for each read config entry from the flat generated configs.
|
16
|
+
#
|
17
|
+
# @param flats [Array] of flatten configs produced by #flatten_settings
|
18
|
+
# @param source [Boolean] flag to set the desired value class, it may be a effective or source value.
|
19
|
+
# @return [Array<Contrast::Config::Diagnostics::SourceConfigValue>]
|
20
|
+
def to_config_values flats, source: false
|
21
|
+
config_value_klass = if source
|
22
|
+
Contrast::Config::Diagnostics::SourceConfigValue
|
23
|
+
else
|
24
|
+
Contrast::Config::Diagnostics::EffectiveConfigValue
|
25
|
+
end
|
26
|
+
settings = []
|
27
|
+
flats.each do |entry|
|
28
|
+
entry.each do |key, value|
|
29
|
+
efc_value = config_value_klass.new.tap do |config_value|
|
30
|
+
config_value.canonical_name = Contrast::Utils::ObjectShare::CONTRAST_DOT + key
|
31
|
+
config_value.key = key
|
32
|
+
config_value.value = value_to_s(value)
|
33
|
+
end
|
34
|
+
settings << efc_value if efc_value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
settings
|
38
|
+
end
|
39
|
+
|
40
|
+
# Flattens out the read settings from file, env or contrast ui.
|
41
|
+
# example: {"agent.polling.server_settings_ms"=>"50000"}
|
42
|
+
#
|
43
|
+
# @param data [Hash, nil]
|
44
|
+
# @param path [String] where to look for settings.
|
45
|
+
# @param config [Hash] symbolized config to fetch keys from.
|
46
|
+
def flatten_settings data, path = [], config: Contrast::CONFIG.config.loaded_config
|
47
|
+
return [] unless data
|
48
|
+
|
49
|
+
data.each_with_object([]) do |(k, v), entries|
|
50
|
+
if v.cs__is_a?(Hash)
|
51
|
+
entries.concat(flatten_settings(v, path.dup.append(k.to_sym)))
|
52
|
+
else
|
53
|
+
entries << { "#{ path.join('.') }.#{ k }" => config.dig(*path, k).to_s }
|
54
|
+
end
|
55
|
+
end.flatten # rubocop:disable Style/MethodCalledOnDoEndBlock
|
56
|
+
end
|
57
|
+
|
58
|
+
# Recursively converts each value to string.
|
59
|
+
#
|
60
|
+
# @param value [Hash, nil]
|
61
|
+
def value_to_s value
|
62
|
+
return if value.nil?
|
63
|
+
return value if value.cs__is_a?(String)
|
64
|
+
|
65
|
+
value.each_with_object({}) do |(k, v), m| # rubocop:disable Style/HashTransformValues
|
66
|
+
m[k] = if v.cs__is_a?(Hash)
|
67
|
+
value_to_s(v)
|
68
|
+
elsif v.cs__is_a?(Array)
|
69
|
+
v.map(&:to_s)
|
70
|
+
else
|
71
|
+
v.to_s
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Converts current configuration from array of values to effective config values class and appends them to
|
78
|
+
# EffectiveConfig class. Must be used inside Config Components only.
|
79
|
+
#
|
80
|
+
# @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
|
81
|
+
# @param config_values [] array of the names of values.
|
82
|
+
# @param canonical_prefix [String] starting of the path to config => api.proxy...
|
83
|
+
# @param name_prefix [String] the name of the config prefix => contrast.api_key, contrast.url
|
84
|
+
def add_effective_config_values effective_config, config_values, canonical_prefix, name_prefix
|
85
|
+
return if config_values.to_s.empty?
|
86
|
+
|
87
|
+
config_values.each do |config_value_name|
|
88
|
+
Contrast::Config::Diagnostics::EffectiveConfigValue.new.tap do |new_effective_value|
|
89
|
+
next if Contrast::Utils::DuckUtils.empty_duck?((config_value = send(config_value_name.to_sym)))
|
90
|
+
|
91
|
+
fill_effective_value(new_effective_value, config_value, config_value_name, canonical_prefix, name_prefix)
|
92
|
+
effective_config.values << new_effective_value
|
93
|
+
rescue StandardError => e
|
94
|
+
log_error(e)
|
95
|
+
next
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Converts current configuration from single value to effective config values class and appends them to
|
101
|
+
# EffectiveConfig class. Must be used inside Config Components only.
|
102
|
+
#
|
103
|
+
# @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
|
104
|
+
# @param config_name [String] name of the config.
|
105
|
+
# @param config_value [String, Boolean] value of the config.
|
106
|
+
# @param canonical_prefix [String] starting of the path to config => api.proxy...
|
107
|
+
# @param name_prefix [String] the name of the config prefix => contrast.api_key, contrast.url
|
108
|
+
def add_single_effective_value effective_config, config_name, config_value, canonical_prefix, name_prefix
|
109
|
+
Contrast::Config::Diagnostics::EffectiveConfigValue.new.tap do |new_effective_value|
|
110
|
+
break if Contrast::Utils::DuckUtils.empty_duck?(config_value)
|
111
|
+
|
112
|
+
fill_effective_value(new_effective_value, config_value, config_name, canonical_prefix, name_prefix)
|
113
|
+
effective_config.values << new_effective_value
|
114
|
+
rescue StandardError => e
|
115
|
+
log_error(e)
|
116
|
+
next
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
# Fills instance of effective configuration value from read configuration.
|
123
|
+
#
|
124
|
+
# @param new_effective_value [Contrast::Config::Diagnostics::EffectiveConfigValue]
|
125
|
+
# @param config_value [String, Boolean] value of the config
|
126
|
+
# @param config_value_name [string] name of the value e.g. enabled?
|
127
|
+
# @param canonical_prefix [String] starting of the path to config => api.proxy...
|
128
|
+
# @param name_prefix [String] the name of the config prefix => contrast.api_key, contrast.url
|
129
|
+
# @return filled_new_effective_config [Contrast::Config::Diagnostics::EffectiveConfigValue]
|
130
|
+
def fill_effective_value new_effective_value, config_value, config_value_name, canonical_prefix, name_prefix
|
131
|
+
find_source(new_effective_value, canonical_prefix, assign_name(config_value_name), name_prefix)
|
132
|
+
new_effective_value.value = config_value
|
133
|
+
new_effective_value
|
134
|
+
end
|
135
|
+
|
136
|
+
# Assigns a proper name for the config removing '?' out of method names.
|
137
|
+
#
|
138
|
+
# @param config [String] name of the configuration
|
139
|
+
# @return [String]
|
140
|
+
def assign_name config
|
141
|
+
return Contrast::Utils::ObjectShare::EMPTY_STRING unless config
|
142
|
+
|
143
|
+
name = config.dup
|
144
|
+
if name.end_with?(Contrast::Utils::ObjectShare::QUESTION_MARK)
|
145
|
+
# check and remove '?' : start_bundled_service? => start_bundled_service
|
146
|
+
name.delete!(Contrast::Utils::ObjectShare::QUESTION_MARK)
|
147
|
+
# converts name e.g. enabled => enable
|
148
|
+
name.chop! if name.end_with?(CHECK)
|
149
|
+
name
|
150
|
+
end
|
151
|
+
name
|
152
|
+
end
|
153
|
+
|
154
|
+
# Retrieves the config value from sources by canonical name and sets the key value.
|
155
|
+
#
|
156
|
+
# @param new_effective_value [Contrast::Config::Diagnostics::EffectiveConfigValue]
|
157
|
+
# @param canonical_prefix [String] starting of the path to config => api.proxy...
|
158
|
+
# @param config_name [String] name of the config.
|
159
|
+
# @param name_prefix [String] the name of the config prefix => contrast.api_key, contrast.url
|
160
|
+
# @return [Contrast::Config::Diagnostics::EffectiveConfigValue]
|
161
|
+
def find_source new_effective_value, canonical_prefix, config_name, name_prefix
|
162
|
+
new_effective_value.key = "#{ name_prefix }.#{ config_name }"
|
163
|
+
new_effective_value.canonical_name = "#{ canonical_prefix }.#{ config_name }"
|
164
|
+
# For files we keep the whole path as source.
|
165
|
+
source = Contrast::CONFIG.sources.get(new_effective_value.canonical_name)
|
166
|
+
new_effective_value.assign_filename(source)
|
167
|
+
new_source = if source.include?(Contrast::Config::LocalSourceValue::YAML_EXT)
|
168
|
+
Contrast::Components::Config::Sources::APP_CONFIGURATION_FILE[0]
|
169
|
+
elsif source.include?(Contrast::Config::LocalSourceValue::YML_EXT)
|
170
|
+
Contrast::Components::Config::Sources::APP_CONFIGURATION_FILE[1]
|
171
|
+
else
|
172
|
+
Contrast::Components::Config::Sources::DEFAULT_VALUE
|
173
|
+
end
|
174
|
+
new_effective_value.source = new_source
|
175
|
+
new_effective_value
|
176
|
+
end
|
177
|
+
|
178
|
+
# Logs any caught error.
|
179
|
+
#
|
180
|
+
# @param error [StandardError]
|
181
|
+
def log_error error
|
182
|
+
Contrast::CONFIG.proto_logger.warn(Contrast::Config::Diagnostics::Monitor::ERROR_MESSAGE,
|
183
|
+
error: error, backtrace: error.backtrace)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|