diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..e4b0e44 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + + - package-ecosystem: cargo + directory: / + schedule: + interval: weekly + + - package-ecosystem: pip + directory: / + schedule: + interval: weekly diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index f583e9b..176f6d0 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -1,12 +1,12 @@ name: CI Build & Test on: - push: + pull_request: branches: + - dev + - stage - main - pull_request: workflow_dispatch: - # For publish workflow workflow_call: permissions: @@ -62,14 +62,19 @@ jobs: ] fail-fast: false steps: - - uses: actions/checkout@v3 + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 + with: + egress-policy: audit + + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Setup Rust - uses: actions-rs/toolchain@v1 + uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7 with: toolchain: 1.90.0 components: rustfmt, clippy - name: Setup Python for maturin - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: '3.13' - name: Install specific Rust version @@ -78,7 +83,7 @@ jobs: rustup default 1.90.0 rustup show - name: Build wheels - uses: PyO3/maturin-action@v1 + uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0 with: target: ${{ matrix.target[0] }} args: --release --out aerospike_async --interpreter ${{ matrix.python }} @@ -122,7 +127,7 @@ jobs: - name: Set up QEMU if: ${{ !startsWith(matrix.target[0], 'x86_64') }} - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 - name: Get Docker image name and tag run: echo DOCKER_IMAGE_TAG=$(echo ${{ matrix.python }} | sed -E "s/(python|pypy)/\1:/") >> $GITHUB_ENV @@ -139,7 +144,7 @@ jobs: - name: Install wheel (non-x86 wheels) if: ${{ !startsWith(matrix.target[0], 'x86_64') }} - run: docker exec --workdir /aerospike-client-python-async ${{ matrix.python }} ${{ matrix.python }} -m pip install --find-links=aerospike_async/ aerospike_client_python_async + run: docker exec --workdir /aerospike-client-python-async ${{ matrix.python }} ${{ matrix.python }} -m pip install --find-links=aerospike_async/ aerospike_async - name: Install pytest (non-x86 wheels) if: ${{ !startsWith(matrix.target[0], 'x86_64') }} run: docker exec --workdir /aerospike-client-python-async ${{ matrix.python }} ${{ matrix.python }} -m pip install pytest pytest-asyncio @@ -166,7 +171,7 @@ jobs: - name: Setup Python for testing if: ${{ startsWith(matrix.target[0], 'x86_64') }} - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ env.PYTHON_VERSION }} @@ -204,7 +209,7 @@ jobs: fi - name: Upload wheels - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: wheels-linux-${{ matrix.python }}-${{ matrix.target[0] }} path: aerospike_async @@ -223,18 +228,23 @@ jobs: ] fail-fast: false steps: - - uses: actions/checkout@v4 + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 + with: + egress-policy: audit + + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Setup Rust - uses: actions-rs/toolchain@v1 + uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7 with: toolchain: 1.90.0 components: rustfmt, clippy - name: Setup Python for maturin - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: '3.13' - name: Build wheels - uses: PyO3/maturin-action@v1 + uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0 with: target: aarch64 args: --release --out aerospike_async --interpreter ${{ matrix.python }} @@ -276,7 +286,7 @@ jobs: run: echo PYTHON_VERSION=$(echo ${{ matrix.python }} | sed -E "s/python(.*)/\1/") >> $GITHUB_ENV - name: Setup Python for testing - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ env.PYTHON_VERSION }} @@ -309,7 +319,7 @@ jobs: fi - name: Upload wheels - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: wheels-linux-arm64-${{ matrix.python }} path: aerospike_async @@ -321,9 +331,14 @@ jobs: target: [x64, x86] fail-fast: false steps: - - uses: actions/checkout@v4 + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 + with: + egress-policy: audit + + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Setup Rust - uses: actions-rs/toolchain@v1 + uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7 with: toolchain: 1.90.0 components: rustfmt, clippy @@ -347,12 +362,12 @@ jobs: echo "NASM installed but path verification skipped (will be available in next step)" } } - - uses: actions/setup-python@v6 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: '3.13' architecture: ${{ matrix.target }} - name: Build wheels - uses: PyO3/maturin-action@v1 + uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0 with: target: ${{ matrix.target }} args: --release --out aerospike_async --find-interpreter @@ -367,7 +382,7 @@ jobs: # Windows wheels are built and uploaded, but tests run on Linux/macOS only. - name: Upload wheels - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: wheels-windows-${{ matrix.target }} path: aerospike_async @@ -385,7 +400,12 @@ jobs: ] fail-fast: false steps: - - uses: actions/checkout@v4 + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 + with: + egress-policy: audit + + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Try Podman run: | brew install podman @@ -419,16 +439,16 @@ jobs: echo "=== Server Build ===" podman exec aerospike-server asinfo -v "build" - name: Setup Rust - uses: actions-rs/toolchain@v1 + uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7 with: toolchain: 1.90.0 components: rustfmt, clippy - name: Setup Python for maturin - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: '3.13' - name: Build wheels - uses: PyO3/maturin-action@v1 + uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0 with: target: x86_64 args: --release --out aerospike_async --interpreter ${{ matrix.python }} @@ -436,11 +456,11 @@ jobs: - name: Remove python prefix for setting up python (CPython only) run: echo PYTHON_VERSION=$(echo ${{ matrix.python }} | sed -E "s/python(.*)/\1/") >> $GITHUB_ENV - name: Setup Python for testing - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install wheel - run: ${{ matrix.python }} -m pip install --find-links=aerospike_async/ aerospike_client_python_async + run: ${{ matrix.python }} -m pip install --find-links=aerospike_async/ aerospike_async - name: Install pytest run: ${{ matrix.python }} -m pip install pytest pytest-asyncio - name: Debug module contents (macOS) @@ -466,7 +486,7 @@ jobs: exit 1 fi - name: Upload wheels - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: wheels-macos-x86-${{ matrix.python }} path: aerospike_async @@ -487,24 +507,29 @@ jobs: ] fail-fast: false steps: - - uses: actions/checkout@v4 + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 + with: + egress-policy: audit + + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Setup Rust - uses: actions-rs/toolchain@v1 + uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7 with: toolchain: 1.90.0 components: rustfmt, clippy - name: Setup Python for maturin - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: '3.13' - name: Build wheels - uses: PyO3/maturin-action@v1 + uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0 with: target: aarch64 args: --release --out aerospike_async --interpreter ${{ matrix.python }} sccache: 'true' - name: Upload wheels - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: wheels-macos-arm64-${{ matrix.python }} path: aerospike_async @@ -512,19 +537,24 @@ jobs: sdist: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 + with: + egress-policy: audit + + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Setup Rust - uses: actions-rs/toolchain@v1 + uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7 with: toolchain: 1.90.0 components: rustfmt, clippy - name: Build sdist - uses: PyO3/maturin-action@v1 + uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0 with: command: sdist args: --out aerospike_async - name: Upload sdist - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: wheels path: aerospike_async diff --git a/.github/workflows/publish-rtd.yml b/.github/workflows/publish-rtd.yml new file mode 100644 index 0000000..2af78d0 --- /dev/null +++ b/.github/workflows/publish-rtd.yml @@ -0,0 +1,67 @@ +# SKELETON — not yet wired into the live release pipeline. +# +# Implements Gate 4 (Product GA, owner: Product) — triggers a +# ReadTheDocs build for the given version. Single curl POST against +# the RTD v3 API. +# +# Status: skeleton. Will not trigger anything until the RTD project +# is created and a token is provisioned. When `vars.RTD_PROJECT` or +# `secrets.RTD_TOKEN` is unset the workflow logs and exits 0. + +name: Publish docs to ReadTheDocs (Gate 4) + +on: + workflow_dispatch: + inputs: + version: + description: "RTD version slug to build (e.g. v0.1.0-alpha.1, latest, stable)" + type: string + required: true + dry-run: + description: "Dry-run (skip the actual RTD API call)" + type: boolean + default: true + +permissions: + contents: read + +jobs: + trigger-rtd: + runs-on: ubuntu-22.04 + steps: + - name: Skip if RTD not provisioned (skeleton phase) + id: gate + run: | + if [[ -z "${{ vars.RTD_PROJECT }}" ]]; then + echo "RTD_PROJECT unset — skeleton phase, skipping trigger." + echo "skip=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + echo "skip=false" >> "$GITHUB_OUTPUT" + + - name: Harden the runner + if: steps.gate.outputs.skip != 'true' + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 + with: + egress-policy: audit + + - name: Trigger RTD build + if: steps.gate.outputs.skip != 'true' + env: + RTD_PROJECT: ${{ vars.RTD_PROJECT }} + RTD_VERSION: ${{ inputs.version }} + RTD_TOKEN: ${{ secrets.RTD_TOKEN }} + DRY_RUN: ${{ inputs.dry-run }} + run: | + if [[ -z "$RTD_TOKEN" ]]; then + echo "::warning::secrets.RTD_TOKEN is not set — skipping RTD trigger." + exit 0 + fi + API="https://readthedocs.org/api/v3/projects/${RTD_PROJECT}/versions/${RTD_VERSION}/builds/" + if [[ "$DRY_RUN" == "true" ]]; then + echo "DRY-RUN: would POST $API" + exit 0 + fi + curl -fSsL -X POST -H "Authorization: Token ${RTD_TOKEN}" "$API" + echo + echo "Triggered RTD build: project=$RTD_PROJECT version=$RTD_VERSION" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e32dbb0..ff6eaba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,5 @@ +# NOTE: This workflow will be retired once the new release pipeline lands +# (CI-driven build + branch promotion + publish workflows). Do not extend. name: Release on: @@ -24,7 +26,12 @@ jobs: validate: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 + with: + egress-policy: audit + + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Validate version matches Cargo.toml run: | @@ -48,18 +55,33 @@ jobs: fi echo "Tag v${{ inputs.version }} is available" - - name: Enforce stable releases from main + - name: Enforce branch gate run: | VERSION="${{ inputs.version }}" BRANCH="${{ github.ref_name }}" - if echo "$VERSION" | grep -q -E "\-alpha|\-beta|\-rc"; then - echo "Pre-release ($VERSION) — allowed from any branch ($BRANCH)" - elif [ "$BRANCH" != "main" ]; then - echo "::error::Stable releases must be cut from the main branch (current: $BRANCH)" - exit 1 - else - echo "Stable release ($VERSION) from main — OK" - fi + case "$VERSION" in + *-alpha.*|*-beta.*) + if [ "$BRANCH" != "dev" ]; then + echo "::error::alpha/beta releases must be cut from 'dev' (current: $BRANCH)" + exit 1 + fi + echo "alpha/beta release ($VERSION) from $BRANCH — OK" + ;; + *-rc.*) + if [ "$BRANCH" != "stage" ]; then + echo "::error::RC releases must be cut from 'stage' (current: $BRANCH)" + exit 1 + fi + echo "RC release ($VERSION) from $BRANCH — OK" + ;; + *) + if [ "$BRANCH" != "main" ]; then + echo "::error::Stable releases must be cut from 'main' (current: $BRANCH)" + exit 1 + fi + echo "Stable release ($VERSION) from $BRANCH — OK" + ;; + esac build: needs: validate @@ -69,17 +91,22 @@ jobs: needs: build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 + with: + egress-policy: audit + + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Download all wheel artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: pattern: wheels-* merge-multiple: true path: dist - name: Download sdist - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: wheels path: dist @@ -117,7 +144,7 @@ jobs: cat release_notes.md - name: Create GitHub Release - uses: softprops/action-gh-release@v2 + uses: step-security/action-gh-release@dc29ef0d1f6f9a032a97ec797d9cb7ea788dde41 # v2.6.1 with: tag_name: "v${{ inputs.version }}" name: "v${{ inputs.version }}" @@ -131,17 +158,23 @@ jobs: needs: release runs-on: ubuntu-latest steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 + with: + egress-policy: audit + - name: Download all artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: pattern: wheels* merge-multiple: true path: dist - name: Publish to PyPI - uses: PyO3/maturin-action@v1 + uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0 env: MATURIN_PYPI_TOKEN: ${{ inputs.publish_pypi == 'pypi.org' && secrets.PYPI_API_TOKEN || secrets.TEST_PYPI_API_TOKEN }} + MATURIN_REPOSITORY_URL: ${{ inputs.publish_pypi == 'pypi.org' && 'https://upload.pypi.org/legacy/' || 'https://test.pypi.org/legacy/' }} with: command: upload args: --non-interactive --skip-existing dist/* diff --git a/.gitignore b/.gitignore index ff5bbf3..3e072b3 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,9 @@ var/ include/ man/ venv/ +# Project-owned helper scripts under bin/ (override the venv-style bin/ rule above). +!bin/ +!bin/* *.egg-info/ .installed.cfg *.egg diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9b979fe..7b972f0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,3 +8,7 @@ repos: hooks: - id: end-of-file-fixer - id: trailing-whitespace +- repo: https://github.com/jumanjihouse/pre-commit-hooks + rev: 3.0.0 + hooks: + - id: shellcheck diff --git a/Cargo.lock b/Cargo.lock index 41ce75e..e81b11b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,8 +4,8 @@ version = 4 [[package]] name = "aerospike-core" -version = "2.0.0" -source = "git+https://github.com/aerospike/aerospike-client-rust?branch=v2#3de909bcafc6ad0a6caf0f0a18f738c77b41a74f" +version = "2.1.0" +source = "git+https://github.com/aerospike/aerospike-client-rust?branch=v2#7b679c6081e299570152359f6855618350a2efb0" dependencies = [ "aerospike-rt", "async-channel", @@ -17,7 +17,7 @@ dependencies = [ "lazy_static", "log", "pwhash", - "rand", + "rand 0.10.1", "regex", "rhexdump", "ripemd", @@ -28,15 +28,15 @@ dependencies = [ [[package]] name = "aerospike-rt" -version = "2.0.0" -source = "git+https://github.com/aerospike/aerospike-client-rust?branch=v2#3de909bcafc6ad0a6caf0f0a18f738c77b41a74f" +version = "2.1.0" +source = "git+https://github.com/aerospike/aerospike-client-rust?branch=v2#7b679c6081e299570152359f6855618350a2efb0" dependencies = [ "tokio", ] [[package]] name = "aerospike_async" -version = "0.3.0-alpha.14" +version = "0.4.0-alpha.1" dependencies = [ "aerospike-core", "aws-lc-rs", @@ -120,11 +120,11 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.16.2" +version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" +checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" dependencies = [ - "aws-lc-sys 0.39.1", + "aws-lc-sys 0.40.0", "untrusted 0.7.1", "zeroize", ] @@ -143,9 +143,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.39.1" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399" +checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" dependencies = [ "cc", "cmake", @@ -155,9 +155,15 @@ dependencies = [ [[package]] name = "base64" -version = "0.13.1" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "block-buffer" @@ -170,11 +176,11 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.4" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" dependencies = [ - "generic-array", + "hybrid-array", ] [[package]] @@ -208,9 +214,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.59" +version = "1.2.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" +checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" dependencies = [ "find-msvc-tools", "jobserver", @@ -224,6 +230,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + [[package]] name = "chrono" version = "0.4.44" @@ -264,6 +281,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -279,6 +302,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -287,12 +319,11 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" -version = "0.1.7" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" dependencies = [ - "generic-array", - "typenum", + "hybrid-array", ] [[package]] @@ -316,11 +347,12 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.7" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" dependencies = [ - "block-buffer 0.10.4", + "block-buffer 0.12.0", + "const-oid", "crypto-common", ] @@ -369,6 +401,12 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "fs_extra" version = "1.3.0" @@ -465,9 +503,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -492,10 +530,33 @@ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasip2", + "wasip3", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + [[package]] name = "hashbrown" version = "0.17.0" @@ -533,6 +594,15 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "hybrid-array" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d46837a0ed51fe95bd3b05de33cd64a1ee88fc797477ca48446872504507c5" +dependencies = [ + "typenum", +] + [[package]] name = "iana-time-zone" version = "0.1.65" @@ -557,6 +627,12 @@ dependencies = [ "cc", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "indexmap" version = "2.14.0" @@ -564,7 +640,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.17.0", + "serde", + "serde_core", ] [[package]] @@ -594,6 +672,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "jobserver" version = "0.1.34" @@ -606,10 +690,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.94" +version = "0.3.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" +checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] @@ -620,11 +706,17 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.184" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "log" @@ -793,9 +885,9 @@ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" dependencies = [ "portable-atomic", ] @@ -809,6 +901,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -828,7 +930,7 @@ dependencies = [ "byteorder", "hmac", "md-5", - "rand", + "rand 0.8.6", "sha-1", "sha2", ] @@ -968,15 +1070,32 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "chacha20", + "getrandom 0.4.2", + "rand_core 0.10.1", ] [[package]] @@ -986,7 +1105,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -998,6 +1117,12 @@ dependencies = [ "getrandom 0.2.17", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "rawpointer" version = "0.2.1" @@ -1055,11 +1180,11 @@ dependencies = [ [[package]] name = "ripemd" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +checksum = "4dd4211456b4172d7e44261920c25acf07367c4f04bb5f5d54fc21b090d9b159" dependencies = [ - "digest 0.10.7", + "digest 0.11.2", ] [[package]] @@ -1070,9 +1195,9 @@ checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" dependencies = [ "aws-lc-rs", "log", @@ -1094,18 +1219,18 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.0" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.10" +version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ "aws-lc-rs", "ring", @@ -1119,6 +1244,12 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.228" @@ -1149,6 +1280,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "serde_spanned" version = "1.1.1" @@ -1166,7 +1310,7 @@ checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ "block-buffer 0.9.0", "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.9.0", "opaque-debug", ] @@ -1179,7 +1323,7 @@ checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.9.0", "opaque-debug", ] @@ -1231,18 +1375,18 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" [[package]] name = "thiserror" -version = "1.0.69" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.69" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -1251,9 +1395,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.51.1" +version = "1.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" dependencies = [ "bytes", "libc", @@ -1303,7 +1447,7 @@ version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow 1.0.1", + "winnow 1.0.2", ] [[package]] @@ -1314,9 +1458,9 @@ checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" [[package]] name = "unicode-ident" @@ -1324,6 +1468,12 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "unindent" version = "0.2.4" @@ -1356,18 +1506,27 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", ] [[package]] name = "wasm-bindgen" -version = "0.2.117" +version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" +checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1" dependencies = [ "cfg-if", "once_cell", @@ -1378,9 +1537,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.117" +version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" +checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1388,9 +1547,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.117" +version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" +checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41" dependencies = [ "bumpalo", "proc-macro2", @@ -1401,18 +1560,52 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.117" +version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" +checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea" dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" dependencies = [ "rustls-pki-types", ] @@ -1566,15 +1759,103 @@ checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" [[package]] name = "winnow" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" +checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" [[package]] name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "zerocopy" @@ -1601,3 +1882,9 @@ name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index e7daa5f..54fe27c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aerospike_async" -version = "0.3.0-alpha.14" +version = "0.4.0-alpha.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/README.md b/README.md index 8dd4dc3..ff8d601 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,17 @@ -# Aerospike Async Python Client +# Aerospike Async Python Client — `core-v2-maintenance` + +> **You are looking at the `core-v2-maintenance` branch.** This branch tracks the +> released **Aerospike Rust client v2** line (`aerospike-core` `branch = "v2"`) +> and exists to give QA a stable PAC build for testing rust-core v2 in the +> field. Mainline development (`main` / `dev`) targets rust-core v3 and +> includes features (MRTs, path expressions, compression, strong-consistency +> read modes) that are **not** present on this branch. +> +> Forward-port policy: only PAC-internal fixes that are independent of v3 +> rust-core APIs are eligible for backport here. +> +> Distributed on PyPI as `aerospike-async-core-v2` (separate from the v3 +> `aerospike-async` distribution). ## Installation @@ -230,6 +243,53 @@ policy.set_auth_mode(AuthMode.PKI) # No user/password needed - Transactions - Dynamic Config +## Versioning + +PAC follows [SemVer](https://semver.org/) for releases. Pre-releases use the +`MAJOR.MINOR.PATCH-{alpha,beta,rc}.N` form (e.g. `0.3.0-alpha.16`). PyPI +normalizes these on upload to the equivalent PEP 440 spelling (`0.3.0a16`). + +### Single source of truth + +`Cargo.toml` is the only place where the version lives: + +```toml +[package] +name = "aerospike_async" +version = "0.3.0-alpha.16" +``` + +`pyproject.toml` does **not** duplicate the version. maturin reads it from +`Cargo.toml` when it builds the wheel, so the two are guaranteed to match. + +### Bumping the version + +Bumps are manual and happen in PRs against `dev`. Promotion workflows +(`dev → stage → main`) do not mutate the version. + +```bash +# 1. Edit Cargo.toml [package] version field, then refresh Cargo.lock: +# e.g. 0.3.0-alpha.16 → 0.3.0-alpha.17 +cargo check # or: cargo update -p aerospike_async --precise 0.3.0-alpha.17 + +# 2. Confirm: +bin/get-version # prints 0.3.0-alpha.17 + +# 3. Open a PR against dev with just this change. +``` + +### Reading the version programmatically + +Anywhere a build script, CI step, or release tool needs the version: + +```bash +bin/get-version # → 0.3.0-alpha.16 +``` + +The script parses the first `version` field inside the `[package]` table of +`Cargo.toml`. It has no Python or cargo runtime dependencies — usable from +any shell, container, or CI environment. + ## License Apache License 2.0. See [LICENSE](LICENSE) for details. diff --git a/bin/get-version b/bin/get-version new file mode 100755 index 0000000..15fb63d --- /dev/null +++ b/bin/get-version @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# Print the package version from Cargo.toml. +# +# Cargo.toml is the single source of truth for PAC's version. maturin reads +# it directly when building wheels; pyproject.toml does not duplicate it. +# +# Output: bare version string with no trailing newline manipulation. +# Example: 0.3.0-alpha.16 + +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cargo_toml="${repo_root}/Cargo.toml" + +if [[ ! -f "${cargo_toml}" ]]; then + echo "error: ${cargo_toml} not found" >&2 + exit 1 +fi + +# Match the first `version = "..."` inside the [package] table only. +# awk state machine: enter [package], grab first version line, exit. +version="$(awk ' + /^\[package\]/ { in_pkg = 1; next } + /^\[/ && in_pkg { exit } + in_pkg && /^version[[:space:]]*=/ { + match($0, /"[^"]+"/) + print substr($0, RSTART + 1, RLENGTH - 2) + exit + } +' "${cargo_toml}")" + +if [[ -z "${version}" ]]; then + echo "error: no [package] version found in ${cargo_toml}" >&2 + exit 1 +fi + +printf '%s\n' "${version}" diff --git a/pyproject.toml b/pyproject.toml index a6ac788..7d747fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,9 @@ requires = ["maturin>=1.9.0,<2.0"] build-backend = "maturin" [project] -name = "aerospike_client_python_async" +name = "aerospike-async-core-v2" +description = "Aerospike Python Async Client (v2 core maintenance line) — async I/O over the released Aerospike Rust client core v2 (PyO3). For QA testing of rust-core v2; for v3 features install `aerospike-async`." +readme = "README.md" dynamic = ["version"] requires-python = ">=3.10" dependencies = ["uvloop>=0.17; sys_platform != 'win32'"] diff --git a/python/aerospike_async/__init__.py b/python/aerospike_async/__init__.py index 7211480..d452d56 100644 --- a/python/aerospike_async/__init__.py +++ b/python/aerospike_async/__init__.py @@ -42,6 +42,6 @@ try: from importlib.metadata import version as _pkg_version - __version__ = _pkg_version("aerospike_client_python_async") + __version__ = _pkg_version("aerospike_async") except Exception: __version__ = "0.0.0-dev" diff --git a/python/aerospike_async/_aerospike_async_native.pyi b/python/aerospike_async/_aerospike_async_native.pyi index a077105..641daa5 100644 --- a/python/aerospike_async/_aerospike_async_native.pyi +++ b/python/aerospike_async/_aerospike_async_native.pyi @@ -429,6 +429,27 @@ class ClientPolicy: @buffer_reclaim_threshold.setter def buffer_reclaim_threshold(self, value: builtins.int) -> None: ... @property + def max_error_rate(self) -> builtins.int: + r""" + Maximum number of errors (network errors plus server-side ``TIMEOUT``, + ``DEVICE_OVERLOAD``, ``KEY_BUSY``) tolerated against a single node within + one ``error_rate_window``. Once exceeded, the client trips a per-node + circuit breaker and rejects further commands targeted at that node with + a ``MaxErrorRate`` exception until the next window resets. Set to ``0`` + to disable. Default: ``100``. + """ + @max_error_rate.setter + def max_error_rate(self, value: builtins.int) -> None: ... + @property + def error_rate_window(self) -> builtins.int: + r""" + Number of cluster tend iterations after which each node's error counter + is reset. Smaller values make the circuit breaker more aggressive, + larger values more lenient. Default: ``1``. + """ + @error_rate_window.setter + def error_rate_window(self, value: builtins.int) -> None: ... + @property def tend_interval(self) -> builtins.int: r""" TendInterval determines interval for checking for cluster state changes. diff --git a/python/aerospike_async/exceptions/__init__.py b/python/aerospike_async/exceptions/__init__.py index 8199716..d65cb4f 100644 --- a/python/aerospike_async/exceptions/__init__.py +++ b/python/aerospike_async/exceptions/__init__.py @@ -28,6 +28,7 @@ PasswordHashError = _exceptions.PasswordHashError InvalidRustClientArgs = _exceptions.InvalidRustClientArgs ClientError = _exceptions.ClientError +MaxErrorRate = _exceptions.MaxErrorRate # ResultCode is in the main native module, not in exceptions submodule ResultCode = _aerospike_async_native.ResultCode diff --git a/python/aerospike_async/exceptions/__init__.pyi b/python/aerospike_async/exceptions/__init__.pyi index 7ece2c4..0f373f2 100644 --- a/python/aerospike_async/exceptions/__init__.pyi +++ b/python/aerospike_async/exceptions/__init__.pyi @@ -81,6 +81,10 @@ class ClientError(AerospikeError): """Exception raised for client-side errors.""" def __init__(self, message: builtins.str) -> None: ... +class MaxErrorRate(AerospikeError): + """Per-node circuit breaker tripped; the command was not sent to the server.""" + def __init__(self, message: builtins.str) -> None: ... + class RecordError(ServerError): """Record-level server errors.""" @@ -131,6 +135,7 @@ __all__ = [ "PasswordHashError", "InvalidRustClientArgs", "ClientError", + "MaxErrorRate", "ResultCode", "RecordError", "IndexError", diff --git a/python/postprocess_stubs.py b/python/postprocess_stubs.py index 4e13c0d..2d29e6a 100755 --- a/python/postprocess_stubs.py +++ b/python/postprocess_stubs.py @@ -112,6 +112,10 @@ def __init__(self, message: builtins.str) -> None: ... class ClientError(AerospikeError): """Exception raised for client-side errors.""" def __init__(self, message: builtins.str) -> None: ... + +class MaxErrorRate(AerospikeError): + """Per-node circuit breaker tripped; the command was not sent to the server.""" + def __init__(self, message: builtins.str) -> None: ... ''' # ServerError subclasses (Python-defined; used by Rust create_server_error dispatch) @@ -163,6 +167,7 @@ class SecurityNotEnabled(SecurityError): ... "PasswordHashError", "InvalidRustClientArgs", "ClientError", + "MaxErrorRate", "ResultCode", "RecordError", "IndexError", @@ -1594,6 +1599,7 @@ def ensure_exceptions_submodule(package_dir: str): f.write('PasswordHashError = _exceptions.PasswordHashError\n') f.write('InvalidRustClientArgs = _exceptions.InvalidRustClientArgs\n') f.write('ClientError = _exceptions.ClientError\n') + f.write('MaxErrorRate = _exceptions.MaxErrorRate\n') f.write('# ResultCode is in the main native module, not in exceptions submodule\n') f.write('ResultCode = _aerospike_async_native.ResultCode\n') f.write('\n') diff --git a/python/tests/unit/policies_test.py b/python/tests/unit/policies_test.py index a09c8bf..50dadfc 100644 --- a/python/tests/unit/policies_test.py +++ b/python/tests/unit/policies_test.py @@ -237,8 +237,12 @@ def test_expiration_values(self): def test_max_retries_default(self): """Test max_retries default value (int, not nullable).""" wp = WritePolicy() - # Default should be 2 (per Rust core default) - assert wp.max_retries == 2 + # On rust-core v2 (CLIENT-4405), WritePolicy::default() explicitly + # overrides max_retries to 0 — writes do not retry by default. + # ReadPolicy/BatchPolicy/QueryPolicy still default to 2 from + # BasePolicy::default(). On rust-core v3 the WritePolicy override + # was not applied, and its default remains 2. + assert wp.max_retries == 0 wp.max_retries = 5 assert wp.max_retries == 5 diff --git a/src/errors.rs b/src/errors.rs index 3586094..3dd6f62 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -103,6 +103,12 @@ create_exception!(aerospike_async.exceptions, InvalidRustClientArgs, AerospikeEr // Client-side errors create_exception!(aerospike_async.exceptions, ClientError, AerospikeError); +// Per-node circuit breaker tripped (client-side, not sent to server). Carries +// the offending node identifier in the exception message. Raised when a node +// exceeds the policy's `max_error_rate` over `error_rate_window` ticks, so the +// client backs off rather than forwarding more commands to that node. +create_exception!(aerospike_async.exceptions, MaxErrorRate, AerospikeError); + // Must define a wrapper type because of the orphan rule pub struct RustClientError(pub(crate) Error); @@ -173,6 +179,10 @@ impl From for PyErr { } }, Error::ClientError(msg) => ClientError::new_err(msg), + Error::MaxErrorRate(node) => MaxErrorRate::new_err(format!( + "Max error rate exceeded for node {node}; backing off" + )), + #[allow(unreachable_patterns)] other => AerospikeError::new_err(format!("Unknown error: {:?}", other)), } } diff --git a/src/lib.rs b/src/lib.rs index d5b3627..afaeb82 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2009,6 +2009,7 @@ fn _aerospike_async_native(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> exceptions_module.add("PasswordHashError", py.get_type::())?; exceptions_module.add("InvalidRustClientArgs", py.get_type::())?; exceptions_module.add("ClientError", py.get_type::())?; + exceptions_module.add("MaxErrorRate", py.get_type::())?; exceptions_module.add("ResultCode", py.get_type::())?; m.add_submodule(&exceptions_module)?; diff --git a/src/policies.rs b/src/policies.rs index 1a76bac..42b9ae8 100644 --- a/src/policies.rs +++ b/src/policies.rs @@ -1663,6 +1663,35 @@ use crate::TlsConfig; self._as.buffer_reclaim_threshold = value; } + /// Maximum number of errors (network errors plus server-side ``TIMEOUT``, + /// ``DEVICE_OVERLOAD``, ``KEY_BUSY``) tolerated against a single node within + /// one ``error_rate_window``. Once exceeded, the client trips a per-node + /// circuit breaker and rejects further commands targeted at that node with + /// a ``MaxErrorRate`` exception until the next window resets. Set to ``0`` + /// to disable. Default: ``100``. + #[getter] + pub fn get_max_error_rate(&self) -> usize { + self._as.max_error_rate + } + + #[setter] + pub fn set_max_error_rate(&mut self, value: usize) { + self._as.max_error_rate = value; + } + + /// Number of cluster tend iterations after which each node's error counter + /// is reset. Smaller values make the circuit breaker more aggressive, + /// larger values more lenient. Default: ``1``. + #[getter] + pub fn get_error_rate_window(&self) -> usize { + self._as.error_rate_window + } + + #[setter] + pub fn set_error_rate_window(&mut self, value: usize) { + self._as.error_rate_window = value; + } + /// TendInterval determines interval for checking for cluster state changes. /// Minimum possible interval is 10 Milliseconds. #[getter]