Signed-off-by: Feng Ruohang <rh@vonng.com>
10 KiB
R7 实现与可合并性独立复审(Opus 5,只读会话)
1. 审阅对象
| 项 | 值 |
|---|---|
| 候选提交 | 4fcdf37ce656152b32ad0f615d47f5e3f9748c3a |
| 候选树 | d5cc904bf2a8b57aea1aac53999b5007522279fc |
| 现场 main/base | 9ebe81c1b3611f9cc73e676b5b741c2be62c467a |
| 审阅 diff | /Users/vonng/tmp/silo-r7-merge-20260916-ad51/reviewed-code.diff |
| diff SHA-256(按调用方声明采信) | 5af32dc2cb4acc34ac91a3e48c5decfcac0d25c70bfa7d6399934c66f629df2a |
| 原始 PR | #187,head b8f2fdde41dff3dc3b8db669c1d42d30ca5c1d3d,未合并 |
本会话无 shell,未运行任何测试、未计算任何哈希、未做任何网络操作,未修改任何文件。
2. 结论
APPROVE_WITH_NONBLOCKING_NOTES。阻塞问题 0。
这份代码在其自身 PR 的 CI 实际变绿后可以合入 main。 合并前提是 CI 真实通过,而不是"预期会通过"(理由见 §5.1)。
3. 我实际核验的内容(非采信)
逐行对读了 diff 与工作区当前源码,确认两者一致(cmd/handler-utils.go:247-308 就是 diff 后的内容;三个测试文件的 grep 行号与 diff 偏移量精确对应,如 replication-content-encoding_test.go:108 = diff:246−138,replication-metadata_test.go:68/90 = diff:488/510−420)。
3.1 等价性(普通路径零行为变化)
基线 allowReplication=false 分支是"命中 supportedHeader → 若属复制映射则 continue";新代码是"若属复制映射则 continue → 再查表写入"。对 nv 的查找、strings.Join(value, ",") 的拼接、user-metadata 前缀循环全部逐字保留(handler-utils.go:262-281)。普通提取路径字节级等价。
3.2 六个 SSE 字段与空标记
supportedHeaders 的后六项(handler-utils.go:86-91)与 replicationToInternalHeaders 的键集完全相同(:106-114),且六→六为单射(含 ReplicationSsecChecksumHeader 的恒等映射,bucket-replication.go:81),因此由"遍历 slice"改为"遍历 map"后迭代顺序无关,无覆盖歧义。空标记 X-Minio-Replication-Encrypted-Multipart: "" 走 ok=true 分支、Join([""])=="",与基线一致,且 internal/crypto 按键存在性消费——测试 replication-metadata_test.go:82-86 的 want 映射显式固定了这一点。
3.3 信任边界(PUT/COPY/MPU/Snowball) diff 未触碰任何调用点与信任判定。我复核了全部五处调用与门控:
- PUT:
object-handlers.go:2199先提取 →:2263evaluateReplicationTrust→:2278-2280applyReplicationTrust→:2281-2282仅replicaTrusted恢复。注意提取发生在剥离之前,因此普通提取器必须无条件跳过复制专用头——新代码正是无条件continue(:263-265),这道纵深防御被完整保留。 - COPY:
object-handlers.go:1144-1152,仅 REPLACE 分支且allowReplication为真时恢复;COPY 指令分支语义不变。 - MPU:
object-multipart-handlers.go:233+:246,仅初始化阶段恢复;Part/Complete 不再提取元数据,测试里的Content-Encoding: br因此是未来回归护栏。 - Snowball:
replication-trust.go:78-90的整包判定 +object-handlers.go:2786-2793的逐条目ReplicateObjectAction复核未变;replicationRequestHeaders(replication-trust.go:96-112)仍覆盖六个 wire 头与 REPLICA 状态。 无新增投毒面。
3.4 Snowball 普通/replica parity(最实质的行为变化,判定为修复而非回归)
object-handlers.go:2802-2804 的 metadata 只含 storage class。基线在 :2836 的恢复调用会把外层 archive 请求的 supportedHeaders + 用户元数据整体灌进每个条目(普通条目则完全没有),补丁后只剩六个映射;PAX 分支 :2864-2872 同理不再用原始 wire 值覆盖 extractMetadata 已归一化的 m。我另行确认仓库内没有生产代码发送 X-Amz-Meta-Snowball-Auto-Extract(只有 api-router.go:391 接收),即不存在依赖旧继承行为的内部生产者。
3.5 空格 token 行为
trimAwsChunkedContentEncoding(handler-utils.go:367-378)按 , 切分后做精确等值比较、不做 TrimSpace。因此 "aws-chunked, gzip" → " gzip"(保留前导空格)、"gzip, aws-chunked" → "gzip, aws-chunked"(整串不变)。测试 replication-metadata_test.go:44-51 的两条期望与代码一致,属于现状固化,不得对外宣称为本次修复。
3.6 原始普通元数据的删除(GHSA 相关,正面收益)
extractMetadata:219-223 删除 X-Amz-Meta-X-Amz-Unencrypted-Content-Length/-Md5。基线的恢复函数会通过 x-amz-meta- 前缀循环把它们重新注入,这是对该 advisory 缓解的实际回退(仅限可信 replica 写)。补丁消除了该路径,测试在 canonical/lowercase 两种写法下都做了断言(:100-105)。
3.7 GET/HEAD 与原始字节
ObjectInfo.ContentEncoding 来自 fi.Metadata["content-encoding"](erasure-metadata.go:138),setObjectHeaders 仅在非空时下发(api-headers.go:129-131)。所以测试同时断言"落盘 UserDefined 无该键"和"响应头不存在该键"是有意义且互相独立的。GET 分支比较原始字节,replica/gzip 用例写入的是真实 gzip 字节。
3.8 签名与请求体
replicaEncodingStream 的顺序正确:newTestStreamingRequest → 设置全部头 → signStreamingRequest → assembleStreamingChunks,chunk 签名逐块校验;非 chunked 分支 newTestSignedRequestV4 对 payload 计算 x-amz-content-sha256 并走 authTypeSigned 校验。测试确实经过签名验证链路,不是绕过。无权 replica 用例断言 XML Code == AccessDenied 并复核对象未被创建,能区分"签名失败"与"授权拒绝"。
3.9 生产代码与 PR #187 的关系
逐行比对 pr187.diff 与候选 diff:cmd/handler-utils.go 与 cmd/handler-utils_test.go 完全一致,唯一差异是恢复函数的三行注释(pr187.diff:76-78 vs 候选:76-78),候选版补充了 Snowball 语义。"仅澄清注释"的说法属实。commit-message.txt 含 Co-authored-by: Mikhail Khadarenka 与 PR #187 归属声明。
3.10 容量夹具是否削弱证据:不削弱
capacity-overlay.json 只替换 cmd/test-utils_test.go;夹具唯一的功能性改动是 ExecObjectLayerAPITest 开头用仓库既有的 tagTestCapacityDisk(cmd/erasure-server-pool-tags_test.go:258-264,DiskInfo 返回 Total=Free, Used=0)包装 set 磁盘。对象字节与 xl.meta 仍写真实临时盘。未适配时的 507/XMinioStorageFull 原始日志保留(http-baseline-unadapted.log)。该文件在仓库外,不在交付 diff 中。
反事实同样成立:exact-baseline-overlay.json 只额外把生产文件换成 baseline-handler-utils.go(我核对该文件确含 extractMetadataFromMimeWithReplication/allowReplication 布尔开关),测试文件一字未改。失败点精确落在 replica/bare、replica/mixed、全部 8 个 Snowball 用例与全部 16 个 helper 子用例,ordinary/untrusted-marker/gzip/unauthorized-replica 全通过——44 通过 / 36 失败与声明吻合。
4. 我采信而未独立验证的部分
- 四个源文件与各日志的 SHA-256、diff SHA-256、提交/树对象哈希(无 shell,无法计算)。
- 所有测试的执行事实:
fixed-targeted(80 叶子)、fixed-sse-trust、fixed-race、make verifiers、make build的通过是读日志所得(我确认了fixed-targeted.log:179-180的PASS/ok、fixed-race.log:209-210、fixed-sse-trust.log:125-126,以及四个 fixed 日志中无--- FAIL),但这些进程不是本会话运行的。 - 提交对象实际携带的 author/trailer(
commit-message.txt内容正确,但我无法确认它就是4fcdf37ce的提交信息)。 - PR #187 远端当前状态(读取的是本地缓存
pr187.json/pr187.diff)。 - 无任何两站点调度器 / 进程重启 / 网络故障 / 线上验收;本次结论只覆盖本机认证 handler 接收链路与既有 SSE 回归。
5. 非阻塞意见
- CI 是真正的门,不是形式。 这两个 HTTP 级测试从未在"无容量 overlay"的环境里跑过(本机盘满,未适配时直接 507)。CI 机器盘空间正常时不需要 overlay,预期可过,但这一点本地无证据。请等该分支自己的 CI 变绿再合,不要用本地日志替代。
- 提交对象自检(推送前,一条命令):
git log -1 --format='%H %T %an %ae%n%b' 4fcdf37ce与git diff --stat 9ebe81c1b..4fcdf37ce,确认树哈希、Co-authored-by与"只动 2 个产品/测试文件 + 2 个新测试 + docs"。 - POST 表单路径仍未归一化:
bucket-handlers.go:1262直接调用低层extractMetadataFromMime,不走extractMetadata的aws-chunked裁剪与默认 content-type。本补丁按 N9 刻意不动它,但这意味着 POST policy 上传仍可能落盘原始aws-chunked。建议单独开 issue,不要在本 PR 顺手统一。 - 测试可加一条断言:
replication-metadata_test.go:68-72只断言普通路径不出现六个 internal 键;再断言六个 wire 键名也不在 metadata 中,可完整封死这一面(当前实现确实不会写入,属加固)。 - Snowball 可选对照:现有 parity 只比 ordinary vs replica,可再加一条 untrusted-marker archive 对照(Opus v1 的可选建议,非必须)。
- 小瑕疵:
assertReplicaEncodingObject用getPutObjectURL构造 GET/HEAD 目标,功能等价但读起来别扭,getGetObjectURL更清楚。 - 存量限制需在 PR 描述里写明:本补丁只阻止目的端再次污染,不修复既有对象;若来源端仍存错误编码,
bucket-replication.go的逐字符串比较会在后续 heal/resync/比较时反复选择元数据复制。措辞按 N5 收窄("可能反复选中",不是"不间断热循环")。设计见stored-metadata-remediation.md,本次不授权任何现网扫描或改写。
6. 明确许可声明
本次审阅的这份代码(候选 4fcdf37ce…,基线 9ebe81c1b…,即上述 diff)在其 PR 的适用 CI 实际通过后,允许合入 main。 不得修改原贡献者的 #187 分支;不授权发布、部署或线上对象改写。若在此期间 main 前进,需重新查看集成增量,并在相关行为改变时重跑相应测试并重新评审。