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 CHANGED
@@ -4,7 +4,7 @@ from setuptools import setup, find_packages
4
4
 
5
5
  setup(
6
6
  name="aient",
7
- version="1.1.33",
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 readonly_path in readonly_paths:
260
- if abs_target_path == readonly_path or abs_target_path.startswith(readonly_path + os.sep):
261
- return True
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 readonly_path in self._readonly_paths:
328
- if abs_target_path == readonly_path or abs_target_path.startswith(readonly_path + os.sep):
329
- return True
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: beswarm
3
- Version: 0.1.87
3
+ Version: 0.1.88
4
4
  Summary: MAS
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -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=NkFRjOyvZkKzSLI_JMU1fJkQzf7gLfSPGt7nj-JDnpg,487
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=8NJCASleffBsA20E3K7HvChCH6rb-7-Qa_ygXXpEsCE,37051
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.87.dist-info/METADATA,sha256=CML-RDiBOUvDdvhSn8ITmQevVj4kUkSIB6rroWnThSU,3553
133
- beswarm-0.1.87.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
134
- beswarm-0.1.87.dist-info/top_level.txt,sha256=pJw4O87wvt5882smuSO6DfByJz7FJ8SxxT8h9fHCmpo,8
135
- beswarm-0.1.87.dist-info/RECORD,,
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,,