Skip to main content
配置 Agent 环境

挂载自有 OSS Bucket(Beta)

在 Environment 中声明自己的 OSS bucket,挂载到 Session 沙箱的 /mnt/buckets/<name>。

你可以在 Environment 的 config.storage.buckets[] 中声明自己的阿里云 OSS bucket。使用该 Environment 创建的 Session 会把每个 bucket(或其一个 prefix)挂载到沙箱的 /mnt/buckets/<name>,Agent 可以像本地目录一样读取和写入。 挂载是 Environment 级配置:Session 创建时会快照当时的配置,之后修改 Environment 不影响已经创建的 Session。
  • 每个 Environment 最多声明 8 个 bucket。
  • 只支持阿里云 OSS(provider: "aliyun-oss")。
  • 支持只读和读写。
  • 读取通过预签名 URL 从 OSS 直接下载;写入通过分片直传直接上传到 OSS(小于 1 MiB 的写入经 Qoder 转发)。
  • 用户的 RAM 角色或 AccessKey 不会进入沙箱。
该功能处于 Beta 阶段。创建或更新 Environment 时,只要结果中的 config.storage.buckets 非空,就必须携带请求头 x-qoder-beta: oss-bucket-2026-09-23。首次为 Environment 添加 bucket 还需要账号满足 Beta 资格(白名单或全量开放);不满足时返回 503 feature_not_available。删除 bucket(结果中不含 bucket)不需要该请求头。

配置字段

config.storage 只允许一个字段 buckets,且只对 cloud Environment 有效:
{
  "type": "cloud",
  "storage": {
    "buckets": []
  }
}
每个 bucket 的字段:
字段类型必填说明
namestring是挂载目录名,即 /mnt/buckets/<name>。1–63 个字符,只允许字母、数字、.、_、-,且以字母或数字开头;同一 Environment 内唯一
providerstring是固定为 "aliyun-oss"
regionstring是OSS region ID,例如 cn-hangzhou、ap-southeast-1。只接受 region ID,不支持自定义 endpoint
bucketstring是bucket 名称,不能包含 /、*、?
prefixstring否只挂载该前缀下的对象;首尾的 / 会被忽略;省略表示整个 bucket。不能包含 *、?、\、NUL,也不能包含空段、. 或 .. 段
accessstring否read_only(默认)或 read_write
accelerator_endpointstring否OSS 加速器域名,格式为 <label>.oss-data-acc.aliyuncs.com;仅在 bucket 与沙箱同地域时使用
credentialobject是访问 bucket 的凭证,见下方凭证
同一次请求中,name 不能重复;region + bucket + prefix 相同的两个 bucket 会被拒绝。 请求字段是严格校验的:出现未知字段、大小写不匹配的键,或字段类型错误时返回 400。

示例

创建带两个 bucket 的 Environment:
curl -s -X POST "https://api.qoder.com.cn/api/v1/cloud/environments" \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "x-qoder-beta: oss-bucket-2026-09-23" \
  -d '{
    "name": "with-oss-buckets",
    "config": {
      "type": "cloud",
      "storage": {
        "buckets": [
          {
            "name": "datasets",
            "provider": "aliyun-oss",
            "region": "cn-hangzhou",
            "bucket": "my-bucket",
            "prefix": "team/data/",
            "access": "read_only",
            "credential": {
              "type": "ram_role",
              "role_arn": "acs:ram::1234567890123456:role/qoder-oss-mount"
            }
          },
          {
            "name": "outputs",
            "provider": "aliyun-oss",
            "region": "cn-hangzhou",
            "bucket": "my-bucket",
            "prefix": "team/outputs/",
            "access": "read_write",
            "credential": {
              "type": "access_key",
              "access_key_id": "LTAI5tExampleAccessKey",
              "access_key_secret": "ExampleSecret"
            }
          }
        ]
      }
    }
  }'
响应中的凭证只返回读取视图:
{
  "id": "env_019e44eb66bb748cabcd1489f6fa4428",
  "type": "environment",
  "name": "with-oss-buckets",
  "description": "",
  "config": {
    "type": "cloud",
    "storage": {
      "buckets": [
        {
          "name": "datasets",
          "provider": "aliyun-oss",
          "region": "cn-hangzhou",
          "bucket": "my-bucket",
          "prefix": "team/data/",
          "access": "read_only",
          "credential": {
            "type": "ram_role"
          }
        },
        {
          "name": "outputs",
          "provider": "aliyun-oss",
          "region": "cn-hangzhou",
          "bucket": "my-bucket",
          "prefix": "team/outputs/",
          "access": "read_write",
          "credential": {
            "type": "access_key",
            "access_key_id": "LTAI****sKey"
          }
        }
      ]
    }
  },
  "metadata": {},
  "archived_at": null,
  "created_at": "2026-10-21T08:00:00.000000Z",
  "updated_at": "2026-10-21T08:00:00.000000Z"
}

凭证

credential.type 二选一:ram_role(推荐)或 access_key。

