Split docs/softbox-catalog-design.md into the numbered harness doc set (00-06, api.md, current-state, agent-context, tasks) following the harness_coding_docs template and soft_quay conventions. Register the nine open decision items from the design spec into the 06-tasks roadmap as W- tasks and backlog entries. Keep the original design spec as an archived design input with a header note. Recreated after the repository's previous git history was lost to an external reset; content matches the original initial commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
21 KiB
soft_quay_web 设计说明(愿景 · 架构 · 协议契约)
定位说明(2026-07-20):本文是立项前的原始设计规格,内容已拆分进本仓库 harness coding 编号文档 (
01-vision.md/02-requirements.md/03-tech-stack.md/04-architecture.md/api.md/06-tasks.md的裁定清单)。 日常开发以编号文档为准,与本文冲突时以编号文档为准;本文保留作设计输入存档,不再逐项维护。
本文是 soft_quay_web(SoftBox 软件盒子的中央发布 / 登记系统;其 Web 管理端即本仓库
soft_quay_web)的设计规格。 权威协议以客户端仓库soft_quay/docs/api.md、soft_quay/schemas/*.json和soft_quay/testdata/catalog/canonical-vectors.json为准;本文引用而非另建一份,两者变化时同步。 状态:尚未落地,属客户端02-requirements.md第七节待确认风险。本文供另起本仓库时作为规格起点。 更新日期:2026-07-19
一、愿景
让 SoftBox 的软件发布者(自己)能够集中、安全、可审计地把自家系列软件发布给所有盒子用户:一处登记元数据、一处签名、一处托管,客户端离线即可验真。
发布者在一个后台里完成"登记软件 → 接收构建包 → 校验 → 签名 → 生成双通道清单 → 上传 → 发现新版本",而签名私钥永不离开发布系统,客户端只内置公钥。
它把整个 SoftBox 产品家族的"信任根"收敛到一处:客户端拿到的每一份清单、每一个安装包、每一张许可证,都能用内置 Ed25519 公钥离线验签,不依赖任何在线接口的可用性。
设计原则
- 静态分发优先:最终产物是放在对象存储 / CDN 上的静态签名文件,不是运行时动态 API;客户端离线验签。
- 私钥隔离至上:Ed25519 私钥是整个体系的信任根,只存在于受控签名服务,绝不进客户端、代码仓库或普通后台进程。
- 协议以客户端为权威源:清单 / 包协议 Schema 和签名向量 corpus 以
soft_quay为准,发布端字节级对齐,不另造 canonicalizer 或第二套验签域。 - 通道隔离:modern / win7 双通道全程不交叉,Win7 用户永不拿到无法启动的现代版包。
- 可审计:每次发布、下架、撤销、许可证签发都有不可否认的记录。
二、定位与范围
2.1 一句话定位
soft_quay_web = 软件登记 + 构建包接收校验 + Ed25519 签名服务 + 双通道清单生成 + 对象存储发布 + 许可证/撤销签发 + Web 管理后台;产物是静态签名文件,信任根是私钥。
2.2 做什么
见第五节功能清单。
2.3 明确不做
- 不含子软件业务源码——那些在各自
app-*仓库。 - 不含盒子的下载 / 更新 / 安装 / 授权实现——那些在
soft_quay客户端。 - 不是动态在线 API / 应用商店服务——无面向客户端的运行时接口、无账号会话;客户端只拉静态签名文件。
- 不生成未测试目标的占位包。
- 不定义第二套包级验签域——外层清单 Ed25519 签名已覆盖 package 的
url/size/sha256/signature文本(见 §6.4)。
三、与客户端的信任模型(核心)
这是本系统一切设计的出发点。客户端 soft_quay 对远端内容的信任仅来自 Ed25519 签名:
soft_quay_web(持私钥) soft_quay 客户端(内置公钥)
───────────────────────── ─────────────────────────
用受限规范 JSON + 私钥签名 ──► 拉取 → 去掉顶层 signature → 同规则规范化
生成 manifest-modern/win7.json → Ed25519 验签 → Schema/channel/架构过滤
上传对象存储 / CDN(HTTPS) → 缓存;验签失败则拒绝、退回上次可信缓存
包 url/size/sha256 写入清单 → 下载 → 同句柄 size→SHA-256→安全解压
由此推出对本系统的硬性要求:
- 规范化必须字节级一致:发布端与客户端对同一 JSON 输入必须产出逐字节相同的规范字节与签名。二者共用
canonical-vectors.jsoncorpus 作为跨实现回归基线,发布端不得用自身 canonicalizer 重新生成期望值。 - 私钥保管是最高安全目标:私钥泄露 = 可伪造任意清单/包记录/许可证 = 客户端全线沦陷。
- 客户端不做在线校验:因此下架、撤销、版本兼容都必须能"离线表达"在签名文件里(status 字段、签名撤销名单 + 宽限期)。
四、系统架构
4.1 组件
┌─────────────────────────────────────────────┐
子软件 app-* CI │ 构建标准 ZIP 包 + Release 元数据 │
└───────────────┬─────────────────────────────┘
│ 上传候选包
▼
┌──────────────────────────────────────────────────────────────┐
│ soft_quay_web │
│ │
│ ┌────────────┐ ┌────────────┐ ┌──────────────────────┐ │
│ │ Ingestion │──►│ Registry │──►│ Manifest Generator │ │
│ │ 包接收校验 │ │ 元数据/发布 │ │ 双通道清单组装 │ │
│ └────────────┘ │ 记录 (DB) │ └──────────┬───────────┘ │
│ │ └────────────┘ │ 待签名规范字节 │
│ │ size/SHA-256 ▼ │
│ │ ┌──────────────────────┐ │
│ │ │ Signing Service │ │
│ │ │ (Ed25519 私钥,隔离/ │ │
│ │ │ KMS/HSM,受限接口) │ │
│ │ └──────────┬───────────┘ │
│ │ │ 签名 │
│ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌──────────────────────┐ │
│ │ License & │ │ Web 管理端 │ │ Publisher (发布器) │ │
│ │ Revocation │ │ soft_quay_ │ │ 上传对象存储/CDN │ │
│ │ 签发 │ │ web(UI) │ │ │ │
│ └────────────┘ └────────────┘ └──────────┬───────────┘ │
│ │ 审计日志 (append-only) │ │
└────────┼──────────────────────────────────────┼──────────────┘
▼ ▼
审计/合规存档 对象存储 / CDN(静态托管)
manifest-*.json / *.zip / icons
│ HTTPS
▼
soft_quay 客户端
4.2 组件职责
| 组件 | 职责 | 不含 |
|---|---|---|
| Ingestion(接收校验) | 接收子软件 CI 的 ZIP 候选包;校验包协议结构(app.json/files.json/payload)、计算 size 与 SHA-256、比对声明版本/ID/架构 | 构建子软件、跑子软件业务 |
| Registry(登记库) | 软件元数据、发布记录、包坐标(url/size/sha256)、status、channel、Catalog 版本 | 子软件源码、客户端状态 |
| Manifest Generator | 从 Registry 按 channel 组装 manifest-modern.json / manifest-win7.json,产出待签名规范字节 |
签名(委托签名服务) |
| Signing Service | 唯一持有 Ed25519 私钥;对规范字节签名(清单/许可证/撤销名单);理想部署为 KMS/HSM 或独立最小权限服务 | 业务逻辑、任意数据签名(只签受控结构) |
| License & Revocation | 绑定 machine_hash + products 签发许可证;维护签名撤销名单 + 宽限期 | 保存原始硬件序列号/MAC |
| Publisher(发布器) | 把签名清单、ZIP 包、图标上传对象存储 / CDN;保证原子发布(先传包再切清单) | 生成未签名/未校验产物 |
| Web 管理端(soft_quay_web) | 发布者操作界面:登记/发布/下架/撤销、发布记录浏览、许可证签发、审计查看 | 直接持有私钥(经受控签名服务接口) |
| Audit | append-only 记录每次发布/下架/撤销/签发 | 可被覆盖的可变日志 |
4.3 关键边界
- 签名服务是唯一持钥点:其余组件(含 Web 后台)只能提交"受限结构 + 请求签名",拿回签名串,拿不到私钥。
- Web 管理端不等于签名端:soft_quay_web 负责人机交互与编排,签名经受控接口调用签名服务;私钥不进 Web 进程。
- 协议 Schema / corpus 单一权威源:引用
soft_quay/schemas/与canonical-vectors.json,CI 校验发布端产物能被同一份 corpus 与 Schema 通过。
五、功能清单
5.1 软件登记与元数据
维护每款软件的元数据(客户端列表页唯一来源),字段与约束见 §6.1:稳定 id、name、description、version、channel、status、category、tags、icon、homepage、tutorial、min_os、architectures、entry_exe、requires_admin、packages。
5.2 构建包接收与校验(Ingestion)
接收子软件 CI 产出的标准 ZIP 包并校验:
- 包结构:根
app.json+ 可选files.json+payload/; app.json与登记的 id/version/channel/min_os/architecture 一致;- 计算
size与SHA-256,写入发布记录; - 只接受实际支持并测试过的目标,不生成未测试平台占位包。
5.3 发布记录(Release)
每次发布登记包的下载坐标与校验信息:url(绝对 HTTPS)、size、sha256、signature(见 §6.4)。
5.4 Schema 校验(协议权威)
发布前用 soft_quay/schemas/manifest.schema.json、app.schema.json 校验:Schema 合规、无未知/重复/缺失字段、id 唯一、SemVer 合法、architectures 与 packages 键一一对应、channel 目标一致、URL 为绝对 HTTPS。
5.5 Ed25519 签名(核心)
- 签名域 = 移除顶层
signature后的受限规范 JSON(§6.3); signature为唯一标准 padded Base64;- 与客户端共用
canonical-vectors.json做跨实现回归。
5.6 双通道清单生成
产出 manifest-modern.json 与 manifest-win7.json,channel 字段隔离,互不交叉。
5.7 发布流水线
见 §七。
5.8 下架与撤销
- 软件下架用
status(active / deprecated / hidden),不改名; - 维护签名的许可证撤销名单,客户端缓存 + 网络失败宽限期。
5.9 许可证签发
绑定 machine_hash + products 签发 Ed25519 许可证(§6.5);不保存原始硬件标识。
5.10 版本 / 协议兼容管理
| 版本类型 | 示例 | 用途 |
|---|---|---|
| 产品版本 | 1.4.2 | 用户看到的软件版本 |
| SDK 版本 | sdk/core v1.2.0 | 公共能力兼容性 |
| 软件包协议 | schema_version 1 | 盒子与包的结构协议 |
| Catalog 版本 | 2026.07.16.1 | 目录发布时间 |
原则:SDK 升级不强迫历史软件立即升级;盒子至少兼容当前与前一个包协议版本;清单顶层 min_box_version 声明所需最低盒子版本。
5.11 审计
append-only 记录发布/下架/撤销/许可证签发,含操作者、时间、内容摘要、签名指纹。
六、数据与协议契约
以下字段与约束必须与
soft_quay/schemas/*.json和api.md一致;此处为发布端视角的摘要,冲突时以客户端仓库为准。
6.1 Catalog 清单 v1(manifest-{modern,win7}.json)
顶层(additionalProperties: false,全部必填):
| 字段 | 约束 |
|---|---|
schema_version |
常量 1 |
channel |
modern 或 win7 |
generated_at |
RFC3339 date-time |
min_box_version |
SemVer |
apps |
app 数组 |
signature |
Ed25519,^[A-Za-z0-9+/]{86}==$ |
每个 app(additionalProperties: false):
| 字段 | 约束 |
|---|---|
id |
^[a-z0-9-]+$,永久稳定不可变 |
name / description |
非空字符串 |
version |
SemVer 2.0.0 |
channel |
常量 stable |
status |
active / deprecated / hidden |
category |
非空(单一分类) |
tags |
非空字符串数组(≥1) |
icon |
^sha256:[0-9A-Fa-f]{64}$(内容引用,非 URL;可选) |
homepage / tutorial |
绝对 HTTPS(可选) |
min_os |
windows-7-sp1 / windows-10 / windows-11 |
architectures |
`["386" |
entry_exe |
安全相对路径(拒绝首尾空格/尾随点/DOS 设备名/反斜杠/`:<>" |
requires_admin |
布尔 |
packages |
{386?, amd64?},≥1;每个含 url/size/sha256/signature |
package 对象:url(绝对 HTTPS)、size(整数 ≥1)、sha256(64 hex)、signature(Ed25519)。
6.2 通用约定
- 传输 HTTPS,JSON UTF-8;时间 RFC3339(UTC)。
- URL 只接受无用户信息、无 fragment 的绝对 HTTPS。
- 数字仅整数 token(签名域拒绝浮点/指数/
-0,大整数保持 token 不失精度)。
6.3 签名域(必须与客户端字节对齐)
- 输入为单个 UTF-8 JSON object;拒绝重复键、尾随数据、浮点/指数数字、非法 Unicode surrogate。
- 读取顶层
signature(标准 padded Base64,严格解码为 64 字节;拒绝 CR/LF、其他空白、缺失/额外 padding),从对象移除该字段。 - 对剩余值递归规范化:对象键按 Unicode 码点升序、数组保序、字符串按 JSON 转义、数字仅整数 token、无多余空白。
- Ed25519 对上述规范字节签名。
跨实现回归:soft_quay/testdata/catalog/canonical-vectors.json 含测试公钥(public_key_base64)与向量(document / signed_payload_base64 / signature / want_error),覆盖 Unicode 键序、转义、<>&/U+2028/U+2029、合法/非法 surrogate、-0/大整数、嵌套 signature、Base64 变体。发布端 CI 必读该 corpus 断言,不得自举期望值。
6.4 package.signature 的语义(待定,见未定项)
当前客户端不独立验证 package 的 signature——其文本已被外层清单 Ed25519 签名覆盖,客户端不臆造第二套包级验签域。但 Schema 要求该字段存在且形状合法。发布端 v1 须产出形状合法的 Ed25519 串;其独立签名域(待签名字节 + 公钥)尚未定义,是未定项。
6.5 许可证(server 签发 → 客户端离线验证)
{
"schema_version": 1,
"license_id": "lic-...",
"machine_hash": "...",
"products": ["product-json-parser"],
"issued_at": "2026-07-16T00:00:00Z",
"perpetual": true,
"update_policy": "updates-until-2027-12-31",
"rebind_policy": "self-service-1-per-90d",
"signature": "..."
}
machine_hash由客户端平台层多硬件标识清洗生成;许可证不保存原始序列号/MAC。- Ed25519 签名;客户端内置公钥离线验签,保存于
licenses/,更新不覆盖。 - 撤销名单同样签名 + 客户端缓存 + 网络失败宽限期。
- 子软件用 SDK licensing 逻辑独立再验证(签名 + machine_hash + product_id)。
6.6 标准软件包协议 v1(ZIP,发布端负责接收校验)
<id>_<version>_windows_<arch>.zip
├─ app.json # schema_version/id/name/vendor/version/channel/min_os/
│ # architecture/entrypoint/working_directory/product_id/
│ # supports_trial/requires_admin/data_policy/update_policy
├─ files.json # 解压后文件清单(v1.1 强制,v1 推荐)
└─ payload/ # 实际安装文件
发布端校验 app.json 与登记一致、payload 结构合法,并计算整包 SHA-256 写入清单;data_policy 固定 local-app-data、update_policy 固定 managed-by-softbox。
七、发布流水线
子软件 CI 产出标准 ZIP 包 + Release 元数据
→ Ingestion 校验包结构 / app.json 一致性 / 计算 size + SHA-256
→ Registry 登记发布记录(url 坐标、status、channel、Catalog 版本)
→ Schema 校验(manifest/app schema)
→ Manifest Generator 组装 modern/win7 待签名规范字节
→ Signing Service 用 Ed25519 私钥签名
→ CI 用 canonical-vectors corpus + Schema 回归验证产物
→ Publisher 原子上传:先传 ZIP 包/图标到对象存储,再切换签名清单
→ soft_quay 客户端发现新版本
一个产品可产出多目标(如 json-parser_1.4.2_windows_amd64.zip、..._win7_amd64.zip、..._win7_386.zip);只生成实际支持并测试过的目标。原子性要求:包必须先于清单可用,避免客户端拿到指向尚未上传包的清单。
八、签名与密钥管理
- 私钥隔离:理想部署为 KMS/HSM 或独立最小权限签名服务;Web 后台与业务进程只经受控接口请求签名,不接触私钥材料。
- 只签受控结构:签名服务只对"清单 / 许可证 / 撤销名单"这几类已知结构签名,不对任意字节签名(防被当通用签名 oracle)。
- 公钥分发:客户端内置公钥;测试用公钥见 corpus。正式公钥的内置与更新方式随密钥轮换设计裁定。
- 审计:每次签名请求记录操作者、目标结构摘要、时间、密钥指纹。
九、技术选型建议(soft_quay_web)
待定,以下为建议,立项时在本仓库 tech-stack 文档固定。
- 形态:Web 管理后台 + 后端 API + 独立签名服务 + 对象存储集成。
- 后端语言:建议 Go(与客户端同栈,可直接复用同一套 canonical/verify 实现与 Schema,天然字节对齐;这是选 Go 的最强理由)。若选其他语言,必须用 corpus 做严格字节回归。
- 存储:发布记录用关系型库;产物用对象存储 / CDN。
- 签名:私钥入 KMS/HSM 或隔离服务;绝不入库、不进 Web 进程环境变量明文。
- 协议 Schema / corpus:以
soft_quay为权威源引用(git submodule 或版本化拷贝 + CI 校验一致),不另建。
十、未定项 / 待确认(立项前必须裁定)
| 项 | 说明 |
|---|---|
| 签名私钥管理 | 谁持有、如何保管与轮换、签发流程;私钥绝不进客户端/仓库/Web 进程 |
| 密钥 ID / 轮换字段 | 清单/许可证尚无 key ID / rotation 字段;api.md 注明"单公钥协议升级前不得另造签名域",多公钥/轮换需先做协议升级 |
| package.signature 独立语义 | v1 客户端不独立验;若要独立包级验签,需定义待签名字节 + 公钥域(见 §6.4) |
| 正式域名与对象存储 | 清单/包的正式 HTTPS 域名、对象存储/CDN 选型、带宽成本与防盗链策略 |
| 图标分发字段 | 图标从内容哈希(sha256:)到实际下载位置/分辨率变体的发布端映射格式(api.md 待实现项) |
| 撤销名单结构 | revocation list 字段结构与宽限期时长 |
| 跨仓库 CI 对齐 | 发布端消费同一 corpus / Schema 的 CI 证据需与 soft_quay(T-614)跨仓库协调 |
| 授权产品映射 | product_id 与许可证 products 的登记与映射管理 |
| 发布端形态与权限模型 | Web 后台的操作者权限、审批流(谁能发布/下架/撤销/签发) |
十一、首期落地建议
- 首期用本地 / 静态文件模拟:本地生成签名清单 + 本地 HTTP 静态服务,即可让客户端跑通"清单→下载→安装"闭环,不必先建正式对象存储。
- 私钥先用离线生成的测试密钥对(与客户端内置测试公钥、corpus
public_key_base64配对);正式私钥管理另裁。 - 先落协议对齐再落 UI:第一里程碑做到"能产出被
soft_quay客户端验签通过、被 corpus + Schema 回归通过的 manifest",再迭代 Web 管理界面。 - 协议 Schema 与 corpus 以
soft_quay为权威源引用,避免漂移。
本文为设计规格;字段与协议细节以
soft_quay/docs/api.md与soft_quay/schemas/为准,两者变化时同步本文。