fleet-python 0.2.66b2__py3-none-any.whl → 0.2.105__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. examples/export_tasks.py +16 -5
  2. examples/export_tasks_filtered.py +245 -0
  3. examples/fetch_tasks.py +230 -0
  4. examples/import_tasks.py +140 -8
  5. examples/iterate_verifiers.py +725 -0
  6. fleet/__init__.py +128 -5
  7. fleet/_async/__init__.py +27 -3
  8. fleet/_async/base.py +24 -9
  9. fleet/_async/client.py +938 -41
  10. fleet/_async/env/client.py +60 -3
  11. fleet/_async/instance/client.py +52 -7
  12. fleet/_async/models.py +15 -0
  13. fleet/_async/resources/api.py +200 -0
  14. fleet/_async/resources/sqlite.py +1801 -46
  15. fleet/_async/tasks.py +122 -25
  16. fleet/_async/verifiers/bundler.py +22 -21
  17. fleet/_async/verifiers/verifier.py +25 -19
  18. fleet/agent/__init__.py +32 -0
  19. fleet/agent/gemini_cua/Dockerfile +45 -0
  20. fleet/agent/gemini_cua/__init__.py +10 -0
  21. fleet/agent/gemini_cua/agent.py +759 -0
  22. fleet/agent/gemini_cua/mcp/main.py +108 -0
  23. fleet/agent/gemini_cua/mcp_server/__init__.py +5 -0
  24. fleet/agent/gemini_cua/mcp_server/main.py +105 -0
  25. fleet/agent/gemini_cua/mcp_server/tools.py +178 -0
  26. fleet/agent/gemini_cua/requirements.txt +5 -0
  27. fleet/agent/gemini_cua/start.sh +30 -0
  28. fleet/agent/orchestrator.py +854 -0
  29. fleet/agent/types.py +49 -0
  30. fleet/agent/utils.py +34 -0
  31. fleet/base.py +34 -9
  32. fleet/cli.py +1061 -0
  33. fleet/client.py +1060 -48
  34. fleet/config.py +1 -1
  35. fleet/env/__init__.py +16 -0
  36. fleet/env/client.py +60 -3
  37. fleet/eval/__init__.py +15 -0
  38. fleet/eval/uploader.py +231 -0
  39. fleet/exceptions.py +8 -0
  40. fleet/instance/client.py +53 -8
  41. fleet/instance/models.py +1 -0
  42. fleet/models.py +303 -0
  43. fleet/proxy/__init__.py +25 -0
  44. fleet/proxy/proxy.py +453 -0
  45. fleet/proxy/whitelist.py +244 -0
  46. fleet/resources/api.py +200 -0
  47. fleet/resources/sqlite.py +1845 -46
  48. fleet/tasks.py +113 -20
  49. fleet/utils/__init__.py +7 -0
  50. fleet/utils/http_logging.py +178 -0
  51. fleet/utils/logging.py +13 -0
  52. fleet/utils/playwright.py +440 -0
  53. fleet/verifiers/bundler.py +22 -21
  54. fleet/verifiers/db.py +985 -1
  55. fleet/verifiers/decorator.py +1 -1
  56. fleet/verifiers/verifier.py +25 -19
  57. {fleet_python-0.2.66b2.dist-info → fleet_python-0.2.105.dist-info}/METADATA +28 -1
  58. fleet_python-0.2.105.dist-info/RECORD +115 -0
  59. {fleet_python-0.2.66b2.dist-info → fleet_python-0.2.105.dist-info}/WHEEL +1 -1
  60. fleet_python-0.2.105.dist-info/entry_points.txt +2 -0
  61. tests/test_app_method.py +85 -0
  62. tests/test_expect_exactly.py +4148 -0
  63. tests/test_expect_only.py +2593 -0
  64. tests/test_instance_dispatch.py +607 -0
  65. tests/test_sqlite_resource_dual_mode.py +263 -0
  66. tests/test_sqlite_shared_memory_behavior.py +117 -0
  67. fleet_python-0.2.66b2.dist-info/RECORD +0 -81
  68. tests/test_verifier_security.py +0 -427
  69. {fleet_python-0.2.66b2.dist-info → fleet_python-0.2.105.dist-info}/licenses/LICENSE +0 -0
  70. {fleet_python-0.2.66b2.dist-info → fleet_python-0.2.105.dist-info}/top_level.txt +0 -0
