内容提要
pgAdmin 作者介绍了 pgbuild 项目:该项目为 Windows 和 macOS 编译 PostgreSQL 及其依赖(如 OpenSSL、Kerberos),供 pgAdmin 打包使用。此前依赖以可变的 -latest 标签发布,缺少校验和,导致供应链风险和构建不可复现。现在改为发布不可变版本并提供校验和,pgAdmin 通过锁文件固定 SHA-256,校验不匹配即失败,过期仅警告,从而保证依赖可追溯、构建可复现。
延伸解读
供应链风险:可变的 -latest 标签
文章指出,pgbuild 此前所有发布都使用以 -latest 结尾的可变标签,且没有校验和。这意味着对 pgbuild 的写权限等同于对 pgAdmin 签名内容的写权限,因为下游构建不会验证下载的依赖是否被篡改。虽然能访问的人都是长期受信任的社区成员,但代码签名证书本应证明“我们构建了什么”,而当时无法做到这一点。
构建不可复现的日常困扰
由于依赖指向可变的 -latest 标签,同一次提交在不同日期构建可能产生不同的二进制文件。如果出现回归,无法确定是哪个依赖变更引入的,也无法在不包含该变更的情况下重新构建。这给调试和问题定位带来了实际困难,而不仅仅是理论上的风险。
修复方案:锁文件与不可变发布
修复分两部分:pgAdmin 增加锁文件记录每个归档的 SHA-256,下载时校验,不匹配则构建失败;pgbuild 为每个上游版本发布不可变版本并附带校验和,pgAdmin 固定到这些版本。这样既保证了依赖可追溯,又确保固定构建能长期工作,因为旧版本不会被覆盖。
失败模式的不对称处理
文章解释了一种有意的设计:摘要不匹配会导致构建失败,因为这意味着没有获得所固定的内容;而依赖过期只会发出警告并继续构建。理由是“落后”需要尽快处理,但不应该阻止发布,否则构建系统会因为他人发布新版本而变红,最终被人们忽视。
Q&A
pgbuild 是什么?它的主要作用是什么?
pgbuild 是 pgAdmin 组织下的一个仓库,负责为 Windows 和 macOS 编译 PostgreSQL 及其依赖(如 OpenSSL、Kerberos、zstd、lz4、ICU 等),并发布归档文件供 pgAdmin 构建时下载和链接。
pgbuild 之前存在哪些供应链风险?
之前 pgbuild 的发布使用可变的 -latest 标签,没有校验和。任何能修改发布的人都可以改变 pgAdmin 构建中使用的库,下游无法检测,因为没有任何校验机制。
pgAdmin 如何确保依赖的完整性和可追溯性?
pgAdmin 使用锁文件记录每个归档的 SHA-256,下载时进行校验,不匹配则构建失败。依赖变更通过提交锁文件更新,形成可审查的差异记录。
pgbuild 现在如何发布版本?与之前有何不同?
现在每个发布都附带校验和,并在发布说明中记录上游版本。除了滚动的 -latest 发布外,还为每个上游版本创建不可变发布,创建后不再更改,pgAdmin 固定到这些不可变发布。
pgAdmin 如何处理依赖校验失败和依赖过期?
校验和不匹配会导致构建失败;依赖过期不会失败,而是发出警告,指明依赖、当前固定版本和可用新版本,然后继续构建并发布固定版本。
对于 pgAdmin 贡献者,更新依赖的流程有什么变化?
更新依赖现在需要两步:先在 pgbuild 中重新构建依赖,然后在 pgAdmin 中刷新锁文件并提交结果。这增加了工作量,但使变更可审查、可追溯。