ci(release): publish to public PyPI through JFrog OIDC only#303
Merged
fsamier merged 1 commit intoMay 29, 2026
Merged
Conversation
Stop using the long-lived PYPI_PUBLIC_API_TOKEN secret and stop the parallel push to `vault-pypi-prod-green`. Releases now go to a single destination: `vault-pypi-prod-public` via JFrog OIDC. JFrog forwards them to public PyPI through the `pypi-ledgerhq` push integration configured in the cybersec PyPI webhook (cybersec-pypi-prd). Why single-push (and not dual-push to prod-green + prod-public): - All local repos have `priority_resolution = true` and JFrog resolves repos in alphabetical order inside `virtual-pypi-prod-green`, so `vault-pypi-prod-green` sits in front of `vault-pypi-prod-public`. As soon as a package name exists in `prod-green`, JFrog stops there and never inspects `prod-public`, no matter what newer versions live there. Dual-push turns any partial failure or asymmetric cleanup into a silent split-brain: PyPI public serves the new version while internal consumers via the virtual continue to see the old one. - The vault project's `virtual-pypi-prod-green` already aggregates `vault-pypi-prod-public`, so internal consumers keep installing through the same virtual without changing anything. - Single source of truth per package, no atomicity issue between two publish steps, no storage duplication, and DELETE is never needed (consistent with the AGENTS.md DELETE policy on CI/CD bindings). Why removing the PyPI secret: - Removes a high-value, long-lived secret from this repository. - Centralizes publishing on JFrog OIDC, consistent with the other Ledger libraries publishing under the cybersec PyPI webhook. Migration note (before this lands): - Past releases pushed `python-erc7730` artifacts into `vault-pypi-prod-green`. Those old versions will shadow any new release in `vault-pypi-prod-public` for internal consumers, because of Priority Resolution + alphabetical order. The legacy versions in `vault-pypi-prod-green` must be moved to (or republished into) `vault-pypi-prod-public`, or removed, before the first release on the new workflow. This is a one-time admin op on JFrog, not done by CI. Follow-up: - Once a release has been published successfully via this new path, the PYPI_PUBLIC_API_TOKEN secret can be removed from the repo. Co-authored-by: Cursor <cursoragent@cursor.com>
fsamier
approved these changes
May 29, 2026
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.
Summary
PYPI_PUBLIC_API_TOKENsecret.vault-pypi-prod-public. JFrog forwards uploads to public PyPI via the cybersecpypi-prdwebhook (pypi-ledgerhqintegration).vault-pypi-prod-green.Why single-push (and not dual push to
prod-green+prod-public)All local repos have
priority_resolution = trueand JFrog resolves repos insidevirtual-pypi-prod-greenin alphabetical order —vault-pypi-prod-greensits beforevault-pypi-prod-public. As soon as a package name exists inprod-green, JFrog stops there and never inspectsprod-public, regardless of newer versions present. Dual-push turns any partial failure into a silent split-brain (PyPI public serves the new version, internal consumers via the virtual still see the old one).The vault project's
virtual-pypi-prod-greenalready aggregatesvault-pypi-prod-public, so internal consumers keep installing through the same virtual without change.Why removing the PyPI secret
Dependencies / coordination
This PR depends on https://github.com/LedgerHQ/tf-jfrog/pull/new/feat/vault-pypi-prod-public-python-eip712-erc7730 which adds the
vault-pypi-prod-publicrepo on the JFrog side. Do not merge before that PR is applied by Atlantis.Migration note (one-time, before first release on the new workflow)
Past releases pushed
python-erc7730artifacts intovault-pypi-prod-green. Those legacy versions will shadow any new release invault-pypi-prod-publicfor internal consumers, due to Priority Resolution + alphabetical order invirtual-pypi-prod-green. The legacy versions invault-pypi-prod-greenmust be moved to (or re-published into)vault-pypi-prod-public, or removed, before the first release on the new workflow. One-time JFrog admin op, not done by CI.Test plan
python-erc7730versions migrated fromvault-pypi-prod-greentovault-pypi-prod-public(admin op).pip install python-erc7730==<new-version>works through the internal virtual.PYPI_PUBLIC_API_TOKENsecret from the repo settings once a release has succeeded.Made with Cursor