From 25771b63444e7bb021aa244cbce23856ea6eb552 Mon Sep 17 00:00:00 2001 From: "Z. Cliffe Schreuders" Date: Sat, 18 Mar 2017 17:03:47 +0000 Subject: [PATCH] unique_module_names for selectively ensuring a scenario doesn't repeat modules (currently only in the scenario for nested under an input) --- lib/objects/module.rb | 1 + lib/objects/system.rb | 29 ++++++++++++++++++++---- lib/readers/system_reader.rb | 6 ++++- lib/schemas/scenario_schema.xsd | 1 + scenarios/ctf/flawed_fortress_1.xml | 34 +++++++++++++++++++---------- 5 files changed, 54 insertions(+), 17 deletions(-) diff --git a/lib/objects/module.rb b/lib/objects/module.rb index a53ecbd12..b0b6122d5 100644 --- a/lib/objects/module.rb +++ b/lib/objects/module.rb @@ -13,6 +13,7 @@ class Module attr_accessor :write_to_module_with_id # the module instance that this module writes to attr_accessor :write_to_datastore # the datastore to store the result to + attr_accessor :write_module_path_to_datastore # the datastore to store the result to attr_accessor :write_output_variable # the variable/fact written to attr_accessor :output # the result of local processing attr_accessor :unique_id # the unique id for this module *instance* diff --git a/lib/objects/system.rb b/lib/objects/system.rb index 9b828b2f1..f57317876 100644 --- a/lib/objects/system.rb +++ b/lib/objects/system.rb @@ -33,7 +33,7 @@ class System # for each module specified in the scenario module_selectors.each do |module_filter| - selected_modules += select_modules(module_filter.module_type, module_filter.attributes, available_modules, selected_modules, module_filter.unique_id, module_filter.write_output_variable, module_filter.write_to_module_with_id, module_filter.received_inputs, module_filter.default_inputs_literals, module_filter.write_to_datastore, module_filter.received_datastores) + selected_modules += select_modules(module_filter.module_type, module_filter.attributes, available_modules, selected_modules, module_filter.unique_id, module_filter.write_output_variable, module_filter.write_to_module_with_id, module_filter.received_inputs, module_filter.default_inputs_literals, module_filter.write_to_datastore, module_filter.received_datastores, module_filter.write_module_path_to_datastore) end selected_modules @@ -53,6 +53,9 @@ class System Print.err "Re-attempting to resolve scenario (##{retry_count + 1})..." sleep 1 retry_count += 1 + # reset globals + $datastore = {} + $datastore_iterators = {} retry else Print.err "Tried re-randomising #{RETRIES_LIMIT} times. Still no joy." @@ -65,7 +68,7 @@ class System # returns a list containing a module (plus any default input modules and dependencies recursively) of the module type with the required attributes # modules are selected from the list of available modules and will be checked against previously selected modules for conflicts # raises an exception when unable to resolve and the retry limit has not been reached - def select_modules(module_type, required_attributes, available_modules, previously_selected_modules, unique_id, write_outputs_to, write_to_module_with_id, received_inputs, default_inputs_literals, write_to_datastore, received_datastores) + def select_modules(module_type, required_attributes, available_modules, previously_selected_modules, unique_id, write_outputs_to, write_to_module_with_id, received_inputs, default_inputs_literals, write_to_datastore, received_datastores, write_module_path_to_datastore) default_modules_to_add = [] search_list = available_modules.clone @@ -91,6 +94,16 @@ class System check_conflicts_with_list(module_for_possible_exclusion, previously_selected_modules) } + # check if modules need to be unique + # write_module_path_to_datastore + if write_module_path_to_datastore != nil && $datastore[write_module_path_to_datastore] != nil + search_list.delete_if{|module_for_possible_exclusion| + ($datastore[write_module_path_to_datastore] ||=[]).include? module_for_possible_exclusion.module_path + } + Print.verbose "Filtering to remove non-unique #{$datastore[write_module_path_to_datastore]} ~= (n=#{search_list.size})" + end + + if search_list.length == 0 raise 'failed' Print.err 'Could not find a matching module. Please check the scenario specification' @@ -106,8 +119,16 @@ class System selected.unique_id = unique_id selected.received_inputs = received_inputs selected.received_datastores = received_datastores + selected.write_module_path_to_datastore = write_module_path_to_datastore selected.default_inputs_literals = selected.default_inputs_literals.merge(default_inputs_literals) + # add module path to write_module_path_to_datastore + if selected.write_module_path_to_datastore != nil && selected.write_module_path_to_datastore != '' + Print.verbose "Adding module_path to datastore (#{selected.write_module_path_to_datastore}) to ensure same module not selected multiple times" + ($datastore[selected.write_module_path_to_datastore]||=[]).push selected.module_path + + end + # feed in input from any received datastores if selected.received_datastores != {} Print.verbose "Receiving datastores: #{selected.received_datastores}" @@ -259,7 +280,7 @@ class System def_unique_id = def_unique_id.gsub(/^.*defaultinput/, selected.unique_id) end - default_modules_to_add.concat select_modules(module_to_add.module_type, module_to_add.attributes, available_modules, previously_selected_modules + default_modules_to_add, def_unique_id, module_to_add.write_output_variable, def_write_to, module_to_add.received_inputs, module_to_add.default_inputs_literals, module_to_add.write_to_datastore, module_to_add.received_datastores) + default_modules_to_add.concat select_modules(module_to_add.module_type, module_to_add.attributes, available_modules, previously_selected_modules + default_modules_to_add, def_unique_id, module_to_add.write_output_variable, def_write_to, module_to_add.received_inputs, module_to_add.default_inputs_literals, module_to_add.write_to_datastore, module_to_add.received_datastores, module_to_add.write_module_path_to_datastore) end end else @@ -311,7 +332,7 @@ class System Print.verbose "Dependency satisfied by previously selected module: #{existing.printable_name}" else Print.verbose 'Adding required modules...' - modules_to_add += select_modules('any', required, available_modules, modules_to_add + selected_modules, '', '', '', {}, {}, {}, {}) + modules_to_add += select_modules('any', required, available_modules, modules_to_add + selected_modules, '', '', '', {}, {}, {}, {}, '') end end modules_to_add diff --git a/lib/readers/system_reader.rb b/lib/readers/system_reader.rb index efc485623..d09e50244 100644 --- a/lib/readers/system_reader.rb +++ b/lib/readers/system_reader.rb @@ -81,9 +81,13 @@ class SystemReader end end # check if we need to send the module output to a datastore - if input.xpath('@into_datastore').to_s + if input.xpath('@into_datastore').to_s != '' module_selector.write_to_datastore = input.xpath('@into_datastore').to_s end + # check if we need to send the module path to a datastore (to ensure unique module selection) + if input.xpath('@unique_module_list').to_s != '' + module_selector.write_module_path_to_datastore = input.xpath('@unique_module_list').to_s + end end diff --git a/lib/schemas/scenario_schema.xsd b/lib/schemas/scenario_schema.xsd index 47e86363d..d316c9628 100644 --- a/lib/schemas/scenario_schema.xsd +++ b/lib/schemas/scenario_schema.xsd @@ -27,6 +27,7 @@ + diff --git a/scenarios/ctf/flawed_fortress_1.xml b/scenarios/ctf/flawed_fortress_1.xml index 716bcaad5..534a39e07 100644 --- a/scenarios/ctf/flawed_fortress_1.xml +++ b/scenarios/ctf/flawed_fortress_1.xml @@ -10,23 +10,33 @@ - + - + - + - + + + + + + + + + + + - + @@ -45,10 +55,10 @@ - + - + @@ -57,12 +67,12 @@ - + - + - + @@ -83,13 +93,13 @@ - + - +