Skip to content

ci(release): publish to public PyPI through JFrog OIDC only#303

Merged
fsamier merged 1 commit into
LedgerHQ:mainfrom
xchalle:feat/publish-to-pypi-via-jfrog-oidc
May 29, 2026
Merged

ci(release): publish to public PyPI through JFrog OIDC only#303
fsamier merged 1 commit into
LedgerHQ:mainfrom
xchalle:feat/publish-to-pypi-via-jfrog-oidc

Conversation

@xchalle
Copy link
Copy Markdown
Contributor

@xchalle xchalle commented May 28, 2026

Summary

  • Stop using the long-lived PYPI_PUBLIC_API_TOKEN secret.
  • Publish releases through JFrog OIDC to a single destination: vault-pypi-prod-public. JFrog forwards uploads to public PyPI via the cybersec pypi-prd webhook (pypi-ledgerhq integration).
  • Drop the parallel push to vault-pypi-prod-green.

Why single-push (and not dual push to prod-green + prod-public)

All local repos have priority_resolution = true and JFrog resolves repos inside virtual-pypi-prod-green in alphabetical order — vault-pypi-prod-green sits before vault-pypi-prod-public. As soon as a package name exists in prod-green, JFrog stops there and never inspects prod-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-green already aggregates vault-pypi-prod-public, so internal consumers keep installing through the same virtual without change.

Why removing the PyPI secret

  • Removes a high-value, long-lived secret from this repository.
  • Centralizes publishing on JFrog OIDC, consistent with other Ledger libraries publishing under the cybersec PyPI webhook.

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-public repo 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-erc7730 artifacts into vault-pypi-prod-green. Those legacy versions will shadow any new release in vault-pypi-prod-public for internal consumers, due to Priority Resolution + alphabetical order in virtual-pypi-prod-green. The legacy versions in vault-pypi-prod-green must 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

  • tf-jfrog PR merged and applied by Atlantis.
  • Legacy python-erc7730 versions migrated from vault-pypi-prod-green to vault-pypi-prod-public (admin op).
  • Cut a test release (RC tag) and verify the release workflow succeeds end-to-end.
  • Verify the new version is available on https://pypi.org/project/erc7730/ (via the cybersec webhook).
  • Verify pip install python-erc7730==<new-version> works through the internal virtual.
  • Remove the PYPI_PUBLIC_API_TOKEN secret from the repo settings once a release has succeeded.

Made with Cursor

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>
@xchalle xchalle requested a review from a team as a code owner May 28, 2026 15:59
@fsamier fsamier merged commit be8a8b8 into LedgerHQ:main May 29, 2026
7 of 8 checks passed
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.

2 participants