Skip to content

V2 Kit 仍受支持,也没有被废弃。claude 和 codex 这样的内置智能体名对应 v3 Kit,无法使用 v2 Mixin。本页介绍 v2 Kit 的用法和规范。对于新的 Kit,Docker 推荐使用 v3。V1 也仍受支持。

使用已有的 Kit ​

一个 v2 Kit 包含 spec.yaml(其中 schemaVersion: "2")和可选的 files/ 目录树。沙箱 Kit 定义智能体环境,Mixin 则往其中添加工具或配置。把沙箱 Kit 放在智能体名的位置,再用 --kit 添加 Mixin:

console
$ sbx run ./my-agent --name my-project --kit ./team-config

sbx run 会把你当前的目录作为工作区。追加一个项目路径即可使用其他目录。要创建但不启动智能体,请使用 sbx create;加入一个工作区路径或 . 来挂载目录。引用可以是本地目录、ZIP 文件、OCI 制品或 Git URL。相对路径以 ./ 或 ../ 开头。对于 Docker Hub 上的 Kit,你可以省略 docker.io/,直接写 <NAMESPACE>/<KIT>:<TAG>。在 Git URL 中,ref 选择某个修订版本,dir 选择 Kit 目录。含 & 的 URL 要加引号:

console
$ sbx run "git+https://github.com/<ORG>/<REPOSITORY>.git#ref=<COMMIT>&dir=my-agent"

git+ssh:// URL 可以配合你本地的 SSH agent 和 Git 凭据使用。 对于私有镜像仓库,请参阅 镜像仓库凭据。

用 --kit 选择 Kit 在创建时生效。要改变沙箱的 Kit 集合,需要重新创建沙箱,只有 sbx kit add支持的有限更新除外。该命令会重启沙箱,同时保留软件包、镜像、卷和智能体历史。无法从运行中的沙箱里移除 Kit。

限制 Kit 来源 ​

来源策略请参阅限制 Kit 来源。kit.allowLocalKits 同样管辖 v2 的 ZIP 文件。

内置智能体的镜像覆盖 ​

用 --template 可以替换内置智能体的镜像,同时保留它的配置和启动命令。替换的镜像必须支持同一个智能体。例如,与 claude 一起使用的镜像必须装有 Claude Code。

要定义带有自己启动命令和沙箱设置的环境,请参阅 v3 流程中的 构建智能体工作负载。

选择模板 ​

Docker 以 docker/sandbox-templates:<variant> 发布智能体镜像。选择与你的智能体匹配的变体。可用的变体请参阅 基础镜像。

带 -docker 后缀的变体,例如 claude-code-docker,包含 Docker Engine,可以在沙箱内构建和运行容器。 不指定自定义模板时,内置智能体默认使用这些变体。

如果你不需要在沙箱内使用 Docker,请选择不带该后缀的变体。它占用更少资源,也不需要特权模式:

console
$ sbx run claude --template docker.io/docker/sandbox-templates:claude-code

--template 的镜像引用中要包含镜像仓库域名。与 Kit 引用不同,模板引用不会自动补上 docker.io。

构建自定义模板 ​

构建自定义模板需要 Docker Desktop。

在 Docker 提供的镜像基础上扩展你要运行的智能体。例如,这个 Dockerfile 给 Claude Code 镜像加上 Rust 和 protocol buffer 工具:

dockerfile
FROM docker/sandbox-templates:claude-code
USER root
RUN apt-get update && apt-get install -y protobuf-compiler
USER agent
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y

以 root 安装系统包,然后切换回 agent,再在智能体主目录中安装工具。

构建镜像并推送到镜像仓库。把 <NAMESPACE> 换成你可以推送的 Docker Hub 命名空间:

console
$ docker build -t docker.io/<NAMESPACE>/my-template:v1 --push .

镜像仓库凭据和加载本地构建的镜像,请参阅 加载模板。

用你的镜像运行沙箱:

console
$ sbx run claude --template docker.io/<NAMESPACE>/my-template:v1

由于该镜像扩展自 claude-code,请与 claude 一起使用。基于 codex 的镜像则配 codex,基于 shell 的镜像配 shell,即可在不启动智能体的情况下打开 Bash。

