Skip to content

Switch PyPI publish workflow to OIDC trusted publishing#7879

Merged
achamayou merged 6 commits into
mainfrom
copilot/update-pypi-publishing-flow
May 13, 2026
Merged

Switch PyPI publish workflow to OIDC trusted publishing#7879
achamayou merged 6 commits into
mainfrom
copilot/update-pypi-publishing-flow

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 12, 2026

Replaces the long-lived PYPI_TOKEN upload in .github/workflows/pypi.yml with PyPA's official action using OIDC trusted publishing, per the linked GitHub/PyPI guidance.

Changes

  • Action: drop the pip install twine + twine upload -u __token__ -p ${{ secrets.PYPI_TOKEN }} step in favour of pypa/gh-action-pypi-publish, pinned to commit SHA cef221092ed1bacb1cc03d23a2d87d1d172e277b (v1.14.0).
  • Permissions: add id-token: write on the job so GitHub can mint the OIDC token PyPI exchanges for a short-lived API token.
  • Artifact layout: download the released wheel into dist/ (the action's default packages-dir) instead of python/.
  • Environment: bind the publish job to a GitHub Actions environment named pypi for additional hardening (deployment branch/tag restrictions, optional required reviewers, deployment record).
  • Secret: secrets.PYPI_TOKEN is no longer referenced and can be removed from repo secrets once trusted publishing is live.
permissions:
  id-token: write
...
jobs:
  build_and_publish:
    runs-on: ubuntu-latest
    environment: pypi
    permissions:
      id-token: write
    ...
    - name: Publish PyPi Package to https://pypi.org/project/ccf/
      uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
      with:
        skip-existing: true

Out-of-band setup required

  1. Repo settings → Environments: create an environment named pypi (must match the workflow exactly). Optionally restrict "Deployment branches and tags" to the release tag pattern (e.g. ccf-*) and add required reviewers for a manual gate.
  2. PyPI: register/update the trusted publisher for the ccf project pointing at microsoft/CCF, workflow pypi.yml, and set the Environment name to pypi. Both sides must match or token minting will fail.

Copilot AI linked an issue May 12, 2026 that may be closed by this pull request
…C trusted publishing

Agent-Logs-Url: https://github.com/microsoft/CCF/sessions/ae6b3f94-23af-4d89-adae-716929b33a1e

Co-authored-by: achamayou <4016369+achamayou@users.noreply.github.com>
Copilot AI changed the title [WIP] Update PyPI publishing flow to use OIDC Switch PyPI publish workflow to OIDC trusted publishing May 12, 2026
Copilot AI requested a review from achamayou May 12, 2026 15:16
@achamayou
Copy link
Copy Markdown
Member

@copilot what does setting an environment on the job do? Also is there a way to set the write permission at the step level rather than the job?

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 12, 2026

@copilot what does setting an environment on the job do? Also is there a way to set the write permission at the step level rather than the job?

Two separate things:

environment: on the job ties the job to a GitHub Actions environment, which gives you:

  • Protection rules: required reviewers, wait timers, and a branch/tag allow-list before the job is allowed to run.
  • Environment-scoped secrets/variables.
  • A deployment record visible in the repo's "Environments" UI.

For trusted publishing specifically, it also acts as an additional constraint on the PyPI side: when you register the trusted publisher on PyPI you can pin it to a workflow and an environment name (e.g. pypi), so even a workflow change on main can't mint a PyPI token unless it runs in that environment — which in turn can be gated by required reviewers. It's the recommended hardening for publish jobs. Happy to add environment: pypi here if you'd like (it'd need to be created in repo settings and matched on PyPI).

Step-level permissions: — no, GitHub Actions doesn't support that. permissions: is only valid at the workflow or job level (docs). The narrowest scope available is the job, which is what this PR does. The usual way to limit blast radius further is to isolate the publish step in its own single-step job (which is already the shape here).

@achamayou
Copy link
Copy Markdown
Member

@copilot add an environment to this workflow, call it pypi - what do I need to do in repo settings?

Agent-Logs-Url: https://github.com/microsoft/CCF/sessions/5bef9d3b-cd2a-45ab-9b30-b8275f2f5b9e

