fix(release):完善当前分发证明与质量门禁
bat-rust / Build and test Rust (push) Canceled after 0s
bat-rust / Build and test Go API (push) Canceled after 0s

This commit is contained in:
2026-09-14 06:39:47 +08:00
parent c17904ee1c
commit 13b0bd5b45
39 changed files with 1590 additions and 228 deletions
@@ -371,10 +371,10 @@ JSON-RPC 2.0 服务,是面向上层服务(Go 层)的**主要跨语言边
- CDN path 支持 `GET` / `HEAD` / Range / 条件请求;ETag 优先使用 download
manifest 中的 BLAKE3,响应包含 Last-Modified、Accept-Ranges 和长期缓存头。
- 版本/清单发现优先走 RPC:先 `daemon.status`,再 `daemon.doctor`,再读取
Rust `release.status` 的 whole-release `official_distribution_ready`,最后
读取 `catalog.status` / `resource.manifest`(可用 `--socket` 指定 socket 文件)。
Go 不重新实现 release verifier;普通 current CDN 只有在该 Rust health fact
和本地只读 manifest 快照都允许时才分发。
Rust 轻量 `release.attestation`,最后按 attested release/publication/manifest
identity 读取 `catalog.status` / `resource.manifest`(可用 `--socket` 指定 socket
文件)。Go 不重新实现 release verifier;普通 current CDN 只有在 attestation
fresh/ready、分页快照完整且本地只读路径检查都允许时才分发。
- `/v1/releases``/v1/distribution` 和受保护的 `/admin/releases/status`
`/admin/releases` 只转发 `release.status/list/distribution` 的 Rust typed
结果;localized 或历史分发不会绕过 Rust 完整性判断。
+5 -4
View File
@@ -92,7 +92,7 @@
### 2.1 双 release 读写边界
Rust `bat``release.status` 是 official/localized 的统一只读视图,基于既有
Rust `bat``release.status` 是 official/localized 的统一重型只读视图,基于既有
version state、current symlink、release manifest、文件系统和必要的 CAS/reference
元数据计算,不建立第二个 release 数据库。`release.list` 返回两个 namespace 的当前
与历史 release,包含稳定 ID、created/published、source official relation、生命周期、
@@ -382,10 +382,11 @@ Addressables 改写后客户端拼接:
1. `daemon.status`
2. `daemon.doctor`
3. `release.status`,消费 Rust 返回的当前 official `official_distribution_ready`
及其 `status` / `status_code` / integrity 事实
3. `release.attestation`,消费 Rust 当前 official `ready`、release/publication/
manifest identity、verification generation、freshness 和 integrity 事实
4. `catalog.status``version.resource_root``addressables_root`、app/bundle
5. `resource.manifest` 分页(url / destination / bytes / blake3
5. `resource.manifest` 分页(请求携带 release/publication/manifest identity;响应每页
返回同一组 identity、generation、total、offset、limit
6.`resource_root` 上 Lstat 校验 Present / size;该检查只验证 Go 读快照,
不替代 Rust release verifier
+1 -1
View File
@@ -45,7 +45,7 @@ make check-docs
说明:
1. 默认 Go 测试只覆盖正式 `bat-api` 依赖的纯 Go 包:`internal/api``internal/backendrpc``make test-go-ffi` / `make test-go-all` 才会包含 FFI 和试验 CLI。
2. `golangci-lint` 当前仍是 optional gate;命令可用时执行并失败即阻断,不可用时明确输出 skipped 及原因
2. `golangci-lint 2.12.2` 是 required gate;版本由 `scripts/ci-versions.sh` 固定,工具缺失或版本不匹配直接失败
3. `make format` / `make fmt` 会修改工作树;`make ci-check``make check``make test``make lint` 不应格式化源码。
4. 官方同步相关修改必须额外运行 `cargo test -p bat-infrastructure --bin bat -- --nocapture`
+1 -1
View File
@@ -439,7 +439,7 @@ BAT_API_TRUST_PROXY_HEADERS=true
否则保持默认 `false``bat-api` 会按 TCP peer IP 做限流和日志归因。应用层访问日志只记录 path,不记录 query string,避免 query token 进入日志。动态 JSON 响应使用 `Cache-Control: no-store`;CDN 字节路径仍使用长期 immutable 缓存。
不要在生产 env 里设置 `BAT_API_RESOURCE_ROOT``bat-api` 会按 `BAT_API_REFRESH_INTERVAL` 周期通过 RPC 重新读取 `catalog.status` / `resource.manifest`,从而跟随 Rust `bat` 切换 `current -> versions/<id>`
不要在生产 env 里设置 `BAT_API_RESOURCE_ROOT``bat-api` 会按 `BAT_API_REFRESH_INTERVAL` 周期通过 RPC 读取当前 official `release.attestation`,再以同一 release/publication/manifest identity 请求 `resource.manifest`,从而跟随 Rust `bat` 切换 `current -> versions/<id>`attestation 过期或分页代际不一致时 fail closed
### 健康检查
+5 -3
View File
@@ -143,14 +143,16 @@ UnityFS / AssetBundle / Addressables / TypeTree 解析当前按路线图继续
make ci-check
```
`make ci-check` 是只读门禁入口;`make format` / `make fmt` 才会修改源码。缺少
`golangci-lint` 时,Go lint 作为 optional gate 明确输出 skipped,不会伪报全部门禁通过。
`make ci-check` 是只读门禁入口;`make format` / `make fmt` 才会修改源码。
required 的 `golangci-lint 2.12.2``scripts/ci-versions.sh` 固定,缺失或版本不匹配
都会失败,不会伪报全部门禁通过。
Go 边界与进度以 `docs/reports/GO_STATUS.md` 为准:
- **同步/运维命令行** = Rust `bat`(近乎全自动)
- **资源 bootstrap/分发服务与内嵌 dashboard** = `cmd/bat-api``make build-go-api`
- **默认 Go 门禁** = `make ci-check` 中的纯 Go API test/vet/build(无 FFI
- **默认 Go 门禁** = `make ci-check` 中的纯 Go API test/vet/build
`golangci-lint 2.12.2`(无 FFI
- 试验 CLI 产物为 `bin/bat-go``make build-go-cli`),**禁止**与 Rust `bat` 重名
- 修改 FFI 时再跑 `make test-go-ffi`
+15 -5
View File
@@ -104,8 +104,8 @@ contract 为准,不应绕过 daemon 状态文件或扩展 `bat-ffi` 作为主
| `resource.sync` | 已实现 | `{ "force": false }` | `{ "task_id": "...", "kind": "resource.sync" }`。 |
| `resource.verify` | 已实现 | `null` | `{ "task_id": "...", "kind": "resource.verify" }`。 |
| `resource.repair` | 已实现 | `null` | `{ "task_id": "...", "kind": "resource.repair" }`。 |
| `resource.manifest` | 已实现 | `{ "offset": 0, "limit": 100 }` | 当前 download manifest 分页。 |
| `resource.list` | 已实现 | `{ "offset": 0, "limit": 100 }` | `resource.manifest` 的兼容别名。 |
| `resource.manifest` | 已实现 | `{ "release_id": "...", "expected_publication_identity": "...", "expected_manifest_identity": "...", "offset": 0, "limit": 100 }` | 绑定一个 Rust attested official generation 的 download manifest 分页。 |
| `resource.list` | 已实现 | `resource.manifest` | `resource.manifest` 的兼容别名。 |
| `resource.index` | 已实现 | `{ "offset": 0, "limit": 100, "type": "asset_bundle", "hash": "...", "path_pattern": "*", "release_id": "...", "platform": "windows", "destination": "...", "archive_entry": "...", "parse_status": "parsed", "format": "json" }` | 当前 `ResourceRepository` 分页/过滤查询。 |
`resource.repair` 会开启本地 manifest audit + repair,不继承 `force`
@@ -119,6 +119,14 @@ SQLite `ResourceRepository`,索引不存在时返回 `ok=true` 且
属于 `parse.text_units` / `parse.errors` 的对象级查询。`limit` 范围是
`1..=1000`,非法参数返回 `BAT-ERR-700002`
`resource.manifest` 的请求必须携带由 `release.attestation` 返回的
`release_id``expected_publication_identity``expected_manifest_identity`
每一页返回 `release_id``resource_root``manifest_version`
`publication_identity``mapping_identity``manifest_identity``generation`
`total_entries``offset``limit``entries`。Rust 在当前 release 切换或 identity
不匹配时拒绝请求;Go 会逐页验证这些字段、页 offset、total 和最终 entry count
任何一页不一致都会丢弃整个候选快照。
`resource.index``entries[]``Resource` JSON,除 `id``local_path`
`entry` 外会包含 `metadata``official_release_id``platform`
`bundle_path``archive_entries``parse_statuses``unity_versions`
@@ -176,7 +184,8 @@ SQLite `ResourceRepository`,索引不存在时返回 `ok=true` 且
| 方法 | 状态 | params | data |
|---|---|---|---|
| `release.status` | 已实现 | `null` | official/localized current、source relation、match、历史 release 和 manifest/artifact/distribution integrity 统一视图;`official_distribution_ready` 是 bat-api 普通 current release readiness/distribution 使用的 Rust-owned whole-release health fact。 |
| `release.attestation` | 已实现 | `null` | 当前 official 的轻量 health/publication proof`available``ready``channel``release_id``resource_root``publication_identity``mapping_identity``manifest_identity``entry_count``integrity_status``status``status_code``verification_generation``verified_at``max_age_seconds` 和 diagnostics。只读取 current、publication anchor、manifest 元数据与 freshness,不扫描历史 release 或计算资源文件 BLAKE3。 |
| `release.status` | 已实现 | `null` | official/localized current、source relation、match、历史 release 和 manifest/artifact/distribution integrity 的重型管理诊断,仍返回管理侧 `official_distribution_ready`;普通 current bat-api readiness 使用 `release.attestation`。 |
| `release.list` | 已实现 | `{ "channel": "official" }``{ "channel": "localized" }`,可省略 | 对应 namespace 的历史 release 摘要,包含 stable ID、created/published、current pointer、`rollback_available`、lifecycle、`stale`/`damaged`/`referenced`/`unknown`、legacy 和诊断。 |
| `release.distribution` | 已实现 | `{ "channel": "official", "release_id": "...", "destination": "...", "offset": 0, "limit": 1000 }`,均可省略 | Rust 只选择具有独立 `official-distribution-publication.json` 且 identity 与当前 manifest 一致的 verified `resource_root`;有 `destination` 时是 single-entry lookup,响应固定 `total=1, offset=0, limit=1, entries.length=1`,使用 published mapping identity/destination index,只校验该实际文件的 bytes/BLAKE3,不重新执行全量映射或资源 audit;无 `destination` 时保留管理查询分页语义。localized 还必须匹配 source official 的 published identity,并使用发布时生成的实际字节 metadata,不复用 official size/hash;默认 channel 为 official,选择失败返回 `available=false`,不跨 channel fallback。 |
| `release.cleanup` | 已实现 | dry-run `{ "execute": false }`;执行 `{ "execute": true, "plan_id": "..." }` | cleanup plan、candidate/retain reasons、blocking references 和 removed paths;执行前会重新生成并比对 `plan_id`。 |
@@ -565,8 +574,9 @@ CLI 对应关系:
| Go 接口 | 允许调用的 RPC | 用途 |
|---|---|---|
| `Backend` | `daemon.status``daemon.doctor``resource.state``catalog.status``resource.manifest` | 启动发现、周期刷新和资源分发基础数据 |
| `ReleaseStatusBackend` | `release.status` | 启动发现和周期刷新使用 Rust-owned whole-release distribution healthGo 不重新实现 verifier |
| `Backend` | `daemon.status``daemon.doctor``resource.state``catalog.status``release.attestation`、绑定后的 `resource.manifest` | 启动发现、周期刷新和资源分发基础数据 |
| `AttestationBackend` | `release.attestation` | current official 轻量 health/publication proof;不触发历史 release 扫描 |
| `ReleaseStatusBackend` | `release.status` | 鉴权管理面的 official/localized 重型 release 诊断;Go 不重新实现 verifier |
| `ControlBackend` | `daemon.restart``daemon.reload``daemon.refresh``resource.sync``resource.verify``resource.repair``catalog.refresh` | 鉴权后的管理控制白名单 |
| `ScheduleBackend` | `schedule.list``schedule.add``schedule.update``schedule.remove``schedule.run` | 鉴权后的 dashboard 调度计划控制 |
| `DaemonLogsBackend` | `daemon.logs` | 鉴权后的 daemon 日志尾部查询 |
+5 -3
View File
@@ -76,9 +76,11 @@ launcher 资源引导兼容、只读 CDN path、readiness、OpenAPI、鉴权管
dashboard;翻译任务和 Rust-owned TM 的 summary/query/confirm 也通过 typed RPC
转发。Rust `bat` 继续拥有资源发现、下载、校验、staging、发布、任务和长期状态。
普通 current release 的 readiness、bootstrap、release summary 和 CDN 共用
Rust `release.status.official_distribution_ready` whole-release health factGo
只建立 manifest 的读快照,不复制 Rust verifier。`make ci-check` 是只读统一门禁,
缺少 `golangci-lint` 时明确报告 optional skipped。
Rust `release.attestation` 是 current official 的轻量 health/publication proof,带
release/publication/manifest identity、verification generation、freshness 和诊断;Go
只建立绑定同一代际的 manifest 读快照,不复制 Rust verifier。`release.status` 仍保留
为重型管理诊断。`make ci-check` 是只读统一门禁,required `golangci-lint 2.12.2`
缺失或版本不匹配直接失败。
仍需完成:
+4 -4
View File
@@ -61,11 +61,11 @@
| ID | 约定 |
|---|---|
| F | 版本/清单经 **`bat.sock` JSON-RPC**`--socket`);不读 daemon 内部状态文件 |
| G | RPC 顺序:先 **`daemon.status`**,再 **`daemon.doctor`**,再 **`release.status`**,再 catalog/manifest |
| G | RPC 顺序:先 **`daemon.status`**,再 **`daemon.doctor`**,再轻量 **`release.attestation`**,再 catalog/manifestmanifest 请求绑定 attested release/publication/manifest identity |
| H | 生产文件字节从 RPC 返回的 `resource_root` 读盘;`bat-api` 与 daemon 同服务器/同容器/共享文件系统部署;`--resource-root` 仅 fixture 或应急只读诊断 |
| I | 生产中 Rust `bat``bat-api` 在同一主机/容器/共享文件系统;开发用 `/tmp` fixture 和真实本地 `bat.sock` smoke,不依赖远程连接 |
| J | Go 索引以 **manifest + 磁盘 Present/size** 建立可读快照,但不将其当作 release integrity |
| J2 | RPC 状态以 Rust 返回的 `status` / `status_code` 为准;`release.status.official_distribution_ready` 是普通 current 分发的 whole-release 授权事实,`bat-api` 只读消费,不自行推导 verifier |
| J2 | 普通 current 分发以 Rust `release.attestation``ready`、identity、freshness 和 integrity/status code 为准;`bat-api` 只读消费,不自行推导 verifier`release.status` 保留为重型管理诊断 |
### 进程配置
@@ -86,7 +86,7 @@
| O | 权威文档与 `go list` 一致,禁止「API 完全没有」等过时句 |
| P | 试验 CLI 产物 **`bin/bat-go`**,禁止 `bin/bat` |
| Q | 空目录标明 reserved empty |
| R | 默认门禁:`make ci-check`;其中 Go 使用纯 API test/vet/build(无 FFI),`golangci-lint` 为明确报告的 optional gate |
| R | 默认门禁:`make ci-check`;其中 Go 使用纯 API test/vet/build、required `golangci-lint 2.12.2`(无 FFI),缺失或版本不匹配失败 |
---
@@ -95,7 +95,7 @@
| 组件 | 路径 | 状态 | 说明 |
|---|---|---|---|
| Module | `go.mod``bat-api` | 已用 | 服务层模块名 |
| RPC client | `internal/backendrpc` | **完成** | Unix socket JSON-RPC transport + typed helpertyped helper 覆盖 daemon 已实现控制/查询、`resource.state/sync/verify/repair/manifest/list``release.status/list/distribution/cleanup``catalog.*``parse.*``localized.status/publish/rollback``task.*``translation.tasks``translation.handoff``translation.task.update``translation.worker.run``translation.proofread``translation.memory.summary/query/confirm``translation.glossary.summary/query/diagnose/add/update/approve/deprecate/delete` 和文件级 UnityFS patch 调用;`localized.publish` 的 typed params 支持 `translation_file``from_worker``patch_manifest` 三选一;`resource.index``patch.apply` 仍通过通用 `Call` 走同一 contractfake transport 单测和 `internal/api/testdata/contract/` mirror test 固化 Rust 输出字段 |
| RPC client | `internal/backendrpc` | **完成** | Unix socket JSON-RPC transport + typed helpertyped helper 覆盖 daemon 已实现控制/查询、`resource.state/sync/verify/repair/manifest/list``release.attestation/status/list/distribution/cleanup``catalog.*``parse.*``localized.status/publish/rollback``task.*``translation.tasks``translation.handoff``translation.task.update``translation.worker.run``translation.proofread``translation.memory.summary/query/confirm``translation.glossary.summary/query/diagnose/add/update/approve/deprecate/delete` 和文件级 UnityFS patch 调用;`resource.manifest` typed params 固定 release/publication/manifest identity`localized.publish` 的 typed params 支持 `translation_file``from_worker``patch_manifest` 三选一;`resource.index``patch.apply` 仍通过通用 `Call` 走同一 contractfake transport 单测和 `internal/api/testdata/contract/` mirror test 固化 Rust 输出字段 |
| 资源 bootstrap/分发 | `cmd/bat-api` + `internal/api` | **MVP+生产控制面** | RPC 发现 + 周期刷新/诊断 + `/v1/bootstrap` + `/v1/launcher/bootstrap` + `/v1/releases` + `/v1/distribution` + launcher 资源 metadata 兼容 + `/readyz` + CDN Range/缓存头 + 鉴权/限流/访问日志/反代适配 + OpenAPI + 管理控制白名单 + release/localized/TM/Glossary admin forwarding + 内嵌 dashboard + `.env` |
| 试验 CLI | `cmd/bat` | **试验** | doctor 固定 okmanifest/sync 走 FFI |
| FFI | `internal/ffi` | **可选** | 需 `build-ffi` |