如果你添加的工具需要网络访问,请在沙箱的网络策略中放行它们使用的域名,除非你使用 allow-all 策略:

console
$ sbx policy allow network "*.example.com:443,example.com:443"

Kit 的种类 ​

kind: mixin ​

Mixin 把能力叠加到已有沙箱上。它不能声明 sandbox: 块、extends: 或 mixins:。Mixin 可以声明 requires:,以锁定它所针对的基础智能体:

yaml
schemaVersion: "2"
kind: mixin
name: github-tools
requires:
  agent: claude

requires.agent 接受一个基础智能体名。它会按 Kit 名进行校验,并在组合时强制执行。

kind: sandbox ​

沙箱 Kit 定义一个完整的智能体。根沙箱必须声明 sandbox: 块。使用 extends: 的沙箱可以继承父镜像,并省略自己的 sandbox: 块:

yaml
schemaVersion: "2"
kind: sandbox
name: claude-safe
extends: claude

extends: 只能用于沙箱。父项必须解析为沙箱 Kit。mixins: 同样只能用于沙箱,解析器接受它,但运行时的组合支持仍在开发中。

顶层字段 ​

规范性的语法请参阅 v2 规范。

字段必填说明
schemaVersion是规范 schema 版本。本语法使用 "2"。
kind是扩展智能体的 Kit 用 mixin;定义智能体的 Kit 用 sandbox。
name是唯一标识符。小写字母、数字和连字符,长度 1 到 64 个字符。
version否Kit 版本。
displayName否便于阅读的名称。
description否简短描述。
sourceURL否源码仓库或文档 URL。
licenses否SPDX 许可证标识符。
locked否子 Kit 不允许覆盖的点分路径。
security否容器安全设置。security.privileged: true 会让容器以特权模式运行。
args否加载 Kit 时传入的参数。仅 schema v2 支持。

Kit 还会声明若干行为块,例如 agentInstructions、permissions、ports、credentials、environment、setup 和 volumes。

参数 ​

schema v2 的 Kit 可以声明参数,并在 spec.yaml 中或 files/ 下的任意位置以 ${{ kit.args.<name> }} 引用它们。替换发生在规范解码之前。

yaml
args:
  version:
    default: latest
    description: Tool version to install
    pattern: '^(latest|[0-9]+\.[0-9]+\.[0-9]+)$'
  channel:
    default: stable
    enum: [stable, beta, nightly]
  target:
    required: true
    description: Build target

environment:
  variables:
    TOOL_VERSION: "${{ kit.args.version }}"

不要用 Kit 参数保存 API 令牌、密码或其他机密。请用 凭据把敏感值提供给沙箱。

字段说明
参数名以字母或下划线开头,只包含字母、数字、下划线和连字符。
default调用方未提供值时使用的字符串。与 required: true 互斥。
required设为 true 表示调用方必须提供值。与 default 互斥。
description可选的帮助文字,在缺少必填值时显示。
enum可选的允许值列表。与 pattern 互斥。
pattern可选的 Go RE2 正则表达式,与完整值匹配。与 enum 互斥。

每个参数必须声明 default(可以为空字符串默认值)或 required: true。

参数值是字符串,但替换发生在 YAML 解码之前。在字符串类型的字段中要给占位符加引号,这样像 1.20 这样的值不会被解码成数字。

向 Kit 传递参数 ​

对每个声明了该参数的 Kit 使用 --kit-arg name=value,或加上 Kit 的 name 前缀来指定某一个 Kit。带作用域的值会覆盖共享的值:

console
$ sbx run ./my-agent --kit ./my-mixin --kit-arg channel=stable \
    --kit-arg my-mixin.channel=beta

--kit-args-file <FILE> 读取 name=value 条目,忽略空行和 # 注释。靠后的文件会覆盖靠前的文件;--kit-arg 覆盖文件中的值。命令行中重复出现的同一个键,以最后一个值为准。缺少必填值、未知参数、未声明的占位符和无效值都会在创建之前失败。必要时,把同样的标志传给 sbx kit validate 或 sbx kit inspect。参数值可能会保留在 shell 历史中,并以未加密的形式存放在参数文件里。

