Source code for yawning_titan.envs.generic.core.blue_action_set

import random
from typing import List, Tuple, Union

from yawning_titan.envs.generic.core.network_interface import NetworkInterface
from yawning_titan.networks.node import Node

"""
A collection of methods that a blue agent could use. This includes multiple ways to defend a network by saving nodes or
making them harder to compromise.
"""


[docs]class BlueActionSet: """A class representing a Blue Agents action set."""
[docs] def __init__(self, network_interface: NetworkInterface): """ Initialise a blue agents action set. Args: network_interface: Object that allows the class to interact with the network settings_file: Dictionary containing configuration data """ self.network_interface = network_interface
[docs] def reduce_node_vulnerability(self, node: Node) -> Tuple[str, Node]: """ Reduce the vulnerability of the target node. Will not reduce the vulnerability past the lower bound setting in the configuration file: - BLUE: node_vulnerability_min :param node: The node to reduce the vulnerability of as an instance of ``Node``. :returns: The name of the action taken ("reduce_vulnerability") and the ``Node`` the action was taken on. """ # gets the current vulnerability current_vulnerability = node.vulnerability_score # updates the vulnerability of the node new_vulnerability_score = current_vulnerability - 0.2 if ( new_vulnerability_score < self.network_interface.current_graph.node_vulnerability_lower_bound ): new_vulnerability_score = ( self.network_interface.current_graph.node_vulnerability_lower_bound ) node.vulnerability_score = new_vulnerability_score return "reduce_vulnerability", node
[docs] def restore_node(self, node: Node) -> Tuple[str, Node]: """ Restore a node to its starting state: safe and with its starting vulnerability. Args: node: the node to restore Returns: The name of the action ("restore_node") The name of the node the action was taken on """ self.network_interface.make_node_safe(node) node.reset_vulnerability() return "restore_node", node
[docs] def make_safe_node(self, node: Node) -> Tuple[str, Node]: """ Make a target node safe. Can also affect the vulnerability of the node. There are settings that can change how this action works in the configuration file: - BLUE: making_node_safe_modifies_vulnerability - BLUE: vulnerability_change - BLUE: making_node_safe_gives_random_vulnerability Args: The name of the action ("make_safe_node") The name of the node to make safe """ self.network_interface.make_node_safe(node) upper = self.network_interface.current_graph.node_vulnerability_upper_bound lower = self.network_interface.current_graph.node_vulnerability_lower_bound # Settings change the effects of making a node safe if ( self.network_interface.game_mode.blue.action_set.make_node_safe.increases_vulnerability.value ): # Modifies the vulnerability by a set amount (cannot increase it past the limit in the config file) change_amount = ( self.network_interface.game_mode.blue.action_set.make_node_safe.vulnerability_change.value ) new_vulnerability_score = change_amount + node.vulnerability_score # checks to make sure that the new value does not go out of the range for vulnerability if new_vulnerability_score > upper: new_vulnerability_score = upper elif new_vulnerability_score < lower: new_vulnerability_score = lower node.vulnerability_score = new_vulnerability_score elif ( self.network_interface.game_mode.blue.action_set.make_node_safe.gives_random_vulnerability.value ): # Gives the node a new random vulnerability new_vulnerability_score = round(random.uniform(lower, upper), 2) node.vulnerability_score = new_vulnerability_score return "make_node_safe", node
[docs] def scan_all_nodes(self) -> Tuple[str, None]: """ Scan all of the nodes within the environment and attempt to get their states. The blue agents ability to see intrusions is based on the values in the config file: - BLUE: chance_to_discover_intrusion_on_scan - BLUE: chance_to_discover_intrusion_on_scan_deceptive_node Returns: The name of the action ("scan") The node the action was performed on (None: as scan affects all nodes, not just 1) """ nodes = self.network_interface.current_graph.get_nodes() for node in nodes: self.network_interface.scan_node(node) return "scan", None
[docs] def isolate_node(self, node: Node) -> Tuple[str, Node]: """ Isolate a node by disabling all of its connections to other nodes. Args: node: the node to disable Returns: The name of the action ("isolate") The node affected """ self.network_interface.isolate_node(node) return "isolate", node
[docs] def reconnect_node(self, node: Node) -> Tuple[str, Node]: """ Enable all of the connections to and from a node. Args: node: the node to enable to connections to Returns: The name of the action ("connect") The node affected """ self.network_interface.reconnect_node(node) return "connect", node
[docs] def do_nothing(self) -> Tuple[str, Node]: """ Do Nothing. Returns: The name of the action ("do_nothing") The nodes affected (None: as do nothing affects no nodes) """ return "do_nothing", None
[docs] def add_deceptive_node(self, edge: int) -> Tuple[str, Union[List, None]]: """ Add a deceptive node into the environment. Deceptive nodes are the same as standard nodes except they have a 100% chance (by default) to be able to detect attacks from the red agent. A deceptive node is added on an edge between two nodes. Args: edge: The edge to place the deceptive node on Returns: The name of the action performed ("add_deceptive_node" or "do_nothing" depending on if action is valid) A pair of nodes that the deceptive node was placed between (or None if no action performed) """ # Get the nodes that are connected via the input edge nodes = self.network_interface.edge_map[edge] node = self.network_interface.add_deceptive_node(nodes[0], nodes[1]) if not node: return "do_nothing", None else: return "add_deceptive_node", [node, nodes]