What's missing to have reproducible builds on PyPI
摘要
作者提出在 PyPI 上实现可复现构建(reproducible builds)的设想,认为这无需发行版生产者额外工作即可实现。文章先说明可复现构建对供应链安全的意义(如第三方可验证发行版与源码一致、发现构建工具被入侵等),并指出纯 Python wheel 同样面临构建后端被攻破的风险。随后分析当前规范缺失的部分:发行版未记录所用源码位置(需在 sdist 和 wheel 元数据中补充);wheel 已支持通过 SBOM 记录构建工具(PEP 770),但 sdist 缺乏类似机制,可能需要新的 sdist v2 格式;构建后端可自动记录运行环境中的软件以生成 SBOM。最后设想由可信第三方验证者将复现结果反馈给 PyPI,并在索引 API 中展示,让安装器可优先选择已复现的发行版,同时强调这应作为可选项而非强制要求。
荐读理由
文中指出 sdist 缺少记录 SBOM 的机制,这是你评估 Python 打包工具链时能直接用的判断依据,避免在供应链安全上踩坑
原文
What's missing to have reproducible builds on PyPI
While writing the section of my 2026 Python Packaging Council (PPC) nomination on secure supply chain, I realized that one thing related to having a secure supply chain that we lack is a defined way to perform reproducible builds. The reason I like the idea of making reproducible builds work is that I think it can be done in such a way as to not require any work on the part of the producer of a distribution (which is a technical term for sdists or wheels, i.e., the people who upload stuff to PyPI), and thus make reproducible builds very low-friction for people to opt into supporting.
Why you should care
In terms of secure supply chain, reproducible builds can let independent 3rd parties verify that the bits in a distribution match what's expected based on the source code the distribution was made from. That lets you potentially detect if anyone tampered with the code during the build process. As well, there's a side-effect that from having to record the software involved in the build process means you can more easily detect if some known, compromised tool was used even if you don't do everything necessary to verify the bits are exactly the same. And this isn't some hypothetical benefit: SolarWinds was compromised due to malicious code being injected into the build process.
And don't let the word "build" fool you into thinking that pure Python wheels aren't vulnerable. There's a build backend that was used to make that wheel, and if that build back-end was compromised then it may inject some malicious code into the wheel. So there isn't some area in Python packaging that gets to ignore these risks.
What's missing from the specs
Where's the source code?
So what do we need in Python packaging to make reproducible builds possible? First, we need to record what source code was used. This isn't recorded in sdists or wheels, but if you install directly from a source repository or an archive then it's recorded in a direct_url.json file by your installer. If we were to record the same information in sdists and wheels (such as in the metadata), then we would know the location of the source code used to make the distribution.
What software was used to make the distribution?
But the next tricky bit is recording all the tools used to create the distribution. For wheels, we have support for recording software bill of materials (SBOMs). And as PEP 770, which added that support, says (disclaimer: I was the PEP delegate), SBOMs can be used to record the build tools used to create a distribution. And if you record all the software used to build a distribution, you can hopefully reproduce the exact same bits and show nothing was tampered with.
Unfortunately, sdists don't have a similar mechanism to record SBOMs. Since sdists are usually just a tarball with a PKG-INFO file that contains some precalculated metadata, there isn't a place to put any other metadata file. So we either have to shrug and say, "don't use sdists if you want reproducible builds," or we will have to come up with some sdist v2 format that allows for more structured data.
Who records what software was used?
Now, you might be wondering how you would even go about reproducing a build even if you do have all of this information. Luckily, since we have the [build-system] table in pyproject.toml, we have a defined entry point into the build back-end that produced the distribution. That means once we have all the software required to run the build backend recorded, we can replay the build process by installing the same things and calling the build backend as defined by [build-system]. And if build backends took care of recording what's installed in the environment they are running in, theoretically we could record all the software used for the build back-end and store it in SBOMs today without distribution producers having to do extra work (but it does mean work for the pip maintainers).
Surfacing reproducibility on PyPI
Assuming all of this comes to pass and we record the where the source code is that went into a distribution and the software used to make the distribution, how do we make it useful to people? Does every person who cares about having a secure supply chain have to rebuild everything they use themselves? Is there some way for even people who don't care about this stuff to benefit?
One possible way is if there were trusted verifiers who could tell PyPI when they successfully reproduced a distribution. Since various enterprises are going to be doing this anyway, they could feed that information back to PyPI so they can visibly say for a distribution file, "this file was independently reproduced by ". That means users get to know a distribution is what the creator expected, and the verifier gets a bit of recognition for helping the community out. This could even be surfaced in the index API so you could have installers prefer reproduced distributions.
This should be done in a way not to shame anyone who happens not to use a build backend that can create a distribution that can be reproduced. This should always be viewed as a perk and not a requirement. It's like getting to say your project meets build level 1 of SLSA (which all of this would meet); some people like getting to say that, but it isn't a knock against anyone who chooses not to care.
Acknowledgments
Thanks to Seth Larson for listening to my idea and also checking over this blog post.
这条对你有帮助吗?