沙箱块 ​

yaml
sandbox:
  image: <image-ref>
  build:
    context: .
    dockerfile: Dockerfile
    args:
      AGENT_VERSION: "1.0.0"
    target: runtime
    platforms:
      - linux/amd64
  entrypoint: [my-agent, "--flag"]
  command:
    default: ["--task-mode"]
    interactive: []
  resources:
    cpu: 2
    memory: 4g
    gpu: "1"
字段必填说明
sandbox.image省略 extends: 时必填Docker 镜像引用。
sandbox.build否构建配置。运行时支持仍在开发中,因此带 build: 的 Kit 还必须设置 image:。
sandbox.entrypoint否固定进程前缀,字符串数组。第一个元素是智能体二进制文件。
sandbox.command否按模式区分的参数尾部。用列表简写表示 default,或用包含 default 和 interactive 的映射。
sandbox.resources否可选的 CPU、内存和 GPU 约束。内存使用 4096m 或 4g 这样的字节大小字符串。

实际的命令在非交互式启动时是 entrypoint 加上 command.default,在 TTY 会话中是 entrypoint 加上 command.interactive。如果省略 interactive,则回退到 default。

对于使用 extends: 的 Kit,sandbox.command 会替换继承来的全部参数尾部,包括父级 sandbox.entrypoint 中二进制文件之后的标志。它不会追加到那个尾部之后。请定义子级需要的每一个参数。例如,一个在 claude 基础上添加 --settings 的子 Kit,还必须包含 --dangerously-skip-permissions 才能保留该行为。

智能体的容器镜像必须提供:

  • 一个 UID 为 1000、无密码 sudo 权限的非 root agent 用户。
  • 一个由 agent 拥有的 /home/agent/ 主目录。
  • 在 sudo 之后依然保留的 HTTP 代理环境变量(HTTP_PROXY、HTTPS_PROXY、NO_PROXY)。
  • 智能体二进制文件,可以是内置的,也可以用 setup.install 安装。

在 docker.io/sbx/shell-docker-image:latest 之上构建即可获得这些基础要求。

智能体说明 ​

在 agentInstructions 下声明这些字段:

字段说明
filenameAI 配置文件名。对 kind: sandbox 有意义;对 kind: mixin 会忽略并给出警告。
contentMarkdown 说明。对沙箱来说内联到该配置文件中;对 Mixin 来说写入 Kit 记忆。

对 Mixin,引擎把 content 写入 <dir-of-AI-file>/kits-memory/<kit-name>.md,并在基础 AI 文件中增加一个 ## Kits 指针小节。这样每个 Mixin 的说明都留在各自的文件里。

生成的配置文件位于沙箱内已挂载工作区的上级目录。它在挂载点之外,不会取代项目中的说明文件。沙箱 Kit 内联的说明会直接进入该配置文件。

凭据 ​

Kit 声明它需要的凭据,以及代理如何把它们注入出站请求。它不声明宿主的发现来源。用户通过密钥存储或首次运行提示提供数值,并由 凭据绑定授权使用。Kit 不能读取任意宿主环境变量或文件。

credentials 是一个列表;每个条目指明一个 service,并配置一种或多种认证机制。

字段说明
service凭据标识符,与 sbx secret set 存储的值匹配。使用小写短横线格式。
description可选。批准绑定时向用户显示。
required标记该凭据对智能体不可或缺。如果没有绑定,sbx 会发出警告并在不提供该凭据的情况下启动。默认 false。
provider为提供商注册表预留。接受该字段但会给出警告,运行时没有作用。
apiKeyAPI 密钥注入(见 apiKey)。
oauthOAuth 拦截(见 oauth)。

每个 service 必须声明 apiKey、oauth 或两者。两者在运行时都能解析时,API 密钥优先,OAuth 作为回退。

apiKey ​

