privateboss commited on
Commit
7b3b5d4
·
verified ·
1 Parent(s): e726e28

Update AINetworkDefense_Competitive/env.py

Browse files
Files changed (1) hide show
  1. AINetworkDefense_Competitive/env.py +47 -23
AINetworkDefense_Competitive/env.py CHANGED
@@ -5,14 +5,13 @@ from config import Config
5
 
6
  class CyberPettingZooEnv(ParallelEnv):
7
  metadata = {'render_modes': ['human'], "name": "cyber_network_defense_v2_gnn"}
8
-
9
  def __init__(self):
10
  super().__init__()
11
 
12
  self.topology = Config.NETWORK_TOPOLOGY
13
  self.total_nodes = Config.TOTAL_HOSTS()
14
- self.features_per_node = 2
15
-
16
  self.possible_agents = ["red", "blue"]
17
  self.agents = self.possible_agents[:]
18
 
@@ -24,8 +23,8 @@ class CyberPettingZooEnv(ParallelEnv):
24
  }
25
 
26
  self.action_spaces = {
27
- 'red': gym.spaces.Discrete(self.total_nodes * 4),
28
- 'blue': gym.spaces.Discrete(self.total_nodes * 2)
29
  }
30
 
31
  self.node_id_to_specs = {}
@@ -43,7 +42,7 @@ class CyberPettingZooEnv(ParallelEnv):
43
  node_id += 1
44
 
45
  def _generate_static_adjacency_matrix(self):
46
- """🚀 GNN CORE: Programmatically wires lateral communication pathways between subnets."""
47
  A = np.zeros((self.total_nodes, self.total_nodes), dtype=np.float32)
48
 
49
  # Define cross-subnet routing permissions
@@ -63,7 +62,6 @@ class CyberPettingZooEnv(ParallelEnv):
63
  if sub_j in allowed_connections[sub_i]:
64
  A[i, j] = 1.0
65
 
66
- # Add Self-Loops (A + I)
67
  A_tilde = A + np.eye(self.total_nodes, dtype=np.float32)
68
 
69
  # Compute Symmetric Degree Normalization:
@@ -78,6 +76,9 @@ class CyberPettingZooEnv(ParallelEnv):
78
  self.agents = self.possible_agents[:]
79
  self.state_matrix = np.zeros((self.total_nodes, self.features_per_node), dtype=np.float32)
80
 
 
 
 
81
  obs_dict = {
82
  'node_features': self.state_matrix.copy(),
83
  'adjacency_matrix': self.normalized_adj.copy()
@@ -96,54 +97,77 @@ class CyberPettingZooEnv(ParallelEnv):
96
  if not actions:
97
  self.agents = []
98
  return {}, {}, {}, {}, {}
99
-
 
 
100
  red_action = actions.get('red', 0)
101
  blue_action = actions.get('blue', 0)
102
-
103
  red_target_node = red_action // 4
104
  red_action_type = red_action % 4
105
  blue_target_node = blue_action // 2
106
  blue_action_type = blue_action % 2
107
-
108
  red_target_node = min(max(0, red_target_node), self.total_nodes - 1)
109
  blue_target_node = min(max(0, blue_target_node), self.total_nodes - 1)
110
-
111
  red_target_specs = self.node_id_to_specs[red_target_node]
112
  red_target_subnet = red_target_specs["subnet"]
113
-
114
- # 1. Defense Execution
115
  if blue_action_type == 1:
116
  self.state_matrix[blue_target_node, 1] = 1.0
117
-
118
- # 2. Attack Execution with Infrastructure Co-Dependencies
119
  if red_action_type == 1:
120
  if self.state_matrix[red_target_node, 1] == 0.0:
121
  exploit_probability = red_target_specs["base_vulnerability"]
122
 
123
  if red_target_subnet == "secure_core":
124
  if not self._is_subnet_compromised("active_directory"):
125
- exploit_probability = 0.0
126
  elif red_target_subnet == "active_directory":
127
  if self._is_subnet_compromised("dns_services"):
128
  exploit_probability = min(1.0, exploit_probability * 2.0)
129
-
130
  if np.random.rand() < exploit_probability:
131
  self.state_matrix[red_target_node, 0] = 1.0
132
-
133
- # 3. Telemetry Preparation
134
  total_compromised = np.sum(self.state_matrix[:, 0])
135
  total_patched = np.sum(self.state_matrix[:, 1])
136
  score_diff = float(total_compromised - total_patched)
137
  progress = float(total_compromised / self.total_nodes) if self.total_nodes > 0 else 0.0
138
-
139
  obs_dict = {
140
  'node_features': self.state_matrix.copy(),
141
  'adjacency_matrix': self.normalized_adj.copy()
142
  }
143
  observations = {'red': obs_dict, 'blue': obs_dict}
144
  rewards = {'red': 0.0, 'blue': 0.0}
145
- terminations = {'red': False, 'blue': False}
146
- truncations = {'red': False, 'blue': False}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  infos = {'score_difference': score_diff, 'team_progress': progress}
148
-
 
 
 
 
149
  return observations, rewards, terminations, truncations, infos
 
5
 
6
  class CyberPettingZooEnv(ParallelEnv):
7
  metadata = {'render_modes': ['human'], "name": "cyber_network_defense_v2_gnn"}
8
+
9
  def __init__(self):
10
  super().__init__()
11
 
12
  self.topology = Config.NETWORK_TOPOLOGY
13
  self.total_nodes = Config.TOTAL_HOSTS()
14
+ self.features_per_node = 2
 
15
  self.possible_agents = ["red", "blue"]
16
  self.agents = self.possible_agents[:]
17
 
 
23
  }
