From e31c0d38d1347d12a4e29f1ccdb2602b1a1ea169 Mon Sep 17 00:00:00 2001 From: Elvis Claros Castro Date: Mon, 17 Aug 2026 15:44:37 -0300 Subject: Publicar en PyPI desde el release, sin tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trusted publishing: PyPI confía en este workflow por OIDC y no hay ningún secreto guardado en el repo. El único permiso que pide el job es id-token: write; el resto del workflow corre sin permisos. Antes de que sirva hay que dar de alta el pending publisher en pypi.org con los cuatro datos que espera (owner, repo, publish.yml, environment pypi). Incluye dos guardas antes de subir nada: - que el tag del release coincida con __version__, porque una versión subida a PyPI no se puede reemplazar, solo yankear; - twine check sobre el sdist y el wheel. Claude-Session: https://claude.ai/code/session_01RmtZ9qBemrc9TncwVTG6ED --- .github/workflows/publish.yml | 60 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 .github/workflows/publish.yml (limited to '.github/workflows') diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..4fc675c --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,60 @@ +name: Publish + +# Publica en PyPI cuando se publica un release de GitHub. +# +# No hay ningún token guardado: PyPI confía en este workflow por OIDC +# (trusted publishing). Del lado de pypi.org hay que haber dado de alta un +# "pending publisher" con exactamente estos cuatro datos: +# +# Owner ElvisClaros +# Repository claude-logbook +# Workflow publish.yml +# Environment pypi +# +# Si alguno no coincide, PyPI rechaza el upload. + +on: + release: + types: [published] + +permissions: {} + +jobs: + publish: + runs-on: ubuntu-latest + + environment: + name: pypi + url: https://pypi.org/p/claude-logbook + + permissions: + id-token: write # lo único que habilita el trusted publishing + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.13" + + # El número vive en claude_logbook/__init__.py y es fácil olvidarse de + # subirlo. Mejor fallar acá que publicar algo mal rotulado: una versión + # subida a PyPI no se puede reemplazar nunca, solo yankear. + - name: El tag coincide con __version__ + run: | + tag="${GITHUB_REF_NAME#v}" + ver="$(python -c 'import claude_logbook; print(claude_logbook.__version__)')" + echo "tag=$tag __version__=$ver" + test "$tag" = "$ver" + + - name: Build + run: | + python -m pip install --upgrade build + python -m build + + - name: Los artefactos están sanos + run: | + python -m pip install --upgrade twine + twine check dist/* + + - uses: pypa/gh-action-pypi-publish@release/v1 -- cgit v1.2.3