Split PyPI publishing workflow: isolate OIDC-privileged upload into its own job#230
Split PyPI publishing workflow: isolate OIDC-privileged upload into its own job#230Copilot wants to merge 4 commits into
Conversation
Agent-Logs-Url: https://github.com/GitHubSecurityLab/seclab-taskflow-agent/sessions/6276aa76-c90b-41a1-9fc7-2b06e27aadfa Co-authored-by: kevinbackhouse <4358136+kevinbackhouse@users.noreply.github.com>
| needs: build | ||
| runs-on: ubuntu-latest | ||
| environment: | ||
| name: pypi |
There was a problem hiding this comment.
Check the repo settings and make sure this is behind an approval button so that when the dists are built, there's that last line of defense where a human can double-check the artifacts if needed.
| path: dist/ | ||
|
|
||
| publish-to-pypi: | ||
| name: Publish to PyPI |
There was a problem hiding this comment.
you'll want the same for testpypi I imagine?
| - name: Install Hatch | ||
| run: pip install --upgrade hatch | ||
|
|
||
| - name: Build distribution packages | ||
| run: hatch build |
There was a problem hiding this comment.
No need for a custom frontend really. Just use a PyPA project.
| - name: Install Hatch | |
| run: pip install --upgrade hatch | |
| - name: Build distribution packages | |
| run: hatch build | |
| - name: Install the build frontend | |
| run: python -Im pip install --upgrade build | |
| - name: Build distribution packages | |
| run: python -Im build |
Although, I must say, it may be a good idea to make this somewhat more predicatable by having a build-deps.in and build-deps.txt managed by pip-tools (supported by Dependabot natively). With just build in build-deps.in.
It's usable as follows:
| - name: Install Hatch | |
| run: pip install --upgrade hatch | |
| - name: Build distribution packages | |
| run: hatch build | |
| - name: Install the build frontend | |
| run: python -Im pip install -r build-deps.in -c build-deps.txt | |
| - name: Build distribution packages | |
| run: python -Im build |
I often take this a bit farther by also pinning the isolated build env:
pip-compile --all-build-deps --only-build-deps --output-file=build-lock.txt --strip-extras pyproject.toml
(https://pip-tools.rtfd.io/en/latest/#maximizing-reproducibility)
This would integrate as follows:
| - name: Install Hatch | |
| run: pip install --upgrade hatch | |
| - name: Build distribution packages | |
| run: hatch build | |
| - name: Install the build frontend | |
| run: python -Im pip install --requirement=build-deps.in --constraint=build-deps.txt | |
| - name: Build distribution packages | |
| env: | |
| PIP_CONSTRAINT: build-lock.txt | |
| run: python -Im build |
There was a problem hiding this comment.
Pull request overview
Adds a new GitHub Actions workflow to publish the Python package to PyPI using trusted publishing, splitting the build and the OIDC-privileged upload into separate jobs to reduce credential blast radius.
Changes:
- Introduces
.github/workflows/publish-to-pypi.ymltriggered onrelease: published. - Builds distributions in an unprivileged
buildjob and uploadsdist/as an artifact. - Downloads the artifact in a separate
publish-to-pypijob gated by thepypienvironment and publishes via OIDC.
Show a summary per file
| File | Description |
|---|---|
| .github/workflows/publish-to-pypi.yml | Adds a two-job (build → publish) PyPI release workflow using artifacts and OIDC trusted publishing. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comments suppressed due to low confidence (4)
.github/workflows/publish-to-pypi.yml:21
- This workflow uses floating major-version refs for GitHub Actions (
actions/checkout@v4,actions/setup-python@v5). Elsewhere in this repo’s release/publishing workflows, actions are pinned to full commit SHAs (e.g.,.github/workflows/publish-to-pypi.yaml). For supply-chain hardening (especially in a release pipeline), please pin these actions to commit SHAs.
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
.github/workflows/publish-to-pypi.yml:33
actions/upload-artifact@v4/actions/download-artifact@v4are referenced by a floating tag. Since these steps are part of the release supply chain, consider pinning them to specific commit SHAs (and preferably aligning to the same major/version used in the existing publish workflows) to reduce the risk of a compromised upstream tag affecting releases.
- name: Upload distribution artifacts
uses: actions/upload-artifact@v4
with:
name: python-package-distributions
path: dist/
.github/workflows/publish-to-pypi.yml:53
- The publish step uses
pypa/gh-action-pypi-publish@release/v1, which is a moving ref. The existing workflow pins this action to a specific commit SHA. For a security-sensitive publishing workflow, pin this action to a commit SHA (or a fully qualified version tag) to prevent upstream tag movement from impacting releases.
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
.github/workflows/publish-to-pypi.yml:34
- Compared to the existing PyPI publishing workflow in this repo, this workflow does not generate build provenance attestations (e.g., via
actions/attest-build-provenance). If attestations are relied on for release integrity/auditing, consider adding an attestation step in the build job and granting only the minimum requiredattestations: writepermission there.
- name: Build distribution packages
run: hatch build
- name: Upload distribution artifacts
uses: actions/upload-artifact@v4
with:
name: python-package-distributions
path: dist/
- Files reviewed: 1/1 changed files
- Comments generated: 2
| release: | ||
| types: [published] |
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 |
| path: dist/ | ||
|
|
||
| - name: Publish to PyPI | ||
| uses: pypa/gh-action-pypi-publish@release/v1 |
|
@copilot: rename the file to |
Done — the old |
PyPI's trusted publisher security model recommends confining the OIDC-privileged upload step to a dedicated job, keeping the build step unprivileged. Granting
id-token: writeto a job that also checks out and builds code unnecessarily widens the blast radius if that job is compromised.Changes
New workflow
.github/workflows/publish-to-pypi.ymltriggered onrelease: publishedbuildjob —contents: readonlyhatch, runshatch builddist/as a GitHub Actions artifactpublish-to-pypijob —id-token: writeonlypypa/gh-action-pypi-publishusing OIDC trusted publishingpypiGitHub environment for additional approval control