2024-06-05 09:11:37 +01:00
|
|
|
# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK
|
2023-11-24 16:32:04 +00:00
|
|
|
import random
|
2024-03-04 10:43:38 +00:00
|
|
|
from typing import Dict, Tuple
|
2023-11-24 16:32:04 +00:00
|
|
|
|
|
|
|
|
from gymnasium.core import ObsType
|
|
|
|
|
|
|
|
|
|
from primaite.game.agent.interface import AbstractScriptedAgent
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DataManipulationAgent(AbstractScriptedAgent):
|
|
|
|
|
"""Agent that uses a DataManipulationBot to perform an SQL injection attack."""
|
|
|
|
|
|
|
|
|
|
next_execution_timestep: int = 0
|
2024-02-08 09:19:18 +00:00
|
|
|
starting_node_idx: int = 0
|
2023-11-24 16:32:04 +00:00
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
super().__init__(*args, **kwargs)
|
2024-03-11 20:10:08 +00:00
|
|
|
self.setup_agent()
|
2023-11-24 16:32:04 +00:00
|
|
|
|
|
|
|
|
def _set_next_execution_timestep(self, timestep: int) -> None:
|
|
|
|
|
"""Set the next execution timestep with a configured random variance.
|
|
|
|
|
|
|
|
|
|
:param timestep: The timestep to add variance to.
|
|
|
|
|
"""
|
|
|
|
|
random_timestep_increment = random.randint(
|
|
|
|
|
-self.agent_settings.start_settings.variance, self.agent_settings.start_settings.variance
|
|
|
|
|
)
|
|
|
|
|
self.next_execution_timestep = timestep + random_timestep_increment
|
|
|
|
|
|
2024-03-04 10:43:38 +00:00
|
|
|
def get_action(self, obs: ObsType, timestep: int) -> Tuple[str, Dict]:
|
|
|
|
|
"""Waits until a specific timestep, then attempts to execute its data manipulation application.
|
2023-11-24 16:32:04 +00:00
|
|
|
|
2024-03-04 10:43:38 +00:00
|
|
|
:param obs: Current observation for this agent, not used in DataManipulationAgent
|
2023-11-24 16:32:04 +00:00
|
|
|
:type obs: ObsType
|
2024-03-04 10:43:38 +00:00
|
|
|
:param timestep: The current simulation timestep, used for scheduling actions
|
|
|
|
|
:type timestep: int
|
|
|
|
|
:return: Action formatted in CAOS format
|
2023-11-24 16:32:04 +00:00
|
|
|
:rtype: Tuple[str, Dict]
|
|
|
|
|
"""
|
2024-02-27 13:30:16 +00:00
|
|
|
if timestep < self.next_execution_timestep:
|
2024-03-04 18:47:50 +00:00
|
|
|
return "DONOTHING", {}
|
2023-11-24 16:32:04 +00:00
|
|
|
|
2024-02-27 13:30:16 +00:00
|
|
|
self._set_next_execution_timestep(timestep + self.agent_settings.start_settings.frequency)
|
2023-11-24 16:32:04 +00:00
|
|
|
|
2024-02-08 09:19:18 +00:00
|
|
|
return "NODE_APPLICATION_EXECUTE", {"node_id": self.starting_node_idx, "application_id": 0}
|
2024-01-09 14:53:15 +00:00
|
|
|
|
2024-03-11 20:10:08 +00:00
|
|
|
def setup_agent(self) -> None:
|
2024-01-09 14:53:15 +00:00
|
|
|
"""Set the next execution timestep when the episode resets."""
|
2024-02-08 09:19:18 +00:00
|
|
|
self._select_start_node()
|
2024-01-09 14:53:15 +00:00
|
|
|
self._set_next_execution_timestep(self.agent_settings.start_settings.start_step)
|
2024-02-08 09:19:18 +00:00
|
|
|
|
|
|
|
|
def _select_start_node(self) -> None:
|
|
|
|
|
"""Set the starting starting node of the agent to be a random node from this agent's action manager."""
|
|
|
|
|
# we are assuming that every node in the node manager has a data manipulation application at idx 0
|
|
|
|
|
num_nodes = len(self.action_manager.node_names)
|
|
|
|
|
self.starting_node_idx = random.randint(0, num_nodes - 1)
|