字段说明
name凭据对应的环境变量名,例如 ANTHROPIC_API_KEY。
proxyManaged为 true 时,sbx 在容器内把 name 设为 proxy-managed 哨兵值。默认 false。
inject[].domain注入凭据的域名。同时也必须在 permissions.network 中被允许。
inject[].header代理设置的 HTTP 请求头,例如 x-api-key、Authorization。
inject[].format请求头值的格式,含一个 %s 占位符,例如 "%s" 或 "Bearer %s"。与 scheme 互斥。
inject[].scheme常用认证方案的简写。bearer 展开为 Authorization: Bearer %s;basic 需要 username。与 format 互斥。
inject[].usernameHTTP Basic 认证的用户名,例如通过 HTTPS 使用 Git 时的 x-access-token。

oauth ​

对于使用 OAuth 认证的智能体(例如 Claude Code),代理会拦截令牌响应,把真实令牌替换为哨兵值,然后在出站请求中换回真实令牌。默认情况下,令牌从不进入沙箱。设置 passthrough: true 可以不使用哨兵掩码,直接把真实的令牌响应送入沙箱。

字段说明
tokenEndpoint.host / path代理拦截的 OAuth 令牌端点。
sentinels.accessToken / refreshToken写入容器、用来替代真实令牌的哨兵值。
credentialFile.path在容器内写入凭据文件的位置(~ 会展开)。
credentialFile.structure声明式 JSON 结构。支持 {{.AccessToken}}、{{.RefreshToken}}、{{.ExpiresAt}} 和 {{.Scopes}}。
credentialFile.templateGo 模板。支持 {{.AccessToken}}、{{.RefreshToken}}、{{.ExpiresAt}}、{{.Scopes}} 和 {{.ScopesJSON}}。
resourceHosts代理在出站请求中附加令牌的 API 主机,与令牌端点主机不同。
skipIfEnv为兼容性而接受,但在 schema v2 中被忽略。v2 绑定才是权威来源,而不是宿主环境变量。
responseFields覆盖代理从令牌响应中读取的默认字段名。
passthrough为 true 时,代理原样传递令牌响应,而不是用哨兵值替换令牌。

credentialFile.structure 为 credentialFile.template 提供了声明式的替代方案。引擎会把它渲染成格式正确的 JSON。如果两个字段都设置了,structure 优先。

网络 ​

网络出站流量在 permissions.network 下声明。凭据不再携带自己的域名映射 —— 代理只会把凭据注入其 apiKey.inject 列出的域名,而沙箱访问的每个域名都必须在这里被允许。

字段说明
permissions.network.allow沙箱可以访问的域名。
permissions.network.deny沙箱被禁止访问的域名。拒绝规则优先于允许规则,在组合的 Kit 之间同样如此。

允许和拒绝的模式:

模式示例状态
精确主机api.example.com已强制执行
精确主机和端口api.example.com:8080已强制执行
单标签通配符*.example.com已强制执行
多标签通配符**.example.com已解析;尚未强制执行
端口范围api.example.com:80-443已解析;尚未强制执行
端口通配符api.example.com:*已解析;尚未强制执行
CIDR10.0.0.0/8已解析;尚未强制执行

在 v1 中这是 network: 块(allowedDomains / deniedDomains,以及 serviceDomains / serviceAuth)。在 v2 中,这些字段会导致解码错误。

端口 ​

把 ports 声明为一个条目列表,用于把沙箱服务暴露给宿主:

字段说明
container容器端口,1 到 65535。
protocoltcp 或 udp。留空表示只发布一种协议族,详见下文。
name可选标签,供列出已发布端口绑定的工具使用。

宿主端口是临时分配的。除非服务监听 IPv6,否则请让 protocol 保持为空:空值只发布 IPv4(127.0.0.1),这正是绑定在 0.0.0.0 上的服务所需要的;而 tcp 会同时发布 127.0.0.1 和 ::1 —— 通过 ::1 到达的客户端会被接受,随后被重置,如果沙箱内没有服务在监听该地址。用户可以用 sbx ports --publish <host>:<container> 固定宿主端口。

环境 ​

字段说明
environment.variables直接在容器中设置的键值对。

不要设置 DASH_、SBX_ 或 DOCKER_ 开头的变量,并避免覆盖 HOME、USER、SHELL、PATH、LD_PRELOAD 和 LD_LIBRARY_PATH。运行时保留这些名称,可能会覆盖它们。

