#2888: Use fixing_duration from ConfigSchema.

This commit is contained in:
Nick Todd
2025-01-06 16:33:57 +00:00
parent 695ebb5ec7
commit cb4e10921e
7 changed files with 38 additions and 44 deletions

View File

@@ -70,7 +70,7 @@ Python
Configuration Configuration
============= =============
The RansomwareScript inherits configuration options such as ``fix_duration`` from its parent class. However, for the ``RansomwareScript`` the most relevant option is ``server_ip``. The RansomwareScript inherits configuration options such as ``fixing_duration`` from its parent class. However, for the ``RansomwareScript`` the most relevant option is ``server_ip``.
``server_ip`` ``server_ip``

View File

@@ -22,8 +22,8 @@ options
The configuration options are the attributes that fall under the options for an application or service. The configuration options are the attributes that fall under the options for an application or service.
fix_duration fixing_duration
"""""""""""" """""""""""""""
Optional. Default value is ``2``. Optional. Default value is ``2``.

View File

@@ -380,8 +380,8 @@ class PrimaiteGame:
new_service = new_node.software_manager.software[service_class.__name__] new_service = new_node.software_manager.software[service_class.__name__]
# fixing duration for the service # fixing duration for the service
if "fix_duration" in service_cfg.get("options", {}): if "fixing_duration" in service_cfg.get("options", {}):
new_service.fixing_duration = service_cfg["options"]["fix_duration"] new_service.config.fixing_duration = service_cfg["options"]["fixing_duration"]
_set_software_listen_on_ports(new_service, service_cfg) _set_software_listen_on_ports(new_service, service_cfg)
# start the service # start the service

View File

@@ -84,7 +84,7 @@ class Software(SimComponent, ABC):
model_config = ConfigDict(extra="forbid") model_config = ConfigDict(extra="forbid")
starting_health_state: SoftwareHealthState = SoftwareHealthState.UNUSED starting_health_state: SoftwareHealthState = SoftwareHealthState.UNUSED
criticality: SoftwareCriticality = SoftwareCriticality.LOWEST criticality: SoftwareCriticality = SoftwareCriticality.LOWEST
fix_duration: int = 2 fixing_duration: int = 2
config: ConfigSchema = Field(default_factory=lambda: Software.ConfigSchema()) config: ConfigSchema = Field(default_factory=lambda: Software.ConfigSchema())
@@ -94,8 +94,6 @@ class Software(SimComponent, ABC):
"The actual health state of the software." "The actual health state of the software."
health_state_visible: SoftwareHealthState = SoftwareHealthState.UNUSED health_state_visible: SoftwareHealthState = SoftwareHealthState.UNUSED
"The health state of the software visible to the red agent." "The health state of the software visible to the red agent."
criticality: SoftwareCriticality = SoftwareCriticality.LOWEST
"The criticality level of the software."
fixing_count: int = 0 fixing_count: int = 0
"The count of patches applied to the software, defaults to 0." "The count of patches applied to the software, defaults to 0."
scanning_count: int = 0 scanning_count: int = 0
@@ -110,16 +108,12 @@ class Software(SimComponent, ABC):
"The FileSystem of the Node the Software is installed on." "The FileSystem of the Node the Software is installed on."
folder: Optional[Folder] = None folder: Optional[Folder] = None
"The folder on the file system the Software uses." "The folder on the file system the Software uses."
fixing_duration: int = 2
"The number of ticks it takes to patch the software."
_fixing_countdown: Optional[int] = None _fixing_countdown: Optional[int] = None
"Current number of ticks left to patch the software." "Current number of ticks left to patch the software."
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
self.health_state_actual = self.config.starting_health_state # don't remove this self.health_state_actual = self.config.starting_health_state # don't remove this
self.criticality = self.config.criticality
self.fixing_duration = self.config.fix_duration
def _init_request_manager(self) -> RequestManager: def _init_request_manager(self) -> RequestManager:
""" """
@@ -168,7 +162,7 @@ class Software(SimComponent, ABC):
{ {
"health_state_actual": self.health_state_actual.value, "health_state_actual": self.health_state_actual.value,
"health_state_visible": self.health_state_visible.value, "health_state_visible": self.health_state_visible.value,
"criticality": self.criticality.value, "criticality": self.config.criticality.value,
"fixing_count": self.fixing_count, "fixing_count": self.fixing_count,
"scanning_count": self.scanning_count, "scanning_count": self.scanning_count,
"revealed_to_red": self.revealed_to_red, "revealed_to_red": self.revealed_to_red,
@@ -217,7 +211,7 @@ class Software(SimComponent, ABC):
def fix(self) -> bool: def fix(self) -> bool:
"""Perform a fix on the software.""" """Perform a fix on the software."""
if self.health_state_actual in (SoftwareHealthState.COMPROMISED, SoftwareHealthState.GOOD): if self.health_state_actual in (SoftwareHealthState.COMPROMISED, SoftwareHealthState.GOOD):
self._fixing_countdown = self.fixing_duration self._fixing_countdown = self.config.fixing_duration
self.set_health_state(SoftwareHealthState.FIXING) self.set_health_state(SoftwareHealthState.FIXING)
return True return True
return False return False

View File

@@ -185,7 +185,7 @@ simulation:
options: options:
db_server_ip: 192.168.1.10 db_server_ip: 192.168.1.10
server_password: arcd server_password: arcd
fix_duration: 1 fixing_duration: 1
- type: DataManipulationBot - type: DataManipulationBot
options: options:
port_scan_p_of_success: 0.8 port_scan_p_of_success: 0.8
@@ -208,7 +208,7 @@ simulation:
arcd.com: 192.168.1.10 arcd.com: 192.168.1.10
- type: DatabaseService - type: DatabaseService
options: options:
fix_duration: 5 fixing_duration: 5
backup_server_ip: 192.168.1.10 backup_server_ip: 192.168.1.10
- type: WebServer - type: WebServer
- type: FTPClient - type: FTPClient

View File

@@ -179,19 +179,19 @@ simulation:
applications: applications:
- type: NMAP - type: NMAP
options: options:
fix_duration: 1 fixing_duration: 1
- type: RansomwareScript - type: RansomwareScript
options: options:
fix_duration: 1 fixing_duration: 1
- type: WebBrowser - type: WebBrowser
options: options:
target_url: http://arcd.com/users/ target_url: http://arcd.com/users/
fix_duration: 1 fixing_duration: 1
- type: DatabaseClient - type: DatabaseClient
options: options:
db_server_ip: 192.168.1.10 db_server_ip: 192.168.1.10
server_password: arcd server_password: arcd
fix_duration: 1 fixing_duration: 1
- type: DataManipulationBot - type: DataManipulationBot
options: options:
port_scan_p_of_success: 0.8 port_scan_p_of_success: 0.8
@@ -199,44 +199,44 @@ simulation:
payload: "DELETE" payload: "DELETE"
server_ip: 192.168.1.21 server_ip: 192.168.1.21
server_password: arcd server_password: arcd
fix_duration: 1 fixing_duration: 1
- type: DoSBot - type: DoSBot
options: options:
target_ip_address: 192.168.10.21 target_ip_address: 192.168.10.21
payload: SPOOF DATA payload: SPOOF DATA
port_scan_p_of_success: 0.8 port_scan_p_of_success: 0.8
fix_duration: 1 fixing_duration: 1
services: services:
- type: DNSClient - type: DNSClient
options: options:
dns_server: 192.168.1.10 dns_server: 192.168.1.10
fix_duration: 3 fixing_duration: 3
- type: DNSServer - type: DNSServer
options: options:
fix_duration: 3 fixing_duration: 3
domain_mapping: domain_mapping:
arcd.com: 192.168.1.10 arcd.com: 192.168.1.10
- type: DatabaseService - type: DatabaseService
options: options:
backup_server_ip: 192.168.1.10 backup_server_ip: 192.168.1.10
fix_duration: 3 fixing_duration: 3
- type: WebServer - type: WebServer
options: options:
fix_duration: 3 fixing_duration: 3
- type: FTPClient - type: FTPClient
options: options:
fix_duration: 3 fixing_duration: 3
- type: FTPServer - type: FTPServer
options: options:
server_password: arcd server_password: arcd
fix_duration: 3 fixing_duration: 3
- type: NTPClient - type: NTPClient
options: options:
ntp_server_ip: 192.168.1.10 ntp_server_ip: 192.168.1.10
fix_duration: 3 fixing_duration: 3
- type: NTPServer - type: NTPServer
options: options:
fix_duration: 3 fixing_duration: 3
- hostname: client_2 - hostname: client_2
type: computer type: computer
ip_address: 192.168.10.22 ip_address: 192.168.10.22

View File

@@ -27,27 +27,27 @@ def load_config(config_path: Union[str, Path]) -> PrimaiteGame:
return PrimaiteGame.from_config(cfg) return PrimaiteGame.from_config(cfg)
def test_default_fix_duration(): def test_default_fixing_duration():
"""Test that software with no defined fix duration in config uses the default fix duration of 2.""" """Test that software with no defined fixing duration in config uses the default fixing duration of 2."""
game = load_config(TEST_CONFIG) game = load_config(TEST_CONFIG)
client_2: Computer = game.simulation.network.get_node_by_hostname("client_2") client_2: Computer = game.simulation.network.get_node_by_hostname("client_2")
database_client: DatabaseClient = client_2.software_manager.software.get("DatabaseClient") database_client: DatabaseClient = client_2.software_manager.software.get("DatabaseClient")
assert database_client.fixing_duration == 2 assert database_client.config.fixing_duration == 2
dns_client: DNSClient = client_2.software_manager.software.get("DNSClient") dns_client: DNSClient = client_2.software_manager.software.get("DNSClient")
assert dns_client.fixing_duration == 2 assert dns_client.config.fixing_duration == 2
def test_fix_duration_set_from_config(): def test_fixing_duration_set_from_config():
"""Test to check that the fix duration set for applications and services works as intended.""" """Test to check that the fixing duration set for applications and services works as intended."""
game = load_config(TEST_CONFIG) game = load_config(TEST_CONFIG)
client_1: Computer = game.simulation.network.get_node_by_hostname("client_1") client_1: Computer = game.simulation.network.get_node_by_hostname("client_1")
# in config - services take 3 timesteps to fix # in config - services take 3 timesteps to fix
for service in ["DNSClient", "DNSServer", "DatabaseService", "WebServer", "FTPClient", "FTPServer", "NTPServer"]: for service in ["DNSClient", "DNSServer", "DatabaseService", "WebServer", "FTPClient", "FTPServer", "NTPServer"]:
assert client_1.software_manager.software.get(service) is not None assert client_1.software_manager.software.get(service) is not None
assert client_1.software_manager.software.get(service).fixing_duration == 3 assert client_1.software_manager.software.get(service).config.fixing_duration == 3
# in config - applications take 1 timestep to fix # in config - applications take 1 timestep to fix
# remove test applications from list # remove test applications from list
@@ -55,27 +55,27 @@ def test_fix_duration_set_from_config():
for application in ["RansomwareScript", "WebBrowser", "DataManipulationBot", "DoSBot", "DatabaseClient"]: for application in ["RansomwareScript", "WebBrowser", "DataManipulationBot", "DoSBot", "DatabaseClient"]:
assert client_1.software_manager.software.get(application) is not None assert client_1.software_manager.software.get(application) is not None
assert client_1.software_manager.software.get(application).fixing_duration == 1 assert client_1.software_manager.software.get(application).config.fixing_duration == 1
def test_fix_duration_for_one_item(): def test_fixing_duration_for_one_item():
"""Test that setting fix duration for one application does not affect other components.""" """Test that setting fixing duration for one application does not affect other components."""
game = load_config(ONE_ITEM_CONFIG) game = load_config(ONE_ITEM_CONFIG)
client_1: Computer = game.simulation.network.get_node_by_hostname("client_1") client_1: Computer = game.simulation.network.get_node_by_hostname("client_1")
# in config - services take 3 timesteps to fix # in config - services take 3 timesteps to fix
for service in ["DNSClient", "DNSServer", "WebServer", "FTPClient", "FTPServer", "NTPServer"]: for service in ["DNSClient", "DNSServer", "WebServer", "FTPClient", "FTPServer", "NTPServer"]:
assert client_1.software_manager.software.get(service) is not None assert client_1.software_manager.software.get(service) is not None
assert client_1.software_manager.software.get(service).fixing_duration == 2 assert client_1.software_manager.software.get(service).config.fixing_duration == 2
# in config - applications take 1 timestep to fix # in config - applications take 1 timestep to fix
# remove test applications from list # remove test applications from list
for applications in ["RansomwareScript", "WebBrowser", "DataManipulationBot", "DoSBot"]: for applications in ["RansomwareScript", "WebBrowser", "DataManipulationBot", "DoSBot"]:
assert client_1.software_manager.software.get(applications) is not None assert client_1.software_manager.software.get(applications) is not None
assert client_1.software_manager.software.get(applications).fixing_duration == 2 assert client_1.software_manager.software.get(applications).config.fixing_duration == 2
database_client: DatabaseClient = client_1.software_manager.software.get("DatabaseClient") database_client: DatabaseClient = client_1.software_manager.software.get("DatabaseClient")
assert database_client.fixing_duration == 1 assert database_client.config.fixing_duration == 1
database_service: DatabaseService = client_1.software_manager.software.get("DatabaseService") database_service: DatabaseService = client_1.software_manager.software.get("DatabaseService")
assert database_service.fixing_duration == 5 assert database_service.config.fixing_duration == 5