认证中心
← 全部文档与搜索
独立页面 ↗下载 Markdown
本文目录 · 5 节

软件版本与 S3 安装包管理

AI 开发工具的应用限定 Token、制品上传和生产审批流程见 机器制品接口。

入口:管理后台 → 应用与授权 → 软件版本 / 安装包存储。版本管理需 releases:write,存储设置需 settings:write。迁移 005_releases.sql 自动授予管理员版本管理权限。

发布流程

  1. 在应用接入中建立软件应用,记录公开的 client_id。
  2. 新增并启用 S3 存储,配置 Bucket 权限及 CORS,测试连接。
  3. 新建软件版本,选择系统、架构、通道,填写版本名称、正整数版本序号、更新说明及是否必须更新。
  4. 上传安装包,完成后立即发布或设置未来发布时间。

版本序号范围1至9007199254740991。同一应用、系统、架构、通道下,未删除版本的版本名称和序号不能重复;删除后可重新使用。未发布过的版本可以修正版本名称和序号,所属应用、系统、架构和通道保持不变。客户端按序号比较更新,名称仅用于展示。发布过的版本不能修改版本标识或替换安装包;新包应创建更大序号的新版本。

状态允许操作客户端可见
待发布 draft编辑说明/策略、上传、发布、定时发布、删除否
定时发布 scheduled查看、取消发布否
已发布 published查看、取消发布是,应用须启用
已取消发布 cancelled编辑说明/策略、再次发布、定时发布、删除;未曾发布时可换包否
已删除 deleted隐藏,保留标识和审计记录否

编辑和发布携带 revision,并发修改返回409。删除前须取消发布。删除后由后台异步清理 S3 对象,失败重试;不提供恢复。已签发链接最多仍有效5分钟,已下载文件无法撤回。

定时任务独立于支付/通知线程,每分钟按数据库时间检查。停机后恢复补发;应用停用期间不发布,重新启用后继续到期计划。页面选择本地时区时间,提交 RFC3339,数据库使用 timestamptz。

S3 设置

AWS S3 的 Endpoint 可留空;兼容存储填写完整地址,如 https://objects.example.com,不含 Bucket 路径、账号密码、查询参数。生产要求 HTTPS。Region、Bucket、Access Key、Secret Key 按服务商填写;MinIO 通常启用 Path Style。

浏览器和后端必须都能访问同一个 Endpoint,不能填写仅容器内可解析的主机名,不能在签发后替换域名。Bucket 保持私有;下载采用临时签名。

密钥用现有 DATA_KEY_FILE 加密且不返回前端。编辑密钥留空保留原值。已有配置的目标不可修改,切换目标须新增配置;历史文件保留原配置,原配置可独立轮换密钥。请备份数据密钥。

Bucket 连接测试只检查 Bucket 访问,实际上传/下载还需要对象权限及 CORS。兼容服务须支持 SigV4、SHA-256 分片校验、列举/合并/终止分片、HEAD/GET/DELETE。部分兼容服务不会在 ListParts 中回传已验证的分片校验和;服务端会校验分片编号、大小和 ETag,并在合并请求中省略对象存储未返回的校验和字段。SSE-KMS 另需相应 KMS 权限。

AWS IAM 示例(替换 YOUR_BUCKET):

{"Version":"2012-10-17","Statement":[
  {"Effect":"Allow","Action":["s3:ListBucket"],"Resource":"arn:aws:s3:::YOUR_BUCKET"},
  {"Effect":"Allow","Action":["s3:PutObject","s3:GetObject","s3:DeleteObject","s3:AbortMultipartUpload","s3:ListMultipartUploadParts"],"Resource":"arn:aws:s3:::YOUR_BUCKET/releases/*"}
]}

CORS 示例(替换为实际网站来源,开发地址须含端口):

[{"AllowedOrigins":["https://account.example.com"],"AllowedMethods":["PUT","GET","HEAD"],"AllowedHeaders":["*"],"ExposeHeaders":["ETag","x-amz-checksum-sha256"],"MaxAgeSeconds":3600}]

上传上限20GiB,每片32MiB,按片占用内存。分片 URL 有效15分钟,自动重试重新签发;会话有效24小时。同名、同大小、同完整 SHA-256 的文件可恢复并跳过已校验分片。取消及过期会话后台清理。

必须配置生命周期,在1天后终止未完成分片,覆盖 S3 创建成功但进程在保存 Upload ID 前退出等跨系统中断。启用版本控制的 Bucket 另需非当前版本清理规则,普通 DeleteObject 仅增加删除标记。Object Lock/保留规则可能阻止清理。

