quipu 0.5.0

Codec criptográfico post-cuántico híbrido con endurecimiento online verificable (VOPRF) y canal visual de glifos.
Documentation
name: release-wheels

# Construye ruedas Python (abi3, una por plataforma sirve para CPython 3.9+) y el
# sdist. En un tag "v*" además publica en PyPI. También ejecutable a mano.
on:
  push:
    tags: ["v*"]
  workflow_dispatch:

permissions:
  contents: read

jobs:
  wheels:
    name: wheels-${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.x"
      - name: Build wheels (maturin, feature python)
        uses: PyO3/maturin-action@v1
        with:
          command: build
          args: --release --features python --out dist
          sccache: "true"
          manylinux: auto
      - uses: actions/upload-artifact@v4
        with:
          name: wheels-${{ matrix.os }}
          path: dist

  sdist:
    name: sdist
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build sdist
        uses: PyO3/maturin-action@v1
        with:
          command: sdist
          args: --out dist
      - uses: actions/upload-artifact@v4
        with:
          name: sdist
          path: dist

  publish:
    name: publish to PyPI
    needs: [wheels, sdist]
    runs-on: ubuntu-latest
    # Solo publica al hacer un tag v*.
    if: startsWith(github.ref, 'refs/tags/v')
    environment: pypi
    permissions:
      id-token: write   # PyPI trusted publishing (OIDC), sin token en secretos
    steps:
      - uses: actions/download-artifact@v4
        with:
          path: dist
          merge-multiple: true
      # Acción oficial de PyPA: soporta trusted publishing (OIDC) de forma nativa,
      # sin necesidad de token. Sube todo lo que haya en dist/ (ruedas + sdist).
      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          skip-existing: true

  sign:
    name: sign artifacts (sigstore) + GitHub Release
    needs: [wheels, sdist]
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/v')
    permissions:
      id-token: write   # cosign keyless (OIDC), sin claves en secretos
      contents: write   # crear el GitHub Release y adjuntar artefactos + firmas
    steps:
      - uses: actions/download-artifact@v4
        with:
          path: dist
          merge-multiple: true
      - name: Install cosign
        uses: sigstore/cosign-installer@v3
      - name: Sign each artifact (keyless)
        run: |
          for f in dist/*; do
            cosign sign-blob --yes --bundle "${f}.sigstore" "${f}"
          done
      - uses: actions/upload-artifact@v4
        with:
          name: signatures
          path: dist/*.sigstore
          if-no-files-found: error
      # Publica un GitHub Release con las ruedas/sdist Y sus bundles .sigstore,
      # para que cualquiera pueda `cosign verify-blob --bundle` según docs/RELEASES.md.
      - name: Create GitHub Release with signed artifacts
        uses: softprops/action-gh-release@v2
        with:
          files: |
            dist/*.whl
            dist/*.tar.gz
            dist/*.sigstore
          fail_on_unmatched_files: true
          generate_release_notes: true
          body: |
            Artefactos firmados con sigstore/cosign (keyless, OIDC).
            Verificación: ver [`docs/RELEASES.md`](https://github.com/isazajuancarlos/quipu/blob/main/docs/RELEASES.md)
            (attestations PEP 740 en PyPI + `cosign verify-blob --bundle` para cada `.sigstore`).