Skip to content

Commit 6c4d208

Browse files
committed
feat(traces): decode non-delta pack structure into bounded objects
Signed-off-by: ELi Ma <eli@patch.sh>
1 parent 6a596ea commit 6c4d208

6 files changed

Lines changed: 778 additions & 14 deletions

File tree

‎Cargo.lock‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mega2"
3-
version = "0.42.64"
3+
version = "0.42.65"
44
edition = "2024"
55
license = "MIT OR Apache-2.0"
66
description = "Monorepo engine and Git hosting server for AI agents: trunk-based storage, Git Smart HTTP, Git LFS, OCI registry, and Agent Session Capture"

‎docs/plan/plan-20261015.md‎

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7269,7 +7269,7 @@ MTR94 v0.42.58完整C/D已核、done/complete;93继承精确94覆盖而done/co
72697269

72707270
**Task type:** `implementation`
72717271

7272-
**Lifecycle / Acceptance:** `pending` / 空
7272+
**Lifecycle / Acceptance:** `in-progress` / `remote-pending`(8AC/3VER、ER-05 R6真实Claude/Codex双PASS与bump后完整C已核;tag/Release后待Docker D)
72737273

72747274
**Description:** 实现无delta Git PACK的结构校验和原始对象解码。输出不是可信identity;SHA1/SHA256对象身份验证正式由98负责,两hash原始bytes fixture回归仍保留。新增`ceres::traces::pack_decode`内部模块,接受明确hash kind和有界输出sink契约,保留原始payload;接口不接入HTTP/SSH,也不直接发布。96自身交付完整结构解析轴,生产wire安全准入由97封闭后才允许98/11消费。
72757275

@@ -7294,22 +7294,24 @@ MTR94 v0.42.58完整C/D已核、done/complete;93继承精确94覆盖而done/co
72947294

72957295
**ER-03 依赖决策(root,2026-10-23):** 不新增/提升 `flate2` 直接依赖;逐对象膨胀复用 git-internal 公开的 `internal::zlib::stream::inflate::ReadBoxed::new_with_kind`,把其 `Read` 输出接入本模块的有界 sink。PACK 的 magic/version/count/trailer/截断/尾随垃圾与两种 delta 拒绝仍由本模块自行实现;该复用不改变 I/R、AC/VER 或依赖边。
72967296

7297+
**2026-10-23 实际A/B(本轮):** 新模块 `ceres::traces::pack_decode` 落地并由 `ceres::traces::mod` 真实注册;解码器显式接收 `HashKind`,复用 git-internal 公开 `ReadBoxed::new_with_kind` 逐对象流式膨胀,按 ≤64 KiB 分块写入 `PackSink`,全程不缓存整个 pack、不派生 OID。真实 git fixture(`git init --object-format=sha1|sha256` + `git hash-object -w` + `git -c pack.window=0 -c pack.depth=0 pack-objects --stdout`)覆盖普通 blob、非 UTF-8 blob、真正入包的 empty tree 与含 `gpgsig` 的 commit;SHA1/SHA256 两 hash 逐对象字节与类型全等,trailer 实际校验通过。拒绝矩阵:magic、version、count±1、trailer、截断、尾随垃圾、对象 size 变长整数溢出(`SizeOverflow`),以及两种真实 git delta 包:默认 pack 含 REF_DELTA(type 7)、`--delta-base-offset` pack 含 OFS_DELTA(type 6),测试先逐对象扫描 pack header 断言目标类型存在,再分别断言解码返回 `Delta`。A:`pack_structure_` 过滤 8/8 通过、exit0(含「声明长度大于实际流且无 trailer」的 inflate-time EOF 用例)。错误映射:底层耗尽/payload 提前结束与 header/trailer 截断为 `Truncated`;完整 zlib 流但声明长度更大为 `Size{declared,actual}`;损坏 deflate 为 `Inflate`;底层 IO 错误保留其种类;size 变长整数按位移/加法溢出拒绝(`SizeOverflow`)。VER-3 手工核:新模块仅被 `tests` 使用,HTTP/SSH/RepoHandler 无新调用,sink 预算留给 97。ER-05 经 6 轮收敛为 R6 真实 Claude/隔离 Codex 双 `VERDICT: PASS`(无 P0/P1)。完整 C(bump 0.42.65 后最终树):`cargo +nightly fmt --all --check`、`cargo clippy --all-targets --all-features -- -D warnings`、`source .env.test && cargo test --all`(20 targets、3028 passed、0 failed、3 原有 ignored、0 filtered)、`cargo build`、`cargo build --tests` 均 exit0、0 警告/0 错误(`/tmp/mtr96_C.log`、`/tmp/mtr96_test.log`)。提交、tag/Release 与 D 随后取得。
7298+
72977299
**Acceptance criteria:**
72987300