安装 ​

setup.install、setup.startup 和 setup.files 是命令或文件的列表,其字段见下文。

执行顺序 ​

创建沙箱时,Kit 内容按以下顺序应用:

  1. 网络权限和环境变量。
  2. files/home/ 下的静态文件。
  3. setup.install 命令,按声明顺序执行。
  4. setup.files 条目。
  5. setup.startup 命令,为每次沙箱启动注册。
  6. files/workspace/ 下的静态文件,在工作区就绪之后。带 --clone 时,这一步在仓库克隆完成之后。

对于堆叠的 Kit,每个阶段的条目按 --kit 的顺序应用。install 命令可以使用 files/home/ 中的捆绑文件,但不能使用 files/workspace/ 或 setup.files 中的文件,因为那些文件更晚才落地。

sbx kit add 会重新创建沙箱,而不是就地修改它。它支持的 Mixin Kit 仅限于 environment.variables、setup.install、setup.startup 和 permissions.network.allow,其顺序与创建沙箱时相同。启动命令在 Kit 被添加之后以及之后每次沙箱启动时运行。该命令会拒绝声明了静态文件或 setup.files 的 Kit。要使用这些字段,请在创建沙箱时一并包含该 Kit。

install ​

在应用 Kit 时同步运行,无论是在创建沙箱期间还是通过 sbx kit add。Shell 字符串会传给 sh -c。

Kit 的 install 命令从模板镜像配置的 WORKDIR 开始。Docker 提供的模板使用 /home/agent/workspace,在直接挂载或克隆模式的沙箱中它不一定是主工作区。不要依赖当前目录来定位工作区文件。对来自 files/home/ 的捆绑资源,请使用绝对路径。

字段默认值说明
command—Shell 命令字符串。
user"0"以哪个用户运行。"0" 表示 root。
description—便于阅读的描述。

startup ​

在每次沙箱启动时运行。字符串数组,不经过 shell 解释。数组中的 $WORKSPACE_DIR 引用会原样传递。要展开它,请通过 shell 运行该命令,例如 ["sh", "-c", "..."]。

字段默认值说明
command—命令及其参数,字符串数组。
user"1000"以哪个用户运行。"1000" 表示智能体。
backgroundfalse在这条命令结束前阻塞后续的启动命令。设为 true 则让后续命令无需等待即可运行。
description—便于阅读的描述。

启动命令是非交互式的。它们在智能体接入之前运行,没有连接终端,因此无法向用户提问(例如交互式的 aws login 会挂起或失败)。它们也不会阻塞智能体的 entrypoint:启动命令一旦分发出去,智能体就会启动,与 background 无关。值为 false 是在启动分发器内部等待当前命令结束后再运行下一条命令;它不会延迟智能体的 entrypoint。把启动命令用于可以与智能体并行进行的工作。任何需要在智能体运行前落到磁盘上的值,请用 setup.files。

启动命令必须满足幂等。它们在每次沙箱启动时运行,并在容器重启时重放,因此一条第二次调用就失败或行为异常的命令会破坏重启路径。用存在性检查加以保护,用更新插入代替单纯插入,并优先选择无论运行多少次都收敛到相同最终状态的命令。

files ​

在沙箱启动时写入的文件,支持运行时替换。

字段默认值说明
path—容器内的绝对路径。
content—文件内容。写 ${WORKDIR} 表示工作区路径。
mode"0644"八进制的文件权限。
onlyIfMissingfalse文件已存在时跳过。

运行时以 UID 1000 的智能体用户身份写入这些文件。目标路径必须对该用户可写。要写入 /etc 这类由 root 拥有的路径,请使用 install 命令,它默认以 root 身份运行。如果智能体之后需要修改该文件,请在 install 命令中设置属主。

在 content 中写 ${WORKDIR},在命令中写 $WORKSPACE_DIR。三个名字看起来相近,含义却不同:

名称是什么适用范围
${WORKDIR}工作区路径的占位符仅 setup.files[].content
WORKSPACE_DIR运行时设置的工作区路径环境变量Shell 命令,以及智能体
WORKDIR模板镜像 Dockerfile 中的工作目录命令的起始位置,见 install

