gh 2.55.0 验证 JSONL bundle 误报 digest 不匹配
核对gh2.55.0的末行与空白行读取问题,保留原始bundle并按正式修复边界验证产物。
用 gh attestation verify --bundle 验证同一份构建产物,文件 SHA-256 没变,结果却随 JSONL bundle 的最后一个换行或两条记录的顺序改变。gh 2.55.0 的本地 JSONL 读取存在已修复的问题:空白行可能触发解析失败,末行没有换行时,最后一条有效记录又可能漏读。
漏读的那条若恰好对应待验证产物,就可能收到:
provided artifact digest does not match any digest in statement
这只解释特定旧版本和文件格式条件。当前版本出现同一句错误,仍要核对产物与证明文件是否配套,不能先假定签名验证器读错了。
先看实际版本和加载条数
在失败的工作流环境中检查,而不只看开发电脑上安装的版本:
gh --version
sha256sum ./release/app.bin
路径换成实际交给验证命令的产物。SHA-256 用于核对这份文件的字节,与证明 statement 的 subject.digest.sha256 对照;它不是源码提交哈希,也不是签名工作流的提交哈希。
保留原始产物、bundle 和失败日志。JSONL 应每条记录一个 JSON 对象;多条证明不等于一个 JSON 数组。看日志里的 Loaded ... attestation 条数,是否与文件中有效记录相符。
gh 2.55.0 的旧读取循环只处理成功读到换行的行,遇到 EOF 时末行内容可能没有进入解析。删除末尾空行虽然能避开一种解析错误,却可能让文件最后一条记录失去行结束符。于是两条记录只加载一条,交换顺序又改变哪份产物能通过。
2.56.0 是这组读取问题的修复边界
2024 年 9 月发布的 gh 2.56.0 同时包含空白行处理和多记录读取修复,正式源码改为 JSON decoder 读取连续对象。这里的版本号用于识别历史修复,升级目标应是项目支持、来源可信的后续版本。
更新后,在实际执行验证的 runner 上再次检查 gh --version。自托管 runner、容器镜像和 PATH 中的旧可执行文件,可能让安装步骤更新了一个位置,验证步骤仍运行另一个位置。
使用原始 bundle 和原来的验证策略重跑,例如:
gh attestation verify ./release/app.bin \
--bundle ./release/attestation.jsonl \
--repo example-org/example-repo
仓库名称必须换成预期产物所属仓库,项目已有的 signer、predicate 等约束继续保留。不要通过删除记录、调换记录顺序或放宽身份验证,让任务暂时变绿。
读取修复后,仍需验证产物与身份
如果有效记录已经完整加载,仍报 digest 不匹配,就检查下载的 artifact 是否属于同一运行、验证前是否被重新打包或修改,以及 bundle 是否真的包含它的 subject。升级解决不了两份不配套的文件。
--source-digest 约束源码提交,--signer-digest 约束签名工作流提交,都不能代替产物的内容哈希。复用工作流签名时,也应继续核对实际 signer,而非只把调用方仓库当成签名者。
恢复标准是原始记录完整读取、预期产物的证明通过既有身份和内容约束。不要把 JSON 解析成功当成签名通过,也不要把任意一份证明成功当成当前文件已被验证。