RAM 角色(推荐)

  1. 在你的阿里云账号创建一个供 Qoder 扮演的 RAM 角色。信任策略需要允许 Qoder 服务角色扮演;Qoder 服务角色信息请提工单获取。
  2. 信任策略通过 sts:ExternalId 限定调用方身份:
会话所有者sts:ExternalId
个人用户用户 ID
企业(Service Account)<组织 ID>@<workspace ID>
{
  "Version": "1",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "RAM": ["<Qoder 服务角色 ARN>"]
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": ["<你的用户 ID 或 组织 ID@workspace ID>"]
        }
      }
    }
  ]
}
  1. 把该角色的 ARN 填到 credential.role_arn。
Qoder 扮演该角色后,还会附带一条 session policy,把权限进一步收窄到声明的 bucket、prefix 和读写模式。角色自身也需要具备下方权限策略中的动作;实际权限是两者交集。

AccessKey

使用一个专用的 RAM 用户的 AccessKey,不要使用主账号 AccessKey,并给该 RAM 用户授予下方权限策略。
  • AccessKey 随 Environment 配置保存,并会快照进之后创建的 Session。
  • 读取 Environment 时只返回打码的 access_key_id(例如 LTAI****sKey),access_key_secret 永远不会返回。
  • 轮换 AccessKey 只影响之后创建的 Session。
  • 没有 STS session policy:prefix 与只读限制由 Qoder 保证,存储侧的最终权限由该 AccessKey 自身的 RAM 策略决定。

更新时保留凭证

config 是整体替换的,但 storage.buckets[].credential 是只写字段,按 bucket 的 name 保留:
  • 更新时省略某个 bucket 的 credential,或原样回传读取到的打码凭证,会保留已保存的凭证。
  • 修改某个 bucket 的 name 会被视为新 bucket,必须提供完整凭证。
  • 把 credential.type 改成另一种类型,或显式传 "credential": null,必须提供完整的新凭证。
  • 从数组中删除某个 bucket,或传 "buckets": [],之后创建的 Session 不再挂载它;已有 Session 使用创建时的快照,不受影响。

授权 bucket

bucket 的所有者需要显式允许 Qoder 挂载。授权由 bucket 标签和可选的访问名单文件组成;两处至少有一处指名允许谁挂载,否则挂载会被拒绝。

标签

在 OSS 控制台给 bucket 打标签。用户 ID、组织 ID 和 workspace ID 可以在 Qoder 控制台查看:
标签必填说明
qoder-mount是值必须为 enabled,表示允许 Qoder 挂载该 bucket
qoder-mount-users否允许挂载的个人用户 ID,英文逗号分隔
qoder-mount-organizations否允许挂载的组织 ID,英文逗号分隔
qoder-mount-workspaces否允许挂载的 workspace ID,英文逗号分隔
规则:
  • 标签值最长 128 字符,只适合放少量 ID。
  • 个人会话只匹配 qoder-mount-users;企业会话只匹配 qoder-mount-organizations。两者是不同命名空间,ID 拼写相同也不互认。
  • 配置了 qoder-mount-workspaces 时,会话所属 workspace 必须命中。
  • 只要存在限制标签,写了的维度都必须命中。
  • 标签缓存约 1 分钟;读取失败时最多沿用 10 分钟;明确拒绝(403)立即生效。

访问名单(可选)

需要在用户 / 组织之外按 Agent 或 Session 做更细控制时,可以在挂载目录旁边放一份访问名单文件。它位于挂载目录之外,沙箱里看不到也改不了。
  • 文件名:<prefix 去掉末尾斜杠>.qoder-acl.json。例如 prefix 为 team/data/ 时,文件是 team/data.qoder-acl.json。
  • 整 bucket 挂载(不填 prefix)没有访问名单,只能靠标签。
  • 只看挂载目录本级这一份,不读取上层目录的名单。
{
  "version": 1,
  "grants": [
    {"users": ["<用户 ID>"]},
    {"organizations": ["<组织 ID>"], "workspaces": ["<workspace ID>"], "agents": ["<agent ID>"], "sessions": ["<session ID>"]}
  ]
}
规则:
  • 支持 users、organizations、workspaces、agents、sessions 五个维度。
  • 一条 grant 里写了的维度都必须命中;没写的维度不限;写了空列表表示谁都不匹配。
  • 任意一条 grant 命中即允许;一条都不命中返回 403。
  • 标签和名单都配置时,两处都要命中(取交集)。
  • 文件超过 64 KB、不是合法的 version 1 JSON、包含未知键、grant 为 null、维度不是非空字符串数组时,一律拒绝。
  • agents / sessions 只在真正挂载时校验,保存 Environment 时不检查。
  • 名单缓存约 1 分钟;过期后读取失败时最多沿用 10 分钟;403 不沿用。
  • 文件不存在不算错误,但此时必须由标签指名允许谁挂载。

权限策略

