anvisinghh commited on
Commit
5e05a3c
·
verified ·
1 Parent(s): 62112a8

Update env.py

Browse files
Files changed (1) hide show
  1. env.py +206 -48
env.py CHANGED
@@ -1,52 +1,191 @@
1
  import asyncio
2
- from typing import Optional, List
 
3
  from types import SimpleNamespace
4
  from fastapi import FastAPI
5
  from openenv.core.env_server import Environment
6
- from models import MyEnvV4Observation, MyEnvV4Action
7
 
8
  class MyEnvV4Env(Environment):
9
  def __init__(self):
10
  super().__init__()
11
- # Realistic Dataset with Digital Seduction/Phishing markers
12
- self.dataset = [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  {
14
- "sender": "dean.office@manipal.edu",
15
- "subject": "B.Tech Lab Exam Schedule",
16
- "body": "Please find the attached PDF for the upcoming CSE lab exams.",
17
- "headers": ["SPF: Pass", "DKIM: Pass"],
18
- "label": "INBOX"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  },
20
  {
21
- "sender": "verify-account@security-amazon.net",
22
- "subject": "Urgent: Your account is locked!",
23
- "body": "Digital Seduction Alert: High urgency used. Click http://bit.ly/fake-link to unlock.",
24
- "headers": ["SPF: Fail", "DMARC: Fail"],
25
- "label": "QUARANTINE"
 
 
 
26
  },
27
  {
28
- "sender": "prize@lottery-winner.co",
29
- "subject": "Congratulations! You won $10,000",
30
- "body": "Reply with your bank details to claim your cash prize immediately.",
31
- "headers": ["SPF: Neutral"],
32
- "label": "SPAM"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  }
34
  ]
35
- self.current_step = 0
36
 
37
  async def reset(self):
38
  self.current_step = 0
39
  return self._get_result()
40
-
41
- async def state(self):
42
- """Returns the current state of the environment."""
43
- return {"current_step": self.current_step, "total_steps": len(self.dataset)}
44
 
45
  def _get_result(self, reward=0.0, done=False):
46
  if self.current_step >= len(self.dataset):
47
  obs = MyEnvV4Observation(
48
- sender="N/A", subject="N/A", body="N/A",
49
- headers=[], echoed_message="End of Data"
50
  )
51
  return SimpleNamespace(observation=obs, reward=reward, done=True)
52
 
@@ -55,8 +194,11 @@ class MyEnvV4Env(Environment):
55
  sender=data["sender"],
56
  subject=data["subject"],
57
  body=data["body"],
58
- headers=data["headers"],
59
- echoed_message=f"Step {self.current_step + 1}"
 
 
 
60
  )
61
  return SimpleNamespace(observation=obs, reward=reward, done=done)
62
 
@@ -64,40 +206,56 @@ class MyEnvV4Env(Environment):
64
  if self.current_step >= len(self.dataset):
65
  return self._get_result(done=True)
66
 
67
- correct_label = self.dataset[self.current_step]["label"]
68
- # Exact match reward logic for 0.0 - 1.0 range
69
- reward = 1.0 if action.message.strip().upper() == correct_label else 0.0
70
 
71
- self.current_step += 1
72
- done = self.current_step >= len(self.dataset)
73
 
74
- return self._get_result(reward=reward, done=done)
75
-
76
- async def close(self):
77
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
- @classmethod
80
- async def from_docker_image(cls, image_name: str):
81
- """Simulated helper for local/containerized runs."""
82
- return cls()
83
 
 
 
 
 
84
 
 
 
85
 
86
- # Create the environment instance
87
  my_env = MyEnvV4Env()
88
-
89
- # defining the FastAPI app and routes
90
  app = FastAPI()
91
 
92
  @app.get("/reset")
93
  async def reset():
94
- result = await my_env.reset()
95
- return {"observation": result.observation, "reward": result.reward, "done": result.done}
96
 
97
  @app.post("/step")
98
  async def step(action: MyEnvV4Action):
99
- result = await my_env.step(action)
100
- return {"observation": result.observation, "reward": result.reward, "done": result.done}
101
 
102
  @app.get("/state")
103
  async def state():
 
1
  import asyncio
2
+ import random
3
+ from typing import Optional, List, Dict
4
  from types import SimpleNamespace
5
  from fastapi import FastAPI
6
  from openenv.core.env_server import Environment
7
+ from models import MyEnvV4Observation, MyEnvV4Action, URLInfo
8
 
9
  class MyEnvV4Env(Environment):
10
  def __init__(self):
11
  super().__init__()
