# 协议合约(发布端视角摘要) > **权威源在客户端仓库**:`soft_quay/docs/api.md`、`soft_quay/schemas/*.json`、`soft_quay/testdata/catalog/canonical-vectors.json`。 > 本文是发布端视角的摘要与本仓库特有接口的合约位;字段冲突时以客户端仓库为准,协议变更必须先在客户端仓库定稿。 ## 一、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"|"amd64"]`,唯一,≥1 | | `entry_exe` | 安全相对路径(拒绝首尾空格/尾随点/DOS 设备名/反斜杠/`:<>"|?*`/`..`) | | `requires_admin` | 布尔 | | `packages` | `{386?, amd64?}`,≥1;键与 `architectures` 一一对应 | package 对象:`url`(绝对 HTTPS)、`size`(整数 ≥1)、`sha256`(64 hex)、`signature`(Ed25519 形状)。 通用约定:传输 HTTPS,JSON UTF-8;时间 RFC3339(UTC);URL 无用户信息、无 fragment;数字仅整数 token(签名域拒绝浮点/指数/`-0`,大整数保持 token 不失精度)。 ## 二、签名域(必须与客户端字节对齐) 1. 输入为单个 UTF-8 JSON object;拒绝重复键、尾随数据、浮点/指数数字、非法 Unicode surrogate。 2. 读取顶层 `signature`(标准 padded Base64,严格解码为 64 字节;拒绝 CR/LF、其他空白、缺失/额外 padding),从对象移除该字段。 3. 对剩余值递归规范化:对象键按 Unicode 码点升序、数组保序、字符串按 JSON 转义、数字仅整数 token、无多余空白。 4. Ed25519 对上述规范字节签名。 **跨实现回归**:corpus 含测试公钥(`public_key_base64`)与向量(`document` / `signed_payload_base64` / `signature` / `want_error`),覆盖 Unicode 键序、转义、`<>&`/U+2028/U+2029、合法/非法 surrogate、`-0`/大整数、嵌套 signature、Base64 变体。发布端 CI **必读该 corpus 断言,不得自举期望值**。 ## 三、package.signature 的语义(未定项) 当前客户端**不独立验证** package 的 `signature`——其文本已被外层清单 Ed25519 签名覆盖。但 Schema 要求该字段存在且形状合法。发布端 v1 须产出形状合法的 Ed25519 串;其独立签名域(待签名字节 + 公钥)尚未定义,在客户端协议升级前**不得**自行定义(见 06-tasks Backlog)。 ## 四、许可证 v1(签发 → 客户端离线验证) ```json { "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 签名;客户端内置公钥离线验签。 - 撤销名单同样签名 + 客户端缓存 + 网络失败宽限期;名单具体结构与宽限期时长是未定项(W-402)。 ## 五、标准软件包协议 v1(ZIP,发布端负责接收校验) ```text __windows_.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 的合约;各自任务落地时在本节定稿。 | 接口 | 说明 | 状态 | | --- | --- | --- | | Ingestion 提交接口 | 子软件 CI 提交候选 ZIP + Release 元数据的方式(HTTP 端点 / 对象存储投递)与认证 | 待定(W-202) | | 签名服务接口 | 受控结构 + 请求签名 → 签名串;调用方拿不到私钥;每次请求审计 | 待定(W-301) | | Web 管理端 API | 操作者认证与登记/发布/下架/撤销/签发操作 | 待定(W-501) | | 静态产物布局 | 对象存储上 manifest-*.json / ZIP / 图标的路径布局与图标 `sha256:` → 实际位置映射 | 待定(W-204 首版本地布局;图标映射见 Backlog) |