Files
ilaandClaude Fable 5 0184595ccc
Harness governance / validate (push) Has been cancelled
Add harness coding docs for SoftBox (Go + Gio dual-build)
Initialize the full harness coding document set from the
harness_coding_docs template, customized for the SoftBox project:

- Vision, requirements, tech stack (modern Go 1.25 + Gio v0.10.1;
  Win7 legacy Go 1.20.14 + Gio v0.6.0), architecture, coding rules
- Protocol contracts (signed catalog, package protocol v1, Ed25519
  license, events, CLI) and Gio view structure
- Roadmap Phase 0-6 with 20 suggested tasks; T-001 (monorepo
  skeleton) filed and ready to claim
- Agent entry points (AGENTS.md, docs/00-ai-start-here.md),
  context manifest, governance scripts and tests
- Merge Go gitignore with harness rules; keep go.work tracked

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 14:33:54 +08:00

7.8 KiB

协议合约(Catalog / 软件包 / 许可证 / 事件 / CLI)

本项目没有自建在线 API;盒子只消费静态签名文件。本文定义所有跨边界数据结构和交互合约的目标形状。 实现前可细化,但不要在代码里另起一套不兼容结构。字段变化必须同步更新本文、04-architecture.md 和 schemas/ 下的 JSON Schema。

通用约定

  • 传输:HTTPS;所有 JSON 使用 UTF-8。
  • 时间格式:ISO 8601(UTC)。
  • 签名:Ed25519;客户端只内置公钥;示例中的 "signature": "..." 均为占位符。
  • 版本号:语义化版本(SemVer)。
  • 软件 ID:^[a-z0-9-]+$,永久稳定,发布后不得更改。

1. Catalog 清单(远端 → 盒子)

现代版与 Win7 版使用不同 channel 文件:manifest-modern.json / manifest-win7.json。更新器必须校验 channel,禁止 Win7 版下载现代版包。

{
  "schema_version": 1,
  "channel": "modern",
  "generated_at": "2026-07-16T00:00:00Z",
  "min_box_version": "1.0.0",
  "apps": [
    {
      "id": "json-parser",
      "name": "JSON解析工具",
      "description": "示例简介",
      "version": "1.2.0",
      "channel": "stable",
      "status": "active",
      "tags": ["工具", "JSON"],
      "icon": "sha256:...",
      "homepage": "https://example.com",
      "tutorial": "https://example.com/tutorial",
      "min_os": "windows-7-sp1",
      "architectures": ["386", "amd64"],
      "entry_exe": "JsonParser.exe",
      "requires_admin": false,
      "packages": {
        "amd64": {
          "url": "https://download.example.com/json-parser-1.2.0-amd64.zip",
          "size": 12345678,
          "sha256": "...",
          "signature": "..."
        }
      }
    }
  ],
  "signature": "..."
}

行为要求:

  • 网络成功:验签通过才替换本地缓存;验签失败拒绝,继续用最后一次验证成功的缓存。
  • 网络失败:用缓存;清单过期给提示,但保留已安装软件的启动能力。
  • 下架:显式 status: deprecated | hidden,不用名称前缀。
  • 过滤:按 min_os 与 architectures 过滤;不兼容软件可见说明但不可下载。

2. 标准软件包协议 v1(ZIP)

json-parser_1.4.2_windows_amd64.zip
├─ app.json      # 身份、版本、入口、兼容性
├─ files.json    # 解压后文件清单(v1.1 强制,v1 推荐)
└─ payload/      # 实际安装到 current/ 的程序文件

2.1 app.json

{
  "schema_version": 1,
  "id": "json-parser",
  "name": "JSON解析工具",
  "vendor": "MyCompany",
  "version": "1.4.2",
  "channel": "stable",
  "min_os": "windows-7-sp1",
  "architecture": "amd64",
  "entrypoint": "JsonParser.exe",
  "working_directory": ".",
  "product_id": "product-json-parser",
  "supports_trial": true,
  "requires_admin": false,
  "data_policy": "local-app-data",
  "update_policy": "managed-by-softbox"
}

校验规则:entrypoint/working_directory 必须是 payload 内安全相对路径;id、version、channel、architecture 必须与 Catalog 记录一致;schema_version 高于盒子支持范围时拒绝安装并提示升级盒子(盒子始终支持当前与前一个 Schema)。

