diff --git a/docs/Makefile b/docs/Makefile index d0f9af01..bc101a07 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -8,16 +8,18 @@ SOURCEDIR = . BUILDDIR = _build AUTOSUMMARY="source/_autosummary" +NOTEBOOKS="source/notebooks/notebooks" # Remove command is different depending on OS ifdef OS - RM = IF exist $(AUTOSUMMARY) ( RMDIR $(AUTOSUMMARY) /s /q ) + RM = IF exist $(AUTOSUMMARY) (RMDIR $(AUTOSUMMARY) /s /q) & IF exist $(NOTEBOOKS) (RMDIR $(NOTEBOOKS) /s /q) else ifeq ($(shell uname), Linux) - RM = rm -rf $(AUTOSUMMARY) + RM = rm -rf $(AUTOSUMMARY) $(NOTEBOOKS) endif endif + # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/index.rst b/docs/index.rst index 79e0c340..39c2e8ee 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -43,7 +43,6 @@ What is PrimAITE? source/simulation source/config source/rewards - source/customising_scenarios source/varying_config_files source/environment source/action_masking diff --git a/docs/source/about.rst b/docs/source/about.rst index 839bbb0b..7baabf48 100644 --- a/docs/source/about.rst +++ b/docs/source/about.rst @@ -39,14 +39,15 @@ PrimAITE provides a training and evaluation capability to AI agents in the conte Scenarios can be constructed to reflect network / system laydowns consisting of any configuration of nodes (e.g., PCs, servers etc.) and the networking equipment and links between them. -All nodes can be configured to contain applications, services, folders and files (and their status). +All nodes can be configured to contain applications, services, folders, and files (and their status), including a powerful terminal simulation for SSH tunnelling and remote command execution. -Traffic flows between services and applications as directed by an ‘execution definition’, with the traffic flow on the network governed by the network equipment (switches, routers and firewalls) and the ACL rules and routing tables they employ. +Realistic network traffic generated by software or by users. Packets move through the network devices (switches, routers, firewalls, network interfaces) in accordance to control rules such as: internet protocols, Access control lists (ACLs), and routing tables. -Highlights of PrimAITE’s training and evaluation capability are: +Highlights of PrimAITE's training and evaluation capability are: -- The scenario is not bound to a representation of any platform, system, or technology; - Fully configurable (network / system laydown, green pattern-of-life, red personas, reward function, ACL rules for each device, number of episodes / steps, action / observation space) and repeatable to suit the requirements of AI agents; +- Domain randomisation through stochastic agent behaviour and the ability to switch between scenario variants between environment episodes. +- Extensible through plugins to model any network behaviour. - Can integrate with any Gymnasium / Ray RLlib compliant AI agent. @@ -56,303 +57,16 @@ What is PrimAITE built with --------------------------- * `Gymnasium `_ is used as the basis for AI blue agent interaction with the PrimAITE environment -* `Networkx `_ is used as the underlying data structure used for the PrimAITE environment -* `Stable Baselines 3 `_ is used as a default source of RL algorithms (although PrimAITE is not limited to SB3 agents) -* `Ray RLlib `_ is used as an additional source of RL algorithms -* `Typer `_ is used for building CLIs (Command Line Interface applications) +* `Pydantic `_ is used for data validation +* `Platformdirs `_ is used for storing user data and configuration correctly between platforms +* `Typer `_ is used for the Command Line Interface * `Jupyterlab `_ is used as an extensible environment for interactive and reproducible computing, based on the Jupyter Notebook Architecture -* `Platformdirs `_ is used for finding the right location to store user data and configuration but varies per platform * `Plotly `_ is used for building high level charts +* `Stable Baselines 3 `_ is used for ensuring compatibility with RL libraries +* `Ray RLlib `_ is also used for ensuring compatibility with RL libraries Getting Started with PrimAITE ----------------------------- Head over to the :ref:`getting-started` page to install and setup PrimAITE! - -.. - Architecture - Nodes and Links - ****************************** - **Nodes** - An inheritance model has been adopted in order to model nodes. All nodes have the following base attributes (Class: Node): - * ID - * Name - * Type (e.g. computer, switch, RTU - enumeration) - * Priority (P1, P2, P3, P4 or P5 - enumeration) - * Hardware State (ON, OFF, RESETTING, SHUTTING_DOWN, BOOTING - enumeration) - Active Nodes also have the following attributes (Class: Active Node): - * IP Address - * Software State (GOOD, FIXING, COMPROMISED - enumeration) - * File System State (GOOD, CORRUPT, DESTROYED, REPAIRING, RESTORING - enumeration) - Service Nodes also have the following attributes (Class: Service Node): - * List of Services (where service is composed of service name and port). There is no theoretical limit on the number of services that can be modelled. Services and protocols are currently intrinsically linked (i.e. a service is an application on a node transmitting traffic of this protocol type) - * Service state (GOOD, FIXING, COMPROMISED, OVERWHELMED - enumeration) - Passive Nodes are currently not used (but may be employed for non IP-based components such as machinery actuators in future releases). - **Links** - Links are modelled both as network edges (networkx) and as Python classes, in order to extend their functionality. Links include the following attributes: - * ID - * Name - * Bandwidth (bits/s) - * Source node ID - * Destination node ID - * Protocol list (containing the loading of protocols currently running on the link) - When the simulation runs, IERs are applied to the links in order to model traffic loading, individually assigned to each protocol. This allows green (background) and red agent behaviour to be modelled, and defensive agents to identify suspicious traffic patterns at a protocol / traffic loading level of fidelity. - Information Exchange Requirements (IERs) - **************************************** - PrimAITE adopts the concept of Information Exchange Requirements (IERs) to model both green agent (background) and red agent (adversary) behaviour. IERs are used to initiate modelling of traffic loading on the network, and have the following attributes: - * ID - * Start step (i.e. which step in the training episode should the IER start) - * End step (i.e. which step in the training episode should the IER end) - * Source node ID - * Destination node ID - * Load (bits/s) - * Protocol - * Port - * Running status (i.e. on / off) - The application of green agent IERs between a source and destination follows a number of rules. Specifically: - 1. Does the current simulation time step fall between IER start and end step - 2. Is the source node operational (both physically and at an O/S level), and is the service (protocol / port) associated with the IER (a) present on this node, and (b) in an operational state (i.e. not FIXING) - 3. Is the destination node operational (both physically and at an O/S level), and is the service (protocol / port) associated with the IER (a) present on this node, and (b) in an operational state (i.e. not FIXING) - 4. Are there any Access Control List rules in place that prevent the application of this IER - 5. Are all switches in the (OSPF) path between source and destination operational (both physically and at an O/S level) - For red agent IERs, the application of IERs between a source and destination follows a number of subtly different rules. Specifically: - 1. Does the current simulation time step fall between IER start and end step - 2. Is the source node operational, and is the service (protocol / port) associated with the IER (a) present on that node and (b) already in a compromised state - 3. Is the destination node operational, and is the service (protocol / port) associated with the IER present on that node - 4. Are there any Access Control List rules in place that prevent the application of this IER - 5. Are all switches in the (OSPF) path between source and destination operational (both physically and at an O/S level) - Assuming the rules pass, the IER is applied to all relevant links (based on use of OSPF) between source and destination. - Node Pattern-of-Life - ******************** - Every node can be impacted (i.e. have a status change applied to it) by either green agent pattern-of-life or red agent pattern-of-life. This is distinct from IERs, and allows for attacks (and defence) to be modelled purely within the confines of a node. - The status changes that can be made to a node are as follows: - * All Nodes: - * Hardware State: - * ON - * OFF - * RESETTING - when a status of resetting is entered, the node will automatically exit this state after a number of steps (as defined by the nodeResetDuration configuration item) after which it returns to an ON state - * BOOTING - * SHUTTING_DOWN - * Active Nodes and Service Nodes: - * Software State: - * GOOD - * FIXING - when a status of FIXING is entered, the node will automatically exit this state after a number of steps (as defined by the osFIXINGDuration configuration item) after which it returns to a GOOD state - * COMPROMISED - * File System State: - * GOOD - * CORRUPT (can be resolved by repair or restore) - * DESTROYED (can be resolved by restore only) - * REPAIRING - when a status of repairing is entered, the node will automatically exit this state after a number of steps (as defined by the fileSystemRepairingLimit configuration item) after which it returns to a GOOD state - * RESTORING - when a status of repairing is entered, the node will automatically exit this state after a number of steps (as defined by the fileSystemRestoringLimit configuration item) after which it returns to a GOOD state - * Service Nodes only: - * Service State (for any associated service): - * GOOD - * FIXING - when a status of FIXING is entered, the service will automatically exit this state after a number of steps (as defined by the serviceFIXINGDuration configuration item) after which it returns to a GOOD state - * COMPROMISED - * OVERWHELMED - Red agent pattern-of-life has an additional feature not found in the green pattern-of-life. This is the ability to influence the state of the attributes of a node via a number of different conditions: - * DIRECT: - The pattern-of-life described by the configuration file item will be applied regardless of any other conditions in the network. This is particularly useful for direct red agent entry into the network. - * IER: - The pattern-of-life described by the configuration file item will be applied to the service on the node, only if there is an IER of the same protocol / service type incoming at the specified timestep. - * SERVICE: - The pattern-of-life described by the configuration file item will be applied to the node based on the state of a service. The service can either be on the same node, or a different node within the network. - Access Control List modelling - ***************************** - An Access Control List (ACL) is modelled to provide the means to manage traffic flows in the system. This will allow defensive agents the means to turn on / off rules, or potentially create new rules, to counter an attack. - The ACL follows a standard network firewall format. For example: - .. list-table:: ACL example - :widths: 25 25 25 25 25 - :header-rows: 1 - * - Permission - - Source IP - - Dest IP - - Protocol - - Port - * - DENY - - 192.168.1.2 - - 192.168.1.3 - - HTTPS - - 443 - * - ALLOW - - 192.168.1.4 - - ANY - - SMTP - - 25 - * - DENY - - ANY - - 192.168.1.5 - - ANY - - ANY - All ACL rules are considered when applying an IER. Logic follows the order of rules, so a DENY or PERMIT for the same parameters will override an earlier entry. - Observation Spaces - ****************** - The observation space provides the blue agent with information about the current status of nodes and links. - PrimAITE builds on top of Gymnasium Spaces to create an observation space that is easily configurable for users. It's made up of components which are managed by the :py:class:`primaite.environment.observations.ObservationsHandler`. Each training scenario can define its own observation space, and the user can choose which information to inlude, and how it should be formatted. - NodeLinkTable component - ----------------------- - For example, the :py:class:`primaite.environment.observations.NodeLinkTable` component represents the status of nodes and links as a ``gym.spaces.Box`` with an example format shown below: - An example observation space is provided below: - .. list-table:: Observation Space example - :widths: 25 25 25 25 25 25 25 - :header-rows: 1 - * - - - ID - - Hardware State - - Software State - - File System State - - Service / Protocol A - - Service / Protocol B - * - Node A - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - * - Node B - - 2 - - 1 - - 3 - - 1 - - 1 - - 1 - * - Node C - - 3 - - 2 - - 1 - - 1 - - 3 - - 2 - * - Link 1 - - 5 - - 0 - - 0 - - 0 - - 0 - - 10000 - * - Link 2 - - 6 - - 0 - - 0 - - 0 - - 0 - - 10000 - * - Link 3 - - 7 - - 0 - - 0 - - 0 - - 5000 - - 0 - For the nodes, the following values are represented: - .. code-block:: - [ - ID - Hardware State (1=ON, 2=OFF, 3=RESETTING, 4=SHUTTING_DOWN, 5=BOOTING) - Operating System State (0=none, 1=GOOD, 2=PATCHING, 3=COMPROMISED) - File System State (0=none, 1=GOOD, 2=CORRUPT, 3=DESTROYED, 4=REPAIRING, 5=RESTORING) - Service1/Protocol1 state (0=none, 1=GOOD, 2=FIXING, 3=COMPROMISED) - Service2/Protocol2 state (0=none, 1=GOOD, 2=FIXING, 3=COMPROMISED) - ] - (Note that each service available in the network is provided as a column, although not all nodes may utilise all services) - For the links, the following statuses are represented: - .. code-block:: - [ - ID - Hardware State (0=not applicable) - Operating System State (0=not applicable) - File System State (0=not applicable) - Service1/Protocol1 state (Traffic load from this protocol on this link) - Service2/Protocol2 state (Traffic load from this protocol on this link) - ] - NodeStatus component - ---------------------- - This is a MultiDiscrete observation space that can be though of as a one-dimensional vector of discrete states. - The example above would have the following structure: - .. code-block:: - [ - node1_info - node2_info - node3_info - ] - Each ``node_info`` contains the following: - .. code-block:: - [ - hardware_state (0=none, 1=ON, 2=OFF, 3=RESETTING, 4=SHUTTING_DOWN, 5=BOOTING) - software_state (0=none, 1=GOOD, 2=PATCHING, 3=COMPROMISED) - file_system_state (0=none, 1=GOOD, 2=CORRUPT, 3=DESTROYED, 4=REPAIRING, 5=RESTORING) - service1_state (0=none, 1=GOOD, 2=FIXING, 3=COMPROMISED) - service2_state (0=none, 1=GOOD, 2=FIXING, 3=COMPROMISED) - ] - In a network with three nodes and two services, the full observation space would have 15 elements. It can be written with ``gym`` notation to indicate the number of discrete options for each of the elements of the observation space. For example: - .. code-block:: - gym.spaces.MultiDiscrete([4,5,6,4,4,4,5,6,4,4,4,5,6,4,4]) - .. note:: - NodeStatus observation component provides information only about nodes. Links are not considered. - LinkTrafficLevels - ----------------- - This component is a MultiDiscrete space showing the traffic flow levels on the links in the network, after applying a threshold to convert it from a continuous to a discrete value. - There are two configurable parameters: - * ``quantisation_levels`` determines how many discrete bins to use for converting the continuous traffic value to discrete (default is 5). - * ``combine_service_traffic`` determines whether to separately output traffic use for each network protocol or whether to combine them into an overall value for the link. (default is ``True``) - For example, with default parameters and a network with three links, the structure of this component would be: - .. code-block:: - [ - link1_status - link2_status - link3_status - ] - Each ``link_status`` is a number from 0-4 representing the network load in relation to bandwidth. - .. code-block:: - 0 = No traffic (0%) - 1 = low traffic (1%-33%) - 2 = medium traffic (33%-66%) - 3 = high traffic (66%-99%) - 4 = max traffic/ overwhelmed (100%) - Using ``gym`` notation, the shape of the obs space is: ``gym.spaces.MultiDiscrete([5,5,5])``. - Action Spaces - ************** - The action space available to the blue agent comes in two types: - 1. Node-based - 2. Access Control List - 3. Any (Agent can take both node-based and ACL-based actions) - The choice of action space used during a training session is determined in the config_[name].yaml file. - **Node-Based** - The agent is able to influence the status of nodes by switching them off, resetting, or FIXING operating systems and services. In this instance, the action space is a Gymnasium spaces.Discrete type, as follows: - * Dictionary item {... ,1: [x1, x2, x3,x4] ...} - The placeholders inside the list under the key '1' mean the following: - * [0, num nodes] - Node ID (0 = nothing, node ID) - * [0, 4] - What property it's acting on (0 = nothing, 1 = state, 2 = SoftwareState, 3 = service state, 4 = file system state) - * [0, 3] - Action on property (0 = nothing, 1 = on / scan, 2 = off / repair, 3 = reset / patch / restore) - * [0, num services] - Resolves to service ID (0 = nothing, resolves to service) - **Access Control List** - The blue agent is able to influence the configuration of the Access Control List rule set (which implements a system-wide firewall). In this instance, the action space is an Gymnasium spaces.Discrete type, as follows: - * Dictionary item {... ,1: [x1, x2, x3, x4, x5, x6] ...} - The placeholders inside the list under the key '1' mean the following: - * [0, 2] - Action (0 = do nothing, 1 = create rule, 2 = delete rule) - * [0, 1] - Permission (0 = DENY, 1 = PERMIT) - * [0, num nodes] - Source IP (0 = any, then 1 -> x resolving to IP addresses) - * [0, num nodes] - Dest IP (0 = any, then 1 -> x resolving to IP addresses) - * [0, num services] - Protocol (0 = any, then 1 -> x resolving to protocol) - * [0, num ports] - Port (0 = any, then 1 -> x resolving to port) - **ANY** - The agent is able to carry out both **Node-Based** and **Access Control List** operations. - This means the dictionary will contain key-value pairs in the format of BOTH Node-Based and Access Control List as seen above. - Rewards - ******* - A reward value is presented back to the blue agent on the conclusion of every step. The reward value is calculated via two methods which combine to give the total value: - 1. Node and service status - 2. IER status - **Node and service status** - On every step, the status of each node is compared against both a reference environment (simulating the situation if the red and blue agents had not impacted the environment) - and the before and after state of the environment. If the comparison against the reference environment shows no difference, then the score provided is "AllOK". If there is a - difference with respect to the reference environment, the before and after states are compared, and a score determined. See :ref:`config` for details of reward values. - **IER status** - On every step, the full IER set is examined to determine whether green and red agent IERs are being permitted to run. Any red agent IERs running incur a penalty; any green agent - IERs not permitted to run also incur a penalty. See :ref:`config` for details of reward values. - Future Enhancements - ******************* - The PrimAITE project has an ambition to include the following enhancements in future releases: - * Integration with a suitable standardised framework to allow multi-agent integration - * Integration with external threat emulation tools, either using off-line data, or integrating at runtime diff --git a/docs/source/action_masking.rst b/docs/source/action_masking.rst index 385cadba..c779ecb5 100644 --- a/docs/source/action_masking.rst +++ b/docs/source/action_masking.rst @@ -8,7 +8,7 @@ Action Masking ************** The PrimAITE simulation is able to provide action masks in the environment output. These action masks let the agents know about which actions are invalid based on the current environment state. For instance, it's not possible to install -software on a node that is turned off. Therefore, if an agent has a NODE_SOFTWARE_INSTALL in it's action map for that node, +software on a node that is turned off. Therefore, if an agent has a ``node-software-install`` in it's action map for that node, the action mask will show `0` in the corresponding entry. *Note: just because an action is available in the action mask does not mean it will be successful when executed. It just means it's possible to try to execute the action at this time.* @@ -22,132 +22,127 @@ Masking Logic ============= The following logic is applied: -+------------------------------------------+---------------------------------------------------------------------+ -| Action | Action Mask Logic | -+==========================================+=====================================================================+ -| **do-nothing** | Always Possible. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-service-scan** | Node is on. Service is running. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-service-stop** | Node is on. Service is running. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-service-start** | Node is on. Service is stopped. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-service-pause** | Node is on. Service is running. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-service-resume** | Node is on. Service is paused. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-service-restart** | Node is on. Service is running. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-service-disable** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-service-enable** | Node is on. Service is disabled. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-service-fix** | Node is on. Service is running. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-application-execute** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-application-scan** | Node is on. Application is running. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-application-close** | Node is on. Application is running. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-application-fix** | Node is on. Application is running. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-application-install** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-application-remove** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-file-scan** | Node is on. File exists. File not deleted. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-file-create** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-file-checkhash** | Node is on. File exists. File not deleted. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-file-delete** | Node is on. File exists. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-file-repair** | Node is on. File exists. File not deleted. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-file-restore** | Node is on. File exists. File is deleted. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-file-corrupt** | Node is on. File exists. File not deleted. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-file-access** | Node is on. File exists. File not deleted. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-folder-create** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-folder-scan** | Node is on. Folder exists. Folder not deleted. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-folder-checkhash** | Node is on. Folder exists. Folder not deleted. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-folder-repair** | Node is on. Folder exists. Folder not deleted. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-folder-restore** | Node is on. Folder exists. Folder is deleted. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-os-scan** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **host-nic-enable** | NIC is disabled. Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **host-nic-disable** | NIC is enabled. Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-shutdown** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-startup** | Node is off. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-reset** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-nmap-ping-scan** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-nmap-port-scan** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-network-service-recon** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **network-port-enable** | Node is on. Router is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **network-port-disable** | Router is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **router-acl-add-rule** | Router is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **router-acl-remove-rule** | Router is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **firewall-acl-add-rule** | Firewall is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **firewall-acl-remove-rule** | Firewall is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **configure-database-client** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **configure-ransomware-script** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **c2-server-ransomware-configure** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **configure-dos-bot** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **configure-c2-beacon** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **c2-server-ransomware-launch** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **c2-server-terminal-command** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **c2-server-data-exfiltrate** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-account-change-password** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-session-remote-login** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-session-remote-logoff** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ -| **node-send-remote-command** | Node is on. | -+------------------------------------------+---------------------------------------------------------------------+ ++------------------------------------------+------------------------------------------------+ +| Action | Action Mask Logic | ++==========================================+================================================+ +| **do-nothing** | Always Possible. | ++------------------------------------------+------------------------------------------------+ +| **node-service-scan** | Node is on. Service is running. | ++------------------------------------------+------------------------------------------------+ +| **node-service-stop** | Node is on. Service is running. | ++------------------------------------------+------------------------------------------------+ +| **node-service-start** | Node is on. Service is stopped. | ++------------------------------------------+------------------------------------------------+ +| **node-service-pause** | Node is on. Service is running. | ++------------------------------------------+------------------------------------------------+ +| **node-service-resume** | Node is on. Service is paused. | ++------------------------------------------+------------------------------------------------+ +| **node-service-restart** | Node is on. Service is running. | ++------------------------------------------+------------------------------------------------+ +| **node-service-disable** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **node-service-enable** | Node is on. Service is disabled. | ++------------------------------------------+------------------------------------------------+ +| **node-service-fix** | Node is on. Service is running. | ++------------------------------------------+------------------------------------------------+ +| **node-application-execute** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **node-application-scan** | Node is on. Application is running. | ++------------------------------------------+------------------------------------------------+ +| **node-application-close** | Node is on. Application is running. | ++------------------------------------------+------------------------------------------------+ +| **node-application-fix** | Node is on. Application is running. | ++------------------------------------------+------------------------------------------------+ +| **node-application-install** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **node-application-remove** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **node-file-scan** | Node is on. File exists. File not deleted. | ++------------------------------------------+------------------------------------------------+ +| **node-file-create** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **node-file-checkhash** | Node is on. File exists. File not deleted. | ++------------------------------------------+------------------------------------------------+ +| **node-file-delete** | Node is on. File exists. | ++------------------------------------------+------------------------------------------------+ +| **node-file-repair** | Node is on. File exists. File not deleted. | ++------------------------------------------+------------------------------------------------+ +| **node-file-restore** | Node is on. File exists. File is deleted. | ++------------------------------------------+------------------------------------------------+ +| **node-file-corrupt** | Node is on. File exists. File not deleted. | ++------------------------------------------+------------------------------------------------+ +| **node-file-access** | Node is on. File exists. File not deleted. | ++------------------------------------------+------------------------------------------------+ +| **node-folder-create** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **node-folder-scan** | Node is on. Folder exists. Folder not deleted. | ++------------------------------------------+------------------------------------------------+ +| **node-folder-checkhash** | Node is on. Folder exists. Folder not deleted. | ++------------------------------------------+------------------------------------------------+ +| **node-folder-repair** | Node is on. Folder exists. Folder not deleted. | ++------------------------------------------+------------------------------------------------+ +| **node-folder-restore** | Node is on. Folder exists. Folder is deleted. | ++------------------------------------------+------------------------------------------------+ +| **node-os-scan** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **host-nic-enable** | NIC is disabled. Node is on. | ++------------------------------------------+------------------------------------------------+ +| **host-nic-disable** | NIC is enabled. Node is on. | ++------------------------------------------+------------------------------------------------+ +| **node-shutdown** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **node-startup** | Node is off. | ++------------------------------------------+------------------------------------------------+ +| **node-reset** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **node-nmap-ping-scan** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **node-nmap-port-scan** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **node-network-service-recon** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **network-port-enable** | Node is on. Router is on. | ++------------------------------------------+------------------------------------------------+ +| **network-port-disable** | Router is on. | ++------------------------------------------+------------------------------------------------+ +| **router-acl-add-rule** | Router is on. | ++------------------------------------------+------------------------------------------------+ +| **router-acl-remove-rule** | Router is on. | ++------------------------------------------+------------------------------------------------+ +| **firewall-acl-add-rule** | Firewall is on. | ++------------------------------------------+------------------------------------------------+ +| **firewall-acl-remove-rule** | Firewall is on. | ++------------------------------------------+------------------------------------------------+ +| **configure-database-client** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **configure-ransomware-script** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **c2-server-ransomware-configure** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **configure-dos-bot** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **configure-c2-beacon** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **c2-server-ransomware-launch** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **c2-server-terminal-command** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **c2-server-data-exfiltrate** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **node-account-change-password** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **node-session-remote-login** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **node-session-remote-logoff** | Node is on. | ++------------------------------------------+------------------------------------------------+ +| **node-send-remote-command** | Node is on. | ++------------------------------------------+------------------------------------------------+ Mechanism ========= -The environment iterates over the RL agent's ``action_map`` and generates the corresponding simulator request string. -It uses the ``RequestManager.check_valid()`` method to invoke the relevant ``RequestPermissionValidator`` without -actually running the request on the simulation. +The environment iterates over the RL agent's ``action_map`` and generates the corresponding simulator :ref:`request ` string. It uses the :py:meth:`RequestManager.check_valid()` method to invoke the relevant :py:class:`RequestPermissionValidator ` without actually running the request on the simulation. Current Limitations =================== -Currently, action masking only considers whether the action as a whole is possible, it doesn't verify that the exact -parameter combination passed to the action make sense in the current context. For instance, if ACL rule 3 on router_1 is -already populated, the action for adding another rule at position 3 will be available regardless, as long as that router -is turned on. This will never block valid actions. It will just occasionally allow invalid actions. +Currently, action masking only considers whether the action as a whole is possible, it doesn't verify that the exact parameter combination passed to the action make sense in the current context. or instance, if ACL rule 3 on router_1 is already populated, the action for adding another rule at position 3 will be available regardless, as long as that router is turned on. This will never block valid actions. It will just occasionally allow invalid actions. diff --git a/docs/source/configuration/agents.rst b/docs/source/configuration/agents.rst index b868dfda..96a09448 100644 --- a/docs/source/configuration/agents.rst +++ b/docs/source/configuration/agents.rst @@ -13,19 +13,19 @@ Agents can be scripted (deterministic and stochastic), or controlled by a reinfo .. code-block:: yaml agents: - - ref: red_agent_example - ... - - ref: blue_agent_example - ... - - ref: green_agent_example - team: GREEN - type: probabilistic-agent + - ref: red_agent_example + ... + - ref: blue_agent_example + ... + - ref: green_agent_example + team: GREEN + type: probabilistic-agent - agent_settings: - start_step: 5 - frequency: 4 - variance: 3 - flatten_obs: False + agent_settings: + start_step: 5 + frequency: 4 + variance: 3 + flatten_obs: False ``ref`` ------- diff --git a/docs/source/configuration/simulation/nodes/computer.rst b/docs/source/configuration/simulation/nodes/computer.rst index 456d11a2..476b6a81 100644 --- a/docs/source/configuration/simulation/nodes/computer.rst +++ b/docs/source/configuration/simulation/nodes/computer.rst @@ -17,19 +17,18 @@ example computer .. code-block:: yaml simulation: - network: - nodes: - - ref: client_1 - hostname: client_1 - type: computer - ip_address: 192.168.0.10 - subnet_mask: 255.255.255.0 - default_gateway: 192.168.0.1 - dns_server: 192.168.1.10 - applications: - ... - services: - ... + network: + nodes: + - hostname: client_1 + type: computer + ip_address: 192.168.0.10c + subnet_mask: 255.255.255.0 + default_gateway: 192.168.0.1 + dns_server: 192.168.1.10 + applications: + ... + services: + ... .. include:: common/common_node_attributes.rst diff --git a/docs/source/configuration/simulation/nodes/firewall.rst b/docs/source/configuration/simulation/nodes/firewall.rst index 84b5c99e..3e553d7b 100644 --- a/docs/source/configuration/simulation/nodes/firewall.rst +++ b/docs/source/configuration/simulation/nodes/firewall.rst @@ -19,38 +19,35 @@ example firewall .. code-block:: yaml simulation: - network: - nodes: - - ref: firewall - hostname: firewall - type: firewall - start_up_duration: 0 - shut_down_duration: 0 - ports: - external_port: # port 1 - ip_address: 192.168.20.1 - subnet_mask: 255.255.255.0 - internal_port: # port 2 - ip_address: 192.168.1.2 - subnet_mask: 255.255.255.0 - dmz_port: # port 3 - ip_address: 192.168.10.1 - subnet_mask: 255.255.255.0 - acl: - internal_inbound_acl: - ... - internal_outbound_acl: - ... - dmz_inbound_acl: - ... - dmz_outbound_acl: - ... - external_inbound_acl: - ... - external_outbound_acl: - ... - routes: - ... + network: + nodes: + - hostname: firewall + type: firewall + ports: + external_port: # port 1 + ip_address: 192.168.20.1 + subnet_mask: 255.255.255.0 + internal_port: # port 2 + ip_address: 192.168.1.2 + subnet_mask: 255.255.255.0 + dmz_port: # port 3 + ip_address: 192.168.10.1 + subnet_mask: 255.255.255.0 + acl: + internal_inbound_acl: + ... + internal_outbound_acl: + ... + dmz_inbound_acl: + ... + dmz_outbound_acl: + ... + external_inbound_acl: + ... + external_outbound_acl: + ... + routes: + ... .. include:: common/common_node_attributes.rst @@ -70,18 +67,18 @@ The ports should be defined with an ip address and subnet mask e.g. .. code-block:: yaml nodes: - - ref: firewall - ... + - hostname: firewall + ... ports: - external_port: # port 1 - ip_address: 192.168.20.1 - subnet_mask: 255.255.255.0 - internal_port: # port 2 - ip_address: 192.168.1.2 - subnet_mask: 255.255.255.0 - dmz_port: # port 3 - ip_address: 192.168.10.1 - subnet_mask: 255.255.255.0 + external_port: # port 1 + ip_address: 192.168.20.1 + subnet_mask: 255.255.255.0 + internal_port: # port 2 + ip_address: 192.168.1.2 + subnet_mask: 255.255.255.0 + dmz_port: # port 3 + ip_address: 192.168.10.1 + subnet_mask: 255.255.255.0 ``ip_address`` """""""""""""" @@ -129,21 +126,21 @@ example: .. code-block:: yaml nodes: - - ref: firewall + - hostname: firewall ... acl: - internal_inbound_acl: - 21: # position 21 on ACL list - action: PERMIT # allow packets that - src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port - dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port - 22: # position 22 on ACL list - action: PERMIT # allow packets that - src_port: ARP # are emitted from the ARP port - dst_port: ARP # are going towards an ARP port - 23: # position 23 on ACL list - action: PERMIT # allow packets that - protocol: ICMP # are ICMP + internal_inbound_acl: + 21: # position 21 on ACL list + action: PERMIT # allow packets that + src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port + dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port + 22: # position 22 on ACL list + action: PERMIT # allow packets that + src_port: ARP # are emitted from the ARP port + dst_port: ARP # are going towards an ARP port + 23: # position 23 on ACL list + action: PERMIT # allow packets that + protocol: ICMP # are ICMP ``internal_outbound_acl`` """"""""""""""""""""""""" @@ -155,21 +152,21 @@ example: .. code-block:: yaml nodes: - - ref: firewall - ... + - hostname: firewall + ... acl: - internal_outbound_acl: - 21: # position 21 on ACL list - action: PERMIT # allow packets that - src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port - dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port - 22: # position 22 on ACL list - action: PERMIT # allow packets that - src_port: ARP # are emitted from the ARP port - dst_port: ARP # are going towards an ARP port - 23: # position 23 on ACL list - action: PERMIT # allow packets that - protocol: ICMP # are ICMP + internal_outbound_acl: + 21: # position 21 on ACL list + action: PERMIT # allow packets that + src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port + dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port + 22: # position 22 on ACL list + action: PERMIT # allow packets that + src_port: ARP # are emitted from the ARP port + dst_port: ARP # are going towards an ARP port + 23: # position 23 on ACL list + action: PERMIT # allow packets that + protocol: ICMP # are ICMP ``dmz_inbound_acl`` @@ -216,29 +213,29 @@ example: .. code-block:: yaml nodes: - - ref: firewall - ... - acl: - dmz_outbound_acl: - 19: # position 19 on ACL list - action: PERMIT # allow packets that - src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port - dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port - 20: # position 20 on ACL list - action: PERMIT # allow packets that - src_port: HTTP # are emitted from the HTTP port - dst_port: HTTP # are going towards an HTTP port - 21: # position 21 on ACL list - action: PERMIT # allow packets that - src_port: HTTPS # are emitted from the HTTPS port - dst_port: HTTPS # are going towards an HTTPS port - 22: # position 22 on ACL list - action: PERMIT # allow packets that - src_port: ARP # are emitted from the ARP port - dst_port: ARP # are going towards an ARP port - 23: # position 23 on ACL list - action: PERMIT # allow packets that - protocol: ICMP # are ICMP + - hostname: firewall + ... + acl: + dmz_outbound_acl: + 19: # position 19 on ACL list + action: PERMIT # allow packets that + src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port + dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port + 20: # position 20 on ACL list + action: PERMIT # allow packets that + src_port: HTTP # are emitted from the HTTP port + dst_port: HTTP # are going towards an HTTP port + 21: # position 21 on ACL list + action: PERMIT # allow packets that + src_port: HTTPS # are emitted from the HTTPS port + dst_port: HTTPS # are going towards an HTTPS port + 22: # position 22 on ACL list + action: PERMIT # allow packets that + src_port: ARP # are emitted from the ARP port + dst_port: ARP # are going towards an ARP port + 23: # position 23 on ACL list + action: PERMIT # allow packets that + protocol: ICMP # are ICMP @@ -254,21 +251,21 @@ example: .. code-block:: yaml nodes: - - ref: firewall - ... - acl: - external_inbound_acl: - 21: # position 19 on ACL list - action: DENY # deny packets that - src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port - dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port - 22: # position 22 on ACL list - action: PERMIT # allow packets that - src_port: ARP # are emitted from the ARP port - dst_port: ARP # are going towards an ARP port - 23: # position 23 on ACL list - action: PERMIT # allow packets that - protocol: ICMP # are ICMP + - hostname: firewall + ... + acl: + external_inbound_acl: + 21: # position 19 on ACL list + action: DENY # deny packets that + src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port + dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port + 22: # position 22 on ACL list + action: PERMIT # allow packets that + src_port: ARP # are emitted from the ARP port + dst_port: ARP # are going towards an ARP port + 23: # position 23 on ACL list + action: PERMIT # allow packets that + protocol: ICMP # are ICMP ``external_outbound_acl`` """"""""""""""""""""""""" @@ -282,17 +279,17 @@ example: .. code-block:: yaml nodes: - - ref: firewall - ... + - hotsname: firewall + ... acl: - external_outbound_acl: - 22: # position 22 on ACL list - action: PERMIT # allow packets that - src_port: ARP # are emitted from the ARP port - dst_port: ARP # are going towards an ARP port - 23: # position 23 on ACL list - action: PERMIT # allow packets that - protocol: ICMP # are ICMP + external_outbound_acl: + 22: # position 22 on ACL list + action: PERMIT # allow packets that + src_port: ARP # are emitted from the ARP port + dst_port: ARP # are going towards an ARP port + 23: # position 23 on ACL list + action: PERMIT # allow packets that + protocol: ICMP # are ICMP .. include:: common/common_network_node_attributes.rst diff --git a/docs/source/configuration/simulation/nodes/router.rst b/docs/source/configuration/simulation/nodes/router.rst index ee278a98..50f40191 100644 --- a/docs/source/configuration/simulation/nodes/router.rst +++ b/docs/source/configuration/simulation/nodes/router.rst @@ -17,16 +17,15 @@ example router .. code-block:: yaml simulation: - network: - nodes: - - ref: router_1 - hostname: router_1 - type: router - num_ports: 5 - ports: - ... - acl: - ... + network: + nodes: + - hostname: router_1 + type: router + num_ports: 5 + ports: + ... + acl: + ... .. include:: common/common_node_attributes.rst @@ -49,15 +48,15 @@ Example of setting ports for a router with 2 ports: .. code-block:: yaml nodes: - - ref: router_1 + - hostname: router_1 ... ports: - 1: - ip_address: 192.168.1.1 - subnet_mask: 255.255.255.0 - 2: - ip_address: 192.168.10.1 - subnet_mask: 255.255.255.0 + 1: + ip_address: 192.168.1.1 + subnet_mask: 255.255.255.0 + 2: + ip_address: 192.168.10.1 + subnet_mask: 255.255.255.0 ``ip_address`` """""""""""""" @@ -81,12 +80,12 @@ e.g. .. code-block:: yaml nodes: - - ref: router_1 + - hostname: router_1 ... acl: - 1: - action: PERMIT - protocol: ICMP + 1: + action: PERMIT + protocol: ICMP See :py:mod:`primaite.simulator.network.hardware.nodes.network.router.AccessControlList` diff --git a/docs/source/configuration/simulation/nodes/server.rst b/docs/source/configuration/simulation/nodes/server.rst index 616efb38..a21ba778 100644 --- a/docs/source/configuration/simulation/nodes/server.rst +++ b/docs/source/configuration/simulation/nodes/server.rst @@ -19,16 +19,15 @@ example server simulation: network: nodes: - - ref: server_1 - hostname: server_1 - type: server - ip_address: 192.168.10.10 - subnet_mask: 255.255.255.0 - default_gateway: 192.168.10.1 - dns_server: 192.168.1.10 - applications: + - hostname: server_1 + type: server + ip_address: 192.168.10.10 + subnet_mask: 255.255.255.0 + default_gateway: 192.168.10.1 + dns_server: 192.168.1.10 + applications: ... - services: + services: ... .. include:: common/common_node_attributes.rst diff --git a/docs/source/configuration/simulation/nodes/switch.rst b/docs/source/configuration/simulation/nodes/switch.rst index d09f5ba7..af940eac 100644 --- a/docs/source/configuration/simulation/nodes/switch.rst +++ b/docs/source/configuration/simulation/nodes/switch.rst @@ -17,12 +17,11 @@ example switch .. code-block:: yaml simulation: - network: - nodes: - - ref: switch_1 - hostname: switch_1 - type: switch - num_ports: 8 + network: + nodes: + hostname: switch_1 + type: switch + num_ports: 8 .. include:: common/common_node_attributes.rst diff --git a/docs/source/customising_scenarios.rst b/docs/source/customising_scenarios.rst deleted file mode 100644 index df7d4b1e..00000000 --- a/docs/source/customising_scenarios.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. only:: comment - - © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK - -Customising Agents -****************** - -For an example of how to customise red agent behaviour in the Data Manipulation scenario, please refer to the notebook ``Data-Manipulation-Customising-Red-Agent.ipynb``. diff --git a/docs/source/glossary.rst b/docs/source/glossary.rst index 02c578d1..89dcdae8 100644 --- a/docs/source/glossary.rst +++ b/docs/source/glossary.rst @@ -9,10 +9,10 @@ Glossary :sorted: Network - The network in primaite is a logical representation of a computer network containing :term:`Nodes` and :term:`Links`. + The network in primaite is a logical representation of a computer network containing :term:`Nodes` and :term:`Links`. See :ref:`network`. Node - A Node represents a network endpoint. For example a computer, server, switch, or an actuator. + A Node represents a network endpoint. For example a computer, server, switch, or an actuator. See :ref:`node_description` Link A Link represents the connection between two Nodes. For example, a physical wire between a computer and a switch or a wireless connection. @@ -21,7 +21,7 @@ Glossary Protocols are used by links to separate different types of network traffic. Common examples would be HTTP, TCP, and UDP. Service - A service represents a piece of software that is installed on a node, such as a web server or a database. + A service represents a piece of software that is installed on a node, such as a web server or a database. See :ref:`software` Access Control List PrimAITE blocks or allows certain traffic on the network by simulating firewall rules, which are defined in the Access Control List. @@ -42,7 +42,7 @@ Glossary PoLs allow agents to change the current hardware, OS, file system, or service statuses of nodes during the course of an episode. For example, a green agent may restart a server node to represent scheduled maintainance. A red agent's Pattern-of-Life can be used to attack nodes by changing their states to CORRUPTED or COMPROMISED. Reward - The reward is a single number used by the blue agent to understand whether it's performing well or poorly. RL agents change their behaviour in an attempt to increase the expected reward each episode. The reward is generated based on the current states of the environment and is impacted positively by things like green PoL running successfully and negatively by things like nodes being compromised. + The reward is a single number used by the blue agent to understand whether it's performing well or poorly. RL agents change their behaviour in an attempt to increase the expected reward each episode. The reward is generated based on the current states of the environment and is impacted positively by things like green PoL running successfully and negatively by things like nodes being compromised. See :ref:`Rewards` Observation An observation is a representation of the current state of the environment that is given to the learning agent so it can decide on which action to perform. If the environment is 'fully observable', the observation contains information about every possible aspect of the environment. More commonly, the environment is 'partially observable' which means the learning agent has to make decisions without knowing every detail of the current environment state. @@ -50,6 +50,9 @@ Glossary Action The learning agent decides on an action to take on every step in the simulation. The action has the chance to positively or negatively impact the environment state. Over time, the agent aims to learn which actions to take when to maximise the expected reward. + Action mask + An input to RL algorithms that contains information about which of the actions in the action space are currently valid. See :ref:`action_masking` + Training During training, an RL agent is placed in the simulated network and it learns which actions to take in which scenarios to obtain maximum reward. @@ -69,4 +72,13 @@ Glossary PrimAITE uses the Gymnasium reinforcement learning framework API to create a training environment and interface with RL agents. Gymnasium defines a common way of creating observations, actions, and rewards. User app home - PrimAITE supports upgrading software version while retaining user data. The user data directory is where configs, notebooks, and results are stored, this location is `~/primaite/` on linux/darwin and `C:\\Users\\\\primaite` on Windows. + PrimAITE supports upgrading software version while retaining user data. The user data directory is where configs, notebooks, and results are stored, this location is ``~/primaite//`` on linux/darwin and ``C:\\Users\\\\primaite\\`` on Windows. + + Episode schedule + The strategy for selecting different variants around the same scenario when advancing from one episode to another in the environment. + + Discriminator + A unique string given to extensible components in PrimAITE that allow them to be mapped from a YAML config definition to a simulation class. + + Plugin + A python package that extends base PrimAITE classes. diff --git a/docs/source/how_to_guides/extensible_agents.rst b/docs/source/how_to_guides/extensible_agents.rst index e02bcfae..7713a554 100644 --- a/docs/source/how_to_guides/extensible_agents.rst +++ b/docs/source/how_to_guides/extensible_agents.rst @@ -45,20 +45,21 @@ Agent generation will fail pydantic checks if incorrect or invalid parameters ar .. code-block:: yaml - ref: example_green_agent - team: GREEN - type: example-agent + team: GREEN + type: example-agent - action_space: - action_map: - 0: - action: do-nothing - options: {} - agent_settings: + agent_settings: start_step: 25 frequency: 20 variance: 5 starting_host: "Server_1" + action_space: + action_map: + 0: + action: do-nothing + options: {} + **discriminators**: diff --git a/docs/source/node_sets.rst b/docs/source/node_sets.rst index 75047d54..db4a35a2 100644 --- a/docs/source/node_sets.rst +++ b/docs/source/node_sets.rst @@ -50,6 +50,7 @@ Via YAML Config --------------- .. code-block:: yaml + simulation: network: nodes: diff --git a/docs/source/rewards.rst b/docs/source/rewards.rst index 3fc464ea..1bd1d997 100644 --- a/docs/source/rewards.rst +++ b/docs/source/rewards.rst @@ -9,8 +9,8 @@ Rewards Rewards in PrimAITE are based on a system of individual components that react to events in the simulation. An agent's reward function is calculated as the weighted sum of several reward components. -Some rewards, such as the ``GreenAdminDatabaseUnreachablePenalty``, can be marked as 'sticky' in their configuration. Setting this to ``True`` will mean that they continue to output the same value after an event until another event of that type. -In the instance of the ``GreenAdminDatabaseUnreachablePenalty``, the database admin reward will stay negative until the next successful database request is made, even if the database admin agents do nothing and the database returns a good state. +Some rewards, such as the ``green-admin-database-unreachable-penalty``, can be marked as 'sticky' in their configuration. Setting this to ``True`` will mean that they continue to output the same value after an event until another event of that type. +In the instance of the ``green-admin-database-unreachable-penalty``, the database admin reward will stay negative until the next successful database request is made, even if the database admin agents do nothing and the database returns a good state. Components ********** @@ -25,8 +25,8 @@ The following API pages describe the use of each reward component and the possib # ... reward_function: reward_components: - - type: dummy - weight: 1.0 + - type: dummy + weight: 1.0 :py:class:`primaite.game.agent.rewards.DatabaseFileIntegrity` @@ -38,12 +38,12 @@ The following API pages describe the use of each reward component and the possib # ... reward_function: reward_components: - - type: database-file-integrity - weight: 1.0 - options: - node_hostname: server_1 - folder_name: database - file_name: database.db + - type: database-file-integrity + weight: 1.0 + options: + node_hostname: server_1 + folder_name: database + file_name: database.db :py:class:`primaite.game.agent.rewards.WebServer404Penalty` @@ -55,12 +55,12 @@ The following API pages describe the use of each reward component and the possib # ... reward_function: reward_components: - - type: web-server-404-penalty - node_hostname: web_server - weight: 1.0 - options: - service_name: WebService - sticky: false + - type: web-server-404-penalty + node_hostname: web_server + weight: 1.0 + options: + service_name: WebService + sticky: false :py:class:`primaite.game.agent.rewards.WebpageUnavailablePenalty` @@ -72,11 +72,11 @@ The following API pages describe the use of each reward component and the possib # ... reward_function: reward_components: - - type: webpage-unavailable-penalty - node_hostname: computer_1 - weight: 1.0 - options: - sticky: false + - type: webpage-unavailable-penalty + node_hostname: computer_1 + weight: 1.0 + options: + sticky: false :py:class:`primaite.game.agent.rewards.GreenAdminDatabaseUnreachablePenalty` @@ -88,11 +88,11 @@ The following API pages describe the use of each reward component and the possib # ... reward_function: reward_components: - - type: green-admin-database-unreachable-penalty - weight: 1.0 - options: - node_hostname: admin_pc_1 - sticky: false + - type: green-admin-database-unreachable-penalty + weight: 1.0 + options: + node_hostname: admin_pc_1 + sticky: false :py:class:`primaite.game.agent.rewards.SharedReward` @@ -106,10 +106,10 @@ The following API pages describe the use of each reward component and the possib # ... reward_function: reward_components: - - type: shared-reward - weight: 1.0 - options: - agent_name: scripted_agent + - type: shared-reward + weight: 1.0 + options: + agent_name: scripted_agent :py:class:`primaite.game.agent.rewards.ActionPenalty` @@ -121,8 +121,8 @@ The following API pages describe the use of each reward component and the possib # ... reward_function: reward_components: - - type: action-penalty - weight: 1.0 - options: - action_penalty: -0.3 - do_nothing_penalty: 0.0 + - type: action-penalty + weight: 1.0 + options: + action_penalty: -0.3 + do_nothing_penalty: 0.0 diff --git a/docs/source/simulation_components/network/base_hardware.rst b/docs/source/simulation_components/network/base_hardware.rst index e60831e2..3aa0b927 100644 --- a/docs/source/simulation_components/network/base_hardware.rst +++ b/docs/source/simulation_components/network/base_hardware.rst @@ -21,6 +21,9 @@ The key elements defined in ``base.py`` are: ``Node`` ======== + +.. _node_description: + The Node class stands as a central component in ``base.py``, acting as the superclass for all network nodes within a PrimAITE simulation. diff --git a/docs/source/simulation_components/network/nodes/wireless_router.rst b/docs/source/simulation_components/network/nodes/wireless_router.rst index 4078ffda..3dfd1193 100644 --- a/docs/source/simulation_components/network/nodes/wireless_router.rst +++ b/docs/source/simulation_components/network/nodes/wireless_router.rst @@ -64,7 +64,7 @@ other wireless devices within the same frequency band. Example Scenario ---------------- -This example sets up a network with two PCs (PC A and PC B), each connected to their own `WirelessRouter` +This example sets up a network with two PCs (PC A and PC B), each connected to their own ``WirelessRouter`` (Router 1 and Router 2). These routers are then wirelessly connected to each other, enabling communication between the PCs through the routers over the airspace. Access Control Lists (ACLs) are configured on the routers to permit ARP and ICMP traffic, ensuring basic network connectivity and ping functionality. @@ -160,7 +160,7 @@ network segments. Viewing Wireless Network Configuration -------------------------------------- -The `AirSpace.show()` function is an invaluable tool for inspecting the current wireless network configuration within +The :py:meth:`AirSpace.show() ` function is an invaluable tool for inspecting the current wireless network configuration within the PrimAITE environment. It presents a table summarising all wireless interfaces, including routers and access points, that are active within the airspace. The table outlines each device's connected node name, MAC address, IP address, subnet mask, operating frequency, and status, providing a comprehensive view of the wireless network topology. @@ -168,7 +168,7 @@ subnet mask, operating frequency, and status, providing a comprehensive view of Example Output ^^^^^^^^^^^^^^^ -Below is an example output of the `AirSpace.show()` function, demonstrating the visibility it provides into the +Below is an example output of the :py:meth:`AirSpace.show() ` function, demonstrating the visibility it provides into the wireless network: .. code-block:: none @@ -182,10 +182,10 @@ wireless network: This table aids in verifying that wireless devices are correctly configured and operational. It also helps in diagnosing connectivity issues by ensuring that devices are on the correct frequency and have the appropriate network -settings. The `Status` column, indicating whether a device is enabled or disabled, further assists in troubleshooting +settings. The ``Status`` column, indicating whether a device is enabled or disabled, further assists in troubleshooting by quickly identifying any devices that are not actively participating in the network. -Utilising the `AirSpace.show()` function is particularly beneficial in complex network simulations where multiple +Utilising the :py:meth:`AirSpace.show() ` function is particularly beneficial in complex network simulations where multiple wireless devices are in use. It provides a snapshot of the wireless landscape, facilitating the understanding of how devices interact within the network and ensuring that configurations are aligned with the intended network architecture. diff --git a/docs/source/simulation_components/network/transport_to_data_link_layer.rst b/docs/source/simulation_components/network/transport_to_data_link_layer.rst index 7d6fec2c..cdad074c 100644 --- a/docs/source/simulation_components/network/transport_to_data_link_layer.rst +++ b/docs/source/simulation_components/network/transport_to_data_link_layer.rst @@ -14,9 +14,11 @@ Transport Layer (Layer 4) **UDPHeader:** Represents a UDP header for the transport layer of a Network Frame. It includes source and destination ports. UDP (User Datagram Protocol) is a connectionless and unreliable transport protocol used for data transmission. -**TCPFlags:** Enum representing TCP control flags used in a TCP connection, such as SYN, ACK, FIN, and RST. TCP -(Transmission Control Protocol) is a connection-oriented and reliable transport protocol used for establishing and -maintaining data streams. +.. + **TCPFlags:** Enum representing TCP control flags used in a TCP connection, such as SYN, ACK, FIN, and RST. TCP + (Transmission Control Protocol) is a connection-oriented and reliable transport protocol used for establishing and + maintaining data streams. +.. not currently used **TCPHeader:** Represents a TCP header for the transport layer of a Network Frame. It includes source and destination ports and TCP flags. This header is used for establishing and managing TCP connections. diff --git a/docs/source/simulation_components/system/applications/c2_suite.rst b/docs/source/simulation_components/system/applications/c2_suite.rst index c2654cea..a153efc4 100644 --- a/docs/source/simulation_components/system/applications/c2_suite.rst +++ b/docs/source/simulation_components/system/applications/c2_suite.rst @@ -77,9 +77,9 @@ Adding to this, the following behaviour of the C2 beacon can be configured by us +---------------------+---------------------------------------------------------------------------+ |keep_alive_frequency | How often should the C2 Beacon confirm it's connection in timesteps. | +---------------------+---------------------------------------------------------------------------+ -|masquerade_protocol | What protocol should the C2 traffic masquerade as? (HTTP, FTP or DNS) | +|masquerade_protocol | What protocol should the C2 traffic masquerade as? (TCP opr UDP) | +---------------------+---------------------------------------------------------------------------+ -|masquerade_port | What port should the C2 traffic use? (TCP or UDP) | +|masquerade_port | What port should the C2 traffic use? (HTTP, FTP, or DNS) | +---------------------+---------------------------------------------------------------------------+ @@ -115,38 +115,30 @@ Python """""" .. code-block:: python - from primaite.simulator.network.container import Network - from primaite.simulator.network.hardware.nodes.host.computer import Computer - from primaite.simulator.network.hardware.nodes.network.switch import Switch - from primaite.simulator.system.applications.database_client import DatabaseClient - from primaite.simulator.system.applications.red_applications.ransomware_script import RansomwareScript - from primaite.simulator.system.services.database.database_service import DatabaseService - from primaite.simulator.system.applications.red_applications.c2.c2_server import C2Command, C2Server - from primaite.simulator.system.applications.red_applications.c2.c2_beacon import C2Beacon - # Network Setup network = Network() - switch = Switch(config={"hostname":"switch", "start_up_duration":0, "num_ports":4}) + switch = Switch(config=Switch.ConfigSchema(hostname="switch", start_up_duration=0, num_ports=4)) switch.power_on() - node_a = Computer(config={"hostname":"node_a", "ip_address":"192.168.0.10", "subnet_mask":"255.255.255.0", "start_up_duration":0}) + node_a = Computer(config=Computer.ConfigSchema(hostname="node_a", ip_address="192.168.0.10", subnet_mask="255.255.255.0", start_up_duration=0)) node_a.power_on() network.connect(node_a.network_interface[1], switch.network_interface[1]) - node_b = Computer(config={"hostname":"node_b", "ip_address":"192.168.0.11", "subnet_mask":"255.255.255.0", "start_up_duration":0}) + node_b = Computer(config=Computer.ConfigSchema(hostname="node_b", ip_address="192.168.0.11", subnet_mask="255.255.255.0", start_up_duration=0)) node_b.power_on() network.connect(node_b.network_interface[1], switch.network_interface[2]) - node_c = Computer(config={"hostname":"node_c", "ip_address":"192.168.0.12", "subnet_mask":"255.255.255.0", "start_up_duration":0}) + node_c = Computer(config=Computer.ConfigSchema(hostname="node_c", ip_address="192.168.0.12", subnet_mask="255.255.255.0", start_up_duration=0)) node_c.power_on() network.connect(node_c.network_interface[1], switch.network_interface[3]) node_c.software_manager.install(software_class=DatabaseService) node_b.software_manager.install(software_class=DatabaseClient) node_b.software_manager.install(software_class=RansomwareScript) + node_b.software_manager.install(software_class=C2Beacon) node_a.software_manager.install(software_class=C2Server) # C2 Application objects @@ -154,8 +146,8 @@ Python c2_server_host: Computer = network.get_node_by_hostname("node_a") c2_beacon_host: Computer = network.get_node_by_hostname("node_b") - c2_server: C2Server = c2_server_host.software_manager.software["C2Server"] - c2_beacon: C2Beacon = c2_beacon_host.software_manager.software["C2Beacon"] + c2_server: C2Server = c2_server_host.software_manager.software["c2-server"] + c2_beacon: C2Beacon = c2_beacon_host.software_manager.software["c2-beacon"] # Configuring the C2 Beacon c2_beacon.configure(c2_server_ip_address="192.168.0.10", keep_alive_frequency=5) @@ -287,8 +279,6 @@ It's worth noting that this may be a useful option to bypass ACL rules. This must be a string i.e *UDP*. Defaults to ``TCP``. -*Please refer to the ``IPProtocol`` class for further reference.* - ``Masquerade Port`` """"""""""""""""""" @@ -300,8 +290,6 @@ It's worth noting that this may be a useful option to bypass ACL rules. This must be a string i.e ``DNS``. Defaults to ``HTTP``. -*Please refer to the ``IPProtocol`` class for further reference.* - ``Common Attributes`` ^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/source/simulation_components/system/applications/data_manipulation_bot.rst b/docs/source/simulation_components/system/applications/data_manipulation_bot.rst index b2229840..de37710b 100644 --- a/docs/source/simulation_components/system/applications/data_manipulation_bot.rst +++ b/docs/source/simulation_components/system/applications/data_manipulation_bot.rst @@ -27,6 +27,7 @@ The bot performs attacks in the following stages to simulate the real pattern of - Attacking - *The bot delivers the payload to the discovered database servers.* Each of these stages has a random, configurable probability of succeeding (by default 10%). The bot can also be configured to repeat the attack once complete. +NB: The Port Scan is achieved using game layer functionality based on a probablility of success calculation. Usage ===== @@ -99,16 +100,12 @@ If not using the data manipulation bot manually, it needs to be used with a data type: red-database-corrupting-agent agent_settings: - start_settings: - start_step: 25 - frequency: 20 - variance: 5 # ... simulation: network: nodes: - - ref: client_1 + - hostname: client_1 type: computer # ... additional configuration here applications: diff --git a/docs/source/simulation_components/system/applications/database_client.rst b/docs/source/simulation_components/system/applications/database_client.rst index 324db17e..18f55efd 100644 --- a/docs/source/simulation_components/system/applications/database_client.rst +++ b/docs/source/simulation_components/system/applications/database_client.rst @@ -76,17 +76,15 @@ Via Configuration .. code-block:: yaml simulation: - network: - nodes: - - ref: example_computer - hostname: example_computer - type: computer - ... - applications: - - ref: database_client - type: database-client - options: - db_server_ip: 192.168.0.1 + network: + nodes: + - hostname: example_computer + type: computer + ... + applications: + - type: database-client + options: + db_server_ip: 192.168.0.1 Configuration ============= diff --git a/docs/source/simulation_components/system/applications/dos_bot.rst b/docs/source/simulation_components/system/applications/dos_bot.rst index e6e03cfe..1ccf9500 100644 --- a/docs/source/simulation_components/system/applications/dos_bot.rst +++ b/docs/source/simulation_components/system/applications/dos_bot.rst @@ -79,22 +79,20 @@ Via Configuration .. code-block:: yaml simulation: - network: - nodes: - - ref: example_computer - hostname: example_computer - type: computer - ... - applications: - - ref: dos_bot - type: dos-bot - options: - target_ip_address: 192.168.0.10 - payload: SPOOF DATA - repeat: False - port_scan_p_of_success: 0.8 - dos_intensity: 1.0 - max_sessions: 1000 + network: + nodes: + - hostname: example_computer + type: computer + ... + applications: + - type: dos-bot + options: + target_ip_address: 192.168.0.10 + payload: SPOOF DATA + repeat: False + port_scan_p_of_success: 0.8 + dos_intensity: 1.0 + max_sessions: 1000 Configuration ============= diff --git a/docs/source/simulation_components/system/applications/web_browser.rst b/docs/source/simulation_components/system/applications/web_browser.rst index 88527caf..d99feacd 100644 --- a/docs/source/simulation_components/system/applications/web_browser.rst +++ b/docs/source/simulation_components/system/applications/web_browser.rst @@ -78,15 +78,15 @@ Via Configuration .. code-block:: yaml simulation: - network: - nodes: - - hostname: example_computer - type: computer - ... - applications: - - type: web-browser - options: - target_url: http://example.com/ + network: + nodes: + - hostname: example_computer + type: computer + ... + applications: + - type: web-browser + options: + target_url: http://example.com/ Configuration ============= diff --git a/docs/source/simulation_components/system/services/database_service.rst b/docs/source/simulation_components/system/services/database_service.rst index c89560a8..b85f33cc 100644 --- a/docs/source/simulation_components/system/services/database_service.rst +++ b/docs/source/simulation_components/system/services/database_service.rst @@ -80,15 +80,15 @@ Via Configuration .. code-block:: yaml simulation: - network: - nodes: - - hostname: example_server - type: server - ... - services: - - type: database-service - options: - backup_server_ip: 192.168.0.10 + network: + nodes: + - hostname: example_server + type: server + ... + services: + - type: database-service + options: + backup_server_ip: 192.168.0.10 Configuration ============= diff --git a/docs/source/simulation_components/system/services/dns_client.rst b/docs/source/simulation_components/system/services/dns_client.rst index 9d131288..35353584 100644 --- a/docs/source/simulation_components/system/services/dns_client.rst +++ b/docs/source/simulation_components/system/services/dns_client.rst @@ -70,17 +70,15 @@ Via Configuration .. code-block:: yaml simulation: - network: - nodes: - - ref: example_server - hostname: example_server - type: server - ... - services: - - ref: dns_client - type: dns-client - options: - dns_server: 192.168.0.10 + network: + nodes: + - hostname: example_server + type: server + ... + services: + - type: dns-client + options: + dns_server: 192.168.0.10 Configuration ============= diff --git a/docs/source/simulation_components/system/services/dns_server.rst b/docs/source/simulation_components/system/services/dns_server.rst index 53b47c54..aa28f329 100644 --- a/docs/source/simulation_components/system/services/dns_server.rst +++ b/docs/source/simulation_components/system/services/dns_server.rst @@ -67,17 +67,17 @@ Via Configuration .. code-block:: yaml simulation: - network: - nodes: - - hostname: example_server - type: server - ... - services: - - type: dns-server - options: - domain_mapping: - example.com: 192.168.0.10 - another-example.com: 192.168.10.10 + network: + nodes: + - hostname: example_server + type: server + ... + services: + - type: dns-server + options: + domain_mapping: + example.com: 192.168.0.10 + another-example.com: 192.168.10.10 Configuration ============= diff --git a/docs/source/simulation_components/system/services/ftp_client.rst b/docs/source/simulation_components/system/services/ftp_client.rst index be4d73e4..b105ba8c 100644 --- a/docs/source/simulation_components/system/services/ftp_client.rst +++ b/docs/source/simulation_components/system/services/ftp_client.rst @@ -71,15 +71,13 @@ Via Configuration .. code-block:: yaml simulation: - network: - nodes: - - ref: example_server - hostname: example_server - type: server - ... - services: - - ref: ftp_client - type: ftp-client + network: + nodes: + - hostname: example_server + type: server + ... + services: + - type: ftp-client Configuration ============= diff --git a/docs/source/simulation_components/system/services/ftp_server.rst b/docs/source/simulation_components/system/services/ftp_server.rst index 390e76ec..19b1b01b 100644 --- a/docs/source/simulation_components/system/services/ftp_server.rst +++ b/docs/source/simulation_components/system/services/ftp_server.rst @@ -67,15 +67,15 @@ Via Configuration .. code-block:: yaml simulation: - network: - nodes: - - hostname: example_server - type: server - ... - services: - - type: ftp-server - options: - server_password: test + network: + nodes: + - hostname: example_server + type: server + ... + services: + - type: ftp-server + options: + server_password: test Configuration ============= diff --git a/docs/source/simulation_components/system/services/ntp_client.rst b/docs/source/simulation_components/system/services/ntp_client.rst index 29215a2d..e45064f9 100644 --- a/docs/source/simulation_components/system/services/ntp_client.rst +++ b/docs/source/simulation_components/system/services/ntp_client.rst @@ -66,17 +66,15 @@ Via Configuration .. code-block:: yaml simulation: - network: - nodes: - - ref: example_server - hostname: example_server - type: server - ... - services: - - ref: ntp_client - type: ntp-client - options: - ntp_server_ip: 192.168.0.10 + network: + nodes: + - hostname: example_server + type: server + ... + services: + - type: ntp-client + options: + ntp_server_ip: 192.168.0.10 Configuration ============= diff --git a/docs/source/simulation_components/system/services/ntp_server.rst b/docs/source/simulation_components/system/services/ntp_server.rst index 57efab4d..440f6894 100644 --- a/docs/source/simulation_components/system/services/ntp_server.rst +++ b/docs/source/simulation_components/system/services/ntp_server.rst @@ -66,15 +66,13 @@ Via Configuration .. code-block:: yaml simulation: - network: - nodes: - - ref: example_server - hostname: example_server - type: server - ... - services: - - ref: ntp_server - type: ntp-server + network: + nodes: + - hostname: example_server + type: server + ... + services: + - type: ntp-server ``Common Attributes`` diff --git a/docs/source/simulation_components/system/services/web_server.rst b/docs/source/simulation_components/system/services/web_server.rst index dece2251..55a99cfd 100644 --- a/docs/source/simulation_components/system/services/web_server.rst +++ b/docs/source/simulation_components/system/services/web_server.rst @@ -66,15 +66,13 @@ Via Configuration .. code-block:: yaml simulation: - network: - nodes: - - ref: example_server - hostname: example_server - type: server - ... - services: - - ref: web_server - type: web-server + network: + nodes: + - hostname: example_server + type: server + ... + services: + - type: web-server ``Common Attributes`` diff --git a/docs/source/simulation_structure.rst b/docs/source/simulation_structure.rst index 7debe112..cb5b67c0 100644 --- a/docs/source/simulation_structure.rst +++ b/docs/source/simulation_structure.rst @@ -7,8 +7,7 @@ Simulation Structure ==================== The simulation is made up of many smaller components which are related to each other in a tree-like structure. At the -top level, there is the :py:meth:`primaite.simulator.sim_container.Simulation`, which keeps track of the physical network -and a domain controller for managing software and users. +top level, there is the :py:meth:`primaite.simulator.sim_container.Simulation`, which keeps track of the physical network and a domain controller for managing software and users. Each node of the simulation 'tree' has responsibility for creating, deleting, and updating its direct descendants. Also, when a component's ``describe_state()`` method is called, it will include the state of its descendants. The @@ -25,48 +24,54 @@ relationship between components. Actions ======= -Agents can interact with the simulation by using actions. Actions are standardised with the -:py:class:`primaite.simulation.core.RequestType` class, which just holds a reference to two special functions. +Agents can interact with the simulation by using actions. Actions adhere to the Common Action and Observation Space (CAOS) specification, and are converted into Requests for use by the simulation. Requests are standardised via the :py:class:`primaite.simulation.core.RequestType` class, which just holds a reference to two special functions. -1. The request function itself, it must accept a `request` parameters which is a list of strings that describe what the - action should do. It must also accept a `context` dict which can house additional information surrounding the action. - For example, the context will typically include information about which entity intiated the action. -2. A validator function. This function should return a boolean value that decides if the request is permitted or not. - It uses the same paramters as the action function. +1. The function that actions the request, it must accept a `request` parameters which is a list of strings that describe what the action should do. It must also accept a `context` dict which can house additional information surrounding the action. +2. A validator function. This function should return a boolean value that decides if the request is permitted or not. It uses the same paramters as the action function. -Action Permissions +Action Validation ------------------ -When an agent tries to perform an action on a simulation component, that action will only be executed if the request is -validated. For example, some actions can require that an agent is logged into an admin account. Each action defines its +When an agent tries to perform an action on a simulation component, that action will only be executed if the request is validated. For example, some actions can require that the target network node is powered on. Each action defines its own permissions using an instance of :py:class:`primaite.simulation.core.ActionPermissionValidator`. The below code snippet demonstrates usage of the ``ActionPermissionValidator``. .. code:: python - from primaite.simulator.core import Action, RequestManager, SimComponent - from primaite.simulator.domain.controller import AccountGroup, GroupMembershipValidator + from primaite.simulator.core import Action, RequestManager, SimComponent, ActionPermissionValidator + from primaite.interface.request import RequestResponse class Smartphone(SimComponent): name: str - apps = [] + connected: bool + apps: List = [] + + class _ConnectedToNetworkValidator(ActionPermissionValidator): + + smartphone: Smarphone + """A reference to the smartphone object.""" + + def __call__(self, request: RequestFormat, context: Dict) -> bool: + return self.smartphone.connected + def _init_request_manager(self) -> RequestManager: am = super()._init_request_manager() am.add_request( "reset_factory_settings", - Action( - func = lambda request, context: self.reset_factory_settings(), - validator = GroupMembershipValidator([AccountGroup.DOMAIN_ADMIN]), + ReqeustType( + func = lambda request, context: RequestResponse.from_bool(self.reset_factory_settings()), + validator = Smartphone._ConnectedToNetworkValidator(smartphone=self), ) ) def reset_factory_settings(self): self.apps = [] + return True - phone = Smartphone(name="phone1") + phone = Smartphone(name="phone1", connected=False) + phone.apply_request(request=["reset_factory_settings"]) + # >>> False - # try to wipe the phone as a domain user, this will have no effect - phone.apply_action(["reset_factory_settings"], context={"request_source":{"groups":["DOMAIN_USER"]}) - - # try to wipe the phone as an admin user, this will wipe the phone - phone.apply_action(["reset_factory_settings"], context={"request_source":{"groups":["DOMAIN_ADMIN"]}) + phone2 = Smartphone(name="phone2", connected=True) + phone.apply_request(request=["reset_factory_settings"]) + # >>> True diff --git a/src/primaite/config/__init__.py b/src/primaite/config/__init__.py index 7b5e2889..ee28e158 100644 --- a/src/primaite/config/__init__.py +++ b/src/primaite/config/__init__.py @@ -1,2 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK -"""Configuration parameters for running experiments.""" +"""A collection of example configuration files.""" diff --git a/src/primaite/config/load.py b/src/primaite/config/load.py index 3553f527..67035e49 100644 --- a/src/primaite/config/load.py +++ b/src/primaite/config/load.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Convenience methods for finding filepaths to default PrimAITE configs.""" from pathlib import Path from typing import Dict, Final, Union diff --git a/src/primaite/exceptions.py b/src/primaite/exceptions.py index 4487111d..abadce77 100644 --- a/src/primaite/exceptions.py +++ b/src/primaite/exceptions.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""PrimAITE-specific exceptions.""" class PrimaiteError(Exception): """The root PrimAITE Error.""" diff --git a/src/primaite/game/agent/__init__.py b/src/primaite/game/agent/__init__.py index c005c173..a23f740f 100644 --- a/src/primaite/game/agent/__init__.py +++ b/src/primaite/game/agent/__init__.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Agents that act in the environment, including RL and scripted agents, their actions, observations, and rewards.""" from primaite.game.agent.interface import ProxyAgent from primaite.game.agent.scripted_agents.data_manipulation_bot import DataManipulationAgent from primaite.game.agent.scripted_agents.probabilistic_agent import ProbabilisticAgent diff --git a/src/primaite/game/agent/actions/__init__.py b/src/primaite/game/agent/actions/__init__.py index 8517ded8..75d8a982 100644 --- a/src/primaite/game/agent/actions/__init__.py +++ b/src/primaite/game/agent/actions/__init__.py @@ -1,5 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK - +"""Actions convert CAOS data into the request format for the PrimAITE simulation.""" from primaite.game.agent.actions import ( abstract, acl, diff --git a/src/primaite/game/agent/actions/abstract.py b/src/primaite/game/agent/actions/abstract.py index 1c039ed3..305226f0 100644 --- a/src/primaite/game/agent/actions/abstract.py +++ b/src/primaite/game/agent/actions/abstract.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Action base class.""" from __future__ import annotations from abc import ABC diff --git a/src/primaite/game/agent/actions/acl.py b/src/primaite/game/agent/actions/acl.py index fb59574d..0976783f 100644 --- a/src/primaite/game/agent/actions/acl.py +++ b/src/primaite/game/agent/actions/acl.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Actions for manipulating Access Control Lists (ACLs).""" from __future__ import annotations from abc import ABC diff --git a/src/primaite/game/agent/actions/application.py b/src/primaite/game/agent/actions/application.py index 9651b600..913b9b70 100644 --- a/src/primaite/game/agent/actions/application.py +++ b/src/primaite/game/agent/actions/application.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Actions for interacting with applications on network hosts.""" from abc import ABC from typing import ClassVar diff --git a/src/primaite/game/agent/actions/file.py b/src/primaite/game/agent/actions/file.py index a2fcd3e2..b06e5720 100644 --- a/src/primaite/game/agent/actions/file.py +++ b/src/primaite/game/agent/actions/file.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Actions for interacting with the files on network hosts.""" from abc import ABC from typing import ClassVar diff --git a/src/primaite/game/agent/actions/folder.py b/src/primaite/game/agent/actions/folder.py index 80be0cd5..f98fa080 100644 --- a/src/primaite/game/agent/actions/folder.py +++ b/src/primaite/game/agent/actions/folder.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Actions for interacting with folders on network hosts.""" from abc import ABC from typing import ClassVar diff --git a/src/primaite/game/agent/actions/host_nic.py b/src/primaite/game/agent/actions/host_nic.py index d192a757..10ab5721 100644 --- a/src/primaite/game/agent/actions/host_nic.py +++ b/src/primaite/game/agent/actions/host_nic.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Actions for interacting with network interfact cards (NICs) on network hosts.""" from abc import ABC from typing import ClassVar diff --git a/src/primaite/game/agent/actions/manager.py b/src/primaite/game/agent/actions/manager.py index 0a9d3ffd..efc3f9f6 100644 --- a/src/primaite/game/agent/actions/manager.py +++ b/src/primaite/game/agent/actions/manager.py @@ -1,15 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK -"""yaml example. - -agents: - - name: agent_1 - action_space: - actions: - - do-nothing - - node-service-start - - node-service-stop - action_map: -""" +"""Validate and keep track of an agent's action set.""" from __future__ import annotations diff --git a/src/primaite/game/agent/actions/network.py b/src/primaite/game/agent/actions/network.py index 22fc2c2d..6ddb4e91 100644 --- a/src/primaite/game/agent/actions/network.py +++ b/src/primaite/game/agent/actions/network.py @@ -1,5 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK - +"""Actions for interacting with network ports of routers, switches, and firewalls.""" from abc import ABC from typing import ClassVar diff --git a/src/primaite/game/agent/actions/node.py b/src/primaite/game/agent/actions/node.py index 5b62957a..e2140e8b 100644 --- a/src/primaite/game/agent/actions/node.py +++ b/src/primaite/game/agent/actions/node.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Actions for interacting with nodes on the network.""" from abc import ABC, abstractmethod from typing import ClassVar, List, Literal, Optional, Union diff --git a/src/primaite/game/agent/actions/service.py b/src/primaite/game/agent/actions/service.py index dfe1f91d..41f6fe3e 100644 --- a/src/primaite/game/agent/actions/service.py +++ b/src/primaite/game/agent/actions/service.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Actions for interacting with services on network hosts.""" from abc import ABC from typing import ClassVar diff --git a/src/primaite/game/agent/actions/session.py b/src/primaite/game/agent/actions/session.py index 63a45c5e..e1c585e8 100644 --- a/src/primaite/game/agent/actions/session.py +++ b/src/primaite/game/agent/actions/session.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Actions for performing login and logout on local and remote hosts.""" from abc import ABC, abstractmethod from primaite.game.agent.actions.manager import AbstractAction diff --git a/src/primaite/game/agent/actions/software.py b/src/primaite/game/agent/actions/software.py index f170146b..dd7d0570 100644 --- a/src/primaite/game/agent/actions/software.py +++ b/src/primaite/game/agent/actions/software.py @@ -1,5 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK - +"""Actions for configuring software on network hosts.""" from typing import List, Optional, Union from pydantic import ConfigDict, Field diff --git a/src/primaite/game/agent/agent_log.py b/src/primaite/game/agent/agent_log.py index ddf14489..6300eb14 100644 --- a/src/primaite/game/agent/agent_log.py +++ b/src/primaite/game/agent/agent_log.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Optional logger for internal agent decisions and debugging.""" import logging from pathlib import Path from typing import Optional diff --git a/src/primaite/game/agent/observations/__init__.py b/src/primaite/game/agent/observations/__init__.py index a38095b3..6c3307a9 100644 --- a/src/primaite/game/agent/observations/__init__.py +++ b/src/primaite/game/agent/observations/__init__.py @@ -1,6 +1,7 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK # flake8: noqa # Pre-import all the observations when we load up the observations module so that they can be resolved by the parser. +"""Converts PrimAITE simulation data into numerical RL-ready observations.""" from primaite.game.agent.observations.acl_observation import ACLObservation from primaite.game.agent.observations.file_system_observations import FileObservation, FolderObservation from primaite.game.agent.observations.firewall_observation import FirewallObservation diff --git a/src/primaite/game/agent/observations/acl_observation.py b/src/primaite/game/agent/observations/acl_observation.py index 8a137629..b5e1e5af 100644 --- a/src/primaite/game/agent/observations/acl_observation.py +++ b/src/primaite/game/agent/observations/acl_observation.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Observations for access control lists (ACLs) on routers and firewalls.""" from __future__ import annotations from typing import Dict, List, Optional diff --git a/src/primaite/game/agent/scripted_agents/__init__.py b/src/primaite/game/agent/scripted_agents/__init__.py index 90a99d01..10fecf99 100644 --- a/src/primaite/game/agent/scripted_agents/__init__.py +++ b/src/primaite/game/agent/scripted_agents/__init__.py @@ -1,5 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK - +"""Agents that automatically choose their behaviour according to scripted rules.""" from primaite.game.agent import interface from primaite.game.agent.scripted_agents import ( abstract_tap, diff --git a/src/primaite/game/agent/utils.py b/src/primaite/game/agent/utils.py index 87b02858..6a5ff949 100644 --- a/src/primaite/game/agent/utils.py +++ b/src/primaite/game/agent/utils.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Utility functions used in the PrimAITE game layer.""" from typing import Any, Dict, Hashable, Optional, Sequence NOT_PRESENT_IN_STATE = object() diff --git a/src/primaite/game/science.py b/src/primaite/game/science.py index 2cb5de7d..e72c0752 100644 --- a/src/primaite/game/science.py +++ b/src/primaite/game/science.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Mathematical methods used in PrimAITE.""" from random import random from typing import Any, Iterable, Mapping diff --git a/src/primaite/interface/__init__.py b/src/primaite/interface/__init__.py index 836b79af..b75c48d1 100644 --- a/src/primaite/interface/__init__.py +++ b/src/primaite/interface/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""The interface between the simulation and game layers of PrimAITE.""" \ No newline at end of file diff --git a/src/primaite/notebooks/UC7-network_connectivity.ipynb b/src/primaite/notebooks/UC7-network_connectivity.ipynb index 8aef5465..bdabacc2 100644 --- a/src/primaite/notebooks/UC7-network_connectivity.ipynb +++ b/src/primaite/notebooks/UC7-network_connectivity.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# UC7 Demonstration\n", + "# UC7 Network Connectivity\n", "\n", "© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK\n" ] @@ -521,7 +521,7 @@ "metadata": {}, "outputs": [], "source": [ - "# Some tech intranet router DR 1 --> Public DNS \n", + "# Some tech intranet router DR 1 --> Public DNS\n", "\n", "st_intra_prv_rt_dr_1.ping(isp_pub_srv_dns.network_interface[1].ip_address)" ] @@ -583,7 +583,7 @@ "metadata": {}, "outputs": [], "source": [ - "# ST Home office PC 3 --> ST Router DR 2 \n", + "# ST Home office PC 3 --> ST Router DR 2\n", "\n", "st_head_office_private_pc_1.ping(st_intra_prv_rt_dr_2.network_interface[1].ip_address)" ] @@ -623,7 +623,7 @@ "metadata": {}, "outputs": [], "source": [ - "# ST Human Resources PC 1 --> ST Human Resources PC 2 \n", + "# ST Human Resources PC 1 --> ST Human Resources PC 2\n", "\n", "st_human_resources_private_pc_1.ping(st_human_resources_private_pc_2.network_interface[1].ip_address)" ] @@ -645,7 +645,7 @@ "metadata": {}, "outputs": [], "source": [ - "# ST Human Resources PC 1 --> ST Intranet Router DR 2 \n", + "# ST Human Resources PC 1 --> ST Intranet Router DR 2\n", "\n", "st_human_resources_private_pc_1.ping(st_intra_prv_rt_dr_2.network_interface[1].ip_address)" ] @@ -656,7 +656,7 @@ "metadata": {}, "outputs": [], "source": [ - "# ST Human Resources PC 1 --> Public DNS \n", + "# ST Human Resources PC 1 --> Public DNS\n", "\n", "st_human_resources_private_pc_1.ping(isp_pub_srv_dns.network_interface[1].ip_address)" ] diff --git a/src/primaite/session/__init__.py b/src/primaite/session/__init__.py index 836b79af..06eeeb4e 100644 --- a/src/primaite/session/__init__.py +++ b/src/primaite/session/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Gymnasium and other RL environments for interfacing PrimAITE with RL models.""" \ No newline at end of file diff --git a/src/primaite/session/environment.py b/src/primaite/session/environment.py index fa545dbc..e05c65ab 100644 --- a/src/primaite/session/environment.py +++ b/src/primaite/session/environment.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Main Gymnasium entrypoint for RL agents into PrimAITE.""" import json import random import sys diff --git a/src/primaite/session/episode_schedule.py b/src/primaite/session/episode_schedule.py index 126dcf9f..82bc2eac 100644 --- a/src/primaite/session/episode_schedule.py +++ b/src/primaite/session/episode_schedule.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Strategies for selecting the game configuration between different episodes of a session.""" import copy from abc import ABC, abstractmethod from itertools import chain diff --git a/src/primaite/session/io.py b/src/primaite/session/io.py index 6c2f4f29..2c40a323 100644 --- a/src/primaite/session/io.py +++ b/src/primaite/session/io.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Utilities for reading settings and writing of log files.""" import json from datetime import datetime from pathlib import Path diff --git a/src/primaite/session/ray_envs.py b/src/primaite/session/ray_envs.py index 16c85cb3..69bcd3f4 100644 --- a/src/primaite/session/ray_envs.py +++ b/src/primaite/session/ray_envs.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Entrypoint for Ray RLLib single- and multi-agent environments.""" import json from typing import Dict, SupportsFloat, Tuple diff --git a/src/primaite/setup/reset_demo_notebooks.py b/src/primaite/setup/reset_demo_notebooks.py index ad4091e3..752106ef 100644 --- a/src/primaite/setup/reset_demo_notebooks.py +++ b/src/primaite/setup/reset_demo_notebooks.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Clear the user data directory of example notebooks and copy fresh copies in.""" import filecmp import shutil from logging import Logger diff --git a/src/primaite/setup/reset_example_configs.py b/src/primaite/setup/reset_example_configs.py index a94d6d4a..59dcd148 100644 --- a/src/primaite/setup/reset_example_configs.py +++ b/src/primaite/setup/reset_example_configs.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Clear user data folder of example config files and put fresh copies in.""" import filecmp import os import shutil diff --git a/src/primaite/simulator/__init__.py b/src/primaite/simulator/__init__.py index e85a2d1e..701d3757 100644 --- a/src/primaite/simulator/__init__.py +++ b/src/primaite/simulator/__init__.py @@ -1,5 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK -"""Warning: SIM_OUTPUT is a mutable global variable for the simulation output directory.""" +"""The PrimAITE simulation layer.""" from datetime import datetime from enum import IntEnum from pathlib import Path diff --git a/src/primaite/simulator/core.py b/src/primaite/simulator/core.py index 750372b3..26ca215d 100644 --- a/src/primaite/simulator/core.py +++ b/src/primaite/simulator/core.py @@ -1,6 +1,6 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK # flake8: noqa -"""Core of the PrimAITE Simulator.""" +"""Baseclasses for the PrimAITE Simulator.""" import warnings from abc import abstractmethod from typing import Callable, Dict, Iterable, List, Literal, Optional, Tuple, Union diff --git a/src/primaite/simulator/domain/__init__.py b/src/primaite/simulator/domain/__init__.py index 836b79af..590f6b00 100644 --- a/src/primaite/simulator/domain/__init__.py +++ b/src/primaite/simulator/domain/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Currently not used.""" \ No newline at end of file diff --git a/src/primaite/simulator/file_system/__init__.py b/src/primaite/simulator/file_system/__init__.py index 836b79af..b7e884b3 100644 --- a/src/primaite/simulator/file_system/__init__.py +++ b/src/primaite/simulator/file_system/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""File system for nodes.""" \ No newline at end of file diff --git a/src/primaite/simulator/file_system/file.py b/src/primaite/simulator/file_system/file.py index 58607bf6..22dee206 100644 --- a/src/primaite/simulator/file_system/file.py +++ b/src/primaite/simulator/file_system/file.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Simulation of a file on a computer file system.""" from __future__ import annotations import hashlib diff --git a/src/primaite/simulator/file_system/file_system.py b/src/primaite/simulator/file_system/file_system.py index 54e649f2..2b647ca4 100644 --- a/src/primaite/simulator/file_system/file_system.py +++ b/src/primaite/simulator/file_system/file_system.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Computer file system.""" from __future__ import annotations from pathlib import Path diff --git a/src/primaite/simulator/file_system/folder.py b/src/primaite/simulator/file_system/folder.py index 5b9a6931..4586ccc8 100644 --- a/src/primaite/simulator/file_system/folder.py +++ b/src/primaite/simulator/file_system/folder.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Simulation of a folder on a computer file system.""" from __future__ import annotations import warnings diff --git a/src/primaite/simulator/network/__init__.py b/src/primaite/simulator/network/__init__.py index 836b79af..872314aa 100644 --- a/src/primaite/simulator/network/__init__.py +++ b/src/primaite/simulator/network/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Top-level network object.""" \ No newline at end of file diff --git a/src/primaite/simulator/sim_container.py b/src/primaite/simulator/sim_container.py index abc83203..09a35a3c 100644 --- a/src/primaite/simulator/sim_container.py +++ b/src/primaite/simulator/sim_container.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Top-level simulation object that holds references to all child simulation components.""" from typing import Dict from primaite.interface.request import RequestResponse diff --git a/src/primaite/simulator/system/__init__.py b/src/primaite/simulator/system/__init__.py index 836b79af..b6c77b1c 100644 --- a/src/primaite/simulator/system/__init__.py +++ b/src/primaite/simulator/system/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Software and system on nodes.""" \ No newline at end of file diff --git a/src/primaite/simulator/system/applications/__init__.py b/src/primaite/simulator/system/applications/__init__.py index 836b79af..cc081d0b 100644 --- a/src/primaite/simulator/system/applications/__init__.py +++ b/src/primaite/simulator/system/applications/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Software applications.""" \ No newline at end of file diff --git a/src/primaite/simulator/system/processes/__init__.py b/src/primaite/simulator/system/processes/__init__.py index 836b79af..b1491199 100644 --- a/src/primaite/simulator/system/processes/__init__.py +++ b/src/primaite/simulator/system/processes/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Software processes. Not yet implemented.""" \ No newline at end of file diff --git a/src/primaite/simulator/system/services/__init__.py b/src/primaite/simulator/system/services/__init__.py index 836b79af..7ae97aee 100644 --- a/src/primaite/simulator/system/services/__init__.py +++ b/src/primaite/simulator/system/services/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Software services.""" \ No newline at end of file diff --git a/src/primaite/simulator/system/services/arp/__init__.py b/src/primaite/simulator/system/services/arp/__init__.py index 836b79af..87c1ad2c 100644 --- a/src/primaite/simulator/system/services/arp/__init__.py +++ b/src/primaite/simulator/system/services/arp/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Address Resolution Protocol software.""" \ No newline at end of file diff --git a/src/primaite/simulator/system/services/arp/arp.py b/src/primaite/simulator/system/services/arp/arp.py index 3302041d..ea60f27a 100644 --- a/src/primaite/simulator/system/services/arp/arp.py +++ b/src/primaite/simulator/system/services/arp/arp.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""ARP software.""" from __future__ import annotations from abc import abstractmethod diff --git a/src/primaite/simulator/system/services/database/__init__.py b/src/primaite/simulator/system/services/database/__init__.py index 836b79af..45a42e31 100644 --- a/src/primaite/simulator/system/services/database/__init__.py +++ b/src/primaite/simulator/system/services/database/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Database simulation.""" \ No newline at end of file diff --git a/src/primaite/simulator/system/services/database/database_service.py b/src/primaite/simulator/system/services/database/database_service.py index edc3f6b4..1f81ace7 100644 --- a/src/primaite/simulator/system/services/database/database_service.py +++ b/src/primaite/simulator/system/services/database/database_service.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Database service.""" from ipaddress import IPv4Address from typing import Any, Dict, List, Literal, Optional, Union from uuid import uuid4 diff --git a/src/primaite/simulator/system/services/dns/__init__.py b/src/primaite/simulator/system/services/dns/__init__.py index 836b79af..d97c1be7 100644 --- a/src/primaite/simulator/system/services/dns/__init__.py +++ b/src/primaite/simulator/system/services/dns/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Domain Name Service software.""" \ No newline at end of file diff --git a/src/primaite/simulator/system/services/dns/dns_client.py b/src/primaite/simulator/system/services/dns/dns_client.py index 8b16af69..b1f22e07 100644 --- a/src/primaite/simulator/system/services/dns/dns_client.py +++ b/src/primaite/simulator/system/services/dns/dns_client.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""DNS Client.""" from ipaddress import IPv4Address from typing import Dict, Optional, TYPE_CHECKING diff --git a/src/primaite/simulator/system/services/dns/dns_server.py b/src/primaite/simulator/system/services/dns/dns_server.py index 696af993..fced793b 100644 --- a/src/primaite/simulator/system/services/dns/dns_server.py +++ b/src/primaite/simulator/system/services/dns/dns_server.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""DNS Server.""" from ipaddress import IPv4Address from typing import Any, Dict, Optional diff --git a/src/primaite/simulator/system/services/ftp/__init__.py b/src/primaite/simulator/system/services/ftp/__init__.py index 836b79af..9a1ea9d3 100644 --- a/src/primaite/simulator/system/services/ftp/__init__.py +++ b/src/primaite/simulator/system/services/ftp/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""File Transfer Protocol Software.""" \ No newline at end of file diff --git a/src/primaite/simulator/system/services/ftp/ftp_client.py b/src/primaite/simulator/system/services/ftp/ftp_client.py index 6b32aee6..325e9428 100644 --- a/src/primaite/simulator/system/services/ftp/ftp_client.py +++ b/src/primaite/simulator/system/services/ftp/ftp_client.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""FTP Client.""" from ipaddress import IPv4Address from typing import Dict, Optional diff --git a/src/primaite/simulator/system/services/ftp/ftp_server.py b/src/primaite/simulator/system/services/ftp/ftp_server.py index 86e07c54..d838b471 100644 --- a/src/primaite/simulator/system/services/ftp/ftp_server.py +++ b/src/primaite/simulator/system/services/ftp/ftp_server.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""FTP Server.""" from typing import Any, Optional from pydantic import Field diff --git a/src/primaite/simulator/system/services/ftp/ftp_service.py b/src/primaite/simulator/system/services/ftp/ftp_service.py index 77582c3c..af8c3ac6 100644 --- a/src/primaite/simulator/system/services/ftp/ftp_service.py +++ b/src/primaite/simulator/system/services/ftp/ftp_service.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""FTP Service base class.""" from abc import ABC from ipaddress import IPv4Address from typing import Dict, Optional diff --git a/src/primaite/simulator/system/services/icmp/__init__.py b/src/primaite/simulator/system/services/icmp/__init__.py index 836b79af..15ea142e 100644 --- a/src/primaite/simulator/system/services/icmp/__init__.py +++ b/src/primaite/simulator/system/services/icmp/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Internet Control Message Protocol.""" \ No newline at end of file diff --git a/src/primaite/simulator/system/services/icmp/icmp.py b/src/primaite/simulator/system/services/icmp/icmp.py index 207940cf..f25d2c18 100644 --- a/src/primaite/simulator/system/services/icmp/icmp.py +++ b/src/primaite/simulator/system/services/icmp/icmp.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Internet Control Message Protocol.""" import secrets from ipaddress import IPv4Address from typing import Any, Dict, Optional, Tuple, Union diff --git a/src/primaite/simulator/system/services/ntp/__init__.py b/src/primaite/simulator/system/services/ntp/__init__.py index 836b79af..34c19992 100644 --- a/src/primaite/simulator/system/services/ntp/__init__.py +++ b/src/primaite/simulator/system/services/ntp/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""NTP software.""" diff --git a/src/primaite/simulator/system/services/ntp/ntp_client.py b/src/primaite/simulator/system/services/ntp/ntp_client.py index 6bd1f4bb..d805cc9f 100644 --- a/src/primaite/simulator/system/services/ntp/ntp_client.py +++ b/src/primaite/simulator/system/services/ntp/ntp_client.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""NTP Client.""" from datetime import datetime from ipaddress import IPv4Address from typing import Dict, Optional diff --git a/src/primaite/simulator/system/services/ntp/ntp_server.py b/src/primaite/simulator/system/services/ntp/ntp_server.py index 05696d9f..24756b90 100644 --- a/src/primaite/simulator/system/services/ntp/ntp_server.py +++ b/src/primaite/simulator/system/services/ntp/ntp_server.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""NTP Server.""" from datetime import datetime from typing import Dict, Optional diff --git a/src/primaite/simulator/system/services/terminal/__init__.py b/src/primaite/simulator/system/services/terminal/__init__.py index 836b79af..85152b4b 100644 --- a/src/primaite/simulator/system/services/terminal/__init__.py +++ b/src/primaite/simulator/system/services/terminal/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Command line interface on network nodes.""" \ No newline at end of file diff --git a/src/primaite/simulator/system/services/terminal/terminal.py b/src/primaite/simulator/system/services/terminal/terminal.py index 08b22fe7..8ef9ca03 100644 --- a/src/primaite/simulator/system/services/terminal/terminal.py +++ b/src/primaite/simulator/system/services/terminal/terminal.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Command line interface on network nodes.""" from __future__ import annotations from abc import abstractmethod diff --git a/src/primaite/simulator/system/services/web_server/__init__.py b/src/primaite/simulator/system/services/web_server/__init__.py index 836b79af..856ba860 100644 --- a/src/primaite/simulator/system/services/web_server/__init__.py +++ b/src/primaite/simulator/system/services/web_server/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""HTTP server.""" \ No newline at end of file diff --git a/src/primaite/simulator/system/services/web_server/web_server.py b/src/primaite/simulator/system/services/web_server/web_server.py index 3f8760c4..b4f8e7ac 100644 --- a/src/primaite/simulator/system/services/web_server/web_server.py +++ b/src/primaite/simulator/system/services/web_server/web_server.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""HTTP server.""" from ipaddress import IPv4Address from typing import Any, Dict, List, Optional from urllib.parse import urlparse diff --git a/src/primaite/simulator/system/software.py b/src/primaite/simulator/system/software.py index 86b57818..1fb30f2a 100644 --- a/src/primaite/simulator/system/software.py +++ b/src/primaite/simulator/system/software.py @@ -1,4 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Base class for system software.""" import copy from abc import ABC, abstractmethod from datetime import datetime diff --git a/src/primaite/utils/validation/__init__.py b/src/primaite/utils/validation/__init__.py index 836b79af..e2318f9a 100644 --- a/src/primaite/utils/validation/__init__.py +++ b/src/primaite/utils/validation/__init__.py @@ -1 +1,2 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +"""Special validation for use with pydantic.""" \ No newline at end of file diff --git a/src/primaite/utils/validation/ip_protocol.py b/src/primaite/utils/validation/ip_protocol.py index 654a5156..0d06a257 100644 --- a/src/primaite/utils/validation/ip_protocol.py +++ b/src/primaite/utils/validation/ip_protocol.py @@ -1,5 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK -# Define a custom IP protocol validator +"""Validation for internet protocols.""" from typing import Any from pydantic import BeforeValidator, TypeAdapter, ValidationError diff --git a/src/primaite/utils/validation/ipv4_address.py b/src/primaite/utils/validation/ipv4_address.py index 1dc6c74e..1e582343 100644 --- a/src/primaite/utils/validation/ipv4_address.py +++ b/src/primaite/utils/validation/ipv4_address.py @@ -1,5 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK - +"""Validation for IPv4 addresses expressed as strings.""" from ipaddress import IPv4Address from typing import Any, Final diff --git a/src/primaite/utils/validation/port.py b/src/primaite/utils/validation/port.py index 564e843c..71d173e7 100644 --- a/src/primaite/utils/validation/port.py +++ b/src/primaite/utils/validation/port.py @@ -1,5 +1,5 @@ # © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK -# Define a custom port validator +"""Custom port validation.""" from typing import Any from pydantic import BeforeValidator, TypeAdapter, ValidationError