3086 UC7 Migration - All YAMLS, tests and notebooks. A few lingering issues such as the OS-SCAN not working and agent logs not appearing.
This commit is contained in:
173
tests/e2e_integration_tests/test_uc7_agents.py
Normal file
173
tests/e2e_integration_tests/test_uc7_agents.py
Normal file
@@ -0,0 +1,173 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
from primaite.config.load import _EXAMPLE_CFG, load
|
||||
from primaite.game.game import PrimaiteGame
|
||||
from primaite.session.environment import PrimaiteGymEnv
|
||||
from primaite.simulator.file_system.file import File
|
||||
from primaite.simulator.file_system.file_system_item_abc import FileSystemItemHealthStatus
|
||||
from primaite.simulator.network.container import Network
|
||||
from primaite.simulator.network.hardware.nodes.host.computer import Computer
|
||||
from primaite.simulator.network.hardware.nodes.host.server import Server
|
||||
from primaite.simulator.network.hardware.nodes.network.firewall import Firewall
|
||||
from primaite.simulator.system.applications.application import ApplicationOperatingState
|
||||
from primaite.simulator.system.applications.database_client import DatabaseClient
|
||||
from primaite.simulator.system.applications.red_applications.c2.c2_beacon import C2Beacon
|
||||
from primaite.simulator.system.applications.red_applications.ransomware_script import RansomwareScript
|
||||
from primaite.simulator.system.applications.web_browser import WebBrowser
|
||||
from primaite.simulator.system.services.database.database_service import DatabaseService
|
||||
from primaite.simulator.system.services.dns.dns_client import DNSClient
|
||||
from primaite.simulator.system.services.dns.dns_server import DNSServer
|
||||
from primaite.simulator.system.services.ftp.ftp_client import FTPClient
|
||||
from primaite.simulator.system.services.ftp.ftp_server import FTPServer
|
||||
from primaite.simulator.system.services.ntp.ntp_client import NTPClient
|
||||
from primaite.simulator.system.services.ntp.ntp_server import NTPServer
|
||||
from primaite.simulator.system.services.service import ServiceOperatingState
|
||||
from primaite.simulator.system.software import SoftwareHealthState
|
||||
|
||||
CONFIG_FILE = _EXAMPLE_CFG / "uc7_config.yaml"
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def uc7_environment() -> PrimaiteGymEnv:
|
||||
with open(_EXAMPLE_CFG / "uc7_config.yaml", mode="r") as uc7_config:
|
||||
cfg = yaml.safe_load(uc7_config)
|
||||
env = PrimaiteGymEnv(env_config=cfg)
|
||||
return env
|
||||
|
||||
|
||||
def assert_agent_reward(env: PrimaiteGymEnv, agent_name: str, positive: bool):
|
||||
"""Asserts that a given agent has a reward that is below/above or equal to 0 dependant on arguments."""
|
||||
agent_reward = env.game.agents[agent_name].reward_function.total_reward
|
||||
if agent_name == "defender":
|
||||
return # ignore blue agent
|
||||
if positive is True:
|
||||
assert agent_reward >= 0 # Asserts that no agents are below a total reward of 0
|
||||
elif positive is False:
|
||||
assert agent_reward <= 0 # Asserts that no agents are above a total reward of 0
|
||||
else:
|
||||
print("Invalid 'positive' argument.")
|
||||
|
||||
|
||||
def test_green_agent_positive_reward(uc7_environment):
|
||||
"""Confirms that the UC7 Green Agents receive a positive reward (Default Behaviour)."""
|
||||
env: PrimaiteGymEnv = uc7_environment
|
||||
|
||||
# Performing no changes to the environment. Default Behaviour
|
||||
|
||||
# Stepping 60 times in the environment
|
||||
for _ in range(60):
|
||||
env.step(0)
|
||||
|
||||
for agent in env.game.agents:
|
||||
assert_agent_reward(env=env, agent_name=env.game.agents[agent].config.ref, positive=True)
|
||||
|
||||
|
||||
def test_green_agent_negative_reward(uc7_environment):
|
||||
"""Confirms that the UC7 Green Agents receive a negative reward. (Disabled web-server and database-service)"""
|
||||
|
||||
env: PrimaiteGymEnv = uc7_environment
|
||||
|
||||
# Purposefully disabling the following services:
|
||||
|
||||
# 1. Disabling the web-server
|
||||
st_dmz_pub_srv_web: Server = env.game.simulation.network.get_node_by_hostname("ST-DMZ-PUB-SRV-WEB")
|
||||
st_web_server = st_dmz_pub_srv_web.software_manager.software["web-server"]
|
||||
st_web_server.operating_state = ServiceOperatingState.DISABLED
|
||||
assert st_web_server.operating_state == ServiceOperatingState.DISABLED
|
||||
|
||||
# 2. Disabling the DatabaseServer
|
||||
st_data_database_server: Server = env.game.simulation.network.get_node_by_hostname("ST-DATA-PRV-SRV-DB")
|
||||
database_service: DatabaseService = st_data_database_server.software_manager.software["database-service"]
|
||||
database_service.operating_state = ServiceOperatingState.DISABLED
|
||||
assert database_service.operating_state == ServiceOperatingState.DISABLED
|
||||
|
||||
# Stepping 100 times in the environment
|
||||
for _ in range(100):
|
||||
env.step(0)
|
||||
|
||||
for agent in env.game.agents:
|
||||
assert_agent_reward(env=env, agent_name=env.game.agents[agent].config.ref, positive=False)
|
||||
|
||||
|
||||
def test_tap001_default_behaviour(uc7_environment):
|
||||
"""Confirms that the TAP001 expected simulation impacts works as expected in the UC7 environment."""
|
||||
env: PrimaiteGymEnv = uc7_environment
|
||||
env.reset()
|
||||
network = env.game.simulation.network
|
||||
|
||||
# Running for 128 episodes
|
||||
for _ in range(128):
|
||||
env.step(0)
|
||||
|
||||
some_tech_proj_a_pc_1: Computer = network.get_node_by_hostname("ST-PROJ-A-PRV-PC-1")
|
||||
|
||||
# Asserting that the `malware_dropper.ps1` was created.
|
||||
|
||||
malware_dropper_file: File = some_tech_proj_a_pc_1.file_system.get_file("downloads", "malware_dropper.ps1")
|
||||
assert malware_dropper_file.health_status == FileSystemItemHealthStatus.GOOD
|
||||
|
||||
# Asserting that the `RansomwareScript` launched successfully.
|
||||
|
||||
ransomware_script: RansomwareScript = some_tech_proj_a_pc_1.software_manager.software["ransomware-script"]
|
||||
assert ransomware_script.health_state_actual == SoftwareHealthState.GOOD
|
||||
assert ransomware_script.operating_state == ApplicationOperatingState.RUNNING
|
||||
|
||||
# Asserting that the `C2Beacon` connected to the `C2Server`.
|
||||
|
||||
c2_beacon: C2Beacon = some_tech_proj_a_pc_1.software_manager.software["c2-beacon"]
|
||||
assert c2_beacon.health_state_actual == SoftwareHealthState.GOOD
|
||||
assert c2_beacon.operating_state == ApplicationOperatingState.RUNNING
|
||||
assert c2_beacon.c2_connection_active == True
|
||||
|
||||
# Asserting that the target database was successfully corrupted.
|
||||
some_tech_data_server_database: Server = network.get_node_by_hostname("ST-DATA-PRV-SRV-DB")
|
||||
database_file: File = some_tech_data_server_database.file_system.get_file(
|
||||
folder_name="database", file_name="database.db"
|
||||
)
|
||||
assert database_file.health_status == FileSystemItemHealthStatus.CORRUPT
|
||||
|
||||
|
||||
def test_tap003_default_behaviour(uc7_environment):
|
||||
"""Confirms that the TAP003 expected simulation impacts works as expected in the UC7 environment."""
|
||||
from primaite.simulator.network.hardware.nodes.network.router import ACLAction, Router
|
||||
from primaite.simulator.network.transmission.network_layer import IPPacket, IPProtocol
|
||||
from primaite.utils.validation.port import PORT_LOOKUP
|
||||
|
||||
def uc7_environment_tap003() -> PrimaiteGymEnv:
|
||||
with open(_EXAMPLE_CFG / "uc7_config_tap003.yaml", mode="r") as uc7_config:
|
||||
cfg = yaml.safe_load(uc7_config)
|
||||
cfg["agents"][32]["agent_settings"]["starting_nodes"] = ["ST-PROJ-A-PRV-PC-1"]
|
||||
cfg["agents"][32]["agent_settings"]["default_starting_node"] = "ST-PROJ-A-PRV-PC-1"
|
||||
env = PrimaiteGymEnv(env_config=cfg)
|
||||
return env
|
||||
|
||||
env: PrimaiteGymEnv = uc7_environment_tap003()
|
||||
env.reset()
|
||||
# Running for 128 episodes
|
||||
for _ in range(128):
|
||||
env.step(0)
|
||||
network = env.game.simulation.network
|
||||
|
||||
# Asserting that a malicious ACL has been added to ST-INTRA-PRV-RT-DR-1
|
||||
st_intra_prv_rt_dr_1: Router = network.get_node_by_hostname(hostname="ST-INTRA-PRV-RT-DR-1")
|
||||
assert st_intra_prv_rt_dr_1.acl.acl[1].action == ACLAction.DENY
|
||||
assert st_intra_prv_rt_dr_1.acl.acl[1].protocol == "tcp"
|
||||
assert st_intra_prv_rt_dr_1.acl.acl[1].src_port == PORT_LOOKUP.get("POSTGRES_SERVER")
|
||||
assert st_intra_prv_rt_dr_1.acl.acl[1].dst_port == PORT_LOOKUP.get("POSTGRES_SERVER")
|
||||
|
||||
# Asserting that a malicious ACL has been added to ST-INTRA-PRV-RT-CR
|
||||
st_intra_prv_rt_cr: Router = network.get_node_by_hostname(hostname="ST-INTRA-PRV-RT-CR")
|
||||
assert st_intra_prv_rt_cr.acl.acl[1].action == ACLAction.DENY
|
||||
assert st_intra_prv_rt_cr.acl.acl[1].protocol == "tcp"
|
||||
assert st_intra_prv_rt_cr.acl.acl[1].src_port == PORT_LOOKUP.get("HTTP")
|
||||
assert st_intra_prv_rt_cr.acl.acl[1].dst_port == PORT_LOOKUP.get("HTTP")
|
||||
|
||||
# Asserting that a malicious ACL has been added to REM-PUB-RT-DR
|
||||
rem_pub_rt_dr: Router = network.get_node_by_hostname(hostname="REM-PUB-RT-DR")
|
||||
assert rem_pub_rt_dr.acl.acl[1].action == ACLAction.DENY
|
||||
assert rem_pub_rt_dr.acl.acl[1].protocol == "tcp"
|
||||
assert rem_pub_rt_dr.acl.acl[1].src_port == PORT_LOOKUP.get("DNS")
|
||||
assert rem_pub_rt_dr.acl.acl[1].dst_port == PORT_LOOKUP.get("DNS")
|
||||
Reference in New Issue
Block a user