2.2 files.json

{
  "schema_version": 1,
  "files": [
    { "path": "JsonParser.exe", "size": 3456789, "sha256": "..." }
  ]
}

完整 ZIP 的 SHA-256 由签名 Catalog 保存(不写入包内部);files.json 用于解压后复核关键文件与修复功能。

2.3 安全限制(必须拒绝)

绝对路径;../ 穿越;符号链接/重解析点逃出 staging;写入其他软件或盒子目录;覆盖 data/ 与 licenses/;包内自动执行脚本(install.bat/PowerShell 钩子);未验证 SHA-256/签名的包被执行;解压文件数、总体积或压缩比无上限;entrypoint 指向 payload 之外。

2.4 安装记录 installed-app.json(本地)

记录实际安装的软件 ID、版本、架构、channel 和文件清单;与 current/、staging/、backup/ 同级存放于 apps/<id>/。

3. 许可证(服务端签发 → 本地离线验证)

{
  "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),决定正式版/试用版/授权错误。

4. application 事件合约(core → UI)

后台任务不直接修改 Gio 控件,只发布事件;UI 按 request_id + app_id 更新 ViewModel 并 Invalidate。

事件 触发时机 负载 结果
CatalogRefreshed 清单验签并缓存成功 catalog 摘要、generated_at 列表刷新
CatalogRejected 清单验签失败 原因码 提示 + 继续用缓存
DownloadStarted 下载任务开始 request_id, app_id 状态 → downloading
DownloadProgress 进度更新 request_id, app_id, done, total, speed 进度条刷新
DownloadPaused 用户暂停 request_id, app_id 状态 → queued(暂停态)
DownloadCompleted 下载并校验通过 request_id, app_id 状态 → verifying/extracting
DownloadFailed 失败(网络/哈希/磁盘) request_id, app_id, error_code 状态 → failed + 可重试
InstallCompleted 原子切换成功 + 健康检查通过 app_id, version 状态 → installed
InstallRolledBack 切换失败恢复 backup app_id, error_code 状态 → rollback 完成提示
AppStarted / AppExited 进程启动/退出检测 app_id, pid 状态 → running / installed
LicenseChanged 许可证导入/撤销 products 授权视图刷新

错误码为稳定英文枚举(如 hash_mismatch, zip_path_escape, disk_full, app_running, signature_invalid),UI 负责本地化文案。

5. CLI 参数合约

5.1 SoftBox.exe

SoftBox.exe                          # 正常启动
SoftBox.exe --open-app <id>          # 打开并定位到指定软件
SoftBox.exe --update-app <id>        # 触发指定软件更新流程
SoftBox.exe --repair-app <id>        # 按 files.json 修复安装(V1.1)

子软件的「检查更新」按钮调用以上参数,不自建下载器;盒子未运行时子软件可启动它。

5.2 SoftBoxUpdater.exe(盒子自更新助手)

SoftBoxUpdater.exe --pid <主程序PID> --staging <暂存目录> --target <目标目录>

等待主进程退出 → 备份旧版 → 切换新版 → 启动新版 SoftBox → 失败时恢复备份。退出码:0 成功;非 0 失败并写日志。

5.3 子软件推荐参数(v1 推荐,非强制)

<App>.exe --softbox-info      # 输出软件 ID、版本、架构、协议版本 JSON,退出码 0
<App>.exe --softbox-health    # 基本环境自检,成功退出码 0

产品自定义参数不得占用 --softbox- 前缀。

6. 进程退出协议(更新前)

v1:进程快照判断运行 → 提示用户保存关闭 → 等待正常退出 → 超时取消更新,不默认强杀。 V1.1:命名管道 \\.\pipe\softbox.<app-id>,盒子发送 {"command": "prepare_update", "request_id": "..."},子软件保存数据回复 ready 后自行退出。

待实现时确认

  • 清单签名封装格式(签名域、密钥轮换字段)定稿后同步 schemas/。
  • 错误码完整枚举表。
  • 图标资源的分发方式(内嵌哈希 vs 独立 URL)。
  • 撤销名单的结构与宽限期时长。
  • machine_hash 的标识来源清单与加权算法(平台层内部文档)。