运行时在创建沙箱时替换 ${WORKDIR},且只在 content 内部替换,绝不会出现在 path 或命令中。WORKSPACE_DIR 是环境变量,因此 $WORKSPACE_DIR 引用只有在 shell 运行该命令时才会展开。install 字符串会通过 sh -c 运行。startup 数组在没有 shell 的情况下运行。Dockerfile 的 WORKDIR 并不定义环境变量。

Shell 初始化和服务日志 ​

使用 Docker 模板时,在 install 命令中把 shell 初始化追加到 /etc/sandbox-persistent.sh。保留已有内容,并且不要加入补全脚本:交互式和非交互式的 Bash 命令都会读取这个文件。对于后台服务,把启动输出重定向到文件,再用 sbx exec 读取。使用 background: true,而不是在末尾加 &。

静态文件 ​

text
my-kit/files/
├── home/       → /home/agent/
└── workspace/  → primary workspace path
Kit 路径容器目标位置
files/home//home/agent/(配置文件、点文件)
files/workspace/主工作区路径

上级目录会自动创建。已存在的文件会被覆盖。绝对路径和路径穿越序列(../../)会被拒绝。

静态文件可以提供 linter 设置、辅助脚本或智能体技能。例如,一个 Claude Code 项目技能应放在 files/workspace/.claude/skills/<NAME>/SKILL.md。

卷 ​

把 volumes 声明为一个挂载列表,包含这些字段:

字段说明
path必填,容器内的绝对路径。
type留空表示块存储卷,或 tmpfs 表示内存支持的存储。
size可选的字节大小字符串。
mode可选的八进制权限。

卷只在创建沙箱时应用。sbx kit add 无法把卷挂载到运行中的容器。

派生已有的智能体 ​

这个例子需要一个带内置 v2 智能体的较旧 sbx 版本。使用最新的 sbx 创建沙箱时,内置名称对应的是 v3 Kit。要做 v3 定制,请参阅 编写 Kit 集合。

沙箱 Kit(kind: sandbox)从头定义一个完整的智能体。最常见的变体是从内置智能体派生。用 extends: 继承父级的完整配置,只声明你想改动的字段。这个例子替换了内置的 claude entrypoint,让 Claude Code 使用手动权限模式,而不是跳过审批提示:

yaml
schemaVersion: "2"
kind: sandbox
name: claude-safe
displayName: Claude Code (with approval prompts)
description: Claude Code in manual permission mode

extends: claude

sandbox:
  entrypoint: [claude, "--permission-mode", "manual"]

子级会继承内置镜像、凭据、网络权限、持久化卷、设置、MCP 集成、智能体说明、安装条目和环境变量。它的 sandbox.entrypoint 会替换继承来的 entrypoint。

启动时,在内置智能体名的位置传入沙箱 Kit:

console
$ sbx run ./claude-safe

安装内部 CA 证书 ​

把每张 PEM 编码的根证书放在 files/home/ 下,扩展名为 .crt。对于 files/home/internal-ca.crt,使用:

yaml
schemaVersion: "2"
kind: mixin
name: internal-ca
setup:
  install:
    - command: "install -m 0644 /home/agent/internal-ca.crt /usr/local/share/ca-certificates/internal-ca.crt && update-ca-certificates"
      user: "0"

这会更新系统信任库。有多个 CA 时,请在运行 update-ca-certificates 之前安装全部证书。

由沙箱管理的智能体配置 ​

内置智能体 Kit 为沙箱安装预留了以下路径。即便某个文件只针对某个功能才需要,也要把这些路径视为沙箱管理。不要用静态文件、setup.files 或 install 命令针对它们。后续的安装步骤可能会替换你的内容,或依赖被你的文件移除的设置。在这张表中,~ 表示 /home/agent。

内置智能体 Kit受管理的配置路径
claude~/.claude.json、~/.claude/settings.json、~/.claude/.config.json
codex~/.codex/config.toml
copilot~/.copilot/config.json
cursor~/.cursor/cli-config.json
devin~/.config/devin/config.json、~/.config/devin/mcp_config.json
kiro~/.kiro/settings/mcp.json
opencode~/.config/opencode/opencode.json