授予 RAM 角色或 RAM 用户的最小权限:
动作用途需要
oss:ListObjects列目录只读 / 读写
oss:GetBucketTagging读 bucket 标签(挂载许可)只读 / 读写
oss:GetObject读文件;读访问名单;改名时读源文件只读 / 读写
oss:HeadObject查看文件信息(stat)只读 / 读写
oss:PutObject写文件、分片直传、新建目录、改名时写目标文件仅读写
oss:DeleteObject删除文件和空目录、改名时删源文件仅读写
oss:AbortMultipartUpload清理中断的直传分片仅读写
oss:ListParts直传完成前核对分片;缺少会导致大文件写入失败仅读写
只读挂载的示例策略(prefix 为 team/data/):
{
  "Version": "1",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["oss:ListObjects", "oss:GetBucketTagging"],
      "Resource": ["acs:oss:*:*:my-bucket"]
    },
    {
      "Effect": "Allow",
      "Action": ["oss:GetObject", "oss:HeadObject"],
      "Resource": ["acs:oss:*:*:my-bucket/team/data/*"]
    },
    {
      "Effect": "Allow",
      "Action": ["oss:GetObject"],
      "Resource": ["acs:oss:*:*:my-bucket/team/data.qoder-acl.json"]
    }
  ]
}
读写挂载还需要在第二个 statement 的 Action 中加入 oss:PutObject、oss:DeleteObject、oss:AbortMultipartUpload 和 oss:ListParts。

保存时校验

保存 Environment 时(创建,或更新中新增 / 改动了某个 bucket),Qoder 会以保存者身份、使用提交的凭证试挂一遍:
  1. 获取凭证(扮演角色或使用 AccessKey);
  2. 读取 bucket 标签;
  3. 读取访问名单(如果存在);
  4. 对 prefix 做一次列举(max-keys=1)。
只有新增或改动的 bucket 会被检查,未改动的 bucket 不会重复检查。校验有 15 秒超时。
  • 配置或权限被拒绝时返回 400 invalid_request_error,message 形如 Bucket '<name>' cannot be mounted: <原因>.。
  • OSS / STS 故障时返回 503 api_error,可重试。
  • 名单中的 agents / sessions 维度不在保存时校验,留到实际挂载。

沙箱中的行为

挂载点:/mnt/buckets/<name>。access 为 read_only 时它是只读文件系统;read_write 时可以创建、修改和删除文件。
  • 目录:对象存储没有真正的目录。目录由对象 key 的前缀表示;空目录用一个 0 字节的 <path>/ 占位对象保持,和 OSS 控制台 / ossutil 的约定一致。
  • 读取:Qoder 返回 302 到预签名 URL,沙箱直接从 OSS 下载。
  • 写入:小于 1 MiB 的文件经 Qoder 普通上传;1 MiB 及以上的文件走分片直传(沙箱 PUT 各分片到预签名 URL,再提交)。
  • 改名:单文件改名是 copy + delete,不原子;多个会话并发改同一路径时可能丢失并发写入,Qoder 不做跨会话仲裁。
  • 目录改名:不提供原生支持,客户端会退化为逐文件移动。
  • 删除目录:非空目录返回 409,需要先删除目录内文件。
  • 列举上限:单个目录超过 100,000 个条目时返回 507,不会截断展示。
  • 单文件上限:分片直传最多 10,000 片 × 64 MiB,即 625 GiB;bucket 自身的配额与规格限制仍然适用。
  • 中断的上传:写入中断会在 bucket 中留下未完成的分片,建议给 bucket 配置生命周期规则自动清理。
  • 地域:bucket 与沙箱同地域时走 OSS 内网 endpoint;跨地域走公网,延迟更高。OSS 加速器只在同地域可用。
  • 网络:读取和 1 MiB 以上的写入由沙箱直接访问 OSS;如果 Environment 启用了受限网络,需要允许对应 OSS 域名。

错误码

HTTPtype说明
400invalid_request_errorbucket 字段不合法、凭证缺失、缺少 x-qoder-beta 请求头,或保存时试挂被拒绝
401authentication_errorPAT 或 SAT 无效或过期
403permission_error无权访问目标 Environment
503feature_not_available账号不满足 oss_bucket Beta 资格
503api_error保存时 OSS / STS 暂时不可用,可重试
挂载阶段的拒绝(标签未授权、访问名单未命中、凭证无权限等)表现为沙箱内的 EACCES,不会作为 Environment API 的错误返回。排查时优先检查 bucket 标签、访问名单和 RAM 权限。

限制

  • 只支持阿里云 OSS,不支持 S3、COS、MinIO 或自定义 endpoint。
  • 不管理对象版本、生命周期、bucket ACL 等 OSS 自身配置。
  • 一个 bucket 的一个 prefix 在一个 Environment 中只能出现一次;需要挂载同一 bucket 的多个目录时,使用不同的 name 和 prefix。
  • 挂载使用环境配置的快照,修改 Environment 不会改变已创建的 Session。