Merge remote-tracking branch 'origin/dev-v3.0.0b5' into bugfix/2176-attack-observation-symptoms

This commit is contained in:
Marek Wolan
2024-01-10 13:07:23 +00:00
8 changed files with 31 additions and 14 deletions

View File

@@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
- Made packet capture and system logging optional (off by default). To turn on, change the io_settings.save_pcap_logs and io_settings.save_sys_logs settings in the config.
- Made observation space flattening optional (on by default). To turn off for an agent, change the agent_settings.flatten_obs setting in the config.
- Fixed an issue where the data manipulation attack was triggered at episode start.
### Added
- Network Hardware - Added base hardware module with NIC, SwitchPort, Node, and Link. Nodes have

View File

@@ -15,7 +15,6 @@ class DataManipulationAgent(AbstractScriptedAgent):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._set_next_execution_timestep(self.agent_settings.start_settings.start_step)
def _set_next_execution_timestep(self, timestep: int) -> None:
@@ -46,3 +45,8 @@ class DataManipulationAgent(AbstractScriptedAgent):
self._set_next_execution_timestep(current_timestep + self.agent_settings.start_settings.frequency)
return "NODE_APPLICATION_EXECUTE", {"node_id": 0, "application_id": 0}
def reset_agent_for_episode(self) -> None:
"""Set the next execution timestep when the episode resets."""
super().reset_agent_for_episode()
self._set_next_execution_timestep(self.agent_settings.start_settings.start_step)

View File

@@ -135,6 +135,10 @@ class AbstractAgent(ABC):
request = self.action_manager.form_request(action_identifier=action, action_options=options)
return request
def reset_agent_for_episode(self) -> None:
"""Agent reset logic should go here."""
pass
class AbstractScriptedAgent(AbstractAgent):
"""Base class for actors which generate their own behaviour."""

View File

@@ -140,7 +140,10 @@ class ServiceObservation(AbstractObservation):
service_state = access_from_nested_dict(state, self.where)
if service_state is NOT_PRESENT_IN_STATE:
return self.default_observation
return {"operating_status": service_state["operating_state"], "health_status": service_state["health_state"]}
return {
"operating_status": service_state["operating_state"],
"health_status": service_state["health_state_visible"],
}
@property
def space(self) -> spaces.Space:

View File

@@ -181,7 +181,6 @@ class WebServer404Penalty(AbstractReward):
"""
web_service_state = access_from_nested_dict(state, self.location_in_state)
if web_service_state is NOT_PRESENT_IN_STATE:
print("error getting web service state")
return 0.0
most_recent_return_code = web_service_state["last_response_status_code"]
# TODO: reward needs to use the current web state. Observation should return web state at the time of last scan.

View File

@@ -162,6 +162,7 @@ class PrimaiteGame:
self.simulation.reset_component_for_episode(episode=self.episode_counter)
for agent in self.agents:
agent.reward_function.total_reward = 0.0
agent.reset_agent_for_episode()
def close(self) -> None:
"""Close the game, this will close the simulation."""

View File

@@ -73,7 +73,7 @@ class DataManipulationBot(DatabaseClient):
def _init_request_manager(self) -> RequestManager:
rm = super()._init_request_manager()
rm.add_request(name="execute", request_type=RequestType(func=lambda request, context: self.run()))
rm.add_request(name="execute", request_type=RequestType(func=lambda request, context: self.attack()))
return rm
@@ -169,6 +169,12 @@ class DataManipulationBot(DatabaseClient):
Calls the parent classes execute method before starting the application loop.
"""
super().run()
def attack(self):
"""Perform the attack steps after opening the application."""
if not self._can_perform_action():
_LOGGER.debug("Data manipulation application attempted to execute but it cannot perform actions right now.")
self.run()
self._application_loop()
def _application_loop(self):
@@ -199,4 +205,4 @@ class DataManipulationBot(DatabaseClient):
:param timestep: The timestep value to update the bot's state.
"""
self._application_loop()
pass

View File

@@ -36,12 +36,12 @@ class SoftwareHealthState(Enum):
"Unused state."
GOOD = 1
"The software is in a good and healthy condition."
COMPROMISED = 2
"The software's security has been compromised."
OVERWHELMED = 3
"he software is overwhelmed and not functioning properly."
PATCHING = 4
PATCHING = 2
"The software is undergoing patching or updates."
COMPROMISED = 3
"The software's security has been compromised."
OVERWHELMED = 4
"he software is overwhelmed and not functioning properly."
class SoftwareCriticality(Enum):
@@ -145,8 +145,8 @@ class Software(SimComponent):
state = super().describe_state()
state.update(
{
"health_state": self.health_state_actual.value,
"health_state_red_view": self.health_state_visible.value,
"health_state_actual": self.health_state_actual.value,
"health_state_visible": self.health_state_visible.value,
"criticality": self.criticality.value,
"patching_count": self.patching_count,
"scanning_count": self.scanning_count,
@@ -278,7 +278,7 @@ class IOSoftware(Software):
Returns true if the software can perform actions.
"""
if self.software_manager and self.software_manager.node.operating_state is NodeOperatingState.OFF:
if self.software_manager and self.software_manager.node.operating_state is not NodeOperatingState.ON:
_LOGGER.debug(f"{self.name} Error: {self.software_manager.node.hostname} is not online.")
return False
return True