浏览器计算完整 SHA-256,上传 URL 将每片 SHA-256 纳入签名并由 S3 校验。服务端读取 S3 分片列表验证数量、顺序、大小和 ETag;对象存储回传分片校验和时还会验证其格式并携带它完成合并,再核验对象大小与元数据。完整哈希由可信管理员上传页计算提交;服务端不重新下载整包计算哈希。S3 multipart 组合校验和不能当完整文件哈希使用。AWS 校验说明。

客户端接口

公开接口,无需登录或内嵌管理密钥,分发公开安装包。软件使用授权仍通过现有授权接口检查。

GET /api/v1/updates/check?client_id=YOUR_CLIENT_ID&platform=windows&arch=x64&channel=stable&version_code=100

platform 支持 windows/macos/linux/android/ios,arch 支持 x64/arm64/x86/universal,channel 支持 stable/beta/alpha。全部精确匹配,不跨架构或通道回退。首次安装可用 version_code=0。

返回标准 {code:0,message:"success",data:...},有更新时 data 示例:

{"update_available":true,"release":{
  "id":"RELEASE_ID","version":"1.2.0","version_code":101,
  "platform":"windows","arch":"x64","channel":"stable",
  "notes":"修复已知问题","mandatory":false,"published_at":"2026-09-09T04:00:00Z",
  "filename":"setup.exe","size":104857600,"sha256":"64位小写十六进制完整文件SHA-256",
  "download_url":"/api/v1/updates/RELEASE_ID/download"
}}

没有更高序号的已发布版本返回 {"update_available":false},包括未知/停用应用,不推送降级。参数错误400,频率限制429,服务异常503;客户端失败时保留当前版本并稍后重试。

将相对 download_url 按认证中心域名解析。下载接口再次验证已发布、应用启用、包就绪,然后302跳转至有效5分钟的 S3 链接。断点下载使用 S3 Range GET,链接过期重新请求下载接口。

客户端流程:启动及定期检查(例如30分钟加随机抖动)→ 展示说明或按应用策略自动下载 → 流式校验长度和完整 SHA-256 → 验证系统代码签名 → 调用软件自己的安装/替换流程 → 成功后更新本地版本序号。mandatory 由客户端落实。本项目实现分发服务,不含各软件的安装器、进程替换或客户端自动升级实现。

管理 API

前缀 /api/v1,管理写入遵循现有 Cookie、Origin 和 CSRF 验证。

方法与路径用途
GET /admin/releases/applications选择应用,不返回密钥
GET /admin/releases分页,application_id/status 过滤
POST /admin/releases新建待发布版本
PUT /admin/releases/:id修改说明/mandatory,携带原标识与 revision
POST /admin/releases/:id/stateaction=publish/schedule/cancel/delete,revision,scheduled_at 可选
GET /admin/releases/historyapplication_id;预览可清除的历史版本数、安装包数和空间
DELETE /admin/releases/historyapplication_id;批量清除历史版本并异步删除安装包
GET /admin/releases/storage-usage按应用汇总安装包占用、可清理空间和后台删除中空间
POST /admin/releases/:id/uploadsfilename,size,sha256,revision;创建/恢复会话
POST /admin/releases/:id/uploads/:asset/partpart_number,sha256(Base64);返回 URL 和 headers
POST /admin/releases/:id/uploads/:asset/complete服务端验证合并,支持幂等重试
DELETE /admin/releases/:id/uploads/:asset取消未完成上传
GET /admin/releases/:id/download管理员下载未发布安装包
GET/POST /admin/release-storage脱敏列表 / 新增配置
PUT /admin/release-storage/:id名称、启用状态、密钥更新
POST /admin/release-storage/:id/test测试 Bucket

“清除历史版本”按应用执行:清除所有已取消发布版本,以及每个系统、架构和通道下已被更高版本序号替代的已发布版本。草稿、定时发布版本和每个分发目标的最新已发布版本始终保留。操作会立即隐藏版本并将相关安装包加入后台删除队列;界面会在确认前预览版本数、安装包数和预计释放空间。

软件版本页同时展示安装包存储占用图。总览区区分当前总占用、可通过历史版本清理释放的空间和后台删除中的空间;应用条形图按占用从高到低排列,并显示每个应用的安装包数量及其占总空间的比例。

验证

docker compose -f compose.test.yaml up --build -d --wait server minio
docker compose -f compose.test.yaml run --rm minio-init
python scripts/release_tests.py

仅对隔离测试栈运行,使用真实 PostgreSQL、Redis、Mailpit、MinIO。覆盖权限、密钥脱敏、版本冲突、大文件分片/恢复/校验/合并、下载哈希、发布/撤销、定时任务、并发发布和停用应用。