SimranShaikh commited on
Commit
220b4a7
·
verified ·
1 Parent(s): 6ffeef4
Files changed (1) hide show
  1. environment/tasks.py +196 -0
environment/tasks.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Task definitions: Easy → Medium → Hard
3
+ Each task has: code snippet, context, ground truth bugs, and grading rubric.
4
+ """
5
+
6
+ TASKS = {
7
+ "easy_syntax": {
8
+ "task_id": "easy_syntax",
9
+ "task_name": "Python Syntax Error Detection",
10
+ "difficulty": "easy",
11
+ "language": "python",
12
+ "max_steps": 5,
13
+ "context": (
14
+ "This Python function is supposed to calculate a discounted price. "
15
+ "It should raise a ValueError if discount exceeds 100%, otherwise "
16
+ "return the price after applying the discount. Find and fix any errors."
17
+ ),
18
+ "code_snippet": """\
19
+ def calculate_discount(price, discount_percent):
20
+ if discount_percent > 100
21
+ raise ValueError("Discount cannot exceed 100%")
22
+ discount = price * (discount_percent / 100)
23
+ return price - discount
24
+
25
+ result = calculate_discount(200, 15)
26
+ print(result)
27
+ """,
28
+ "ground_truth": {
29
+ "issue_type": "syntax_error",
30
+ "bug_line": 2,
31
+ "keywords": ["colon", "syntax", "if statement", "missing :", ":"],
32
+ "fix_keywords": ["if discount_percent > 100:"],
33
+ "description": "Missing colon at end of if statement on line 2",
34
+ },
35
+ },
36
+
37
+ "medium_logic": {
38
+ "task_id": "medium_logic",
39
+ "task_name": "Logic Bug: Off-by-One in Palindrome Check",
40
+ "difficulty": "medium",
41
+ "language": "python",
42
+ "max_steps": 8,
43
+ "context": (
44
+ "This function checks whether a given string is a palindrome "
45
+ "(reads the same forwards and backwards, ignoring spaces and case). "
46
+ "It passes some basic tests but fails on others. Find the logic bug and fix it."
47
+ ),
48
+ "code_snippet": """\
49
+ def is_palindrome(s: str) -> bool:
50
+ s = s.lower().replace(" ", "")
51
+ for i in range(len(s) // 2):
52
+ if s[i] != s[-i]: # Compare from both ends
53
+ return False
54
+ return True
55
+
56
+ # Expected: True for "racecar", "A man a plan a canal Panama"
57
+ # Expected: False for "hello", "world"
58
+ print(is_palindrome("racecar")) # Should be True
59
+ print(is_palindrome("hello")) # Should be False
60
+ print(is_palindrome("A man a plan a canal Panama")) # Should be True
61
+ """,
62
+ "ground_truth": {
63
+ "issue_type": "logic_bug",
64
+ "bug_line": 4,
65
+ "keywords": [
66
+ "off-by-one", "index", "-i", "-(i+1)", "s[-i]",
67
+ "s[0]", "zero", "first character", "always equal"
68
+ ],
69
+ "fix_keywords": ["s[-(i+1)]", "s[-i-1]", "-(i+1)"],
70
+ "description": (
71
+ "s[-i] when i=0 evaluates to s[0] (the first character), "
72
+ "so it always equals s[i] at i=0. Should be s[-(i+1)]."
73
+ ),
74
+ "test_cases": [
75
+ {"input": "racecar", "expected": True},
76
+ {"input": "hello", "expected": False},
77
+ {"input": "amanaplanacanalpanama", "expected": True},
78
+ {"input": "abba", "expected": True},
79
+ {"input": "abc", "expected": False},
80
+ ],
81
+ },
82
+ },
83
+
84
+ "hard_security": {
85
+ "task_id": "hard_security",
86
+ "task_name": "Security Vulnerability: SQL Injection & Path Traversal",
87
+ "difficulty": "hard",
88
+ "language": "python",
89
+ "max_steps": 10,
90
+ "context": (
91
+ "This is a user authentication module for a web application. "
92
+ "It handles login and serves user-uploaded profile documents. "
93
+ "Perform a thorough security review — identify ALL vulnerabilities "
94
+ "and provide a fixed, secure version of the code."
95
+ ),
96
+ "code_snippet": """\
97
+ import sqlite3
98
+ import os
99
+
100
+
101
+ def authenticate_user(username: str, password: str) -> bool:
102
+ \"\"\"Authenticate user against the database.\"\"\"
103
+ conn = sqlite3.connect("users.db")
104
+ cursor = conn.cursor()
105
+ # Build query with user input directly
106
+ query = (
107
+ "SELECT * FROM users WHERE username='"
108
+ + username
109
+ + "' AND password='"
110
+ + password
111
+ + "'"
112
+ )
113
+ cursor.execute(query)
114
+ result = cursor.fetchone()
115
+ conn.close()
116
+ return result is not None
117
+
118
+
119
+ def get_user_document(username: str, filename: str) -> str:
120
+ \"\"\"Return contents of a user's uploaded document.\"\"\"
121
+ base_dir = "/app/user_docs"
122
+ filepath = os.path.join(base_dir, username, filename)
123
+ with open(filepath, "r") as f:
124
+ return f.read()
125
+
126
+
127
+ def hash_password(password: str) -> str:
128
+ \"\"\"Hash password before storage.\"\"\"
129
+ import hashlib
130
+ return hashlib.md5(password.encode()).hexdigest()
131
+ """,
132
+ "ground_truth": {
133
+ "vulnerabilities": [
134
+ {
135
+ "issue_type": "security_vulnerability",
136
+ "name": "SQL Injection",
137
+ "keywords": [
138
+ "sql injection", "injection", "parameterized",
139
+ "prepared statement", "user input", "string concatenation",
140
+ "sanitize", "placeholder", "?"
141
+ ],
142
+ "fix_keywords": [
143
+ "?", "parameterized", "cursor.execute(query, (username",
144
+ "execute(query, "
145
+ ],
146
+ "severity": "critical",
147
+ },
148
+ {
149
+ "issue_type": "security_vulnerability",
150
+ "name": "Path Traversal",
151
+ "keywords": [
152
+ "path traversal", "directory traversal", "../",
153
+ "os.path.abspath", "startswith", "realpath",
154
+ "sanitize", "filename", "escape"
155
+ ],
156
+ "fix_keywords": [
157
+ "abspath", "realpath", "startswith", "normpath"
158
+ ],
159
+ "severity": "high",
160
+ },
161
+ {
162
+ "issue_type": "security_vulnerability",
163
+ "name": "Weak Password Hashing (MD5)",
164
+ "keywords": [
165
+ "md5", "weak", "hash", "bcrypt", "argon2",
166
+ "sha256", "pbkdf2", "salt", "password hashing"
167
+ ],
168
+ "fix_keywords": [
169
+ "bcrypt", "argon2", "pbkdf2", "hashlib.sha256",
170
+ "passlib", "werkzeug"
171
+ ],
172
+ "severity": "high",
173
+ },
174
+ ],
175
+ },
176
+ },
177
+ }
178
+
179
+
180
+ def get_task(task_id: str) -> dict:
181
+ if task_id not in TASKS:
182
+ raise ValueError(f"Unknown task: {task_id}. Available: {list(TASKS.keys())}")
183
+ return TASKS[task_id]
184
+
185
+
186
+ def list_tasks() -> list:
187
+ return [
188
+ {
189
+ "task_id": t["task_id"],
190
+ "task_name": t["task_name"],
191
+ "difficulty": t["difficulty"],
192
+ "language": t["language"],
193
+ "max_steps": t["max_steps"],
194
+ }
195
+ for t in TASKS.values()
196
+ ]