24
 
25
  self.action_spaces = {
26
+ 'red': gym.spaces.Discrete(self.total_nodes * 4),
27
+ 'blue': gym.spaces.Discrete(self.total_nodes * 2)
28
  }
29
 
30
  self.node_id_to_specs = {}
 
42
  node_id += 1
43
 
44
  def _generate_static_adjacency_matrix(self):
45
+ """ GNN CORE: Programmatically wires lateral communication pathways between subnets."""
46
  A = np.zeros((self.total_nodes, self.total_nodes), dtype=np.float32)
47
 
48
  # Define cross-subnet routing permissions
 
62
  if sub_j in allowed_connections[sub_i]:
63
  A[i, j] = 1.0
64
 
 
65
  A_tilde = A + np.eye(self.total_nodes, dtype=np.float32)
66
 
67
  # Compute Symmetric Degree Normalization:
 
76
  self.agents = self.possible_agents[:]
77
  self.state_matrix = np.zeros((self.total_nodes, self.features_per_node), dtype=np.float32)
78
 
79
+ # Initialize step tracker
80
+ self.current_step = 0
81
+
82
  obs_dict = {
83
  'node_features': self.state_matrix.copy(),
84
  'adjacency_matrix': self.normalized_adj.copy()
 
97
  if not actions:
98
  self.agents = []
99
  return {}, {}, {}, {}, {}
100
+
101
+ self.current_step += 1
102
+
103
  red_action = actions.get('red', 0)
104
  blue_action = actions.get('blue', 0)
105
+
106
  red_target_node = red_action // 4
107
  red_action_type = red_action % 4
108
  blue_target_node = blue_action // 2
109
  blue_action_type = blue_action % 2
110
+
111
  red_target_node = min(max(0, red_target_node), self.total_nodes - 1)
112
  blue_target_node = min(max(0, blue_target_node), self.total_nodes - 1)
113
+
114
  red_target_specs = self.node_id_to_specs[red_target_node]
115
  red_target_subnet = red_target_specs["subnet"]
116
+
117
+ # Defense Execution
118
  if blue_action_type == 1:
119
  self.state_matrix[blue_target_node, 1] = 1.0
120
+
121
+ # Attack Execution with Infrastructure Co-Dependencies
122
  if red_action_type == 1:
123
  if self.state_matrix[red_target_node, 1] == 0.0:
124
  exploit_probability = red_target_specs["base_vulnerability"]
125
 
126
  if red_target_subnet == "secure_core":
127
  if not self._is_subnet_compromised("active_directory"):
128
+ exploit_probability = 0.0
129
  elif red_target_subnet == "active_directory":
130
  if self._is_subnet_compromised("dns_services"):
131
  exploit_probability = min(1.0, exploit_probability * 2.0)
132
+
133
  if np.random.rand() < exploit_probability:
134
  self.state_matrix[red_target_node, 0] = 1.0
135
+
136
+ # Telemetry Preparation
137
  total_compromised = np.sum(self.state_matrix[:, 0])
138
  total_patched = np.sum(self.state_matrix[:, 1])
139
  score_diff = float(total_compromised - total_patched)
140
  progress = float(total_compromised / self.total_nodes) if self.total_nodes > 0 else 0.0
141
+
142
  obs_dict = {
143
  'node_features': self.state_matrix.copy(),
144
  'adjacency_matrix': self.normalized_adj.copy()
145
  }
146
  observations = {'red': obs_dict, 'blue': obs_dict}
147
  rewards = {'red': 0.0, 'blue': 0.0}
148
+
149
+ # DYNAMIC EPISODE TERMINATIONS AND TRUNCATIONS
150
+ reached_max_steps = self.current_step >= Config.MAX_STEPS_PER_EPISODE
151
+
152
+ if str(Config.MODE).lower() == "cooperative":
153
+ # Cooperative: Runs the full duration of the step limit
154
+ is_terminated = False
155
+ is_truncated = reached_max_steps
156
+ else:
157
+ # Competitive: Allow early wins (e.g.Red conquers all, or Blue erases threat)
158
+ red_won = (total_compromised == self.total_nodes)
159
+ blue_won = (total_compromised == 0 and self.current_step > 5)
160
+
161
+ is_terminated = red_won or blue_won
162
+ is_truncated = reached_max_steps
163
+
164
+ terminations = {agent: is_terminated for agent in self.possible_agents}
165
+ truncations = {agent: is_truncated for agent in self.possible_agents}
166
+
167
  infos = {'score_difference': score_diff, 'team_progress': progress}
168
+
169
+ # Cleanup agent lists if active sequence ends
170
+ if is_terminated or is_truncated:
171
+ self.agents = []
172
+
173
  return observations, rewards, terminations, truncations, infos