在支持的情况下请使用独立的设置文件:Claude Code 接受 --settings,OpenCode 读取 OPENCODE_CONFIG。不要用 setup.startup 保存智能体必须在初始化期间读取的设置;启动命令不会阻塞 entrypoint。

校验并检查 Kit ​

用下面这些命令在分享之前检查一个 Kit:

  • sbx kit validate <path> —— 检查 Kit 目录或 ZIP 的格式是否正确。
  • sbx kit inspect <path> —— 显示 Kit 的详情。加上 --json 可获得机器可读的输出。

加上 --offline 可以不启动守护进程、不登录,就地校验或检查一个本地目录或 ZIP。离线检查会跳过 Kit 来源和签名策略;它们并不能说明该 Kit 是否被允许加载。

打包与分发 ​

  • sbx kit pack <path> -o <file.zip> —— 把目录打包成 ZIP 文件以便分享。
  • sbx kit push <path> <ref> —— 发布到 OCI 镜像仓库(例如 ghcr.io/myorg/my-kit:1.0)。
  • sbx kit pull <ref> —— 把 Kit 下载到当前目录,schema v1 为 .zip,schema v2 为 .tar.gz。用 --output <FILE> 指定输出路径。

对于 Docker Hub,sbx kit pull 和 sbx kit push 使用 sbx login 的会话。对于其他镜像仓库,它们优先使用通过 sbx secret set --registry存储的凭据。 两条命令都会回退到 Docker 凭据存储,因此 docker login 得到的凭据同样可用。

签名并验证 Kit ​

使用兼容 cosign 的 Sigstore 签名来验证是谁批准了一个 Kit,以及它被签名的内容是否未被改动。默认采用无密钥签名。用证书身份和 OpenID Connect(OIDC)签发者验证无密钥签名:

console
$ sbx kit sign ./my-kit/
$ sbx kit verify \
    --certificate-identity user@example.com \
    --certificate-oidc-issuer https://accounts.google.com \
    ./my-kit/

对于基于密钥的签名,请使用 ECDSA P-256 密钥对:

console
$ sbx kit sign --key cosign.key ./my-kit/
$ sbx kit verify --key cosign.pub ./my-kit/

对于本地目录,sbx kit sign 会在 spec.yaml 旁边写入一个 kit.sig.bundle 文件。请提交这个文件,这样使用者就能验证从 Git 仓库加载的 Kit。

Git 的行尾转换和 clean filter 可能让源码签名失效。如果 sbx kit sign 警告存在这类转换,请确保 Git 在分享 Git 引用之前原样保留被签名的文件。

对于 OCI Kit,签名以 OCI referrer 的形式保存。你可以在推送之后签名,也可以一步完成推送和签名:

console
$ sbx kit push ./my-kit/ ghcr.io/myorg/my-kit:1.0 --sign

ZIP Kit 无法携带可验证的签名。

查看来源证明 ​

推送一个 Kit 时还会附带一份来源证明(provenance)attestation,记录它的内容 digest、声明的沙箱镜像,以及从工作树推送时的源码 Git 提交。检查它可以确认已发布 Kit 的来源:

console
$ sbx kit provenance ghcr.io/myorg/my-kit:1.0

来源证明默认不带签名。发布时使用 sbx kit push --sign,可以为 Kit 清单和它的来源证明同时签名。

要求 Kit 必须签名 ​

在要求签名之前,先把 kit.trustedSigners 设为你信任的身份或密钥。否则,sbx 会使用默认策略,即信任由 Google 的 OpenID Connect 签发者出具的 Docker 员工身份。无密钥策略必须同时指定证书身份及其 OpenID Connect 签发者:

console
$ sbx settings set kit.trustedSigners \
    '[{"identity":"release-bot@example.com","issuer":"https://accounts.google.com"}]'
$ sbx settings set kit.requireSignature true

要信任基于密钥的签名,把策略设为公钥路径:

console
$ sbx settings set kit.trustedSigners '[{"key":"/path/to/cosign.pub"}]'
$ sbx settings set kit.requireSignature true