7299-
- [ ] AC-1: PACK magic正确。
7300-
- [ ] AC-2: PACK版本被支持。
7301-
- [ ] AC-3: 声明对象count与实际对象数一致。
7302-
- [ ] AC-4: pack trailer校验失败时拒绝。
7303-
- [ ] AC-5: 截断PACK拒绝。
7304-
- [ ] AC-6: 尾随垃圾拒绝。
7305-
- [ ] AC-7: ref-delta拒绝。
7306-
- [ ] AC-8: ofs-delta拒绝。
7301+
- [x] AC-1: PACK magic正确。
7302+
- [x] AC-2: PACK版本被支持。
7303+
- [x] AC-3: 声明对象count与实际对象数一致。
7304+
- [x] AC-4: pack trailer校验失败时拒绝。
7305+
- [x] AC-5: 截断PACK拒绝。
7306+
- [x] AC-6: 尾随垃圾拒绝。
7307+
- [x] AC-7: ref-delta拒绝。
7308+
- [x] AC-8: ofs-delta拒绝。
73077309

73087310
**Verification:**
73097311

7310-
- [ ] VER-1: `source .env.test && cargo test -p mega2 --lib ceres::traces::pack_decode::tests::pack_structure_valid_ -- --test-threads=1`(new;cfg(test)调用生产decoder;真实Git hash-object/pack-objects生成SHA1/SHA256 fixture,含原始header/gpgsig/非UTF8,逐对象比原bytes)。
7311-
- [ ] VER-2: `source .env.test && cargo test -p mega2 --lib ceres::traces::pack_decode::tests::pack_structure_reject_ -- --test-threads=1`(new;从真实pack逐项修改magic/version/count/trailer/截断/尾随;真实Git产生两种delta包并确认确实含目标delta后断言拒绝)。
7312-
- [ ] VER-3: 手工审查可见性及调用图:新模块只向受控后继暴露内部接口;HTTP/SSH/普通RepoHandler没有新调用。记录待97完成的sink约束,不声称96独自具备可暴露wire接收能力。
7312+
- [x] VER-1: `source .env.test && cargo test -p mega2 --lib ceres::traces::pack_decode::tests::pack_structure_valid_ -- --test-threads=1`(new;cfg(test)调用生产decoder;真实Git hash-object/pack-objects生成SHA1/SHA256 fixture,含原始header/gpgsig/非UTF8,逐对象比原bytes)。
7313+
- [x] VER-2: `source .env.test && cargo test -p mega2 --lib ceres::traces::pack_decode::tests::pack_structure_reject_ -- --test-threads=1`(new;从真实pack逐项修改magic/version/count/trailer/截断/尾随;真实Git产生两种delta包并确认确实含目标delta后断言拒绝)。
7314+
- [x] VER-3: 手工审查可见性及调用图:新模块只向受控后继暴露内部接口;HTTP/SSH/普通RepoHandler没有新调用。记录待97完成的sink约束,不声称96独自具备可暴露wire接收能力。
73137315

73147316
**Dependencies:** `MTR-95, MTR-93`。消费限定:MTR-95仅为串行发布边;MTR-93中07/09/45当前资格及既有HashKind契约。不得把96自身PASS当作97预算门通过。
73157317

‎docs/refactoring/traces.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ traces/v1/staging/<ingest-uuid>/...
7979

