Repository navigation
ci(release): publish Python packages with PyPI trusted publishing - #3146
Merged
Merged
Conversation
Drop the long-lived PYPI_API_TOKEN from both Python publish steps and run uv publish with --trusted-publishing always. The publish job already has id-token: write and environment: npm for npm OIDC, so each PyPI project's trusted publisher binds to ag-ui-protocol/ag-ui, publish-release.yml, environment npm.
@ag-ui/a2a-middleware
@ag-ui/a2ui-middleware
@ag-ui/event-throttle-middleware
@ag-ui/mcp-apps-middleware
@ag-ui/mcp-middleware
@ag-ui/a2a
@ag-ui/adk-js
@ag-ui/adk
@ag-ui/ag2
@ag-ui/agno
@ag-ui/antigravity
@ag-ui/aws-strands
@ag-ui/claude-agent-sdk
@ag-ui/claude-managed-agents
@ag-ui/crewai
@ag-ui/langchain
@ag-ui/langgraph
@ag-ui/llamaindex
@ag-ui/mastra
@ag-ui/pydantic-ai
@ag-ui/vercel-ai-sdk
@ag-ui/watsonx
@ag-ui/a2ui-toolkit
create-ag-ui-app
@ag-ui/client
@ag-ui/core
@ag-ui/encoder
@ag-ui/proto
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Switch Python publishing in
release / publish(.github/workflows/publish-release.yml) from the long-livedPYPI_API_TOKENsecret to PyPI Trusted Publishing (GitHub OIDC).UV_PUBLISH_TOKEN.uv publish --trusted-publishing always. Withalways, uv uses trusted publishing unconditionally, so a missing or mismatched publisher on pypi.org fails the step with PyPI's error. The existingPY_PUBLISH_FAILEDgate then fails the job before any git tags or GitHub Releases are created.publishjob already hadpermissions: id-token: writeandenvironment: npm(npm OIDC uses the same job). Neither changes. The trusted publisher binds to this file name and this environment, and a comment now says so.PYPI_API_TOKENsecret is not deleted. See the rollout order below.Out of scope:
publish-python-preview.yml(TestPyPI previews for PR builds) still uses the repo-scopedTEST_PYPI_API_TOKEN. It is a different index, runs fromworkflow_runfor fork PRs, and can publish packages that do not exist on TestPyPI yet (ag-ui-a2ui-toolkit,ag_ui_antigravity,ag-ui-claude-sdk,ag-ui-claude-managed-agents,ag-ui-langroid,ag_ui_watsonx). Under OIDC, those would each need a pending publisher first. That is tracked as a separate follow-up.Trusted publisher to add on pypi.org
Add one GitHub publisher per project (Manage project → Publishing → Add a new publisher → GitHub). Every project uses the same values:
The project list is every
"ecosystem": "python"entry inscripts/release/release.config.json, matched against eachpyproject.tomlname. The PyPI JSON API (ownership.roles) shows all 12 projects have a singleOwner: the PyPI user CopilotKit, with no PyPI organization. Only that account can add the publishers. The JSON API does not expose trusted-publisher config. That is visible only in the project's Publishing page. No latest release of any project has a PEP 740 provenance attestation (/integrity/.../provenancereturns 404), which fits token uploads only.RED: current state
main, both Python publish steps setUV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}. The secret is scoped to thenpmenvironment, which has required reviewerscopilotkit-adminandjpr5.id-token: writewas already present. The job already hasid-token: write, so nothing had to be added. The same job already gets OIDC tokens in thenpmenvironment. In the same run, at 11:59 PM PDT on Oct 20, npm published with OIDC:npm notice publish Signed provenance statement with source and build information from GitHub Actions/+ @ag-ui/claude-agent-sdk@0.0.8.Publish Python packages (stable)step exactly as written in the YAML. It used uv 0.12.1, the version the workflow pins, with a simulated GitHub Actions OIDC environment. A local fakeACTIONS_ID_TOKEN_REQUEST_URLendpoint recorded requests. PyPI was real, every credential was fake, and the probe uploaded a dummyag-ui-tp-probe-do-not-publishdist:GREEN: after this change
pypi) from real pypi.org and asked the GitHub OIDC endpoint for an id-token. It then sent that token to real pypi.org/_/oidc/mint-token, which rejected the fake JWT. No upload was attempted. On failure, the step writesPY_PUBLISH_FAILED=true, which fails the job before tags are created.actionlint1.7.12 passed on the full list of files thatlint-release-workflows.ymlchecks (exit 0).zizmor1.26.1 with.github/zizmor.ymlreported no findings onpublish-release.yml.verify-python-toolchain-pins.shandverify-release-scope-dropdowns.shpassed, andnode --test scripts/release/*.test.tspassed 252 of 252 tests with Python 3.12, the version CI uses.What this does not prove: a real exchange with a GitHub-issued token. That needs the PyPI-side publishers above and the next release. The
dry_rundispatch skips thepublishjob completely. A prerelease dispatch would publish real canary versions to PyPI, so it was not used.Rollout order
CopilotKitPyPI owner, add the tuple above to all 12 projects.uv publishsucceeding with noUV_PUBLISH_TOKENin the step env. If a project was missed in step 1, its upload fails loudly and the job stops before tags are created. Add the publisher and re-run the job.PYPI_API_TOKENsecret from thenpmenvironment and revoke the token on pypi.org.