当 kit.requireSignature 为 true 时,sbx 会拒绝未签名的 Kit、与 kit.trustedSigners 不匹配的签名,以及 ZIP Kit。该策略在从本地目录、Git 仓库或 OCI 镜像仓库加载 Kit 时都生效。

签名覆盖 spec.yaml 和 Kit 的 files/ 内容,但不覆盖镜像标签这类可变的依赖,也不覆盖 install 和 startup 命令下载的内容。当这些依赖必须保持不可变时,请用 digest 或校验和来锁定它们。

Schema 版本 ​

Schema v2 从 Docker Sandboxes 0.36 版本起开始支持。本页的语法使用 schemaVersion: "2"。版本 "1" 也仍然接受。V3 是另一种格式,用于完全由 v3 工作负载和 Mixin 构建的环境。V3 Kit 不能与 v1 或 v2 Kit 组合。该流程请参阅 Kits v3。

迁移到 schemaVersion: "2" 时,把 v1 字段替换为对应的 v2 字段:

v1v2
credentials.sources.<id>带 service 的 credentials: 列表条目
network.allowedDomains / deniedDomainspermissions.network.allow / deny
network.serviceDomains / serviceAuthcredentials[].apiKey.inject
network.publishedPorts / publishedPorts顶层的 ports
独立的 oauth: 块credentials[].oauth
oauth.skipIfEnv接受但被忽略
environment.proxyManagedcredentials[].apiKey.proxyManaged
memory / agentContextagentInstructions.content
kind: agent / agent: 块kind: sandbox / sandbox: 块
sandbox.aiFilenameagentInstructions.filename
sandbox.entrypoint.runsandbox.entrypoint
sandbox.entrypoint.argssandbox.command.default
sandbox.entrypoint.ttyArgssandbox.command.interactive
tmpfs:type: tmpfs 的 volumes: 条目
volumes:(映射形式)volumes: 序列(- path: <path>)
commands: / commands.initFilessetup: / setup.files
settings: / kitDir / persistence已移除

在 v2 中,凭据发现也移出了 Kit:Kit 声明自己需要哪些凭据以及如何注入,但每个值来自哪里由用户通过 凭据绑定控制。

NOTE

mixins 和 sandbox.build 解析器可以接受,但运行时支持仍在开发中。 设置了 sandbox.build 的 Kit 还必须设置 sandbox.image。

把环境迁移到 v3 ​

选择一个 v3 工作负载,转换或替换它的 Mixin,然后创建一个独立的沙箱。每个被选中的 Kit 都必须使用 v3。运行已有的沙箱会保留它记录的 Kit 配置。

对于环境文件,请参阅添加 v3 Kit。 保持它的 schemaVersion: "1":环境文件的版本与 Kit 描述符版本无关。

仅修改 schemaVersion 并不会转换一个 Kit。请把可复用的镜像内容与沙箱初始化分开,并声明运行时能力:

V2 的写法V3 的对应写法
kind: sandbox带 Dockerfile 配方的 kind: workload
sandbox.imageDockerfile 的 FROM
sandbox.entrypoint、sandbox.command、environment.variablesDockerfile 的 ENTRYPOINT、CMD 和 ENV
extends用于组合的 Mixin,或带自己描述符的派生工作负载镜像
setup.install用于可复用内容的 Dockerfile RUN;用于沙箱初始化的生命周期 install
setup.startup 和 setup.files生命周期能力的 startup 和 files
setup.files[].onlyIfMissing: true生命周期的 files[].overwrite: false
自动注入 files/home/ 和 files/workspace/Dockerfile COPY,目标路径由运行时挂载提供时使用生命周期钩子
permissions.network 和 credentials网络策略能力和凭据能力
agentInstructionsAgent context 能力
setup.files[].content 中的 ${WORKDIR}生命周期 files 内容中的 ${{ kit.env.WORKSPACE_DIR }}

转换运行时安装步骤和能力声明时,请遵循 v3 编写指南。 用 Kit 集合把已发布的 v3 组件与你的设置组合起来。要从基础镜像重新构建智能体环境,请参阅 构建智能体工作负载。