@cogitator-ai/ sandbox (英语)
安全地执行沙盒 科吉塔特特工。 在孤立的多克容器,WASM模块,操作系统的自有沙盒(MacOS上的Seatbelt,Linux上的bigwrap)或本土倒置后加上资源限制,网络隔离,和超时执行,并在多克容器或E2B,代托纳或Vercel Sandbox上的云沙盒中给代理商一个工作空间.
安装
pnpm add @cogitator-ai/sandbox
# Optional peer dependencies
pnpm add dockerode # For Docker sandbox
pnpm add @extism/extism # For WASM sandbox
pnpm add e2b # For E2BWorkspace (2.28.1 or later)
pnpm add @daytona/sdk # For DaytonaWorkspace
pnpm add @vercel/sandbox # For VercelSandboxWorkspace
快速启动
import { SandboxManager } from '@cogitator-ai/sandbox';
const manager = new SandboxManager();
await manager.initialize();
const result = await manager.execute(
{ command: ['python', '-c', 'print("Hello!")'] },
{ type: 'docker', image: 'python:3.11-alpine' }
);
if (result.success) {
console.log(result.data.stdout); // "Hello!"
} else {
console.error(result.error);
}
execute() 返回 a SandboxResult数字 : { success: true, data } 或者说 { success: false, error }。退出非零的命令仍然成功;检查 data.exitCode。 。 。 .
特征
- 嵌入沙盒 - 集装箱完全隔离,能力下降
- 原子弹沙盒 - 以极端主义为动力的Web大会执行
- OS 沙盒 - Seatbelt (macOS) 或 bigwrap (Linux) 下的本地命令: 只在工作空间中写, 到处读, 但你否认什么, 网络只能通过一个代理来检查每个主机, 即
sandboxclaude 代码的设置 - 原生倒计时 - 无法使用 Docker 工具时可选主机执行(
allowNativeFallback(中文(简体) ) - 集装箱池 - 每一次处决都要有一个新的、预先启动的容器
- 嵌入工作空间 - 每个代理工作空间有一个长寿命容器,安装项目,在主机上保管文件
- 远程工作空间 - E2B、Daytona或Vercel沙盒中整个工作空间,每个供应商都有相同的行为
- 守护进程发现 - 发现多克像
dockerCLI: 爱丽丝DOCKER_HOST,上下文,多克桌面, OrbStack, Colima, Rancher, 无根 - 资源限制 - 内存、CPU、PID限制
- 网络隔离 - 默认禁用
- 超时执行 - 杀出逃进程
- 安保强化 - 没有特权升级,所有能力下降
沙盒管理器
这个 SandboxManager 管好执行后端和每个请求的路径 type 名称.
import { SandboxManager } from '@cogitator-ai/sandbox';
const manager = new SandboxManager({
allowNativeFallback: false,
pool: {
maxSize: 10,
idleTimeoutMs: 120_000,
},
defaults: {
timeout: 30_000,
resources: {
memory: '256MB',
cpus: 1,
},
network: { mode: 'none' },
},
});
await manager.initialize();
const result = await manager.execute(
{
command: ['node', '-e', 'console.log(2+2)'],
timeout: 5000,
env: { NODE_ENV: 'production' },
cwd: '/workspace',
},
{
type: 'docker',
image: 'node:20-alpine',
}
);
if (result.success) {
console.log('Output:', result.data.stdout);
console.log('Exit code:', result.data.exitCode);
console.log('Duration:', result.data.duration, 'ms');
}
倒置和初始化
initialize() (a) 具有同等能力并能安全地同时打电话; execute() 自动调用.
经理退后一次:a docker 当 Docker 不可用时, 请通过本地执行器在主机上运行, 并且 无隔离,第一个这样的调用记录会发出警告. allowNativeFallback: false 拒绝这些请求 { success: false, error } 相反,它默认 true管理者 defaults 也适用于倒计时执行。 A 类 wasm 请求永不后退:没有 @extism/extism 失败 WASM sandbox unavailable: install @extism/extism to run WASM tools。一个 os 要求永远不要退缩 无论是什么 allowNativeFallback 说:在没有操作系统沙盒的机器上,它因原因失败(除非它的政策设定) failIfUnavailable: false,参见 OS 沙盒) (中文(简体) ).
找到 Docker 守护进程
与 docker.socketPath 或者说 docker.host (+ 数) port执行者在那里连接。 否则,它试图,按顺序,第一个答案是:
DOCKER_HOST当设置( 手交给多克罗德, 没有别的尝试)- 当前 Docker 语境的终点(
DOCKER_CONTEXT,则currentContext内$DOCKER_CONFIG/config.json默认值~/.docker(中文(简体) ) - 存在于
/var/run/docker.sock, (中文(简体) ),~/.docker/run/docker.sock(鼠标桌面),~/.orbstack/run/docker.sock(OrbStack), (英语:OrbStack),~/.colima/default/docker.sock财务报告和审定财务报表~/.colima/docker.sock(科利马),~/.rd/docker.sock(朗彻桌面)和$XDG_RUNTIME_DIR/docker.sock(无根多克) - Dockerode 的默认值, 当不存在上述任何一种时
可用性检查
const dockerAvailable = await manager.isDockerAvailable();
const wasmAvailable = await manager.isWasmAvailable();
const osAvailable = await manager.isOsAvailable();
console.log('Docker:', dockerAvailable);
console.log('WASM:', wasmAvailable);
关闭
await manager.shutdown();
Docker 执行器
集装箱完全隔离 安全性强化.
import { DockerSandboxExecutor } from '@cogitator-ai/sandbox';
const docker = new DockerSandboxExecutor({
docker: {
socketPath: '/var/run/docker.sock',
},
pool: {
maxSize: 5,
idleTimeoutMs: 60_000,
},
});
const connectResult = await docker.connect();
if (!connectResult.success) {
console.error('Docker not available:', connectResult.error);
}
const result = await docker.execute(
{
command: ['python', '-c', 'print("Hello!")'],
stdin: 'input data',
timeout: 10_000,
cwd: '/app',
env: { MY_VAR: 'value' },
},
{
type: 'docker',
image: 'python:3.11-alpine',
timeout: 30_000,
resources: {
memory: '512MB',
cpus: 2,
pidsLimit: 50,
},
network: {
mode: 'none',
},
mounts: [{ source: '/tmp/data', target: '/data', readOnly: true }],
env: { GLOBAL_VAR: 'value' },
workdir: '/workspace',
user: 'nobody',
}
);
await docker.disconnect();
安全特性
此主机配置创建了嵌入容器 :
| 设置 | 数值 |
|---|---|
NetworkMode | network.mode默认值 'none' (无网络) |
CapDrop | ['ALL'] (每个能力下降) |
SecurityOpt | ['no-new-privileges'] |
PidsLimit | resources.pidsLimit默认值 100 |
| 根 FS 系统 | 可写( 非可画) |
| 工作目录 | /workspace |
| 标签 | ai.cogitator.sandbox=true |
command以 argv 数组执行( 无 shell); 使用['sh', '-c', '...']用于外壳语法.- 输出由帧分解框架(分出网络块的帧被重新组装)并封顶为每流50000字节.
- 每一次处决都有一个容器,以前没有放过任何东西(见 集装箱池);超时容器总是被销毁.
network.dns适用于新集装箱.network.allowedHosts被拒绝, 因为 Docker 无法强制执行 Egress 允许列表 —— 使用mode: 'none'或专用网络.- 集装箱贴上标签
ai.cogitator.sandbox=true(单位:千美元)SANDBOX_CONTAINER_LABEL),因此,崩溃过程的剩余部分可以通过docker rm -f $(docker ps -aq --filter label=ai.cogitator.sandbox)。 。 。 .
集装箱池
集装箱在处决前开始。 默认一个已放行的容器被销毁,而一个设置相同的新容器在其位置上启动,所以下一个执行会得到一个温暖的容器,在运行或用户之间不会结转任何内容.
import { ContainerPool } from '@cogitator-ai/sandbox';
const pool = new ContainerPool(dockerClient, {
maxSize: 10,
idleTimeoutMs: 60_000,
});
const container = await pool.acquire('python:3.11-alpine', {
memory: 256 * 1024 * 1024,
cpus: 1,
networkMode: 'none',
mounts: [],
});
await pool.release(container);
await pool.destroyAll();
一个容器只服务于设置相同的请求(图像,资源,网络模式,DNS,挂载和用户),因此一个使用主机挂载或网络访问所创建的容器从未被交给请求隔离的请求. release(container, { corrupted: true }) 总是破坏容器. destroyAll() 移除每个容器并关闭游泳池。 闲置-清理计时器不能使节点.js进程保持活性.
集合选项
| 选项 | 类型 | 默认 | 说明 |
|---|---|---|---|
maxSize | number | 5 | 最大闲置和变暖容器;除此之外没有备用装置 |
idleTimeoutMs | number | 60000 | 销毁闲置容器的时间 |
reuseContainers | boolean | false | 将放行的容器按原样运回池中:速度更快,但留下的枪弹在下一个枪弹上可以看见,从任何运行或用户那里 |
传出与 pool 改为 SandboxManager, (中文(简体) ), DockerSandboxExecutor 或者说 new Cogitator({ sandbox: { pool } })。 。 。 .
嵌入工作空间
DockerWorkspace 是一个 工作空间 命令在一个长寿命容器中运行: start()),在命令之间保留,删除 dispose()。主机工作空间的根(a) LocalWorkspace 从 @cogitator-ai/core装入 /workspace,通过主机工作空间及其路径守护(下面的路径)读取并写入文件 /workspace 被映射为根, remove 财务报告和审定财务报表 rename 在没有连结连接到主机的容器中运行,命令运行 docker exec 在匹配目录中。 一个快照会还原容器里的东西 然后主机会写出改变的东西 然后被拒绝 BUSY 当命令运行在容器或主机上时.
import { Agent, LocalWorkspace, workspaceTools } from '@cogitator-ai/core';
import { DockerWorkspace } from '@cogitator-ai/sandbox';
const workspace = new DockerWorkspace({
host: new LocalWorkspace({ root: './project' }),
image: 'node:24-alpine',
resources: { memory: '4GB', cpus: 4 },
});
try {
const agent = new Agent({
name: 'coder',
instructions: '...',
tools: workspaceTools(),
workspace,
});
await cog.run(agent, { input: 'Run the tests and fix what fails' });
} finally {
await workspace.dispose();
}
容器有Docker执行器的安全默认值,即输入程序,限制为2GB、2 CPU和512进程,除非 resources 设置其它, 除非 network.mode 允许它,并在Linux上运行命令作为您的 uid 和 gid 。 每个命令领导自己的进程组: 超时或中止信号组( SIGTERM, 然后是 SIGKILLL) killGrace页:1 env -i 包括各种流程,容器继续运行。 一个要求 setsid 离开组直到 dispose()。图像需要 sh。开始去除该机器已消失的过程所留下的同根容器。 没有多克,第一个命令失败 WorkspaceError 代码 UNAVAILABLE,多克 API 失败作为代码 IO。 。 。 . dispose() 还处理主机工作空间.
远程工作空间
E2BWorkspace, (中文(简体) ), DaytonaWorkspace 财务报告和审定财务报表 VercelSandboxWorkspace 为: 工作空间 其文件和命令活在一个云沙盒中:在第一次使用时创建(或由id或name重用),在 dispose()。每个用户都需要其供应商的SDK、可选的同伴依赖关系以及证书:
| 工作空间 | 软件包 | 全权证书 | 默认根 |
|---|---|---|---|
E2BWorkspace | e2b | E2B_API_KEY | /home/user |
DaytonaWorkspace | @daytona/sdk | DAYTONA_API_KEY (单位:千美元)DAYTONA_API_URL, (中文(简体) ), DAYTONA_TARGET(中文(简体) ) | /home/daytona |
VercelSandboxWorkspace | @vercel/sandbox | Vercel的OIDC标志,或 VERCEL_TOKEN, (中文(简体) ), VERCEL_TEAM_ID, (中文(简体) ), VERCEL_PROJECT_ID | /vercel/sandbox |
import { Agent, workspaceTools } from '@cogitator-ai/core';
import { E2BWorkspace } from '@cogitator-ai/sandbox';
const workspace = new E2BWorkspace({ root: 'project', lifetime: 30 * 60_000 });
try {
const agent = new Agent({
name: 'coder',
instructions: '...',
tools: workspaceTools(),
workspace,
});
await cog.run(agent, { input: 'Clone the repo and make its tests pass' });
} finally {
await workspace.dispose();
}
三个都是 RemoteShellWorkspace 超过一个小驱动程序(创建或连接,读取并写入字节,运行一个程序,发布),其他一切作为沙盒中的 shell 脚本运行,所以行为相同:
- 路径在根上正常化,并在沙盒中解决
realpath -m,从根部取出一个连结 拒绝与OUTSIDE_ROOT - 将沙盒的临时目录上传到新文件,一步一步地移动到文件上,保持其模式,在沙盒的临时目录中读取私人副本,从不写出根,
maxFileBytes双盖 list, (中文(简体) ),remove(把垃圾放进去).cogitator/trash和rename跟着LocalWorkspace规则和拒绝BUSY当命令运行或保存背景进程时- 运行在下面的命令
setsid在他们自己的流程组中,有不可原谅的标记行(指使符出现在 stdin上):超时返回124并杀死该组,background: 'keep'离开背景进程直到dispose() snapshot(), (中文(简体) ),restore(), (中文(简体) ),listSnapshots()财务报告和审定财务报表deleteSnapshot()将焦油档案保存在.cogitator/snapshots在沙盒内,.cogitator, (中文(简体) ),node_modules财务报告和审定财务报表.git总是被排除在外, 文件结束maxFileBytes(10个小米B)跳出并列出于skipped,不保留UTF-8名称,以及maxSnapshotBytes(1 GiB) 拒绝更大的一个TOO_LARGE。 。 。 .restore(id, { dryRun })保存在快照大小限制上保存排除条目和文件的目录,并报告内容restored, (中文(简体) ),deleted财务报告和审定财务报表kept,与本地工作空间相同的API 备案检查站- 最多读取一个字节
maxFileBytes在下载之前, 列表会被排序, 切到limit缩入glob在沙盒中,还有一个打印超过maxStreamBytes(64 MiB)被停止,因为SDKs将全部输出保存在内存中 - E2B和Vercel沙盒得到一个
lifetime(30分)工作空间在使用时向后推
onDispose 选择什么 dispose() 与沙盒连接 : destroy (对被创造者), stop (Daytona和Vercel,文件存续)或 keep (由 id 或 name 给出的默认, stop 一个叫Vercel的沙盒。 图像需要 sh, GNU creautils, findutils 和 tar, 以及 util- linux setsid,如同提供者的默认图像 start() 名称 缺少。 没有SDK或证书 第一次操作失败 WorkspaceError 代码 UNAVAILABLE。 。 。 . e2b 需要2.28.1或以后,从2.59起,它需要22.19节点或以后。 启动自己的届会的过程(setsid)逃出群杀并活到沙盒去. DaytonaWorkspace 通过 env 在一个私人目录的短命文件中,因此代托纳对命令行的记录从没有持有过这些值.
通过执行来带来另一个提供者 RemoteShellDriver 并传递给 new RemoteShellWorkspace({ driver })。 。 。 . shellQuote 财务报告和审定财务报表 shellCommand 从argv上建立安全壳线.
WASM 执行器
通过Extism执行WebAssembly模块. 每个插件在自己的工人线程中运行,因此超时终止了运行的模块而不是阻挡事件循环. 每个模块 / WASI / 允许主机组合(最多 cacheSize);同时执行时使用单独的插件例.
import { WasmSandboxExecutor } from '@cogitator-ai/sandbox';
const wasm = new WasmSandboxExecutor({
wasm: {
cacheSize: 10,
wasi: true,
},
});
await wasm.connect();
const result = await wasm.execute(
{
command: ['process'],
stdin: JSON.stringify({ data: 'input' }),
},
{
type: 'wasm',
wasmModule: 'https://example.com/plugin.wasm',
wasmFunction: 'run',
wasi: true,
timeout: 5000,
}
);
await wasm.disconnect();
wasmModule需要一个http(s)URL, 文件路径或软件包路径 :- 绝对路径或起始路径
.相对于工作目录读取 - 其它文件首先作为相对于工作目录的文件进行尝试,然后像您应用程序的导入那样解决(例如)
@cogitator-ai/wasm-tools/wasm/calc.wasm:从工作目录,然后从条目脚本目录,然后从@cogitator-ai/sandbox(涵盖NODE_PATH和升起的装置。 这与 pnpm 的严格布局配合, 沙盒包无法看到您的依赖性 . - 当模块载运一个导出路径帮助软件包时,例如
getWasmPath()从@cogitator-ai/wasm-tools,通过绝对路径来完全跳过分辨率.
- 绝对路径或起始路径
wasmModule, (中文(简体) ),functionName财务报告和审定财务报表wasi当请求配置省略时,则使用执行器选项.network.allowedHosts已转发到 Extism 的 HTTP 允许列表( 当空时)network.mode实值'none') (中文(简体) ).memoryPages(default 256 = 16 MB) 封装了模块自己的内存:它的内存部分在模块加载前获得最大值,所以memory.grow通过它失败在模块内,需要更多启动的模块被拒绝。 Extism对插件输入,输出和 vars 的内存获得相同的限制. 执行者从 URL 中获取模块, 因此上限也适用于它们 .
OS 沙盒
OsSandbox 在操作系统的沙盒内运行本地命令,其中有克洛德密码的沙盒巴什工具的语义:Seatbelt(sandbox-exec 在macOS, 气泡包装(bwrap在Linux上。 Linux 也需要 socat数字 : apt-get install bubblewrap socat给一个 LocalWorkspace 联 合 国 @cogitator-ai/core,并且每个工作空间运行的命令(run_command经历它:
import { LocalWorkspace, loadSandboxPolicy, workspaceTools } from '@cogitator-ai/core';
import { OsSandbox } from '@cogitator-ai/sandbox';
const { policy } = await loadSandboxPolicy('./project'); // the `sandbox` section of .claude/settings.json
const sandbox = new OsSandbox({ policy });
const workspace = new LocalWorkspace({ root: './project', exec: { sandbox } });
await workspace.start(); // fails with SANDBOX_UNAVAILABLE when the sandbox cannot run here
一个沙盒命令能达到什么:
| 访问 | 默认 | 换一个 |
|---|---|---|
| 写作 | 仅此命令的工作空间根和一个临时目录(TMPDIR(中文(简体) ) | filesystem.allowWrite, (中文(简体) ), filesystem.denyWrite |
| 读取 | 任何地方, 证书文件, 如 ~/.ssh 包含 | filesystem.denyRead, (中文(简体) ), filesystem.allowRead, (中文(简体) ), credentials.files |
| 网络 | 除沙盒的代理外, 没有路由, 在列出主机之前, 不允许任何内容 | network.allowedDomains, (中文(简体) ), network.deniedDomains, (中文(简体) ), onUnknownHost |
| 信封 | 工作空间通过什么( 默认没有 API 密钥) | credentials.envVars |
- 文件系统. 较窄的规则获胜:
allowRead更宽denyRead重新打开该部分, adenyRead更宽allowRead仍然坚守。 一个allowRead仅通过符号链接到达被否定区域时被忽略,文件denyRead或者说credentials.files带有另一个硬链接的名字无法发射,因为其所列名字被拒绝。 写否定总是胜过许可 道路是绝对的,~/对于主目录,或相对于工作空间根.*, (中文(简体) ),?, (中文(简体) ),**财务报告和审定财务报表[...]在 macOS 的每个列表和 Linux 的读取列表中工作,一个后缀/**到处都是. - 防护道. 即使在可写入目录中,命令也不能写入克劳德代码和Cogitator的设置、钩子、技能、代理、命令和插件(在根和上方的所有目录中,以及
~/.claude, (中文(简体) ),~/.cogitator, (中文(简体) ),~/.claude.json),整个.cogitator根的目录(它的垃圾和快照),.mcp.json,贝壳启动文件,.gitconfig, (中文(简体) ),.gitmodules, (中文(简体) ),.vscode, (中文(简体) ),.idea,该寄存器的 git 目录中运行或遵循的文件(hooks, (中文(简体) ),config, (中文(简体) ),commondir, (中文(简体) ),config.worktree,是连接工作树的主要寄存处,也是连接工作树和子模块的主要寄存处,根的.git条目本身( 无命令替换为gitdir:内部仍然写着它自己的文件)HEAD在根部,所以没有命令将根变成一个赤裸的寄存器, 它的配置会从沙盒外读取。 被保护路径的同义链接也保护了目标,一个有多个硬链接的被保护文件会使发射失败. 仅filesystem.disabled把他们抬起来, 剩下的文件系统隔离. - 腾讯网. 命令获得
HTTP_PROXY, (中文(简体) ),HTTPS_PROXY财务报告和审定财务报表ALL_PROXY(SOCKS5)指向一个只服务于这个命令的代理. 一个主机deniedDomains名字被拒绝,一个allowedDomains名称通过( n)github.com只有那个宿主,*.npmjs.org它的子域,*每个主机, IPv4 和括号内的 IPv6 地址, 每个地址都有可选:port),任何其他主机则由调用决定onUnknownHost(一跑电传到它的许可作为一个WebFetch(domain:...)电话,否则沙盒是自己的onUnknownHost,其他拒绝.strictAllowlist拒绝未知主机而不询问 。 仅决定回回回,链接-局部,云元数据端点或此机地址的宿主名被拒绝,localhost列表地址本身(127.0.0.1:3000)以名称到达本地服务器。 UDP, QUIC 和 ICMP 不离开, 忽略代理变量的工具( plan)ssh,大多数数据库驱动程序)无法连接. - 每个命令主机.
exec(command, { allowedDomains })(和run_command是因为allowedDomains) 单独打开命令的主机,当它运行时,它不列出的主机则被拒绝而不询问.deniedDomains仍然赢,一个strictAllowlist政策拒绝这样的呼吁. - 违反规定. 代理拒绝什么,文件访问系统拒绝(
Operation not permitted, (中文(简体) ),Read-only file system页:1result.sandbox.violations,还有消毒<sandbox_violations>块附在其 stderr上,所以模型会看到它为什么失败.ignoreViolations压制预期的({ "*": ["/etc/hosts"] }) (中文(简体) ). 网络违规来自代理,文件违规是咨询(从命令本身的错误读取,它控制),a<sandbox_violations>标记命令指纹本身已失效. - Linux 筑巢. 命令在一秒钟内运行
bwrap在第一个,与--disable-userns(bulble wrap 0.8.0及后)和一分接滤波器(x86 64,arm64)拒绝新建命名空间,挂载,io uring和Unix套接字,包含数据gram套接字对(任何)allowUnixSockets条目或allowAllUnixSockets打开全部,过滤器无法将路径区分开来),所以它无法从它自己的命名空间中取消只读绑定 。 seccomp过滤器是需要的,作为避免命令出现在路径名Unix sockets上的唯一东西:没有它,沙盒是没有的,除非allowAllUnixSockets设置, 当--disable-userns一个人可以. - 取出沙盒外来.
excludedCommands(内容:Bash(...)规则,例如:docker *当线条的每个命令都匹配而线条没有方向调整时, 运行未保存框,cd从变量中替换或程序.dangerouslyDisableSandbox只有在政策设定时才打开allowUnsandboxed(违约不实,否则被忽略). 都经过正常的许可流,结果说sandboxed: false与缘由. - 无所取取.
failIfUnavailable(默认为真)拒绝开始,带有SANDBOX_UNAVAILABLE命名出错: 无sandbox-exec,没有bwrap或者说socat,用户名空间被屏蔽(一个容器,Ubuntu的AppArmor限制). 与false命令以警告方式解开框,每个结果都这么说(unsandboxedReason: 'unavailable') (中文(简体) ). 没有任何沉默的后退. - 权限. 内部运行的命令跳过它需要的批准( )
autoAllow,默认为真 ):run_command自己和一个赤裸裸的Bash问规则。 拒绝规则,要求规则有规律(Bash(git push *), (中文(简体) ),rm财务报告和审定财务报表rmdir以一条关键的道路盟誓,~, (中文(简体) ),/, (中文(简体) ),.git)和计划模式仍然适用,并使用VAR=x玡,eval, (中文(简体) ),make X=y, (中文(简体) ),source, (中文(简体) ),alias, (中文(简体) ),export, (中文(简体) ),set -a或 shell reading stdin通过正常的流出,以及命令给自己的主机取名. 仅run_command联 合 国workspaceTools()在沙盒工作空间运行是自动分配的,绝不是核心exec工具.
OsSandbox.probe() 说沙盒是否在这里运行, OsSandbox.create(options) 返回已启动的, dispose() 关闭仍在运行的命令的代理并删除其目录。 这个 os 类型 SandboxManager 在它下运行一个执行程序({ type: 'os', workdir, os: policy },工作目录其可写根),总是与 failIfUnavailable: true。 。 。 .
不覆盖,说实话: 外壳 rm 删除为好( 垃圾为 delete_file 工具的,见 @cogitator-ai/core),处理在背景中运行的命令叶会丢失网络及其 TMPDIR 一旦它退出(并在Linux上随它停止),文件被从命令的错误中读取,而不是从系统日志中读取,Linux在命令启动时否认路径通配符(一个后来制作的文件没有覆盖),Linux保护一个连接目录后面的路径,链接引出,而不是在链接中,在根下方的git寄存器保留了它们的钩子可写,没有检查TLS,所以一个允许的域携带任何到它的东西.
原生执行器
直接执行而不隔离(倒回模式).
import { NativeSandboxExecutor } from '@cogitator-ai/sandbox';
const native = new NativeSandboxExecutor();
await native.connect();
const result = await native.execute(
{
command: ['ls', '-la'],
cwd: '/tmp',
env: { LC_ALL: 'C' },
timeout: 5000,
},
{ type: 'native' }
);
if (result.success) console.log(result.data.stdout);
警告: 本地处决没有孤立。 仅在无法使用 Docker 时使用 .
- 单元素命令( A)
['ls -la | wc -l'])运行于系统 shell;较长的命令直接以精确的 argv(无 shell)执行,就像 Docker. stdin已连接到进程.- 仅
PATH, (中文(简体) ),HOME,临时目录、语言和Windows系统变量从主机环境继承; 机密process.env没有传递到执行代码。 明确通过env。 。 。 . - 超时时, 整个进程组都会被杀死(
SIGKILL)并立即以退出代码返回结果124。 。 。 . - 输出上限为每流有5万字节,而过程仍然被排出.
执行请求
interface SandboxExecutionRequest {
command: string[];
stdin?: string;
timeout?: number;
cwd?: string;
env?: Record<string, string>;
signal?: AbortSignal;
}
取消执行
中止 signal 立即停止执行:原生执行器杀死进程组,多克执行器结束执行并取出其容器(一个中止的容器永远不会被再利用),而WASM执行器关闭了插件,它结束它的工人. 结果是无法命名原因,并且已经中止的信号不会运行。 所以取消一个运行会停止它的沙箱工具.
const controller = new AbortController();
setTimeout(() => controller.abort(new Error('user cancelled')), 1000);
const result = await manager.execute(
{ command: ['sleep', '30'], signal: controller.signal },
{ type: 'docker', image: 'alpine:3.19' }
);
// { success: false, error: 'Execution aborted: user cancelled' }
执行结果
interface SandboxExecutionResult {
stdout: string;
stderr: string;
exitCode: number;
timedOut: boolean;
duration: number;
truncated?: boolean;
}
资源限制
内存
const result = await manager.execute(request, {
type: 'docker',
image: 'alpine',
resources: {
memory: '256MB',
},
});
支持的格式 : '256B', (中文(简体) ), '256KB', (中文(简体) ), '256MB', (中文(简体) ), '1GB', (中文(简体) ), '1TB'鼠标样式 '512m' 编号 : '2g' 二进制 '1GiB' (所有二进制倍数,大小写不敏感). 0或负内存和CPU限制被拒绝,而不是默默地运行无限.
CPU 软件
SandboxConfig 以类型导出( e)import type { SandboxConfig } from '@cogitator-ai/sandbox') (中文(简体) ).
const config: SandboxConfig = {
type: 'docker',
image: 'alpine',
resources: {
cpus: 0.5,
cpuShares: 512,
},
};
进程限制
const config: SandboxConfig = {
type: 'docker',
image: 'alpine',
resources: {
pidsLimit: 50,
},
};
网络配置
const config: SandboxConfig = {
type: 'docker',
image: 'alpine',
network: {
mode: 'none',
},
};
网络模式 :
'none'- 没有网络访问(默认,最安全)'bridge'- 多克桥网'host'- 主机网络(不推荐)
音量山数
将主机目录挂入容器 :
const config: SandboxConfig = {
type: 'docker',
image: 'alpine',
mounts: [
{ source: '/host/data', target: '/data', readOnly: true },
{ source: '/host/output', target: '/output', readOnly: false },
],
};
工具函数
解析内存
import { parseMemory } from '@cogitator-ai/sandbox';
parseMemory('256MB');
parseMemory('1GB');
parseMemory('512KB');
CPU 到 NanoCPUs
import { cpusToNanoCpus } from '@cogitator-ai/sandbox';
cpusToNanoCpus(0.5);
cpusToNanoCpus(2);
类型参考
import type {
SandboxType,
SandboxConfig,
SandboxResourceLimits,
SandboxNetworkConfig,
SandboxMount,
SandboxExecutionRequest,
SandboxExecutionResult,
SandboxManagerConfig,
SandboxPoolConfig,
SandboxDockerConfig,
SandboxResult,
OsSandboxPolicy,
OsSandboxKind,
OsSandboxAvailability,
SandboxViolation,
SandboxHostRequest,
SandboxHostDecider,
} from '@cogitator-ai/sandbox';
与 Cogitator 合并
在代理中使用沙盒工具 :
import { Cogitator, tool } from '@cogitator-ai/core';
import { z } from 'zod';
const shellTool = tool({
name: 'run_shell',
description: 'Execute shell commands safely',
parameters: z.object({
command: z.string(),
}),
sandbox: {
type: 'docker',
image: 'ubuntu:22.04',
resources: { memory: '256MB' },
network: { mode: 'none' },
},
timeout: 30000,
execute: async ({ command }) => command,
});
const cog = new Cogitator({
sandbox: {
pool: { maxSize: 5 },
allowNativeFallback: false,
},
});
运行时间开始 a SandboxManager 从 new Cogitator({ sandbox }) 第一个沙箱工具呼叫。 对于一个Docker工具,它不叫 execute: 沙盒运行工具的 command 参数 sh -c (可选) cwd 编号 : env 参数)和输出成为工具结果. 一个WASM工具得到了它的论据,因为JSON在stdin上,它的JSON stdout是结果. 当 Docker 不可用时—— 或此软件包丢失或启动失败—— 一个 Docker 工具运行 execute 在主机上卸下一个警告,除非 sandbox.allowNativeFallback: false 将调用变成工具错误。 一个 WASM 工具在 Extism 缺失时失败, 并运行它自己的 execute 仅当此软件包丢失或启动失败时。 见 沙盒 在网站上.
实例
运行 Python 代码
const result = await manager.execute(
{
command: [
'python',
'-c',
`
import json
data = {"sum": 2 + 2}
print(json.dumps(data))
`,
],
},
{
type: 'docker',
image: 'python:3.11-alpine',
timeout: 10_000,
}
);
if (result.success) {
const output = JSON.parse(result.data.stdout);
console.log(output.sum);
}
运行节点.js代码
const result = await manager.execute(
{
command: ['node', '-e', 'console.log(JSON.stringify({result: 42}))'],
},
{
type: 'docker',
image: 'node:20-alpine',
resources: { memory: '128MB' },
}
);
运行 shell 命令
const result = await manager.execute(
{
command: ['sh', '-c', 'ls -la /workspace && pwd'],
cwd: '/workspace',
},
{
type: 'docker',
image: 'alpine:3.19',
}
);
处理超时
const result = await manager.execute(
{ command: ['sleep', '60'] },
{ type: 'docker', image: 'alpine', timeout: 5000 }
);
if (result.success && result.data.timedOut) {
console.log('Command timed out');
}
检查退出代码
const result = await manager.execute(
{ command: ['sh', '-c', 'exit 42'] },
{ type: 'docker', image: 'alpine' }
);
if (result.success) console.log('Exit code:', result.data.exitCode);
许可证
麻省理工学院