@@ -1,427 +0,0 @@
1
- """Security tests for verifier_from_string function.
2
-
3
- Tests that the verifier parsing and validation properly blocks
4
- arbitrary code execution during import.
5
- """
6
-
7
- import pytest
8
- from fleet.tasks import verifier_from_string as sync_verifier_from_string
9
- from fleet._async.tasks import verifier_from_string as async_verifier_from_string
10
-
11
-
12
- class TestSyncVerifierSecurity:
13
- """Security tests for sync version of verifier_from_string."""
14
-
15
- def test_blocks_module_level_subprocess_run(self):
16
- """Test that module-level subprocess.run() is blocked."""
17
- code = """
18
- import subprocess
19
- subprocess.run(['echo', 'malicious'])
20
-
21
- def my_verifier(env):
22
- return 1.0
23
- """
24
- with pytest.raises(ValueError, match="Expression statements that are not constants"):
25
- sync_verifier_from_string(
26
- verifier_func=code,
27
- verifier_id="test-verifier",
28
- verifier_key="test-key",
29
- sha256="test-sha",
30
- )
31
-
32
- def test_blocks_module_level_open(self):
33
- """Test that module-level open() is blocked."""
34
- code = """
35
- open('/etc/passwd', 'r')
36
-
37
- def my_verifier(env):
38
- return 1.0
39
- """
40
- with pytest.raises(ValueError, match="Expression statements that are not constants"):
41
- sync_verifier_from_string(
42
- verifier_func=code,
43
- verifier_id="test-verifier",
44
- verifier_key="test-key",
45
- sha256="test-sha",
46
- )
47
-
48
- def test_blocks_assignment_with_subprocess_call(self):
49
- """Test that variable assignment with subprocess call is blocked."""
50
- code = """
51
- import subprocess
52
- result = subprocess.run(['echo', 'malicious'])
53
-
54
- def my_verifier(env):
55
- return 1.0
56
- """
57
- with pytest.raises(ValueError, match="Variable assignments with function calls"):
58
- sync_verifier_from_string(
59
- verifier_func=code,
60
- verifier_id="test-verifier",
61
- verifier_key="test-key",
62
- sha256="test-sha",
63
- )
64
-
65
- def test_blocks_assignment_with_open_call(self):
66
- """Test that variable assignment with open() is blocked."""
67
- code = """
68
- file_handle = open('/etc/passwd', 'r')
69
-
70
- def my_verifier(env):
71
- return 1.0
72
- """
73
- with pytest.raises(ValueError, match="Variable assignments with function calls"):
74
- sync_verifier_from_string(
75
- verifier_func=code,
76
- verifier_id="test-verifier",
77
- verifier_key="test-key",
78
- sha256="test-sha",
79
- )
80
-
81
- def test_blocks_assignment_with_any_function_call(self):
82
- """Test that variable assignment with any function call is blocked."""
83
- code = """
84
- import os
85
- path = os.getcwd()
86
-
87
- def my_verifier(env):
88
- return 1.0
89
- """
90
- with pytest.raises(ValueError, match="Variable assignments with function calls"):
91
- sync_verifier_from_string(
92
- verifier_func=code,
93
- verifier_id="test-verifier",
94
- verifier_key="test-key",
95
- sha256="test-sha",
96
- )
97
-
98
- def test_allows_constant_assignment(self):
99
- """Test that constant variable assignments are allowed."""
100
- code = """
101
- CONSTANT_VALUE = 42
102
- ANOTHER_CONSTANT = "test"
103
- PI = 3.14159
104
-
105
- def my_verifier(env):
106
- return CONSTANT_VALUE
107
- """
108
- # Should not raise
109
- verifier = sync_verifier_from_string(
110
- verifier_func=code,
111
- verifier_id="test-verifier",
112
- verifier_key="test-key",
113
- sha256="test-sha",
114
- )
115
- assert verifier is not None
116
-
117
- def test_allows_list_dict_constant_assignment(self):
118
- """Test that list/dict constant assignments are allowed."""
119
- code = """
120
- MY_LIST = [1, 2, 3]
121
- MY_DICT = {"key": "value"}
122
- MY_TUPLE = (1, 2, 3)
123
-
124
- def my_verifier(env):
125
- return 1.0
126
- """
127
- # Should not raise
128
- verifier = sync_verifier_from_string(
129
- verifier_func=code,
130
- verifier_id="test-verifier",
131
- verifier_key="test-key",
132
- sha256="test-sha",
133
- )
134
- assert verifier is not None
135
-
136
- def test_allows_valid_imports(self):
137
- """Test that imports are allowed."""
138
- code = """
139
- import json
140
- import os
141
- from typing import Dict
142
-
143
- def my_verifier(env):
144
- return 1.0
145
- """
146
- # Should not raise
147
- verifier = sync_verifier_from_string(
148
- verifier_func=code,
149
- verifier_id="test-verifier",
150
- verifier_key="test-key",
151
- sha256="test-sha",
152
- )
153
- assert verifier is not None
154
-
155
- def test_allows_class_definitions(self):
156
- """Test that class definitions are allowed."""
157
- code = """
158
- class MyHelper:
159
- def __init__(self):
160
- self.value = 42
161
-
162
- def get_value(self):
163
- return self.value
164
-
165
- def my_verifier(env):
166
- helper = MyHelper()
167
- return helper.get_value()
168
- """
169
- # Should not raise
170
- verifier = sync_verifier_from_string(
171
- verifier_func=code,
172
- verifier_id="test-verifier",
173
- verifier_key="test-key",
174
- sha256="test-sha",
175
- )
176
- assert verifier is not None
177
-
178
- def test_allows_multiple_functions(self):
179
- """Test that multiple function definitions are allowed."""
180
- code = """
181
- def helper_function(x):
182
- return x * 2
183
-
184
- def my_verifier(env):
185
- return helper_function(0.5)
186
- """
187
- # Should not raise
188
- verifier = sync_verifier_from_string(
189
- verifier_func=code,
190
- verifier_id="test-verifier",
191
- verifier_key="test-key",
192
- sha256="test-sha",
193
- )
194
- assert verifier is not None
195
-
196
- def test_extracts_first_function_name(self):
197
- """Test that the first function name is correctly extracted."""
198
- code = """
199
- def first_function(env):
200
- return 1.0
201
-
202
- def second_function(env):
203
- return 0.5
204
- """
205
- verifier = sync_verifier_from_string(
206
- verifier_func=code,
207
- verifier_id="test-verifier",
208
- verifier_key="test-key",
209
- sha256="test-sha",
210
- )
211
- # The first function should be used
212
- assert verifier.func.__name__ == "first_function"
213
-
214
- def test_error_message_includes_line_number(self):
215
- """Test that error messages include helpful line numbers."""
216
- code = """
217
- import subprocess
218
-
219
- subprocess.run(['echo', 'test'])
220
-
221
- def my_verifier(env):
222
- return 1.0
223
- """
224
- with pytest.raises(ValueError, match=r"Line \d+"):
225
- sync_verifier_from_string(
226
- verifier_func=code,
227
- verifier_id="test-verifier",
228
- verifier_key="test-key",
229
- sha256="test-sha",
230
- )
231
-
232
- def test_blocks_nested_function_call_in_list(self):
233
- """Test that function calls nested in list assignments are blocked."""
234
- code = """
235
- import os
236
- MY_LIST = [1, 2, os.getcwd()]
237
-
238
- def my_verifier(env):
239
- return 1.0
240
- """
241
- with pytest.raises(ValueError, match="Variable assignments with function calls"):
242
- sync_verifier_from_string(
243
- verifier_func=code,
244
- verifier_id="test-verifier",
245
- verifier_key="test-key",
246
- sha256="test-sha",
247
- )
248
-
249
- def test_blocks_nested_function_call_in_dict(self):
250
- """Test that function calls nested in dict assignments are blocked."""
251
- code = """
252
- import os
253
- MY_DICT = {"cwd": os.getcwd()}
254
-
255
- def my_verifier(env):
256
- return 1.0
257
- """
258
- with pytest.raises(ValueError, match="Variable assignments with function calls"):
259
- sync_verifier_from_string(
260
- verifier_func=code,
261
- verifier_id="test-verifier",
262
- verifier_key="test-key",
263
- sha256="test-sha",
264
- )
265
-
266
- def test_allows_docstrings(self):
267
- """Test that module-level docstrings are allowed."""
268
- code = '''
269
- """This is a module docstring."""
270
-
271
- def my_verifier(env):
272
- """This is a function docstring."""
273
- return 1.0
274
- '''
275
- # Should not raise
276
- verifier = sync_verifier_from_string(
277
- verifier_func=code,
278
- verifier_id="test-verifier",
279
- verifier_key="test-key",
280
- sha256="test-sha",
281
- )
282
- assert verifier is not None
283
-
284
- def test_function_with_decorator_extracts_correct_name(self):
285
- """Test that decorators don't affect function name extraction."""
286
- code = """
287
- def some_decorator(func):
288
- return func
289
-
290
- @some_decorator
291
- def my_actual_function(env):
292
- return 1.0
293
- """
294
- verifier = sync_verifier_from_string(
295
- verifier_func=code,
296
- verifier_id="test-verifier",
297
- verifier_key="test-key",
298
- sha256="test-sha",
299
- )
300
- # Should extract 'some_decorator' (first function) or 'my_actual_function'
301
- # depending on order, but NOT the decorator name itself
302
- assert verifier.func.__name__ in ["some_decorator", "my_actual_function"]
303
-
304
- def test_blocks_decorator_with_function_call(self):
305
- """Test that decorators with function calls are blocked."""
306
- code = """
307
- import subprocess
308
-
309
- @subprocess.run(['echo', 'bad'])
310
- def my_verifier(env):
311
- return 1.0
312
- """
313
- # Decorators execute during import, so calls in decorators are dangerous
314
- with pytest.raises(ValueError, match="Function decorators with function calls"):
315
- sync_verifier_from_string(
316
- verifier_func=code,
317
- verifier_id="test-verifier",
318
- verifier_key="test-key",
319
- sha256="test-sha",
320
- )
321
-
322
- def test_allows_simple_decorator_reference(self):
323
- """Test that simple decorator references (no calls) are allowed."""
324
- code = """
325
- def my_decorator(func):
326
- return func
327
-
328
- @my_decorator
329
- def my_verifier(env):
330
- return 1.0
331
- """
332
- # Simple decorator reference (no call) should be allowed
333
- verifier = sync_verifier_from_string(
334
- verifier_func=code,
335
- verifier_id="test-verifier",
336
- verifier_key="test-key",
337
- sha256="test-sha",
338
- )
339
- assert verifier is not None
340
-
341
-
342
- class TestAsyncVerifierSecurity:
343
- """Security tests for async version of verifier_from_string."""
344
-
345
- def test_blocks_module_level_subprocess_run(self):
346
- """Test that module-level subprocess.run() is blocked."""
347
- code = """
348
- import subprocess
349
- subprocess.run(['echo', 'malicious'])
350
-
351
- async def my_async_verifier(env):
352
- return 1.0
353
- """
354
- with pytest.raises(ValueError, match="Expression statements that are not constants"):
355
- async_verifier_from_string(
356
- verifier_func=code,
357
- verifier_id="test-verifier",
358
- verifier_key="test-key",
359
- sha256="test-sha",
360
- )
361
-
362
- def test_blocks_assignment_with_function_call(self):
363
- """Test that variable assignment with function call is blocked."""
364
- code = """
365
- import subprocess
366
- result = subprocess.run(['echo', 'malicious'])
367
-
368
- async def my_async_verifier(env):
369
- return 1.0
370
- """
371
- with pytest.raises(ValueError, match="Variable assignments with function calls"):
372
- async_verifier_from_string(
373
- verifier_func=code,
374
- verifier_id="test-verifier",
375
- verifier_key="test-key",
376
- sha256="test-sha",
377
- )
378
-
379
- def test_allows_constant_assignment(self):
380
- """Test that constant variable assignments are allowed."""
381
- code = """
382
- CONSTANT_VALUE = 42
383
-
384
- async def my_async_verifier(env):
385
- return CONSTANT_VALUE
386
- """
387
- # Should not raise
388
- verifier = async_verifier_from_string(
389
- verifier_func=code,
390
- verifier_id="test-verifier",
391
- verifier_key="test-key",
392
- sha256="test-sha",
393
- )
394
- assert verifier is not None
395
-
396
- def test_allows_async_function_definitions(self):
397
- """Test that async function definitions are recognized."""
398
- code = """
399
- async def my_async_verifier(env):
400
- return 1.0
401
- """
402
- # Should not raise
403
- verifier = async_verifier_from_string(
404
- verifier_func=code,
405
- verifier_id="test-verifier",
406
- verifier_key="test-key",
407
- sha256="test-sha",
408
- )
409
- assert verifier is not None
410
-
411
- def test_extracts_first_async_function_name(self):
412
- """Test that the first async function name is correctly extracted."""
413
- code = """
414
- async def first_async_function(env):
415
- return 1.0
416
-
417
- async def second_async_function(env):
418
- return 0.5
419
- """
420
- verifier = async_verifier_from_string(
421
- verifier_func=code,
422
- verifier_id="test-verifier",
423
- verifier_key="test-key",
424
- sha256="test-sha",
425
- )
426
- # The first function should be used
427
- assert verifier.func.__name__ == "first_async_function"