diff --git a/.github/actions/setup-patched-deps/action.yml b/.github/actions/setup-patched-deps/action.yml new file mode 100644 index 0000000..f237603 --- /dev/null +++ b/.github/actions/setup-patched-deps/action.yml @@ -0,0 +1,25 @@ +name: Setup Patched Dependencies +description: Clone and patch orchard and sapling-crypto repositories + +runs: + using: composite + steps: + - name: Clone orchard + shell: bash + run: | + git clone --branch v0.11.0 --single-branch \ + https://github.com/zcash/orchard.git .patched-orchard + - name: Patch orchard + shell: bash + run: | + git -C .patched-orchard apply "../nix/airdrop-orchard-nullifier.patch" + - name: Clone sapling-crypto + shell: bash + run: | + git clone --branch v0.5.0 --single-branch \ + https://github.com/zcash/sapling-crypto.git .patched-sapling-crypto + - name: Patch sapling-crypto + shell: bash + run: | + git -C .patched-sapling-crypto apply \ + "../nix/airdrop-sapling-nullifier.patch" diff --git a/.github/actions/setup-protoc/action.yml b/.github/actions/setup-protoc/action.yml new file mode 100644 index 0000000..fbc1b8b --- /dev/null +++ b/.github/actions/setup-protoc/action.yml @@ -0,0 +1,9 @@ +name: Setup Protoc +description: Install the Protocol Buffers compiler + +runs: + using: composite + steps: + - name: Install protoc + shell: bash + run: sudo apt-get update && sudo apt-get install -y protobuf-compiler diff --git a/.github/actions/setup-rust-build/action.yml b/.github/actions/setup-rust-build/action.yml new file mode 100644 index 0000000..f3c122a --- /dev/null +++ b/.github/actions/setup-rust-build/action.yml @@ -0,0 +1,37 @@ +name: Setup Rust Build +description: Install protoc, setup patched deps, install Rust toolchain, and configure cache + +inputs: + toolchain: + description: Rust toolchain to install (e.g., nightly, stable, 1.88.0) + required: true + components: + description: Additional Rust components to install (e.g., clippy, rustfmt) + required: false + default: "" + shared-key: + description: Shared key for Rust cache + required: true + +runs: + using: composite + steps: + - name: Install protoc + uses: ./.github/actions/setup-protoc + - name: Setup patched dependencies + uses: ./.github/actions/setup-patched-deps + - name: Install toolchain + uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # branch=master + id: toolchain + with: + toolchain: ${{ inputs.toolchain }} + components: ${{ inputs.components }} + - name: Set toolchain override + shell: bash + run: rustup override set "${TOOLCHAIN}" + env: + TOOLCHAIN: ${{ steps.toolchain.outputs.name }} + - name: Setup Rust cache + uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # tag: v2.8.2 + with: + shared-key: ${{ inputs.shared-key }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..03a2dc0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,180 @@ +# CI runs when a PR is opened/ready or before merging. +# +# | Event | When | +# |---------------------------------|----------------------------| +# | pull_request (opened) | PR created (draft or not) | +# | pull_request (ready_for_review) | Draft PR marked ready | +# | merge_group | Merge queue (before merge) | +# | workflow_dispatch | Manual trigger | +# +# Note: `synchronize` is intentionally omitted to avoid workflow runs on +# every push. + +name: ci +on: + pull_request: + types: [opened, ready_for_review] + branches: + - main + merge_group: + workflow_dispatch: +permissions: + contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: + fmt: + name: nightly / fmt + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag: v6.0.1 + - name: Install nightly + uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # branch=master + id: toolchain + with: + toolchain: nightly + components: rustfmt + - name: Toolchain override + run: rustup override set "${TOOLCHAIN}" + env: + TOOLCHAIN: ${{steps.toolchain.outputs.name}} + - name: cargo fmt --all --check + run: cargo fmt --all --check + lint: + name: nightly / clippy, test and docs + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag: v6.0.1 + with: + submodules: recursive + - name: Setup Rust build environment + uses: ./.github/actions/setup-rust-build + with: + toolchain: nightly + components: clippy + shared-key: lint-all-features + - name: cargo clippy + run: cargo clippy --locked --all-targets --all-features -- -D warnings + - name: Install cargo-hack + uses: taiki-e/install-action@b9c5db3aef04caffaf95a1d03931de10fb2a140f # tag: v2.65.1 + with: + tool: cargo-hack + - name: cargo hack + run: cargo hack --no-dev-deps --feature-powerset check --locked + - name: cargo test + run: cargo test --locked --all-features + - name: Check Documentation + run: cargo doc --locked --no-deps --workspace --all-features --document-private-items + env: + RUSTDOCFLAGS: -D warnings + build: + name: stable / build + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag: v6.0.1 + with: + submodules: recursive + - name: Setup Rust build environment + uses: ./.github/actions/setup-rust-build + with: + toolchain: stable + shared-key: build-release + - name: cargo build --release + run: cargo build --release --locked + msrv: + name: MSRV / 1.88.0 + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag: v6.0.1 + with: + submodules: recursive + - name: Setup Rust build environment + uses: ./.github/actions/setup-rust-build + with: + toolchain: "1.88.0" + shared-key: msrv + - name: cargo check + run: cargo check --locked --all-targets --all-features + cargo-deny: + name: Check licenses & security + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag: v6.0.1 + with: + submodules: recursive + - name: Setup patched dependencies + uses: ./.github/actions/setup-patched-deps + - name: Check licenses + uses: EmbarkStudios/cargo-deny-action@76cd80eb775d7bbbd2d80292136d74d39e1b4918 # tag: v2.0.14 + with: + command: check licenses + - name: Install cargo-audit + uses: taiki-e/install-action@b9c5db3aef04caffaf95a1d03931de10fb2a140f # tag: v2.65.1 + with: + tool: cargo-audit + - name: cargo audit + run: cargo audit + machete: + name: Check unused dependencies + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag: v6.0.1 + - name: Install cargo-machete + uses: taiki-e/install-action@b9c5db3aef04caffaf95a1d03931de10fb2a140f # tag: v2.65.1 + with: + tool: cargo-machete + - name: cargo machete + run: cargo machete + toml-fmt: + name: toml fmt + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag: v6.0.1 + - name: Install taplo + uses: taiki-e/install-action@b9c5db3aef04caffaf95a1d03931de10fb2a140f # tag: v2.65.1 + with: + tool: taplo + - name: taplo fmt --check + run: taplo fmt --check + markdown-lint: + name: markdown lint + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag: v6.0.1 + - name: Lint markdown + uses: DavidAnson/markdownlint-cli2-action@07035fd053f7be764496c0f8d8f9f41f98305101 # tag: v22.0.0 + yaml-lint: + name: yaml lint + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag: v6.0.1 + - name: Lint YAML + uses: ibiqlik/action-yamllint@2576378a8e339169678f9939646ee3ee325e845c # tag: v3.1.1 + typos: + name: typos + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag: v6.0.1 + - name: Check typos + uses: crate-ci/typos@2d0ce569feab1f8752f1dde43cc2f2aa53236e06 # tag: v1.40.0 diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..18e3c71 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,4 @@ +{ + "MD013": false, + "MD024": false +} diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..140dfa5 --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,11 @@ +--- +extends: default + +rules: + document-start: disable + truthy: + check-keys: false + line-length: + max: 120 + comments: + min-spaces-from-content: 1 diff --git a/Cargo.toml b/Cargo.toml index 8bcbac3..a45ebab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = [ [workspace.package] edition = "2024" -rust-version = "1.91.1" +rust-version = "1.88.0" repository = "https://github.com/eigerco/zcash-namada-airdrop" license = "MIT" @@ -73,3 +73,6 @@ unused_qualifications = "warn" arithmetic_side_effects = "deny" indexing_slicing = "deny" unwrap_used = "deny" + +[workspace.lints.rustdoc] +broken_intra_doc_links = "deny" diff --git a/crates/airdrop/Cargo.toml b/crates/airdrop/Cargo.toml index c127ad2..c97d1cd 100644 --- a/crates/airdrop/Cargo.toml +++ b/crates/airdrop/Cargo.toml @@ -2,7 +2,8 @@ name = "airdrop" version = "0.1.0" edition.workspace = true -license = "MIT" +license.workspace = true +rust-version.workspace = true [features] default = [] diff --git a/crates/light-wallet-api/Cargo.toml b/crates/light-wallet-api/Cargo.toml index 2722078..b0066d3 100644 --- a/crates/light-wallet-api/Cargo.toml +++ b/crates/light-wallet-api/Cargo.toml @@ -2,7 +2,8 @@ name = "light-wallet-api" version = "0.1.0" edition.workspace = true -license = "MIT" +license.workspace = true +rust-version.workspace = true [dependencies] prost = { workspace = true } diff --git a/crates/mnemonic-to-fvks/Cargo.toml b/crates/mnemonic-to-fvks/Cargo.toml index aff782a..7299462 100644 --- a/crates/mnemonic-to-fvks/Cargo.toml +++ b/crates/mnemonic-to-fvks/Cargo.toml @@ -2,7 +2,8 @@ name = "mnemonic-to-fvks" version = "0.1.0" edition.workspace = true -license = "MIT" +license.workspace = true +rust-version.workspace = true [dependencies] bip39 = { workspace = true } diff --git a/crates/non-membership-proofs/Cargo.toml b/crates/non-membership-proofs/Cargo.toml index 536f3da..4c92634 100644 --- a/crates/non-membership-proofs/Cargo.toml +++ b/crates/non-membership-proofs/Cargo.toml @@ -2,7 +2,8 @@ name = "non-membership-proofs" version = "0.1.0" edition.workspace = true -license = "MIT" +license.workspace = true +rust-version.workspace = true [dependencies] async-stream = { workspace = true } diff --git a/docs/USAGE.md b/docs/USAGE.md index 997a4b0..b04fb15 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -69,7 +69,7 @@ The `.bin` snapshot files use a simple binary format: - Nullifiers must be **sorted in ascending lexicographic order** - File size must be a multiple of 32 bytes -``` +```console ┌──────────────────┬──────────────────┬─────┬──────────────────┐ │ Nullifier 0 │ Nullifier 1 │ ... │ Nullifier N │ │ (32 bytes) │ (32 bytes) │ │ (32 bytes) │ diff --git a/nix/devshell.nix b/nix/devshell.nix index 1761ae3..87cd03a 100644 --- a/nix/devshell.nix +++ b/nix/devshell.nix @@ -42,6 +42,7 @@ cargo-machete # Check for unused dependencies cargo-deny # Cargo plugin for linting your dependencies cargo-llvm-cov # Code coverage + cargo-msrv # Check minimum supported Rust version # General development tools git diff --git a/nix/git-hooks.nix b/nix/git-hooks.nix index 6ab6f49..4c284cc 100644 --- a/nix/git-hooks.nix +++ b/nix/git-hooks.nix @@ -18,88 +18,72 @@ # $ nix develop -c pre-commit run -a pre-commit = { check.enable = true; - settings.hooks = { - # markdown - markdownlint = { - enable = true; - args = [ - "--disable" - "MD013" - ]; - }; + settings = { + hooks = { + # markdown (config in .markdownlint.json) + markdownlint.enable = true; - # shell - shellcheck.enable = true; + # shell + shellcheck.enable = true; - # nix - nixfmt-rfc-style.enable = true; - flake-checker.enable = true; - statix = { - enable = true; - settings = { - ignore = [ ".direnv" ]; + # nix + nixfmt-rfc-style.enable = true; + flake-checker.enable = true; + statix = { + enable = true; + settings = { + ignore = [ ".direnv" ]; + }; }; - }; - # Rust - cargo-check = { - package = rustToolchain; - enable = false; # Disabled due to offline mode issues with new dependencies - }; + # Rust + cargo-check = { + package = rustToolchain; + enable = false; # Disabled due to offline mode issues with new dependencies + }; - cargo-test = { - enable = false; # Disabled due to offline mode issues with new dependencies - name = "cargo test"; - entry = "${rustToolchain}/bin/cargo test"; - pass_filenames = false; - }; + cargo-test = { + enable = false; # Disabled due to offline mode issues with new dependencies + name = "cargo test"; + entry = "${rustToolchain}/bin/cargo test"; + pass_filenames = false; + }; - # Check for security vulnerabilities - cargo-audit = { - enable = false; # Disabled due to offline mode issues with new dependencies - name = "cargo-audit"; - entry = "${pkgs.cargo-audit}/bin/cargo-audit audit"; - pass_filenames = false; - }; + # Check for security vulnerabilities + cargo-audit = { + enable = false; # Disabled due to offline mode issues with new dependencies + name = "cargo-audit"; + entry = "${pkgs.cargo-audit}/bin/cargo-audit audit"; + pass_filenames = false; + }; - # Check for unused dependencies - cargo-machete = { - enable = true; - name = "cargo-machete"; - entry = "${pkgs.cargo-machete}/bin/cargo-machete"; - pass_filenames = false; - }; + # Check for unused dependencies + cargo-machete = { + enable = true; + name = "cargo-machete"; + entry = "${pkgs.cargo-machete}/bin/cargo-machete"; + pass_filenames = false; + }; - # Rust linter - clippy = { - package = rustToolchain; - enable = false; # Disabled due to offline mode issues with new dependencies - }; + # Rust linter + clippy = { + package = rustToolchain; + enable = false; # Disabled due to offline mode issues with new dependencies + }; - # secret detection - ripsecrets.enable = true; - trufflehog.enable = true; + # secret detection + ripsecrets.enable = true; + trufflehog.enable = true; - # spell checker - typos = { - enable = true; - settings.config = { - # Ignore words matching long alphanumeric patterns (hashes, addresses) - # This regex matches strings with 16+ alphanumeric chars (adjust as needed) - # See: https://github.com/crate-ci/typos#configuration - default.extend-ignore-re = [ "([a-zA-Z0-9]{16,})" ]; - default.extend-words = { - groth = "groth"; - Groth = "Groth"; - }; - }; - }; + # spell checker (config in typos.toml) + typos.enable = true; - # toml - taplo.enable = true; + # toml + taplo.enable = true; - # yaml - yamllint.enable = true; + # yaml + yamllint.enable = true; + }; }; }; }; diff --git a/typos.toml b/typos.toml new file mode 100644 index 0000000..efbd5a2 --- /dev/null +++ b/typos.toml @@ -0,0 +1,7 @@ +[default] +# Ignore words matching long alphanumeric patterns (hashes, addresses) +extend-ignore-re = ["([a-zA-Z0-9]{16,})"] + +[default.extend-words] +groth = "groth" +Groth = "Groth"