12
+ self.dataset = self._generate_sophisticated_dataset()
13
+ # For evaluation reproducibility, we could shuffle, but for benchmark stability, we keep order
14
+ self.current_step = 0
15
+
16
+ def _generate_sophisticated_dataset(self):
17
+ """
18
+ Expanded dataset with 15 samples across 3 difficulty levels.
19
+ Covers Clean, Spam, and Phishing (Digital Seduction).
20
+ """
21
+ base_data = [
22
+ # LEVEL 1: CLEAR CASES (5)
23
+ {
24
+ "sender": "registrar@manipal.edu",
25
+ "subject": "Semester Registration Open",
26
+ "body": "Dear student, please register for the Fall semester via the student portal.",
27
+ "raw_headers": "Received: from mail.manipal.edu (14.139.161.20) by mx.google.com; SPF: pass; DKIM: pass;",
28
+ "auth_results": {"SPF": "pass", "DKIM": "pass", "DMARC": "pass"},
29
+ "urls": [],
30
+ "label": "INBOX",
31
+ "difficulty": 1
32
+ },
33
+ {
34
+ "sender": "no-reply@amazon.com",
35
+ "subject": "Your Order #123-4567 has shipped",
36
+ "body": "Track your package delivery status in your Amazon account.",
37
+ "raw_headers": "Received: from a9-12.smtp-out.amazonses.com... SPF: pass; DKIM: pass;",
38
+ "auth_results": {"SPF": "pass", "DKIM": "pass", "DMARC": "pass"},
39
+ "urls": [{"url": "https://amazon.com/track", "is_shortened": False, "domain_age_days": 8000, "has_ssl": True, "reputation_score": 1.0}],
40
+ "label": "INBOX",
41
+ "difficulty": 1
42
+ },
43
+ {
44
+ "sender": "win-money@lottery-global.net",
45
+ "subject": "YOU WON!! $1,000,000",
46
+ "body": "Congratulations! You have been selected as our winner. CLAIM YOUR $1M NOW!",
47
+ "raw_headers": "Received: from unknown-relay.co (103.22.1.5)... SPF: none; DKIM: fail;",
48
+ "auth_results": {"SPF": "none", "DKIM": "fail", "DMARC": "none"},
49
+ "urls": [{"url": "http://get-cash-free.net/claim", "is_shortened": False, "domain_age_days": 2, "has_ssl": False, "reputation_score": 0.1}],
50
+ "label": "SPAM",
51
+ "difficulty": 1
52
+ },
53
+ {
54
+ "sender": "viagra-sales@pharma-dealz.biz",
55
+ "subject": "Cheapest Meds Online",
56
+ "body": "Buy now and save 90% on all prescription drugs. No prescription needed!",
57
+ "raw_headers": "Received: from botnet-node.ru... SPF: softfail;",
58
+ "auth_results": {"SPF": "softfail", "DKIM": "none", "DMARC": "none"},
59
+ "urls": [{"url": "http://cheap-rx.biz", "is_shortened": False, "domain_age_days": 15, "has_ssl": False, "reputation_score": 0.05}],
60
+ "label": "SPAM",
61
+ "difficulty": 1
62
+ },
63
  {
64
+ "sender": "support@netflix-security.com",
65
+ "subject": "Update Payment Method",
66
+ "body": "Your Netflix subscription has expired. Click here to login and update billing.",
67
+ "raw_headers": "Received: from suspicious-vps.com... SPF: fail; DMARC: fail;",
68
+ "auth_results": {"SPF": "fail", "DKIM": "none", "DMARC": "fail"},
69
+ "urls": [{"url": "https://bit.ly/fake-netflix-login", "is_shortened": True, "domain_age_days": 3, "has_ssl": True, "reputation_score": 0.02}],
70
+ "label": "QUARANTINE",
71
+ "difficulty": 1
72
+ },
73
+
74
+ # LEVEL 2: NUANCED / MARKETING / LEGIT BUT ANNOYING (5)
75
+ {
76
+ "sender": "news@internshala-mail.com",
77
+ "subject": "New Internships in Manipal",
78
+ "body": "Check out these new opportunities for CSE students. Apply today!",
79
+ "raw_headers": "Received: from mktg.server.com... SPF: pass; DKIM: pass;",
80
+ "auth_results": {"SPF": "pass", "DKIM": "pass", "DMARC": "pass"},
81
+ "urls": [{"url": "https://internshala.com/n/123", "is_shortened": False, "domain_age_days": 2500, "has_ssl": True, "reputation_score": 0.95}],
82
+ "label": "SPAM", # Triaged as Promotions/Spam
83
+ "difficulty": 2
84
+ },
85
+ {
86
+ "sender": "marketing@swiggy.in",
87
+ "subject": "50% OFF your next meal!",
88
+ "body": "Hungry? Use code HUNGRY50 at checkout.",
89
+ "raw_headers": "Received: from swiggy-mail.in... SPF: pass; DKIM: pass;",
90
+ "auth_results": {"SPF": "pass", "DKIM": "pass", "DMARC": "pass"},
91
+ "urls": [],
92
+ "label": "SPAM",
93
+ "difficulty": 2
94
+ },
95
+ {
96
+ "sender": "hr@startup-hiring.co",
97
+ "subject": "Interview Invitation",
98
+ "body": "We saw your profile on LinkedIn and want to chat about a role.",
99
+ "raw_headers": "Received: from linkedin-referral.com... SPF: neutral;",
100
+ "auth_results": {"SPF": "neutral", "DKIM": "none", "DMARC": "none"},
101
+ "urls": [{"url": "https://startup-hiring.co/apply", "is_shortened": False, "domain_age_days": 45, "has_ssl": True, "reputation_score": 0.6}],
102
+ "label": "INBOX", # Legitimate cold outreach
103
+ "difficulty": 2
104
  },
105
  {
106
+ "sender": "alert@banking-secure.net",
107
+ "subject": "Suspicious Activity Detected",
108
+ "body": "We detected an unusual login to your account from Russia. Please verify.",
109
+ "raw_headers": "Received: from spoofed-host.com... SPF: softfail; DMARC: none;",
110
+ "auth_results": {"SPF": "softfail", "DKIM": "none", "DMARC": "none"},
111
+ "urls": [{"url": "https://t.co/secure-bank-login", "is_shortened": True, "domain_age_days": 10, "has_ssl": True, "reputation_score": 0.3}],
112
+ "label": "QUARANTINE",
113
+ "difficulty": 2
114
  },
115
  {
116
+ "sender": "noreply@github.com",
117
+ "subject": "[GitHub] A personal access token has been added",
118
+ "body": "A new personal access token was added to your account. If this wasn't you, click here.",
119
+ "raw_headers": "Received: from out-21.smtp.github.com... SPF: pass; DKIM: pass;",
120
+ "auth_results": {"SPF": "pass", "DKIM": "pass", "DMARC": "pass"},
121
+ "urls": [{"url": "https://github.com/settings/tokens", "is_shortened": False, "domain_age_days": 6000, "has_ssl": True, "reputation_score": 1.0}],
122
+ "label": "INBOX",
123
+ "difficulty": 2
124
+ },
125
+
126
+ # LEVEL 3: DIGITAL SEDUCTION (PHISHING / SPEAR PHISHING) (5)
127
+ {
128
+ "sender": "dean.office@manipal-edu.in", # Typo-squatted (.in instead of .edu)
129
+ "subject": "Urgent: Faculty Grievance Report",
130
+ "body": "A report has been filed against your department. Review the grievances here immediately.",
131
+ "raw_headers": "Received: from rogue-vps.xyz (45.33.22.11) by mx.google.com; SPF: fail; DMARC: fail;",
132
+ "auth_results": {"SPF": "fail", "DKIM": "none", "DMARC": "fail"},
133
+ "urls": [{"url": "https://bit.ly/3xYz1-grievance", "is_shortened": True, "domain_age_days": 5, "has_ssl": True, "reputation_score": 0.05}],
134
+ "label": "QUARANTINE",
135
+ "difficulty": 3
136
+ },
137
+ {
138
+ "sender": "it-support@manipal-helpdesk.com", # Look-alike domain
139
+ "subject": "Mandatory Password Reset",
140
+ "body": "As per the new MIT security policy, all students must reset their password today.",
141
+ "raw_headers": "Received: from mail-delivery.online... SPF: pass; DKIM: pass;", # Attacker set up SPF/DKIM correctly!
142
+ "auth_results": {"SPF": "pass", "DKIM": "pass", "DMARC": "none"},
143
+ "urls": [{"url": "http://manipal-helpdesk.com/reset", "is_shortened": False, "domain_age_days": 1, "has_ssl": False, "reputation_score": 0.1}],
144
+ "label": "QUARANTINE",
145
+ "difficulty": 3
146
+ },
147
+ {
148
+ "sender": "prof.sharma@mit-manipal.org", # Wrong TLD
149
+ "subject": "Final Exam Paper Leak?",
150
+ "body": "I suspect the paper has leaked. Look at this screenshot and confirm if these are your questions.",
151
+ "raw_headers": "Received: from sendgrid.net... SPF: pass;",
152
+ "auth_results": {"SPF": "pass", "DKIM": "none", "DMARC": "none"},
153
+ "urls": [{"url": "https://dropbox-files.com/s/xyz", "is_shortened": False, "domain_age_days": 4, "has_ssl": True, "reputation_score": 0.2}],
154
+ "label": "QUARANTINE",
155
+ "difficulty": 3
156
+ },
157
+ {
158
+ "sender": "accounts@google-security.info",
159
+ "subject": "Critical Security Alert",
160
+ "body": "Someone just used your password to try to sign in to your account. Go to your Google account now.",
161
+ "raw_headers": "Received: from host-12.xyz... SPF: fail;",
162
+ "auth_results": {"SPF": "fail", "DKIM": "none", "DMARC": "fail"},
163
+ "urls": [{"url": "https://google-secure-login.info", "is_shortened": False, "domain_age_days": 2, "has_ssl": True, "reputation_score": 0.01}],
164
+ "label": "QUARANTINE",
165
+ "difficulty": 3
166
+ },
167
+ {
168
+ "sender": "library@manipal.edu",
169
+ "subject": "Overdue Book Notice",
170
+ "body": "Your copy of 'Computer Networks' is overdue. Click to pay the fine of ₹50.",
171
+ "raw_headers": "Received: from mail.manipal.edu... SPF: pass; DKIM: pass;",
172
+ "auth_results": {"SPF": "pass", "DKIM": "pass", "DMARC": "pass"},
173
+ "urls": [{"url": "https://portal.manipal.edu/pay", "is_shortened": False, "domain_age_days": 4000, "has_ssl": True, "reputation_score": 1.0}],
174
+ "label": "INBOX",
175
+ "difficulty": 3 # Difficult because it looks like a phishing lure but is legit.
176
  }
177
  ]
