nexpose 7.2.1 → 7.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,145 @@
1
+ module Eso
2
+ ##
3
+ # This class represents a configuration manager service, which manages a number of configurations (ie a hostname,
4
+ # port, username, and password) used to connect to services, and the services they connect to (ie, ePO, dxl, palo-alto).
5
+ #
6
+ class ConfigurationManager
7
+ attr_accessor :url, :nexpose_console
8
+
9
+ ##
10
+ # Constructor for ConfigurationManager.
11
+ #
12
+ # @param [Nexpose::Connection] nsc A logged-in Nexpose::Connection object with a valid session used to authenticate.
13
+ # @return [Eso::ConfigurationManager] The newly created configurationManager object
14
+ #
15
+ def initialize(nsc)
16
+ @nexpose_console = nsc
17
+ @url = "https://#{nsc.host}:#{nsc.port}/eso/configuration-manager/api/"
18
+ end
19
+
20
+ ##
21
+ # Return all of the services that are currently supported by this configuration manager.
22
+ #
23
+ # @return [Array] An array containing all of services in the configuration manager in String object form.
24
+ # Returns an empty array if no services have been configured.
25
+ #
26
+ def services
27
+ json_data = ::Nexpose::AJAX.get(@nexpose_console, "#{@url}service/", ::Nexpose::AJAX::CONTENT_TYPE::JSON)
28
+ JSON.parse(json_data)
29
+ end
30
+
31
+ ##
32
+ # Return all of the configurations of a particular service type.
33
+ #
34
+ # @param [String] service_name The name of a service to find configurations of.
35
+ # @return [Array] An array containing all the configurations of the given service type.
36
+ #
37
+ def service_configurations(service_name)
38
+ json_data = ::Nexpose::AJAX.get(@nexpose_console,
39
+ "#{@url}service/configuration/#{service_name}/",
40
+ ::Nexpose::AJAX::CONTENT_TYPE::JSON)
41
+ JSON.parse(json_data, :symbolize_names => true)
42
+ end
43
+
44
+ ##
45
+ # Return the configuration of a particular service type with a particular name.
46
+ #
47
+ # @param [String] service_name The name of a service to find configurations of.
48
+ # @param [String] config_name The name of the Configuration.
49
+ # @return [Eso::Configuration] A Configuration object which matches the service name and config name requested.
50
+ def configuration_by_name(service_name, config_name)
51
+ service_configs_by_type = service_configurations(service_name)
52
+ config_hash = service_configs_by_type.find { |config| config[:configName] == config_name }
53
+ Eso::Configuration.load(config_hash)
54
+ end
55
+
56
+ def configuration_type(service_name:)
57
+ json_data = ::Nexpose::AJAX.get(@nexpose_console,
58
+ "#{@url}service/configurationType/#{service_name.downcase}",
59
+ ::Nexpose::AJAX::CONTENT_TYPE::JSON)
60
+ JSON.parse(json_data)
61
+ end
62
+
63
+ ##
64
+ # Get a configuration by id. Runs a GET call against the eso/configuration-manager/api/service/configuration/CONFIGURATION_ID endpoint
65
+ # @param [String] configuration_id The id of the configuration to get
66
+ # return [JSON] A json object representing a configuration
67
+ # TODO : Update to use an Eso::Configuration
68
+ def get_configuration(configuration_id)
69
+ json_data = ::Nexpose::AJAX.get(@nexpose_console, "#{@url}/service/configuration/id/#{configuration_id}", ::Nexpose::AJAX::CONTENT_TYPE::JSON)
70
+ JSON.parse(json_data, :symbolize_names => true)
71
+ end
72
+
73
+ ##
74
+ # Create a new configuration.
75
+ #
76
+ # @param [String] payload The JSON representation of a configuration.
77
+ # @return [Integer] The configID (>= 1) of the newly created configuration. Raises error on failure.
78
+ # TODO: Update to use an Eso::Configuration
79
+ def post_service_configuration(payload)
80
+ # TODO retry if the post fails on timeout
81
+ response_body = ::Nexpose::AJAX.post(@nexpose_console, "#{@url}service/configuration", payload, ::Nexpose::AJAX::CONTENT_TYPE::JSON)
82
+ config_id = Integer(JSON.parse(response_body)['data'])
83
+ raise Exception.new("API returned invalid configID (#{config_id}) while attempting to create configuration.") unless config_id >= 1
84
+ config_id
85
+ end
86
+
87
+ ##
88
+ # Test a configuration.
89
+ #
90
+ # @param [String] payload The JSON representation of a configuration.
91
+ # @return [String] The response from the call or an APIError
92
+ # TODO: Update to use an Eso::Configuration
93
+ def test_service_configuration(payload)
94
+ ::Nexpose::AJAX.post(@nexpose_console,
95
+ "#{@url}service/configuration/test",
96
+ payload,
97
+ ::Nexpose::AJAX::CONTENT_TYPE::JSON)
98
+ end
99
+
100
+ ##
101
+ # Delete a configuration. Runs a DELETE call against the eso/configuration-manager/api/service/configuration/CONFIGURATION_ID endpoint
102
+ #
103
+ # @param [String] configuration_id The id of the configuration to delete
104
+ # return [Boolean] Return true if the api reports a successful delete. Raises an error on failure.
105
+ def delete(configuration_id)
106
+ response_body = ::Nexpose::AJAX.delete(@nexpose_console, "#{@url}service/configuration/#{configuration_id}")
107
+ raise Exception.new("Failed to delete configuration with ID: #{configuration_id}") unless 'success' == response_body
108
+ true
109
+ end
110
+
111
+ ##
112
+ # Preview assets for a configuration. Calls a POST to the eso/configuration-manager/api/service/configuration/preview endpoint
113
+ #
114
+ # @param configuration The configuration to preview
115
+ # return [Array] previewed assets
116
+ # TODO: Update to use an Eso::Configuration
117
+ def preview_assets(configuration)
118
+ response_body = ::Nexpose::AJAX.post(@nexpose_console,
119
+ "#{@url}service/configuration/preview",
120
+ configuration,
121
+ ::Nexpose::AJAX::CONTENT_TYPE::JSON)
122
+ @preview_assets = JSON.parse(response_body)["previewAssets"]
123
+ end
124
+ end
125
+
126
+ module ConfigManagerMessages
127
+ module TestConfig
128
+ AUTH_FAILED_AWS = 'Could not authenticate to Amazon Web Services.'
129
+ # Actual message will list out the bad ARNs
130
+ AUTH_FAILED_AWS_ARN = /Could not authenticate to Amazon Web Services with the following ARNs/
131
+
132
+ CONNECTION_SUCCESSFUL = 'The connection to the external service was successful.'
133
+ # Applies to invalid user, password, wrong protocol, can't reach server, bad base or search query
134
+ CONNECTION_FAILED = 'The connection to the external service failed.'
135
+
136
+ INVALID_FIELDS = 'The configuration had invalid fields.'
137
+
138
+ RETRY_AD = 'Failed to reach out to the Active Directory service, will try again.'
139
+ RETRY_AWS = 'Failed to reach out to Amazon Web Services, will try again.'
140
+ RETRY_AZURE = 'Failed to reach out to the Azure service, will try again.'
141
+ RETRY_DXL = 'The DXL connection is currently down and the connection is in retry status.'
142
+ RETRY_EPO = 'Failed to reach out to the ePO service, will try again.'
143
+ end
144
+ end
145
+ end
data/lib/eso/filter.rb ADDED
@@ -0,0 +1,137 @@
1
+ module Eso
2
+ class Filter
3
+ # These are defined in Eso::Filters which reside in the respective service they are related to.
4
+ attr_accessor :type
5
+
6
+ # These are the individual filter items
7
+ attr_accessor :filter_items
8
+
9
+ # Constructor for Filter.
10
+ #
11
+ # @param [String] type The type of filter this is. They are based on the service this filter exists in. These are defined in Eso::Filters which reside in the respective service they are related to.
12
+ # @param [Array] items Array of filters of this type
13
+ # @return [Eso::Filter] The newly created filter object
14
+ #
15
+ def initialize(type:, items: [])
16
+ @type = type
17
+ @filter_items = items
18
+ end
19
+
20
+ # Append a filter_item later
21
+ def <<(filter_item)
22
+ @filter_items << filter_item
23
+ end
24
+
25
+ def to_json
26
+ self.to_hash.to_json
27
+ end
28
+
29
+ def to_hash
30
+ hash = {}
31
+ hash[@type.to_sym] = {
32
+ valueClass: 'Array',
33
+ items: @filter_items.map{|item| item.to_hash}
34
+ }
35
+ hash
36
+ end
37
+ alias_method :to_h, :to_hash
38
+
39
+ class FilterItem
40
+ attr_accessor :type
41
+ # Examples are "OR", "IN", "CONTAINS". These should probably be constantized somewhere.
42
+ attr_accessor :operator
43
+
44
+ # Array containing the values to filter on
45
+ attr_accessor :operands
46
+
47
+ def initialize(type:, operator:, operands:)
48
+ @type = "#{type}_ITEM"
49
+ @operator = operator
50
+ process_operands(operands)
51
+ end
52
+
53
+ def process_operands(operands)
54
+ @operands =
55
+ if ["IS_EMPTY", "IS_NOT_EMPTY"].include? @operator
56
+ nil
57
+ elsif @type == "#{Eso::Filters::IP_ADDRESS}_ITEM" ||
58
+ @type == "#{Eso::Filters::IP_RANGE}_ITEM" ||
59
+ @type == "#{Eso::Filters::OPEN_PORT}_ITEM" ||
60
+ @type == "#{Eso::Filters::RISK_SCORE}_ITEM" ||
61
+ @type == "#{Eso::Filters::CVSS_SCORE}_ITEM"
62
+ operands.first.split('-')
63
+ else
64
+ operands
65
+ end
66
+
67
+ if @operands == nil
68
+ return
69
+ end
70
+ @operands.map! do |value|
71
+ # This regex is used to determine if the string is actually a float.
72
+ # http://stackoverflow.com/questions/1034418/determine-if-a-string-is-a-valid-float-value
73
+ if value =~ /^\s*[+-]?((\d+_?)*\d+(\.(\d+_?)*\d+)?|\.(\d+_?)*\d+)(\s*|([eE][+-]?(\d+_?)*\d+)\s*)$/
74
+ if (@type == "#{Eso::Filters::OPEN_PORT}_ITEM")
75
+ value.to_i
76
+ else
77
+ value.to_f
78
+ end
79
+ # If it's not a float, let's see if it's an integer.
80
+ elsif value.to_i.to_s == value
81
+ value.to_i
82
+ # Guess not, so lets keep the original value.
83
+ else
84
+ value
85
+ end
86
+ end
87
+ end
88
+
89
+ def to_hash
90
+ hash = {
91
+ valueClass: "Object",
92
+ objectType: @type,
93
+ properties: {
94
+ operator: {
95
+ valueClass: "String",
96
+ value: @operator
97
+ }
98
+ }
99
+ }
100
+ # Currently there are no standards that say how many operands a filter can have
101
+ operand_hash = {}
102
+ operand_counter = 1
103
+ unless @operands.nil?
104
+ @operands.each do |operand|
105
+ label = "operand#{operand_counter}".to_sym
106
+
107
+ # A correct value class is required because Jackson expects it.
108
+ # A Jackson processor for Ruby would probably make this much nicer
109
+ # Also, defaulting to Number is probably a bad idea, but based on current possible values in ESO this works.
110
+ case operand.class.to_s
111
+
112
+ when "String"
113
+ value_class = "String"
114
+ when "Array"
115
+ value_class = "Array"
116
+ when "Fixnum"
117
+ value_class = "Integer"
118
+ else
119
+ value_class = "Number"
120
+ end
121
+
122
+ operand_hash[label] = {
123
+ valueClass: value_class,
124
+ value: operand
125
+ }
126
+ operand_counter += 1
127
+ end
128
+
129
+ hash[:properties].merge! operand_hash
130
+ end
131
+
132
+ hash
133
+ end
134
+ end
135
+ end
136
+ end
137
+
@@ -0,0 +1,88 @@
1
+ module Eso
2
+
3
+ module IntegrationOptionNames
4
+ IMPORT_AD_ASSETS = 'import_ad_assets'
5
+ IMPORT_EPO_ASSETS = 'import_epo_assets'
6
+ SYNC_AZURE_ASSETS = 'sync_azure_assets'
7
+ SYNC_AZURE_ASSETS_WITH_TAGS = 'sync_azure_assets_with_tags'
8
+ end
9
+
10
+ # IntegrationOptionTypes is a way to categorize what various Integration Options do.
11
+ module IntegrationOptionTypes
12
+ # The IMPORT_TO_SITE Array tracks Integration Options which load Assets into a Site.
13
+ IMPORT_TO_SITE = [
14
+ IntegrationOptionNames::IMPORT_AD_ASSETS,
15
+ IntegrationOptionNames::IMPORT_EPO_ASSETS,
16
+ IntegrationOptionNames::SYNC_AZURE_ASSETS,
17
+ IntegrationOptionNames::SYNC_AZURE_ASSETS_WITH_TAGS
18
+ ]
19
+ end
20
+
21
+ class IntegrationOption
22
+ attr_accessor :name
23
+ attr_accessor :steps
24
+ attr_accessor :id
25
+
26
+ def initialize(id: nil, name:, steps: [])
27
+ @id = id
28
+ @name = name
29
+ @steps = steps
30
+ end
31
+
32
+ def site_id=(site_id)
33
+ # As of now, the site is always in the last Step of the IntegrationOption. Might change.
34
+ @steps.last.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, site_id)
35
+ end
36
+
37
+ def site_id
38
+ # As of now, the site is always in the last Step of the IntegrationOption. Might change.
39
+ @steps.last.site_id
40
+ end
41
+
42
+ # Return this object and the associated steps in a digestible JSON format.
43
+ #
44
+ # @return [String] JSON interpretation of this workflow.
45
+ #
46
+ def to_json
47
+ # Convert Object to Hash
48
+ hash = self.to_hash
49
+
50
+ # Grab the Step objects and convert to Hashes
51
+ steps = hash['steps']
52
+ hashified_steps = []
53
+ steps.each {|step| hashified_steps << step.to_hash}
54
+ hash['steps'] = hashified_steps
55
+
56
+ # Convert Hash to JSON
57
+ hash.to_json
58
+ end
59
+
60
+ # Return this object as a Hash. The corresponding Steps will still be objects.
61
+ #
62
+ # @return [Hash] Hash interpretation of this IntegrationOption.
63
+ def to_hash
64
+ hash = {}
65
+ instance_variables.each {|var| hash[var.to_s.delete("@")] = instance_variable_get(var)}
66
+ hash
67
+ end
68
+
69
+ # Load a Hash of an IntegrationOption into an actual IntegrationOption. Probably didn't need to
70
+ # break out separately, but might be useful
71
+ #
72
+ # @param [Hash] raw_integration_option is a Hash representation of an IntegrationOption
73
+ # @return [IntegrationOption] The IntegrationOption version of the Hash
74
+ def self.load(raw_integration_option)
75
+ integration_option = IntegrationOption.new(id: raw_integration_option[:id], name: raw_integration_option[:name])
76
+ steps = raw_integration_option[:steps]
77
+ steps.each do |step|
78
+ step_config = step[:stepConfiguration]
79
+ integration_option.steps << Step.new(uuid: step[:uuid],
80
+ service_name: step[:serviceName],
81
+ type_name: step_config[:typeName],
82
+ previous_type_name: step_config[:previousTypeName],
83
+ configuration_params: step_config[:configurationParams])
84
+ end
85
+ integration_option
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,178 @@
1
+ require 'nexpose'
2
+
3
+ module Eso
4
+ ##
5
+ # This class is a manager for the integration options api. Integration options match epo/dxl/etc steps
6
+ # (ie discover-epo-assets) to nexpose steps (ie import-external-assets).
7
+
8
+ class IntegrationOptionsManager
9
+
10
+ ##
11
+ # Constructor for IntegrationOptionsManager.
12
+ #
13
+ # @param [Nexpose::Connection] nsc A logged-in Nexpose::Connection object with a valid session used to authenticate.
14
+ # @return [Eso::IntegrationOptionsManager] The newly created IntegrationOptionManager object
15
+ #
16
+ def initialize(nsc)
17
+ @nexpose_console = nsc
18
+ @url = "https://#{nsc.host}:#{nsc.port}/eso/integration-manager-service/api/integration-options/"
19
+ end
20
+
21
+ ##
22
+ # Create a new or Update existing integration option.
23
+ #
24
+ # @param [String] payload The JSON representation of an integration option.
25
+ # @return [String] The integrationOptionID (a UUID) of the newly created configuration. Raises error on failure.
26
+ #
27
+ def create(payload)
28
+ # TODO retry if the post fails on timeout
29
+ response_body = ::Nexpose::AJAX.post(@nexpose_console, "#{@url}", payload, ::Nexpose::AJAX::CONTENT_TYPE::JSON)
30
+ JSON.parse(response_body)['data']['id']
31
+ end
32
+ alias_method :update, :create
33
+
34
+ # Deleting and stopping are the same thing
35
+ def delete(integration_option_id)
36
+ ::Nexpose::AJAX.delete(@nexpose_console, "#{@url}#{integration_option_id}/state")
37
+ end
38
+ alias_method :stop, :delete
39
+
40
+ ##
41
+ # Get an existing integration option.
42
+ #
43
+ # @param [String] integration_option_id The integration_option_id of the integration option.
44
+ # @return IntegrationOption for that id, or nil
45
+ #
46
+ def get(integration_option_id)
47
+ # Gets all integration options
48
+ response_body = ::Nexpose::AJAX.get(@nexpose_console, "#{@url}", ::Nexpose::AJAX::CONTENT_TYPE::JSON)
49
+ response = JSON.parse(response_body, symbolize_names: true)
50
+
51
+ # Find the desired one
52
+ raw_integration_option = response.find{|raw| raw[:id] == integration_option_id}
53
+ raise "No IntegrationOption with ID #{integration_option_id}" if raw_integration_option.nil?
54
+
55
+ # Load it to an object
56
+ IntegrationOption.load(raw_integration_option)
57
+ end
58
+
59
+ ##
60
+ # Get the status of an integration option.
61
+ #
62
+ # @param [String] integration_option_id The integration_option_id of the integration option.
63
+ # @return the state (READY, STOPPED, etc)
64
+ #
65
+ def status(integration_option_id)
66
+ response_body = ::Nexpose::AJAX.get(@nexpose_console, "#{@url}#{integration_option_id}/status", ::Nexpose::AJAX::CONTENT_TYPE::JSON)
67
+ response = JSON.parse(response_body)
68
+ response['state']
69
+ end
70
+
71
+ def start(integration_option_id)
72
+ response_body = ::Nexpose::AJAX.post(@nexpose_console, "#{@url}#{integration_option_id}/state", ::Nexpose::AJAX::CONTENT_TYPE::JSON)
73
+ JSON.parse(response_body)
74
+ end
75
+
76
+ # TODO: These build_* methods must die.
77
+ def self.build_import_epo_assets_option(name:, discovery_conn_id:, site_id: nil)
78
+ step1 = Step.new(service_name: ServiceNames::EPO, type_name: StepNames::DISCOVER_EPO)
79
+ .add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
80
+ step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::IMPORT_EXTERNAL, previous_type_name: step1.type_name)
81
+
82
+ #This isn't always known immediately, which is why we have IntegrationOption.site_id=
83
+ step2.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, site_id) if site_id
84
+ IntegrationOption.new(name: name, steps: [step1, step2])
85
+ end
86
+
87
+ def self.build_import_ad_assets_option(name:, discovery_conn_id:, site_id: nil)
88
+ step1 = Step.new(service_name: ServiceNames::ACTIVE_DIRECTORY, type_name: StepNames::DISCOVER_ACTIVE_DIRECTORY)
89
+ .add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
90
+ step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::IMPORT_EXTERNAL, previous_type_name: step1.type_name)
91
+
92
+ #This isn't always known immediately, which is why we have IntegrationOption.site_id=
93
+ step2.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, site_id) if site_id
94
+ IntegrationOption.new(name: name, steps: [step1, step2])
95
+ end
96
+
97
+ def self.build_sync_aws_assets_option(name:, discovery_conn_id:, site_id: nil)
98
+ step1 = Step.new(service_name: ServiceNames::AWS, type_name: StepNames::DISCOVER_AWS_ASSETS)
99
+ .add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
100
+ step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::SYNC_EXTERNAL, previous_type_name: step1.type_name)
101
+
102
+ #This isn't always known immediately, which is why we have IntegrationOption.site_id=
103
+ step2.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, site_id) if site_id
104
+ IntegrationOption.new(name: name, steps: [step1, step2])
105
+ end
106
+
107
+ def self.build_verify_aws_targets_option(name:, discovery_conn_id:)
108
+ step1 = Step.new(service_name: ServiceNames::AWS, type_name: StepNames::VERIFY_AWS_ASSETS)
109
+ .add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
110
+ step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::VERIFY_EXTERNAL_TARGETS,
111
+ previous_type_name: step1.type_name)
112
+ step3 = Step.new(service_name: ServiceNames::AWS, type_name: StepNames::VERIFY_AWS_ASSETS,
113
+ previous_type_name: step2.type_name)
114
+ .add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
115
+
116
+ IntegrationOption.new(name: name, steps: [step1, step2, step3])
117
+ end
118
+
119
+ def self.build_sync_azure_assets_option(name:, discovery_conn_id:, site_id: nil)
120
+ step1 = Step.new(service_name: ServiceNames::AZURE, type_name: StepNames::DISCOVER_AZURE_ASSETS)
121
+ .add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
122
+ step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::SYNC_EXTERNAL, previous_type_name: step1.type_name)
123
+
124
+ #This isn't always known immediately, which is why we have IntegrationOption.site_id=
125
+ step2.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, site_id) if site_id
126
+ IntegrationOption.new(name: name, steps: [step1, step2])
127
+ end
128
+
129
+ def self.build_sync_aws_assets_with_tags_option(name:, discovery_conn_id:, site_id: nil, tags: '')
130
+ step1 = Step.new(service_name: ServiceNames::AWS, type_name: StepNames::DISCOVER_AWS_ASSETS)
131
+ .add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
132
+ .add_property(StepConfiguration::ConfigParamProperties::IMPORT_TAGS, true)
133
+ .add_property(StepConfiguration::ConfigParamProperties::EXCLUDE_ASSETS_WITH_TAGS, "")
134
+ .add_property(StepConfiguration::ConfigParamProperties::ONLY_IMPORT_THESE_TAGS, tags)
135
+ step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::SYNC_EXTERNAL, previous_type_name: step1.type_name)
136
+
137
+ #This isn't always known immediately, which is why we have IntegrationOption.site_id=
138
+ step2.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, site_id) if site_id
139
+ IntegrationOption.new(name: name, steps: [step1, step2])
140
+ end
141
+
142
+ def self.build_sync_azure_assets_with_tags_option(name:, discovery_conn_id:, site_id: nil, only_tags: '', exclude_tags: '')
143
+ step1 = Step.new(service_name: ServiceNames::AZURE, type_name: StepNames::DISCOVER_AZURE_ASSETS)
144
+ .add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
145
+ .add_property(StepConfiguration::ConfigParamProperties::IMPORT_TAGS, true)
146
+ .add_property(StepConfiguration::ConfigParamProperties::EXCLUDE_ASSETS_WITH_TAGS, exclude_tags)
147
+ .add_property(StepConfiguration::ConfigParamProperties::ONLY_IMPORT_THESE_TAGS, only_tags)
148
+ step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::SYNC_EXTERNAL, previous_type_name: step1.type_name)
149
+
150
+ #This isn't always known immediately, which is why we have IntegrationOption.site_id=
151
+ step2.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, site_id) if site_id
152
+ IntegrationOption.new(name: name, steps: [step1, step2])
153
+ end
154
+
155
+ def self.build_export_risk_scores_option(name:, discovery_conn_id:)
156
+ step1 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::RISK_SCORE_UPDATED)
157
+ step2 = Step.new(service_name: ServiceNames::EPO, type_name: StepNames::PUSH_RISK_SCORE, previous_type_name: step1.type_name)
158
+ .add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
159
+ IntegrationOption.new(name: name, steps: [step1, step2])
160
+ end
161
+
162
+ def self.build_find_vuln_details_option(name:, discovery_conn_id:)
163
+ step1 = Step.new(service_name: ServiceNames::DXL, type_name: StepNames::VULN_DETAILS_REQUEST)
164
+ .add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
165
+ step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::VULN_DETAILS, previous_type_name: step1.type_name)
166
+ step3 = Step.new(service_name: ServiceNames::DXL, type_name: StepNames::VULN_DETAILS_REQUEST, previous_type_name: step2.type_name)
167
+ .add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
168
+ IntegrationOption.new(name: name, steps: [step1, step2, step3])
169
+ end
170
+
171
+ def self.build_publish_vulnerabilities_option(name:, discovery_conn_id:)
172
+ step1 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::NEW_ASSET_VULN)
173
+ step2 = Step.new(service_name: ServiceNames::DXL, type_name: StepNames::PUBLISH_VULN_INT_TYPE, previous_type_name: step1.type_name)
174
+ .add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
175
+ IntegrationOption.new(name: name, steps: [step1, step2])
176
+ end
177
+ end
178
+ end