pypa/gh-action-pypi-publish

GitHub: pypa/gh-action-pypi-publish

Python 官方可信发布工具,安全自动化上传 Python 包至 PyPI。

Stars: 1145 | Forks: 108

[![SWUbanner]][SWUdocs] ![PyPA badge] [![🧪 GitHub Actions CI/CD workflow tests badge]][GHA workflow runs list] [![pre-commit.ci status badge]][pre-commit.ci results page] [![GH Sponsors badge]][GH Sponsors URL] # PyPI 发布 GitHub Action 此 Action 允许您将 `dist/` 目录中的 [Python distribution packages] 上传到 PyPI。 本文档提供了一个简明的使用概述。如需更详细的演练,请查看 [PyPA guide]。 如果您对特定的 Action 版本有任何反馈,请在相应的 [per-release announcement discussions] 中留言。 ## 🌇 `master` 分支日落 ❗ `master` 分支版本已停止维护。请将您使用的 GitHub Action 版本从 `master` 更改为 `release/v1` 或使用具体的标签,或选择 [use a full Git commit SHA] 和 Dependabot。 ## 用法 ### 可信发布 本示例直接介绍当前的最佳实践。如果您想直接使用 API token 或安全性较低的用户名和密码,请查看 [how to specify username and password]。 此 Action 支持 PyPI 的 [trusted publishing] 实现,该实现允许在没有手动配置的 API token 或用户名/密码组合的情况下向 PyPI 进行身份验证。要使用此 Action 执行 [trusted publishing],您项目的发布者必须已经在 [configured on PyPI]。 要进入可信发布流程,请为此 Action 的 job 配置 `id-token: write` 权限,并且**不要**显式指定用户名或密码: ``` # .github/workflows/ci-cd.yml jobs: pypi-publish: name: Upload release to PyPI runs-on: ubuntu-latest environment: name: pypi url: https://pypi.org/p/ permissions: id-token: write # IMPORTANT: this permission is mandatory for trusted publishing steps: # retrieve your distributions here - name: Publish package distributions to PyPI uses: pypa/gh-action-pypi-publish@release/v1 ``` 也可以使用其他支持可信发布的索引,例如 TestPyPI: ``` - name: Publish package distributions to TestPyPI uses: pypa/gh-action-pypi-publish@release/v1 with: repository-url: https://test.pypi.org/legacy/ ``` _(不要忘记将环境名称更新为 `testpypi` 或类似的名称!)_ 一个常见的用例是仅在 tagged commit 时上传包。为此,请向 job 添加过滤器: ``` if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') ``` ### 生成并上传证明 为所有分发文件生成签名的 [digital attestations] 并将它们一起上传,现在对于所有使用可信发布的项目默认开启。要禁用它,请按如下方式设置 `attestations`: ``` with: attestations: false ``` 证明对象是使用 [Sigstore] 为每个分发包创建的,并使用与当前工作流关联的 GitHub OIDC token 提供的身份对其进行签名。这意味着可信发布身份验证和证明都绑定到同一个身份。 ## 非目标 此 GitHub Action [has nothing to do with _building package distributions_]。用户负责在运行此 Action 之前通过将 dists 放入 `dist/` 文件夹来准备上传。通常期望用户在调用此 Action 之前的一个**独立的 GitHub Actions CI/CD job** 中执行此操作,且该 job 具有受限的权限。 运行 `pypi-publish` 的预期环境是 GitHub 提供的 Ubuntu VM。我们在 CI 中针对 `ubuntu-latest` 运行了冒烟测试,但任何当前可用的编号版本应该都可以。只要 GitHub 自己支持它们,我们就认为它们是受支持的。 不支持在设置了 `container:` 的 job 中运行此 Action。它可能对您有用,但如果出现问题,您需要自行解决。 如果您觉得需要使用它,很可能是因为您没有遵循在单独的 job 中调用构建自动化的建议,这被视为一个安全问题(特别是当使用 [Trusted Publishing][trusted publisher] 时,可能会导致权限提升,并使攻击者能够通过传递性构建依赖投毒来冒充仓库的 GitHub 支持的身份)。解决方案是使用一个 job(或者,对于具有 C 扩展的项目,使用多个 job)来构建分发包,然后使用另一个 job 来发布它们。 自托管 runner 尽力支持,前提是没有其他不受支持的事物影响它们。我们无法在 CI 中测试这一点,它们可能会出错。当使用自定义运行时而非官方 GitHub 提供的 VM 时,通常会出现这种情况。通常,如果您遵循在单独的 job 中构建的建议,您不需要在自托管 runner 中运行此 Action —— 应该可以在自托管 runner 中构建 dists,将它们作为 GitHub Actions artifact 保存在该 job 中,然后调用将在 GitHub 提供的 runner 中运行的发布 job,下载包含 dists 的 artifact 并发布它们。这种分离是处理此场景的**推荐**/**受支持**方式。 我们的理解是,可信发布预期可以在自托管 runner 上工作。它由 OIDC 支持。如果它不起作用,您应该询问 GitHub 是否遗漏了什么。我们在这里无法提供帮助。 遗憾的是,可信发布目前无法在 CI 中进行测试。它是受支持的,并且应该报告错误,但可能需要时间来解决,因为这通常需要跨项目协作来调试(有时,问题是由于 PyPI 的变化而不是 Action 的变化引起的)。 目前明确不受支持的情况是在可重用工作流中使用 [Trusted Publishing][trusted publisher]。这需要 PyPI 方面的支持,正在开发中。请不要报告与此情况相关的错误。当前的建议是将您想要的所有其他内容放入可重用工作流中,但将调用 `pypi-publish` 的 job 保留在顶层工作流中。 不支持从 composite actions 调用 `pypi-publish`。它没有经过测试。在这种情况下,GitHub Runners 存在限制和错误。但更重要的是,这通常表明使用方式不安全。当使用 [Trusted Publishing][trusted publisher] 时,必须将构建工具调用保留在具有受限权限的单独 job 中,因为 [Trusted Publishing][trusted publisher] 本身需要提升的权限才能使用 OIDC。我们观察到,用户有时会创建项目内的 composite actions,在同一个 job 中调用构建和发布。因此,我们不打算首先支持这种危险的配置。解决方案与前一个问题几乎相同 —— 使用具有专用且范围受限权限的单独 job 仅用于发布;并从另一个 job 调用该项目内的 composite action。 最后,不支持在同一个 job 中多次调用 `pypi-publish`。它可能在少数情况下有效,但请不要这样做。如果您想发布到多个索引,请在一个 job 中构建 dists 并添加多个发布 job,每次上传一个。 ## 高级发布管理 为了获得最佳效果,请弄清楚哪种工作流适合您项目的特定需求。 例如,您可以实现一个并行 job,将每次提交推送到 TestPyPI 或您自己的索引服务器,如 `devpi`。为此,您需要 (1) 指定一个自定义的 `repository-url` 值,并且 (2) 为每次上传生成一个唯一的版本号,以免它们产生冲突。 如果您使用 `setuptools_scm` 包,后者是可能的,但您也可以根据与最新 tagged commit 的距离发明自己的解决方案。 您需要为单独的主机创建另一个 token,然后将其 [save it as a GitHub repo secret][Creating & using secrets] 保存在您 job 中使用的环境下。不过,传递密码将禁用无秘密的 [trusted publishing],因此当发布到 TestPyPI 而不是自定义内容时,最好改为配置它。 这种情况下的 Action 调用如下所示: ``` - name: Publish package to TestPyPI uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.TEST_PYPI_API_TOKEN }} repository-url: https://test.pypi.org/legacy/ ``` ### 自定义目标包 dists 目录 您可以将 `dist/` 的默认目标目录更改为您喜欢的任何目录。Action 调用现在如下所示: ``` - name: Publish package to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: packages-dir: custom-dir/ ``` ### 禁用元数据验证 建议您在生成文件后立即运行 `twine check`,但这也会在上传前运行 `twine check`。您也可以使用以下命令禁用 twine 检查: ``` with: verify-metadata: false ``` ### 容忍发布包文件重复 有时,当您从多个地方发布版本时,您的工作流可能会遇到竞争条件。例如,当从多个 CI 发布时,甚至在 GitHub Actions CI/CD 中针对涉及同一高级行为的某些不同事件触发了具有相同步骤的工作流时。 为了促进此用例,您可以使用 `skip-existing`(默认禁用)设置,如下所示: ``` with: skip-existing: true ``` ### 用于调试 有时,`twine upload` 可能会失败。要进行调试,请按如下方式使用 `verbose` 设置: ``` with: verbose: true ``` ### 显示待上传文件的哈希值 您可能想要验证 PyPI 上的文件是否由 CI 脚本自动上传。 它将显示待上传文件的 SHA256、MD5、BLAKE2-256 值。 ``` with: print-hash: true ``` ### 指定不同的用户名 默认用户名值是 `__token__`。如果您发布到不提供 API token 的自定义 registry(如 `devpi`),您可能需要指定自定义的用户名和密码对。操作方法如下。 ``` with: user: guido password: ${{ secrets.DEVPI_PASSWORD }} ``` `${{ secrets.DEVPI_PASSWORD }}` 中使用的 secret 需要在 GitHub 上您项目设置的环境页面下创建。 请参阅 [Creating & using secrets]。 过去,在发布到 PyPI 时,自动发布的访问范围最安全的方式是使用 PyPI 的 [API tokens][PyPI API token] 功能。用户可以将其设为项目范围,并作为绑定环境的 secret 保存在其 GitHub 存储库设置中,例如将其命名为 `${{ secrets.PYPI_API_TOKEN }}`。请参阅 [Creating & using secrets]。虽然仍然安全,但在支持的平台上(如 GitHub),现在鼓励将 [trusted publishing] 作为优于 API token 的最佳实践。 ## 许可证 本项目中的 Dockerfile、相关脚本和文档均在 [BSD 3-clause license](LICENSE.md) 下发布。
标签:DNS解析, GitHub Action, OIDC, PyPA, PyPI, Python, Python 分发包, 上游组件, 分发, 包管理, 可信发布, 安全认证, 工作流, 开源框架, 开源项目, 持续集成, 无后门, 无密码, 自动化发布, 请求拦截, 软件打包, 逆向工具, 部署