✨ feat: Sandbox Runtime——isolated 插件子进程隔离执行(WP-06/07 收口)
- 迁移 17:plugin_execution(五态、退出码、时长、stdout 摘要、错误留痕) - 沙箱执行器:独立子进程(代码经 stdin JSON 安全传输,不进命令行)、CPU rlimit + RLIMIT_AS(平台不支持时尽力而为并注明)、墙钟超时强杀、输出限额;runner 仅暴露 input/output 作用域 - 执行端点:isolated_process 形态、已安装且启用后可执行;**未启用沙箱一律 503 fail-closed**(HUNJING_SANDBOX_ENABLED 显式开启,审计记录拒绝原因)——AGENTS 第 6 节"无符合策略的 Sandbox 时拒绝执行"落地 - 每次执行落 plugin_execution + 审计(状态/时长);进程级隔离的边界如实注明(网络/文件系统最小化在 Linux 容器档交付) - 测试 96 项全绿(+2):echo 真实执行回填、死循环 5s 超时强杀、异常 failed 含 stderr、无沙箱 503
This commit is contained in:
1 parent
21eacc8c75
commit
99a7789432
8 files changed
+389
No files matched your search
@@ -144,3 +144,27 @@ async def invoke(
|
||||
db, domain.id, name, body.get("input", {}), body.get("run_id"),
|
||||
getattr(request.state, "trace_id", None),
|
||||
)
|
||||
|
||||
|
||||
@inst_router.post("/{installation_id}/executions", status_code=201)
|
||||
async def execute_plugin(
|
||||
installation_id: str,
|
||||
db: DbSession,
|
||||
user: Annotated[User, Depends(require_state_change)],
|
||||
request: Request,
|
||||
body: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
"""沙箱执行 isolated 插件:未启用沙箱一律 503(fail-closed)。"""
|
||||
domain = await _domain_of(db, user)
|
||||
from app.core.config import get_settings
|
||||
|
||||
execution, result = await service.execute_isolated(
|
||||
db, domain.id, installation_id, body.get("input", {}),
|
||||
sandbox_enabled=get_settings().sandbox_enabled,
|
||||
trace_id=getattr(request.state, "trace_id", None),
|
||||
)
|
||||
return {
|
||||
"execution_id": execution.id, "status": result["status"],
|
||||
"duration_ms": result.get("duration_ms"),
|
||||
"output": result.get("output"), "error": result.get("error"),
|
||||
}
|
||||
Reference in new issue
Block a user