178
+ return base_data
179
 
180
  async def reset(self):
181
  self.current_step = 0
182
  return self._get_result()
 
 
 
 
183
 
184
  def _get_result(self, reward=0.0, done=False):
185
  if self.current_step >= len(self.dataset):
186
  obs = MyEnvV4Observation(
187
+ sender="N/A", subject="N/A", body="N/A", raw_headers="",
188
+ hop_count=0, auth_results={}, urls=[], echoed_message="End of Session"
189
  )
190
  return SimpleNamespace(observation=obs, reward=reward, done=True)
191
 
 
194
  sender=data["sender"],
195
  subject=data["subject"],
196
  body=data["body"],
197
+ raw_headers=data["raw_headers"],
198
+ hop_count=data["raw_headers"].count("Received:"),
199
+ auth_results=data["auth_results"],
200
+ urls=[URLInfo(**u) for u in data["urls"]],
201
+ echoed_message=f"Task {self.current_step + 1}/{len(self.dataset)}"
202
  )
203
  return SimpleNamespace(observation=obs, reward=reward, done=done)
204
 
 
206
  if self.current_step >= len(self.dataset):
207
  return self._get_result(done=True)
208
 
209
+ target = self.dataset[self.current_step]
210
+ correct = target["label"]
211
+ prediction = action.message.strip().upper()
212
 
