ndurner commited on
Commit
e7bbb2c
·
1 Parent(s): 0c39b50

extend code eval

Browse files
Files changed (2) hide show
  1. app.py +9 -4
  2. code_exec.py +137 -4
app.py CHANGED
@@ -46,14 +46,19 @@ def bot(message, history, aws_access, aws_secret, aws_token, system_prompt, temp
46
  "tools": [{
47
  "toolSpec": {
48
  "name": "eval_python",
49
- "description": "Evaluate RestrictedPython script",
 
 
 
50
  "inputSchema": {
51
  "json": {
52
  "type": "object",
53
  "properties": {
54
  "script": {
55
  "type": "string",
56
- "description": "The Python script that will run in a RestrictedPython context"
 
 
57
  }
58
  },
59
  "required": ["script"]
@@ -111,13 +116,13 @@ def bot(message, history, aws_access, aws_secret, aws_token, system_prompt, temp
111
  {
112
  "toolResult": {
113
  "toolUseId": tool['toolUseId'],
114
- "content": [{"json": tool_result}]
115
  }
116
  }
117
  ]
118
  }
119
 
120
- whole_response += f"\n``` result\n{tool_result}\n```\n"
121
  yield whole_response
122
  except Exception as e:
123
  tool_result_message = {
 
46
  "tools": [{
47
  "toolSpec": {
48
  "name": "eval_python",
49
+ "description": "Evaluate a simple script written in a conservative, restricted subset of Python."
50
+ "Note: Augmented assignments, in-place operations (e.g., +=, -=), lambdas (e.g. list comprehensions) are not supported. "
51
+ "Use regular assignments and operations instead. Only 'import math' is allowed. "
52
+ "Returns: unquoted results without HTML encoding.",
53
  "inputSchema": {
54
  "json": {
55
  "type": "object",
56
  "properties": {
57
  "script": {
58
  "type": "string",
59
+ "description": "The Python script that will run in a RestrictedPython context. "
60
+ "Avoid using augmented assignments or in-place operations (+=, -=, etc.), as well as lambdas (e.g. list comprehensions). "
61
+ "Use regular assignments and operations instead. Only 'import math' is allowed."
62
  }
63
  },
64
  "required": ["script"]
 
116
  {
117
  "toolResult": {
118
  "toolUseId": tool['toolUseId'],
119
+ "content": [{"json": tool_result }]
120
  }
121
  }
122
  ]
123
  }
124
 
125
+ whole_response += f"\n``` result\n{tool_result if not tool_result['success'] else tool_result['prints']}\n```\n"
126
  yield whole_response
127
  except Exception as e:
128
  tool_result_message = {
code_exec.py CHANGED
@@ -1,8 +1,10 @@
1
  from RestrictedPython import compile_restricted
2
  from RestrictedPython.PrintCollector import PrintCollector
3
  from RestrictedPython.Guards import safe_globals, safe_builtins, guarded_iter_unpack_sequence
4
- from RestrictedPython.Eval import default_guarded_getiter
5
  from RestrictedPython.Utilities import utility_builtins
 
 
6
  from io import StringIO
7
 
8
  def eval_restricted_script(script):
@@ -39,8 +41,13 @@ def eval_restricted_script(script):
39
  # Print handling
40
  '_print_': CustomPrintCollector,
41
  '_getattr_': getattr,
 
42
  '_getiter_': default_guarded_getiter,
43
  '_iter_unpack_sequence_': guarded_iter_unpack_sequence,
 
 
 
 
44
 
45
  # Define allowed imports
46
  '__allowed_modules__': ['math'],
@@ -48,7 +55,7 @@ def eval_restricted_script(script):
48
 
49
  # Basic functions
50
  'len': len,
51
- 'range': range,
52
  'enumerate': enumerate,
53
  'zip': zip,
54
 
@@ -65,8 +72,8 @@ def eval_restricted_script(script):
65
  'float': float,
66
  'str': str,
67
  'bool': bool,
68
- 'list': list,
69
- 'tuple': tuple,
70
  'set': set,
71
  'dict': dict,
72
  'bytes': bytes,
@@ -107,3 +114,129 @@ def eval_restricted_script(script):
107
  'error': str(e),
108
  'success': False
109
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from RestrictedPython import compile_restricted
2
  from RestrictedPython.PrintCollector import PrintCollector
3
  from RestrictedPython.Guards import safe_globals, safe_builtins, guarded_iter_unpack_sequence
4
+ from RestrictedPython.Eval import default_guarded_getiter, default_guarded_getitem
5
  from RestrictedPython.Utilities import utility_builtins
6
+ from RestrictedPython.Guards import guarded_unpack_sequence
7
+ from RestrictedPython.Limits import limited_range, limited_list, limited_tuple
8
  from io import StringIO
9
 
10
  def eval_restricted_script(script):
 
41
  # Print handling
42
  '_print_': CustomPrintCollector,
43
  '_getattr_': getattr,
44
+ '_getitem_': default_guarded_getitem,
45
  '_getiter_': default_guarded_getiter,
46
  '_iter_unpack_sequence_': guarded_iter_unpack_sequence,
47
+ '_unpack_sequence_': guarded_unpack_sequence,
48
+ '_inplacevar_': protected_inplacevar,
49
+ '_apply_': _apply,
50
+ '_write_': _default_write_,
51
 
52
  # Define allowed imports
53
  '__allowed_modules__': ['math'],
 
55
 
56
  # Basic functions
57
  'len': len,
58
+ 'range': limited_range,
59
  'enumerate': enumerate,
60
  'zip': zip,
61
 
 
72
  'float': float,
73
  'str': str,
74
  'bool': bool,
75
+ 'list': limited_list,
76
+ 'tuple': limited_tuple,
77
  'set': set,
78
  'dict': dict,
79
  'bytes': bytes,
 
114
  'error': str(e),
115
  'success': False
116
  }
117
+
118
+ def _default_write_(obj):
119
+ if isinstance(obj, types.ModuleType):
120
+ raise ValueError("Modules are not allowed in to be written to.")
121
+
122
+ return obj
123
+
124
+ """
125
+ Borrowed implementation of _inplacevar_ from the Zope Foundations's AccessControl module
126
+ https://github.com/zopefoundation/AccessControl/blob/f9ae58816f0712eb6ea97459b4ccafbf4662d9db/src/AccessControl/ZopeGuards.py#L530
127
+ """
128
+
129
+ valid_inplace_types = (list, set)
130
+
131
+
132
+ inplace_slots = {
133
+ '+=': '__iadd__',
134
+ '-=': '__isub__',
135
+ '*=': '__imul__',
136
+ '/=': (1 / 2 == 0) and '__idiv__' or '__itruediv__',
137
+ '//=': '__ifloordiv__',
138
+ '%=': '__imod__',
139
+ '**=': '__ipow__',
140
+ '<<=': '__ilshift__',
141
+ '>>=': '__irshift__',
142
+ '&=': '__iand__',
143
+ '^=': '__ixor__',
144
+ '|=': '__ior__',
145
+ }
146
+
147
+
148
+ def __iadd__(x, y):
149
+ x += y
150
+ return x
151
+
152
+
153
+ def __isub__(x, y):
154
+ x -= y
155
+ return x
156
+
157
+
158
+ def __imul__(x, y):
159
+ x *= y
160
+ return x
161
+
162
+
163
+ def __idiv__(x, y):
164
+ x /= y
165
+ return x
166
+
167
+
168
+ def __ifloordiv__(x, y):
169
+ x //= y
170
+ return x
171
+
172
+
173
+ def __imod__(x, y):
174
+ x %= y
175
+ return x
176
+
177
+
178
+ def __ipow__(x, y):
179
+ x **= y
180
+ return x
181
+
182
+
183
+ def __ilshift__(x, y):
184
+ x <<= y
185
+ return x
186
+
187
+
188
+ def __irshift__(x, y):
189
+ x >>= y
190
+ return x
191
+
192
+
193
+ def __iand__(x, y):
194
+ x &= y
195
+ return x
196
+
197
+
198
+ def __ixor__(x, y):
199
+ x ^= y
200
+ return x
201
+
202
+
203
+ def __ior__(x, y):
204
+ x |= y
205
+ return x
206
+
207
+
208
+ inplace_ops = {
209
+ '+=': __iadd__,
210
+ '-=': __isub__,
211
+ '*=': __imul__,
212
+ '/=': __idiv__,
213
+ '//=': __ifloordiv__,
214
+ '%=': __imod__,
215
+ '**=': __ipow__,
216
+ '<<=': __ilshift__,
217
+ '>>=': __irshift__,
218
+ '&=': __iand__,
219
+ '^=': __ixor__,
220
+ '|=': __ior__,
221
+ }
222
+
223
+
224
+ def protected_inplacevar(op, var, expr):
225
+ """Do an inplace operation
226
+
227
+ If the var has an inplace slot, then disallow the operation
228
+ unless the var an instance of ``valid_inplace_types``.
229
+ """
230
+ if hasattr(var, inplace_slots[op]) and \
231
+ not isinstance(var, valid_inplace_types):
232
+ try:
233
+ cls = var.__class__
234
+ except AttributeError:
235
+ cls = type(var)
236
+ raise TypeError(
237
+ "Augmented assignment to %s objects is not allowed"
238
+ " in untrusted code" % cls.__name__)
239
+ return inplace_ops[op](var, expr)
240
+
241
+ def _apply(f, *a, **kw):
242
+ return f(*a, **kw)