ci: publish Python packages to PyPI via trusted publishing - #1828
Conversation
Co-Authored-By: mish@e2b.dev <mish@e2b.dev>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
There was a problem hiding this comment.
TASTE.md review: no violations. The PR only changes CI publish workflows and package.json postPublish scripts (PyPI trusted publishing); it touches no SDK public surface, so none of T-1–T-74 (API shape, parity, streaming, timeouts, config, errors, docs) apply. 0 violations.
Package ArtifactsBuilt from bbb74e4. Download artifacts from this workflow run. JS SDK ( npm install ./e2b-2.47.1-devin-1788793531-pypi-trusted-publishing.0.tgzCLI ( npm install ./e2b-cli-2.18.2-devin-1788793531-pypi-trusted-publishing.0.tgzCode Interpreter JS SDK ( npm install ./e2b-code-interpreter-2.8.1-devin-1788793531-pypi-trusted-publishing.0.tgzDesktop JS SDK ( npm install ./e2b-desktop-2.4.1-devin-1788793531-pypi-trusted-publishing.0.tgzPython SDK ( pip install ./e2b-2.47.0+devin.1788793531.pypi.trusted.publishing-py3-none-any.whlCode Interpreter Python SDK ( pip install ./e2b_code_interpreter-2.10.0+devin.1788793531.pypi.trusted.publishing-py3-none-any.whlDesktop Python SDK ( pip install ./e2b_desktop-2.5.0+devin.1788793531.pypi.trusted.publishing-py3-none-any.whl |
|
do we need the NPM_TOKEN anywhere still or is it reset on purpose? |
Not needed anywhere — no The pinned v1.9.0 (src/index.ts) only writes |
|
can you drop it then? |
Co-Authored-By: mish@e2b.dev <mish@e2b.dev>
Done in cdb2fdd — |
There was a problem hiding this comment.
Looks good, straightforward CI/publish config change.
What was reviewed: the --token→--trusted-publishing always swap in the four publish call sites (RC workflow step and the three Python packages' postPublish scripts) — all consistent; confirmed PYPI_TOKEN is fully removed from publish_packages.yml's secrets and env with no other references left; verified id-token: write permission is already present in both publish_candidates.yml and publish_packages.yml, which OIDC trusted publishing requires. No SDK public-API surface changed, so no changeset is needed.
Extended reasoning...
Overview
This PR touches only CI publish tooling: .github/workflows/publish_candidates.yml, .github/workflows/publish_packages.yml, and the postPublish npm scripts in three Python package.json files (code-interpreter-python, desktop-python, python-sdk). It replaces PyPI token-based auth (uv publish --token ${PYPI_TOKEN}) with PyPI trusted publishing (uv publish --trusted-publishing always), and removes the now-unused PYPI_TOKEN secret plumbing from the reusable workflow.
Security risks
This change reduces attack surface by removing a long-lived PyPI API token from the secrets store in favor of short-lived OIDC-based trusted publishing, which is a security improvement. I confirmed id-token: write permission (required for OIDC token minting) is already present in both affected workflows, so the mechanism should function as intended, contingent on the PyPI-side trusted publisher registration described in the PR body (an out-of-band config step, not verifiable from the diff). Using always instead of the default automatic is a reasonable choice — it fails fast if OIDC isn't available rather than silently attempting other auth methods.
Level of scrutiny
This is a low-risk, mechanical, and consistent change across four call sites with no application logic or SDK behavior affected — appropriate for a light review. The change is easily reversible and doesn't touch runtime code paths.
Other factors
No changeset is needed since only internal postPublish build scripts changed, not public API surface. No test coverage applies since this is publish-time CI tooling. The PR author's description matches the actual diff exactly.
This review covers commit decbdb7, which is no longer the latest commit on this pull request; later commits are not covered by it.
## Summary
Runs the production publish job inside a GitHub environment so that the
environment's deployment branch policy — not only the `Check the ref`
preflight step — decides which refs may publish `latest` to npm and
PyPI.
```yaml
# .github/workflows/publish_packages.yml
jobs:
test:
runs-on: ubuntu-22.04
+ environment: deployment
```
It lives on the job in `publish_packages.yml`, not on `publish:` in
`release.yml`, because a job that `uses:` a reusable workflow only
accepts
`name/uses/with/secrets/strategy/needs/if/concurrency/permissions`
([docs](https://docs.github.com/en/actions/reference/workflows-and-actions/reusable-workflows#supported-keywords-for-jobs-that-call-a-reusable-workflow)).
The preflight ref check stays: it fails fast before the SDK test matrix
runs, whereas the environment rule only rejects the publish job itself.
`release-candidate.yml` / `publish_candidates.yml` are intentionally
left without an environment — candidates are cut from feature branches,
which a main-only policy would block.
## Required repository configuration
The `deployment` environment doesn't exist yet (GitHub would auto-create
it on first run with no rules). The Devin GitHub App has no admin on
this repo, so an admin needs to create it and restrict it to `main`:
```sh
gh api -X PUT repos/e2b-dev/E2B/environments/deployment \
--input - <<'EOF'
{"deployment_branch_policy":{"protected_branches":false,"custom_branch_policies":true}}
EOF
gh api -X POST repos/e2b-dev/E2B/environments/deployment/deployment-branch-policies \
-f name=main -f type=branch
```
Or in the UI: Settings → Environments → New environment `deployment` →
Deployment branches and tags → Selected branches and tags → add `main`.
No trusted-publisher change is needed: the PyPI publishers from #1828
and the npm publishers were registered with an empty environment, which
matches any environment. Optionally tighten them afterwards by setting
the environment to `deployment` on the `publish_packages.yml` publishers
(leave the `publish_candidates.yml` ones empty).
Link to Devin session:
https://app.devin.ai/sessions/a59b5e364c484ced9524a652f80a49f9
Open in Devin Desktop:
https://app.devin.ai/desktop/session/a59b5e364c484ced9524a652f80a49f9?variant=devin
Requested by: @mishushakov
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: mish@e2b.dev <mish@e2b.dev>
## Summary Deletes `release-candidate.yml` and the `publish_candidates.yml` reusable workflow it called. Neither has been run since the candidate flow was split out of `release.yml` in #1483 (2026-06-25); the last RC published through the old combined workflow was `e2b@2.24.1-connections.1189.0` on 2026-05-26, and the last PyPI RC was `e2b==2.0.0rc2` (2025-08). `release.yml` keeps its `release-${{ github.ref }}` concurrency group and the main-only preflight check; only the comments pointing at the candidate workflow are dropped. `publish_packages.yml` (now running in the `deployment` environment, #1850) is unaffected. ## Follow-up (PyPI) The trusted publishers registered for `publish_candidates.yml` on the `e2b`, `e2b-code-interpreter` and `e2b-desktop` PyPI projects (see #1828) no longer have a workflow behind them and can be removed. Since the remaining `publish_packages.yml` publishers are now the only ones, they can also be tightened to require the `deployment` environment. Link to Devin session: https://app.devin.ai/sessions/a59b5e364c484ced9524a652f80a49f9 Open in Devin Desktop: https://app.devin.ai/desktop/session/a59b5e364c484ced9524a652f80a49f9?variant=devin Requested by: @mishushakov Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: mish@e2b.dev <mish@e2b.dev>
Summary
Drops the long-lived
PYPI_TOKENand publishese2b,e2b-code-interpreterande2b-desktopto PyPI through GitHub OIDC trusted publishing, the same way the npm packages already publish with--provenance.applied to the three
postPublishscripts (run bychangeset publishinsidechangesets/action) and to the RC step inpublish_candidates.yml.alwaysrather than the defaultautomaticso a missing OIDC token fails immediately instead of falling back to prompting for credentials.PYPI_TOKENis removed frompublish_packages.yml'sworkflow_callsecrets and the release step env; both callers already usesecrets: inherit, and both publish workflows already carryid-token: write, so nothing else in the workflows changes.Also removes the
NPM_TOKEN: ''env from the changesets step. It was the changesets/changesets#1152 workaround for olderchangesets/actionversions that wrote a literalundefinedtoken to~/.npmrcwhen the var was unset; the pinned v1.9.0 only writes.npmrcif (process.env.NPM_TOKEN)and otherwise uses OIDC, so''and unset are equivalent and noNPM_TOKENsecret exists in the repo.Required PyPI configuration (before merging)
PyPI verifies the OIDC
job_workflow_refclaim, which for a same-repo reusable workflow names the called file (OWNER/REPO/.github/workflows/<called>.yml@<ref>), notrelease.yml/release-candidate.yml. Register a GitHub Actions trusted publisher on each of the three PyPI projects (e2b,e2b-code-interpreter,e2b-desktop) for each of:e2b-devE2Bpublish_packages.ymle2b-devE2Bpublish_candidates.ymlLeave the environment empty; the publish jobs don't run in a GitHub environment. Once the first trusted-publishing release succeeds, the
PYPI_TOKENrepository secret can be revoked and deleted.Link to Devin session: https://app.devin.ai/sessions/75f1691f0870441a85dd0bc09797fef4
Open in Devin Desktop: https://app.devin.ai/desktop/session/75f1691f0870441a85dd0bc09797fef4?variant=devin
Requested by: @mishushakov