8080
已落地的引用发布只接受唯一 ref `refs/libra/traces`。删除、非快进、父数大于 1 的新提交、改掉已有 checkpoint 的 `original_tree`,或让已有 checkpoint 从本次提交中消失,都拒绝,并且不改 tip、membership 或 journal。通过校验后,同一数据库事务把本次对象 membership 标为可见、用当前 tip 做 CAS 更新 `trace_stream.tip_oid`,并追加一条 `trace_ref_update`。同一 old tip 的并发发布只有一个事务成功。同一 idempotency key 在 tip 已经是该 new tip 时返回原 journal,不再写第二条。对象字节在该事务开始前写入 `traces` namespace;事务失败时这些字节仍不可见。已知 schema 标识是 `manifest-v1` 与 `metadata-v2`。其它 schema 仍按上述规则归档,发布结果标为 `unsupported`,不拒绝这次引用更新。同一事务在写入 membership、移动 tip 或追加 journal 之前重查 credential 仍未退役、target 仍在本次授权路径上处于 active、binding generation 与发布前一致,以及调用者对这条当前路径仍有写权限。解包期间 credential 退役,或 target 改到别的路径,都会拒绝这次发布,并且不移动 tip、membership 或 journal。没有出示 credential 时这次拒绝是 `unauthenticated`;其余重查失败是 `unknown_scope`,不收成 `invalid_parameter`。Mono 账户的写权限在这次事务里读取进程当前的 Cedar 快照;解包前留下的快照不能放行。快照缺失或该快照被标记为 dirty 时拒绝。`off` 不消费快照,因此拒绝。`shadow` 仍按这份当前快照的 Cedar 决定,不会把代码推送里的 shadow 放行当成 traces 写权限。
8181

82+
内部 PACK 结构解码器 `ceres::traces::pack_decode` 只校验 PACK magic、版本、声明对象数、逐对象类型/长度、zlib 载荷、trailer 摘要与流结束,并显式接收 hash kind;它把每个对象以不超过 64 KiB 的分块写入调用方 sink,不缓存整个 pack,也不派生可信 OID。`ref-delta` 与 `ofs-delta` 在对象头即拒绝。该模块当前没有 wire 消费者;资源准入、quarantine 与身份验证仍分别由 MTR-97/98 接入。
83+
8284
已落地的解包先把 loose object 写入 `traces/v1/staging/<ingest-uuid>/objects/...`。这个前缀不是已发布 object key,也不读取其它 stream 或 `git` namespace 里的基对象。`ref-delta` 与 `ofs-delta` 直接拒绝。每个 blob、tree、commit、tag 的声明 OID 按 Git `type size\\0payload` 用 sha1 或 sha256 重算,不符则拒绝并且不把该对象写入已发布 key。commit、tag、tree 引用的对象必须已经在本次 quarantine 或本 stream 已归档字节中,否则在 ref 发布前拒绝。即将成为可见 membership 的每个 OID,包括 new tip,也必须已经在本 stream 有字节,否则不发布 ref。压缩字节数超过 512 MiB,或本次累计解包字节数超过 1 GiB,立即停止,超限的那个对象不写入 quarantine。staging 恢复只删除尚未出现在可见 `trace_object` membership 中的暂存对象;可见 membership 和已发布 object key 在崩溃恢复时保留。同一次解包还拒绝超过 100,000 个对象、10,000 个新 commit、64 层 delta 或 tree、300 秒接收时限,以及单个对象超过 64 MiB 的尝试。这些上限读取 `TracesProtocolLimits`。超限或取消本次 worker 时不写入该对象,也不发布 ref;取消会清掉这次 worker 上的计数。闭包通过之后、ref 发布之前,本次每个新 commit 里 `checkpoint/<prefix>/<rest>/` 下的 `metadata.json` 与 `manifest.json` 还要按原始 blob 字节对照 `MAX_METADATA_BYTES` 与 `MAX_MANIFEST_BYTES`。其它路径上的同名文件不走这道门。超限不发布 ref。
8385

8486
每次 push 只允许更新唯一 `refs/libra/traces`;拒绝额外 ref、删除、非 FF、force rewrite 与 merge commit。对所有新提交逐一校验:已有 checkpoint ID 的 subtree/tree OID 不变且不删除,新增内容必须使用新 ID;不能只比较最终 tip 从而漏掉中途篡改。

‎src/ceres/traces/mod.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ pub mod auth;
33
pub mod cleanup;
44
pub mod error;
55
pub mod ingest;
6+
pub mod pack_decode;

0 commit comments

Comments
 (0)