Co-authored-by: achamayou <4016369+achamayou@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 12, 2026

@copilot add an environment to this workflow, call it pypi - what do I need to do in repo settings?

Done in 84b59be — added environment: pypi to the build_and_publish job.

Repo settings to do:

  1. Settings → Environments → New environment → name it pypi (must match the workflow exactly).
  2. (Recommended) On that environment, configure:
    • Deployment branches and tags → "Selected branches and tags" → allow only the tag pattern ccf-* (or main), so only release tags can deploy.
    • Required reviewers → add yourself / the release approvers if you want a manual gate before publishing.
    • Wait timer is optional.
  3. No secrets need to live in the environment — OIDC handles auth, and PYPI_TOKEN can be deleted from repo secrets once trusted publishing is confirmed working.

PyPI side: in the ccf project's Publishing settings, edit the existing trusted publisher and set Environment name to pypi. Both sides must match or token minting will fail.

Comment thread .github/workflows/pypi.yml Outdated
Agent-Logs-Url: https://github.com/microsoft/CCF/sessions/5ac86288-f25c-4ed3-8558-ec5c766a1811

Co-authored-by: achamayou <4016369+achamayou@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 13, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/repos/pypa/gh-action-pypi-publish/git/ref/tags/release/v1
    • Triggering command: /usr/bin/curl curl -s REDACTED (http block)
  • https://api.github.com/repos/pypa/gh-action-pypi-publish/git/refs/tags
    • Triggering command: /usr/bin/curl curl -s REDACTED (http block)
  • https://api.github.com/repos/pypa/gh-action-pypi-publish/releases/latest
    • Triggering command: /usr/bin/curl curl -s REDACTED (http block)
    • Triggering command: /usr/bin/curl curl -sI REDACTED (http block)
    • Triggering command: /usr/bin/curl curl -sv REDACTED (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Comment thread .github/workflows/pypi.yml
@achamayou achamayou marked this pull request as ready for review May 13, 2026 13:32
@achamayou achamayou requested a review from a team as a code owner May 13, 2026 13:32
Copilot AI review requested due to automatic review settings May 13, 2026 13:32
@achamayou achamayou merged commit d72b69d into main May 13, 2026
11 of 12 checks passed
@achamayou achamayou deleted the copilot/update-pypi-publishing-flow branch May 13, 2026 13:32
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the PyPI publish workflow to use OIDC trusted publishing (via pypa/gh-action-pypi-publish) instead of a long-lived PYPI_TOKEN, aligning CCF’s release publishing with PyPA’s recommended approach.

Changes:

  • Switch upload mechanism from twine upload with a repository secret to pypa/gh-action-pypi-publish (pinned by commit SHA).
  • Add GitHub Actions environment binding (environment: pypi) and enable OIDC (id-token: write) for token minting.
  • Download the release wheel into dist/ to match the publish action’s default packages-dir.

Custom instructions used:

  • .github/copilot-instructions.md

name: "Publish ccf package to PyPi"
runs-on: ubuntu-latest
environment: pypi
permissions:
Comment on lines 25 to 30
- name: Fetch PyPi Package from release
run: |
cd python
mkdir -p dist
cd dist
RELEASE_WHEEL_URL=$(curl -s https://api.github.com/repos/microsoft/ccf/releases/tags/ccf-${{steps.tref.outputs.version}} | jq -r '.assets[] | select(.name|test("ccf-.*.whl")) | .browser_download_url')
wget ${RELEASE_WHEEL_URL}
Comment on lines 29 to 30
RELEASE_WHEEL_URL=$(curl -s https://api.github.com/repos/microsoft/ccf/releases/tags/ccf-${{steps.tref.outputs.version}} | jq -r '.assets[] | select(.name|test("ccf-.*.whl")) | .browser_download_url')
wget ${RELEASE_WHEEL_URL}
@achamayou
Copy link
Copy Markdown
Member

@copilot create a follow up PR addressing the review comments.

@achamayou
Copy link
Copy Markdown
Member

@copilot create a new PR addressing the comments you posted after this one was merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PyPI releases with OIDC/Trusted Publishing

5 participants