diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1fcdfc8..21ab7cf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: matrix: PYTHON: - {VERSION: "3.7", TOXENV: "py37"} - - {VERSION: "3.12", TOXENV: "py312"} + - {VERSION: "3.13", TOXENV: "py313"} MACOS: - macos-13 - macos-latest @@ -57,7 +57,7 @@ jobs: - {ARCH: 'x64', WINDOWS: 'win64', RUST_TRIPLE: 'x86_64-pc-windows-msvc'} PYTHON: - {VERSION: "3.7", TOXENV: "py37"} - - {VERSION: "3.12", TOXENV: "py312"} + - {VERSION: "3.13", TOXENV: "py313"} name: "Python ${{ matrix.PYTHON.VERSION }} on ${{ matrix.WINDOWS.WINDOWS }}" steps: - uses: actions/checkout@v4.2.1 @@ -89,22 +89,22 @@ jobs: strategy: matrix: PYTHON: - - {VERSION: "3.12", TOXENV: "pep8,packaging"} - - {VERSION: "3.12", TOXENV: "mypy"} + - {VERSION: "3.13", TOXENV: "pep8,packaging"} + - {VERSION: "3.13", TOXENV: "mypy"} - {VERSION: "3.7", TOXENV: "py37"} - {VERSION: "3.8", TOXENV: "py38"} - {VERSION: "3.9", TOXENV: "py39"} - {VERSION: "3.10", TOXENV: "py310"} - {VERSION: "3.11", TOXENV: "py311"} - {VERSION: "3.12", TOXENV: "py312"} - - {VERSION: "3.13-dev", TOXENV: "py313"} + - {VERSION: "3.13", TOXENV: "py313"} - {VERSION: "pypy-3.9", TOXENV: "pypy3"} - {VERSION: "pypy-3.10", TOXENV: "pypy3"} # MSRV - - {VERSION: "3.12", TOXENV: "py312", RUST_VERSION: "1.64.0"} - - {VERSION: "3.12", TOXENV: "py312", RUST_VERSION: "beta"} - - {VERSION: "3.12", TOXENV: "py312", RUST_VERSION: "nightly"} + - {VERSION: "3.13", TOXENV: "py313", RUST_VERSION: "1.64.0"} + - {VERSION: "3.13", TOXENV: "py313", RUST_VERSION: "beta"} + - {VERSION: "3.13", TOXENV: "py313", RUST_VERSION: "nightly"} name: "${{ matrix.PYTHON.TOXENV }} on linux, Rust ${{ matrix.PYTHON.RUST_VERSION || 'stable' }}" steps: - uses: actions/checkout@v4.2.1 diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml index f5f91df..1d8696c 100644 --- a/.github/workflows/pypi-publish.yml +++ b/.github/workflows/pypi-publish.yml @@ -32,56 +32,28 @@ jobs: - run: echo "$EVENT_CONTEXT" env: EVENT_CONTEXT: ${{ toJson(github.event) }} - - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 - with: - python-version: "3.11" - uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6 with: - path: dist/ + path: tmpdist/ run_id: ${{ github.event.inputs.run_id || github.event.workflow_run.id }} - - run: pip install twine requests + - run: mkdir dist/ + - run: | + find tmpdist/ -type f -name 'bcrypt*' -exec mv {} dist/ \; - run: | - echo "OIDC_AUDIENCE=pypi" >> $GITHUB_ENV - echo "PYPI_DOMAIN=pypi.org" >> $GITHUB_ENV - echo "TWINE_REPOSITORY=pypi" >> $GITHUB_ENV - echo "TWINE_USERNAME=__token__" >> $GITHUB_ENV + echo "PYPI_URL=https://pypi.org/legacy/" >> $GITHUB_ENV if: github.event_name == 'workflow_run' || (github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'pypi') - run: | - echo "OIDC_AUDIENCE=testpypi" >> $GITHUB_ENV - echo "PYPI_DOMAIN=test.pypi.org" >> $GITHUB_ENV - echo "TWINE_REPOSITORY=testpypi" >> $GITHUB_ENV - echo "TWINE_USERNAME=__token__" >> $GITHUB_ENV + echo "PYPI_URL=https://test.pypi.org/legacy/" >> $GITHUB_ENV if: github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'testpypi' - - run: | - import os - - import requests - - response = requests.get( - os.environ["ACTIONS_ID_TOKEN_REQUEST_URL"], - params={"audience": os.environ["OIDC_AUDIENCE"]}, - headers={"Authorization": f"bearer {os.environ['ACTIONS_ID_TOKEN_REQUEST_TOKEN']}"} - ) - response.raise_for_status() - token = response.json()["value"] - - response = requests.post(f"https://{os.environ['PYPI_DOMAIN']}/_/oidc/mint-token", json={"token": token}) - response.raise_for_status() - pypi_token = response.json()["token"] - - with open(os.environ["GITHUB_ENV"], "a") as f: - print(f"::add-mask::{pypi_token}") - f.write(f"TWINE_PASSWORD={pypi_token}\n") - shell: python - - - run: find dist/ -type f -name 'bcrypt*' -print0 | xargs -0 twine upload --skip-existing - - # Do not perform attestation for things for TestPyPI. This is because - # there's nothing that would prevent a malicious PyPI from serving a - # signed TestPyPI asset in place of a release intended for PyPI. - - uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3 + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@v1.10.3 with: - subject-path: 'dist/**/bcrypt*' - if: env.TWINE_REPOSITORY == 'pypi' + repository-url: ${{ env.PYPI_URL }} + skip-existing: true + # Do not perform attestation for things for TestPyPI. This is + # because there's nothing that would prevent a malicious PyPI from + # serving a signed TestPyPI asset in place of a release intended for + # PyPI. + attestations: ${{ env.PYPI_URL == 'https://pypi.org/legacy/' }} diff --git a/pyproject.toml b/pyproject.toml index 4cdce8f..3c47670 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] requires-python = ">= 3.7" dynamic = ["readme"]