213
+ # SOPHISTICATED REWARD LOGIC
214
+ reward = 0.0
215
 
216
+ if prediction == correct:
217
+ # Perfect Match: reward scales with difficulty
218
+ reward = 1.0 + (target["difficulty"] * 0.1)
219
+ elif correct in ["SPAM", "QUARANTINE"] and prediction in ["SPAM", "QUARANTINE"]:
220
+ # Partial Credit: Recognized threat but misclassified type
221
+ reward = 0.4
222
+ elif correct == "QUARANTINE" and prediction == "INBOX":
223
+ # Dangerous Failure: Penalty for letting a threat into the Inbox
224
+ reward = -1.5
225
+ elif correct == "INBOX" and prediction == "QUARANTINE":
226
+ # False Positive: Penalty for blocking legitimate mail
227
+ reward = -0.5
228
+
229
+ # Add Reasoning Bonus (Explainability)
230
+ if hasattr(action, 'reasoning') and action.reasoning and len(action.reasoning) > 30:
231
+ # Small bonus if agent provides a justification
232
+ reward += 0.05
233
 
234
+ # Normalize reward to [0, 1] range as per OpenEnv specs (clipping/rescaling)
235
+ # However, many environments allow negative for penalties; we clip to [0,1] for final score
236
+ final_reward = max(0.0, min(1.0, reward))
 
237
 
238
+ self.current_step += 1
239
+ done = self.current_step >= len(self.dataset)
240
+
241
+ return self._get_result(reward=final_reward, done=done)
242
 
243
+ async def state(self):
244
+ return {"current_step": self.current_step, "total_tasks": len(self.dataset)}
245
 
246
+ # Global instance for the server
247
  my_env = MyEnvV4Env()
 
 
248
  app = FastAPI()
249
 
250
  @app.get("/reset")
251
  async def reset():
252
+ res = await my_env.reset()
253
+ return {"observation": res.observation, "reward": res.reward, "done": res.done}
254
 
255
  @app.post("/step")
256
  async def step(action: MyEnvV4Action):
257
+ res = await my_env.step(action)
258
+ return {"observation": res.observation, "reward": res.reward, "done": res.done}
259
 
260
  @app.get("/state")
261
  async def state():