beswarm 0.1.87__py3-none-any.whl → 0.1.88__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.
- beswarm/aient/setup.py +1 -1
- beswarm/aient/src/aient/utils/scripts.py +98 -12
- {beswarm-0.1.87.dist-info → beswarm-0.1.88.dist-info}/METADATA +1 -1
- {beswarm-0.1.87.dist-info → beswarm-0.1.88.dist-info}/RECORD +6 -6
- {beswarm-0.1.87.dist-info → beswarm-0.1.88.dist-info}/WHEEL +0 -0
- {beswarm-0.1.87.dist-info → beswarm-0.1.88.dist-info}/top_level.txt +0 -0
beswarm/aient/setup.py
CHANGED
@@ -4,7 +4,7 @@ from setuptools import setup, find_packages
|
|
4
4
|
|
5
5
|
setup(
|
6
6
|
name="aient",
|
7
|
-
version="1.1.
|
7
|
+
version="1.1.34",
|
8
8
|
description="Aient: The Awakening of Agent.",
|
9
9
|
long_description=Path.open(Path("README.md"), encoding="utf-8").read(),
|
10
10
|
long_description_content_type="text/markdown",
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
import re
|
3
3
|
import json
|
4
|
+
import fnmatch
|
4
5
|
import requests
|
5
6
|
import urllib.parse
|
6
7
|
|
@@ -241,30 +242,65 @@ import subprocess
|
|
241
242
|
readonly_paths_str = os.getenv('SANDBOX_READONLY_PATHS', '')
|
242
243
|
READONLY_PATHS = [p for p in readonly_paths_str.split(os.pathsep) if p]
|
243
244
|
|
245
|
+
# 新增: 从环境变量 'SANDBOX_NO_READ_PATHS' 读取禁止读取的路径列表
|
246
|
+
no_read_paths_str = os.getenv('SANDBOX_NO_READ_PATHS', '')
|
247
|
+
NO_READ_PATHS = [p for p in no_read_paths_str.split(os.pathsep) if p]
|
248
|
+
|
244
249
|
# --- 子进程注入代码 (更智能的版本) ---
|
245
250
|
INJECTION_CODE = """
|
246
251
|
import builtins
|
247
252
|
import os
|
248
253
|
import sys
|
249
254
|
import runpy
|
255
|
+
import fnmatch
|
250
256
|
|
251
257
|
# 1. 从环境变量中获取沙箱规则并设置补丁
|
252
258
|
# 子进程从和父进程完全相同的环境变量中读取配置
|
253
259
|
readonly_paths_str = os.getenv('SANDBOX_READONLY_PATHS', '')
|
254
260
|
readonly_paths = [os.path.abspath(p) for p in readonly_paths_str.split(os.pathsep) if p]
|
261
|
+
no_read_paths_str = os.getenv('SANDBOX_NO_READ_PATHS', '')
|
262
|
+
no_read_paths = [os.path.abspath(p) for p in no_read_paths_str.split(os.pathsep) if p]
|
255
263
|
original_open = builtins.open
|
256
264
|
|
257
265
|
def _is_path_protected(target_path):
|
258
266
|
abs_target_path = os.path.abspath(target_path)
|
259
|
-
for
|
260
|
-
|
261
|
-
|
267
|
+
for protected_pattern in readonly_paths:
|
268
|
+
# 检查是否是 glob 模式
|
269
|
+
is_glob = '*' in protected_pattern or '?' in protected_pattern or '[' in protected_pattern
|
270
|
+
if is_glob:
|
271
|
+
if fnmatch.fnmatch(abs_target_path, protected_pattern):
|
272
|
+
return True
|
273
|
+
else:
|
274
|
+
# 兼容旧的精确/目录匹配
|
275
|
+
if abs_target_path == protected_pattern or abs_target_path.startswith(protected_pattern + os.sep):
|
276
|
+
return True
|
277
|
+
return False
|
278
|
+
|
279
|
+
def _is_path_no_read(target_path):
|
280
|
+
abs_target_path = os.path.abspath(target_path)
|
281
|
+
for no_read_pattern in no_read_paths:
|
282
|
+
# 检查是否是 glob 模式
|
283
|
+
is_glob = '*' in no_read_pattern or '?' in no_read_pattern or '[' in no_read_pattern
|
284
|
+
if is_glob:
|
285
|
+
if fnmatch.fnmatch(abs_target_path, no_read_pattern):
|
286
|
+
return True
|
287
|
+
else:
|
288
|
+
# 兼容旧的精确/目录匹配
|
289
|
+
if abs_target_path == no_read_pattern or abs_target_path.startswith(no_read_pattern + os.sep):
|
290
|
+
return True
|
262
291
|
return False
|
263
292
|
|
264
293
|
def _sandboxed_open(file, mode='r', *args, **kwargs):
|
294
|
+
# 检查写保护
|
265
295
|
is_write_mode = 'w' in mode or 'a' in mode or 'x' in mode or '+' in mode
|
266
296
|
if is_write_mode and _is_path_protected(file):
|
267
|
-
raise PermissionError(f"路径 '{file}'
|
297
|
+
raise PermissionError(f"路径 '{file}' 被禁止写入。")
|
298
|
+
|
299
|
+
# 检查读保护 (默认模式是 'r')
|
300
|
+
is_read_mode = 'r' in mode or '+' in mode
|
301
|
+
if is_read_mode and _is_path_no_read(file):
|
302
|
+
raise PermissionError(f"路径 '{file}' 被禁止读取。")
|
303
|
+
|
268
304
|
return original_open(file, mode, *args, **kwargs)
|
269
305
|
|
270
306
|
builtins.open = _sandboxed_open
|
@@ -316,24 +352,52 @@ else:
|
|
316
352
|
|
317
353
|
class Sandbox:
|
318
354
|
"""一个通过猴子补丁实现文件访问控制的沙箱,支持向子进程注入。"""
|
319
|
-
def __init__(self, readonly_paths):
|
355
|
+
def __init__(self, readonly_paths, no_read_paths):
|
320
356
|
self._readonly_paths = [os.path.abspath(p) for p in readonly_paths]
|
357
|
+
self._no_read_paths = [os.path.abspath(p) for p in no_read_paths]
|
321
358
|
self._original_open = builtins.open
|
322
|
-
self.is_active = bool(self._readonly_paths) #
|
359
|
+
self.is_active = bool(self._readonly_paths or self._no_read_paths) # 如果有任一规则,则沙箱激活
|
323
360
|
|
324
361
|
def _is_path_protected(self, target_path):
|
325
|
-
"""
|
362
|
+
"""检查给定路径是否位于或就是只读路径之一(支持 glob 模式)。"""
|
326
363
|
abs_target_path = os.path.abspath(target_path)
|
327
|
-
for
|
328
|
-
|
329
|
-
|
364
|
+
for protected_pattern in self._readonly_paths:
|
365
|
+
is_glob = '*' in protected_pattern or '?' in protected_pattern or '[' in protected_pattern
|
366
|
+
if is_glob:
|
367
|
+
if fnmatch.fnmatch(abs_target_path, protected_pattern):
|
368
|
+
return True
|
369
|
+
else:
|
370
|
+
# 兼容旧的精确/目录匹配
|
371
|
+
if abs_target_path == protected_pattern or abs_target_path.startswith(protected_pattern + os.sep):
|
372
|
+
return True
|
373
|
+
return False
|
374
|
+
|
375
|
+
def _is_path_no_read(self, target_path):
|
376
|
+
"""检查给定路径是否位于或就是禁止读取的路径之一(支持 glob 模式)。"""
|
377
|
+
abs_target_path = os.path.abspath(target_path)
|
378
|
+
for no_read_pattern in self._no_read_paths:
|
379
|
+
is_glob = '*' in no_read_pattern or '?' in no_read_pattern or '[' in no_read_pattern
|
380
|
+
if is_glob:
|
381
|
+
if fnmatch.fnmatch(abs_target_path, no_read_pattern):
|
382
|
+
return True
|
383
|
+
else:
|
384
|
+
# 兼容旧的精确/目录匹配
|
385
|
+
if abs_target_path == no_read_pattern or abs_target_path.startswith(no_read_pattern + os.sep):
|
386
|
+
return True
|
330
387
|
return False
|
331
388
|
|
332
389
|
def _sandboxed_open(self, file, mode='r', *args, **kwargs):
|
333
390
|
"""我们自己编写的、带安全检查的 open 函数代理"""
|
391
|
+
# 检查写保护
|
334
392
|
is_write_mode = 'w' in mode or 'a' in mode or 'x' in mode or '+' in mode
|
335
393
|
if is_write_mode and self._is_path_protected(file):
|
336
|
-
raise PermissionError(f"路径 '{file}'
|
394
|
+
raise PermissionError(f"路径 '{file}' 被禁止写入。")
|
395
|
+
|
396
|
+
# 检查读保护 (默认模式是 'r')
|
397
|
+
is_read_mode = 'r' in mode or '+' in mode
|
398
|
+
if is_read_mode and self._is_path_no_read(file):
|
399
|
+
raise PermissionError(f"路径 '{file}' 被禁止读取。")
|
400
|
+
|
337
401
|
return self._original_open(file, mode, *args, **kwargs)
|
338
402
|
|
339
403
|
def enable(self):
|
@@ -348,6 +412,10 @@ class Sandbox:
|
|
348
412
|
return
|
349
413
|
builtins.open = self._original_open
|
350
414
|
|
415
|
+
def _update_env_var(self, var_name, path_list):
|
416
|
+
"""辅助函数,用于更新环境变量,确保子进程能继承最新的沙箱规则。"""
|
417
|
+
os.environ[var_name] = os.pathsep.join(path_list)
|
418
|
+
|
351
419
|
def add_readonly_path(self, path: str):
|
352
420
|
"""动态添加一个新的只读路径。如果沙箱因此从非激活状态变为激活状态,则会启用沙箱。"""
|
353
421
|
if not path:
|
@@ -358,6 +426,7 @@ class Sandbox:
|
|
358
426
|
abs_path = os.path.abspath(path)
|
359
427
|
if abs_path not in self._readonly_paths:
|
360
428
|
self._readonly_paths.append(abs_path)
|
429
|
+
self._update_env_var('SANDBOX_READONLY_PATHS', self._readonly_paths)
|
361
430
|
self.is_active = True # 确保沙箱被激活
|
362
431
|
|
363
432
|
# 如果沙箱之前未激活,但现在因为添加了路径而激活了,则启用它
|
@@ -366,6 +435,23 @@ class Sandbox:
|
|
366
435
|
|
367
436
|
return "Success"
|
368
437
|
|
438
|
+
def add_no_read_path(self, path: str):
|
439
|
+
"""动态添加一个新的禁止读取的路径。"""
|
440
|
+
if not path:
|
441
|
+
return "Fail"
|
442
|
+
|
443
|
+
was_active = self.is_active
|
444
|
+
abs_path = os.path.abspath(path)
|
445
|
+
if abs_path not in self._no_read_paths:
|
446
|
+
self._no_read_paths.append(abs_path)
|
447
|
+
self._update_env_var('SANDBOX_NO_READ_PATHS', self._no_read_paths)
|
448
|
+
self.is_active = True
|
449
|
+
|
450
|
+
if not was_active and self.is_active:
|
451
|
+
self.enable()
|
452
|
+
|
453
|
+
return "Success"
|
454
|
+
|
369
455
|
def __enter__(self):
|
370
456
|
"""进入 'with' 块时,应用猴子补丁"""
|
371
457
|
self.enable()
|
@@ -408,7 +494,7 @@ class Sandbox:
|
|
408
494
|
|
409
495
|
# --- 全局沙箱实例 ---
|
410
496
|
# 沙箱现在会自动从环境变量中读取配置
|
411
|
-
sandbox = Sandbox(readonly_paths=READONLY_PATHS)
|
497
|
+
sandbox = Sandbox(readonly_paths=READONLY_PATHS, no_read_paths=NO_READ_PATHS)
|
412
498
|
sandbox.enable() # 在模块加载时全局启用沙箱
|
413
499
|
|
414
500
|
from dataclasses import dataclass
|
@@ -2,7 +2,7 @@ beswarm/__init__.py,sha256=HZjUOJtZR5QhMuDbq-wukQQn1VrBusNWai_ysGo-VVI,20
|
|
2
2
|
beswarm/prompt.py,sha256=1jNxVXjfhb-A8CVHoudRxytV4qDT6FZIIk1NRCCE1Ns,31365
|
3
3
|
beswarm/utils.py,sha256=cOYwuONpNG_dkSYIvdEqQOxRUdIy0Bh9CTYkvKKskdw,2816
|
4
4
|
beswarm/aient/main.py,sha256=SiYAIgQlLJqYusnTVEJOx1WNkSJKMImhgn5aWjfroxg,3814
|
5
|
-
beswarm/aient/setup.py,sha256=
|
5
|
+
beswarm/aient/setup.py,sha256=NJ0hlKbFBw5PK_tZYBvhIIrBUzmgGiAQzJ07Eu3CKdg,487
|
6
6
|
beswarm/aient/src/aient/__init__.py,sha256=SRfF7oDVlOOAi6nGKiJIUK6B_arqYLO9iSMp-2IZZps,21
|
7
7
|
beswarm/aient/src/aient/core/__init__.py,sha256=NxjebTlku35S4Dzr16rdSqSTWUvvwEeACe8KvHJnjPg,34
|
8
8
|
beswarm/aient/src/aient/core/log_config.py,sha256=kz2_yJv1p-o3lUQOwA3qh-LSc3wMHv13iCQclw44W9c,274
|
@@ -39,7 +39,7 @@ beswarm/aient/src/aient/plugins/websearch.py,sha256=FsUxM9GL4AAjmYJ8TS2jSqv4qfCA
|
|
39
39
|
beswarm/aient/src/aient/plugins/write_file.py,sha256=7spYxloI_aUbeANEQK-oXrGPoBqSfsD7sdfMAWlNxhU,3656
|
40
40
|
beswarm/aient/src/aient/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
41
41
|
beswarm/aient/src/aient/utils/prompt.py,sha256=UcSzKkFE4-h_1b6NofI6xgk3GoleqALRKY8VBaXLjmI,11311
|
42
|
-
beswarm/aient/src/aient/utils/scripts.py,sha256=
|
42
|
+
beswarm/aient/src/aient/utils/scripts.py,sha256=FUPnJIMRzXQLW6nGdx4MO72iUEk68PyZBUHg5fNZPmw,40852
|
43
43
|
beswarm/aient/test/chatgpt.py,sha256=Hvl7FuDt1c74N5TVBmhErOPvJbJJzA7FNp5VoZM4u30,4957
|
44
44
|
beswarm/aient/test/claude.py,sha256=IyB4qI1eJLwlSfDNSnt2FhbQWYyBighHUjJxEXc3osQ,1095
|
45
45
|
beswarm/aient/test/test.py,sha256=rldnoLQdtRR8IKFSIzTti7eIK2MpPMoi9gL5qD8_K44,29
|
@@ -129,7 +129,7 @@ beswarm/tools/search_arxiv.py,sha256=GpuIOYX8T0iRC-X-hmuR9AUJVn15WWZq864DaoC7BUc
|
|
129
129
|
beswarm/tools/search_web.py,sha256=B24amOnGHnmdV_6S8bw8O2PdhZRRIDtJjg-wXcfP7dQ,11859
|
130
130
|
beswarm/tools/think.py,sha256=WLw-7jNIsnS6n8MMSYUin_f-BGLENFmnKM2LISEp0co,1760
|
131
131
|
beswarm/tools/worker.py,sha256=VOulEZBEc5nF2RBR9aLYs0vT7WBD-r2mlWH5ueEo4hM,16007
|
132
|
-
beswarm-0.1.
|
133
|
-
beswarm-0.1.
|
134
|
-
beswarm-0.1.
|
135
|
-
beswarm-0.1.
|
132
|
+
beswarm-0.1.88.dist-info/METADATA,sha256=qzPOL8McdAQ-iL748wzyb0xaq_-38645_1PwZ9pQiik,3553
|
133
|
+
beswarm-0.1.88.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
134
|
+
beswarm-0.1.88.dist-info/top_level.txt,sha256=pJw4O87wvt5882smuSO6DfByJz7FJ8SxxT8h9fHCmpo,8
|
135
|
+
beswarm-0.1.88.dist-info/RECORD,,
|
File without changes
|
File without changes
|