diff --git a/.github/workflows/compat.yml b/.github/workflows/compat.yml new file mode 100644 index 0000000..1ccba26 --- /dev/null +++ b/.github/workflows/compat.yml @@ -0,0 +1,49 @@ +name: Compatibility + +on: + schedule: + - cron: "0 6 * * 1" # Weekly, Monday 06:00 UTC + pull_request: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +defaults: + run: + shell: bash + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + +jobs: + compat: + if: github.event_name != 'pull_request' || startsWith(github.head_ref, 'mergify/merge-queue/') + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + toolchain: + - stable + - stable minus 2 releases + - stable minus 5 releases + - "1.85.0" # MSRV — edition 2024 minimum + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # master + with: + toolchain: ${{ matrix.toolchain }} + + - name: Build + run: cargo build + + - name: Run tests + run: cargo test diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml new file mode 100644 index 0000000..0f35623 --- /dev/null +++ b/.github/workflows/fuzz.yml @@ -0,0 +1,60 @@ +name: Fuzz + +on: + schedule: + - cron: "0 6 * * 1" # Weekly, Monday 06:00 UTC + pull_request: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +defaults: + run: + shell: bash + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + # Duration (seconds) each fuzz target runs before moving on. + FUZZ_SECONDS: "60" + +jobs: + fuzz: + if: github.event_name != 'pull_request' || startsWith(github.head_ref, 'mergify/merge-queue/') + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + target: [fuzz_read_bounded, fuzz_map_file] + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Install nightly toolchain + uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # master + with: + toolchain: nightly + + - name: Install cargo-fuzz + env: + RUSTUP_TOOLCHAIN: nightly + run: cargo install cargo-fuzz --locked + + - name: Run fuzz target + env: + TARGET: ${{ matrix.target }} + RUSTUP_TOOLCHAIN: nightly + run: cargo fuzz run "$TARGET" -- -max_total_time="$FUZZ_SECONDS" + + - name: Upload crash artifacts + if: failure() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: fuzz-crashes-${{ matrix.target }} + path: fuzz/artifacts/${{ matrix.target }}/ + retention-days: 30 diff --git a/.gitignore b/.gitignore index b4b4b14..113f602 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,10 @@ docs/book/ .history/ .ionide +# Fuzzing (machine-generated, not committed) +fuzz/artifacts/ +fuzz/corpus/ + # Testing **/mutants.out*/ diff --git a/.mergify.yml b/.mergify.yml index 6fb7175..bf22b1c 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -16,6 +16,13 @@ queue_rules: - check-success = test-cross-platform (macos-latest, macOS) - check-success = test-cross-platform (windows-latest, Windows) - check-success = coverage + # Weekly workflows — block merge if they ran and failed, pass if absent + - check-success-or-neutral = fuzz (fuzz_read_bounded) + - check-success-or-neutral = fuzz (fuzz_map_file) + - check-success-or-neutral = compat (stable) + - check-success-or-neutral = compat (stable minus 2 releases) + - check-success-or-neutral = compat (stable minus 5 releases) + - check-success-or-neutral = compat (1.85.0) # NOTE: The check-success conditions in pull_request_rules duplicate those in # queue_rules.merge_conditions. This is intentional defense-in-depth: the rule diff --git a/AGENTS.md b/AGENTS.md index 90f5228..1490b64 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -70,7 +70,47 @@ The crate is a thin library with four source files: - `src/map.rs` — `map_file()` with pre-flight stat check; contains the single `unsafe` block - `src/load.rs` — `load()` routes `"-"` to `load_stdin(Some(1 GiB))`; other paths to `map_file()`. `load_stdin(max_bytes)` reads stdin into a heap buffer with optional byte cap -Runtime dependencies: `memmap2`, `fs4` (advisory file locking). Dev-dependency: `tempfile`. +Runtime dependencies: `memmap2`, `fs4` (advisory file locking). Dev-dependencies: `tempfile`, `proptest`. + +## Fuzzing & Property Tests + +Coverage-guided fuzzing via `cargo-fuzz` (nightly) and property tests via `proptest` (stable). + +### Fuzz targets (`fuzz/`) + +The `fuzz/` directory is a separate Cargo workspace (not published). It depends on `mmap-guard` with the `__fuzz` feature to access internal functions. + +```bash +# Install cargo-fuzz (one-time) +cargo install cargo-fuzz --locked + +# Run a fuzz target (nightly required) +cargo +nightly fuzz run fuzz_read_bounded -- -max_total_time=60 +cargo +nightly fuzz run fuzz_map_file -- -max_total_time=60 + +# List available targets +cargo +nightly fuzz list +``` + +Targets: + +- `fuzz_read_bounded` — structured input (`Arbitrary`) exercising the bounded-read logic with fuzzer-controlled data and cap +- `fuzz_map_file` — writes fuzzer bytes to a temp file, maps it, asserts round-trip integrity + +### Property tests + +- `tests/prop_map_file.rs` — proptest integration test for `map_file` round-trip +- `src/load.rs` `mod tests::prop` — proptest for `read_bounded` (unit test, has access to private API) + +### `__fuzz` feature flag + +The `__fuzz` feature exposes `read_bounded` (normally private) as `#[doc(hidden)] pub`. It is not part of the public API — the leading underscores signal internal-only use. Only the fuzz crate enables it. + +### CI workflows + +- `.github/workflows/fuzz.yml` — weekly nightly fuzzing + merge queue gate, matrix over targets, uploads crash artifacts on failure +- `.github/workflows/compat.yml` — weekly Rust version compatibility matrix (stable, stable minus 2, stable minus 5, MSRV 1.85) + merge queue gate, runs build + tests with default features +- Both fuzz and compat workflows use the two-step CI pattern: they trigger on `pull_request` but skip on regular PRs via `if: startsWith(github.head_ref, 'mergify/merge-queue/')`. Mergify's `merge_conditions` use `check-success-or-neutral` so skipped jobs pass on regular PRs but block merge if they fail in the queue. ## Lint Configuration diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dd4d747..ba7ce2d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,13 +8,13 @@ This project follows the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT. ## Gotchas -Before working in a specific area, check [GOTCHAS.md](GOTCHAS.md) for hard-won lessons and edge cases organized by domain. It covers unsafe code rules, clippy/rustdoc pitfalls, CI quirks, pre-commit hook behavior, and platform-specific mmap limitations. +Before working in a specific area, check [GOTCHAS.md](GOTCHAS.md) for hard-won lessons and edge cases organized by domain. It covers unsafe code rules, clippy/rustdoc pitfalls, CI quirks, pre-commit hook behavior, platform-specific mmap limitations, and fuzzing with cargo-fuzz. ## Getting Started ### Prerequisites -- **Rust 1.89+** (edition 2024, stable toolchain) +- **Rust 1.85+** (edition 2024, stable toolchain) - **Git** for version control - **[mise](https://mise.jdx.dev/)** for tool management (recommended) @@ -45,6 +45,7 @@ All tools are managed via mise — run `mise install` to bootstrap: - **cargo-llvm-cov** — code coverage - **cargo-audit** / **cargo-deny** — security auditing - **cargo-about** — third-party license notices +- **cargo-fuzz** — coverage-guided fuzzing (requires nightly) - **just** — task runner - **pre-commit** — git hooks - **mdbook** — documentation @@ -166,6 +167,13 @@ cargo nextest run -- --nocapture # Check coverage just coverage-check # 85% threshold + +# Run property tests +cargo test --test prop_map_file + +# Run fuzz targets (requires nightly) +cargo +nightly fuzz run fuzz_read_bounded -- -max_total_time=60 +cargo +nightly fuzz run fuzz_map_file -- -max_total_time=60 ``` ### Writing Tests @@ -174,6 +182,8 @@ just coverage-check # 85% threshold - Use `#[cfg(test)]` modules with `#[allow(clippy::unwrap_used, clippy::expect_used)]` - Include doc tests for public API examples - Test both success and error cases +- Property tests using `proptest` are included in the test suite +- Fuzz targets live in the `fuzz/` workspace and require nightly Example test structure: @@ -232,7 +242,7 @@ All pull requests require review before merging. Reviewers check for: - **Style** — Follows project conventions, passes `cargo fmt` and `cargo clippy -- -D warnings` - **Documentation** — Public APIs have rustdoc with examples, AGENTS.md updated if architecture changes -CI checks run before merge, including quality checks, tests, coverage, and cross-platform tests (Ubuntu, macOS, Windows). +CI checks run before merge, including quality checks, tests, coverage, and cross-platform tests (Ubuntu, macOS, Windows). Weekly workflows run fuzzing (`fuzz.yml`) and compatibility checks across Rust versions (`compat.yml`). These weekly workflows use `check-success-or-neutral` for merge gating, allowing merges when checks are skipped on regular PRs but blocking merges if they fail in the merge queue. ### Developer Certificate of Origin (DCO) diff --git a/Cargo.toml b/Cargo.toml index 64e4313..f803458 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/EvilBit-Labs/mmap-guard" documentation = "https://docs.rs/mmap-guard" keywords = ["mmap", "memmap", "memory-map", "file", "io"] categories = ["filesystem", "memory-management"] -rust-version = "1.89" +rust-version = "1.85" readme = "README.md" exclude = [ # Directories @@ -20,6 +20,7 @@ exclude = [ "/.git", "/.vscode", "/docs", + "/fuzz", "/reports", # CI / tooling config "/.coderabbitai.yaml", @@ -138,12 +139,16 @@ module_name_repetitions = "warn" similar_names = "warn" too_many_lines = "warn" +[features] +__fuzz = [] + [dependencies] fs4 = "0.13.1" memmap2 = "0.9.10" [dev-dependencies] -tempfile = "3.26.0" +proptest = "1.6.0" +tempfile = "3.26.0" [lints] workspace = true diff --git a/GOTCHAS.md b/GOTCHAS.md index e3b849a..8225a50 100644 --- a/GOTCHAS.md +++ b/GOTCHAS.md @@ -47,6 +47,13 @@ Referenced from [AGENTS.md](AGENTS.md) and [CONTRIBUTING.md](CONTRIBUTING.md) -- - `cargo-dist` plan/build does nothing for a library crate (no binary targets). That's why `dist-plan` is excluded from `just ci-check`. - Mergify merge protections evaluate from the **main branch** config, not the PR branch. - The docs workflow builds rustdoc with `--document-private-items` -- see Rustdoc section above for link pitfalls. +- Always verify pinned action SHAs with `gh api repos/{owner}/{repo}/commits/{sha} --jq '.sha'` before using them. Do not fabricate SHAs. + +## Local CI with `act` + +- `act` defaults to `push` event -- schedule-only workflows need `workflow_dispatch` passed as the event argument. +- `act` Docker containers run as root -- Unix permission tests (e.g., `chmod 000` → expect `PermissionDenied`) false-positive because root bypasses file permission checks. +- Use `--container-architecture linux/amd64` on Apple Silicon to avoid image pull failures. ## Pre-commit Hooks @@ -62,6 +69,17 @@ Referenced from [AGENTS.md](AGENTS.md) and [CONTRIBUTING.md](CONTRIBUTING.md) -- - SIGBUS from concurrent file truncation is a **known, documented limitation** -- it cannot be fully prevented without advisory file locking. It is explicitly out of scope for security reports (see SECURITY.md). - `map_file()` acquires a shared advisory lock via `fs4::fs_std::FileExt::try_lock_shared()` before mapping. Lock contention returns `WouldBlock`. The lock is held by the `File` inside `FileData::Mapped` and released on drop. +## Fuzzing + +- The `__fuzz` feature flag exposes `read_bounded` as `#[doc(hidden)] pub` for fuzz targets. Do not use this feature in production or library code. +- `read_bounded` is `pub fn` in `src/load.rs` but the module is private — it is only reachable outside the crate when re-exported via `#[cfg(feature = "__fuzz")]` in `lib.rs`. +- Fuzz targets live in `fuzz/` (separate workspace, edition 2021). They require nightly and `cargo-fuzz`. +- The `fuzz/Cargo.toml` uses `edition = "2021"` (not 2024) because `cargo-fuzz` / `libfuzzer-sys` requires nightly and edition 2021 avoids compatibility issues. +- Property tests (`proptest`) run on stable and are part of the normal test suite. The `read_bounded` proptest is a unit test inside `src/load.rs` (not in `tests/`) because it needs access to the private function. +- `rust-toolchain.toml` overrides `rustup default` -- CI workflows that need nightly must set `RUSTUP_TOOLCHAIN: nightly` as an env var on the run step, not just install the toolchain. +- `read_bounded` needs `#[allow(unreachable_pub)]` and `#[allow(clippy::missing_errors_doc)]` because it's `pub` (for re-export) in a private module -- clippy flags both even though the function is `#[doc(hidden)]`. +- `#[derive(Arbitrary)]` generates code referencing `arbitrary::` by path -- `use libfuzzer_sys::arbitrary::{self, Arbitrary}` requires the `self` import. Do not remove it; the derive macro will fail without it. + ## load / load_stdin - `load("-")` delegates to `load_stdin(Some(1_073_741_824))` (1 GiB default cap). Callers needing a custom limit should call `load_stdin(Some(n))` directly. diff --git a/docs/src/development.md b/docs/src/development.md index 842c44d..12d7a4f 100644 --- a/docs/src/development.md +++ b/docs/src/development.md @@ -27,6 +27,39 @@ This installs the Rust toolchain, cargo extensions (nextest, llvm-cov, audit, de | `just docs-build` | Build mdBook + rustdoc | | `just docs-serve` | Serve docs locally with live reload | +### Running Tests + +**Standard tests:** + +```bash +just test +``` + +**Property-based tests:** + +```bash +cargo test --test prop_map_file +``` + +Property tests use [proptest](https://github.com/proptest-rs/proptest) to verify round-trip integrity with randomized inputs. + +**Fuzz tests:** + +Fuzzing requires nightly Rust and `cargo-fuzz`. Install it first: + +```bash +cargo install cargo-fuzz +``` + +Run a specific fuzz target (available targets: `fuzz_read_bounded`, `fuzz_map_file`): + +```bash +cargo +nightly fuzz run fuzz_read_bounded +cargo +nightly fuzz run fuzz_map_file +``` + +Fuzz tests use the `__fuzz` feature flag to expose internal APIs for testing. This feature is for internal use only and should not be enabled in production code. + ## Pre-commit Hooks Pre-commit hooks run automatically on `git commit`: @@ -49,3 +82,10 @@ The GitHub Actions CI runs on every push to `main` and on pull requests: 2. **test** — nextest + release build 3. **test-cross-platform** — Linux (x2), macOS, Windows 4. **coverage** — llvm-cov uploaded to Codecov + +**Weekly scheduled workflows:** + +- **fuzz** — runs fuzzing tests (`fuzz_read_bounded`, `fuzz_map_file`) with nightly Rust. Also runs on merge queue PRs. +- **compat** — tests Rust version compatibility across stable, stable-2, stable-5, and MSRV 1.85. Also runs on merge queue PRs. + +These weekly workflows use `check-success-or-neutral` conditions for merge gating, allowing merges when the checks pass or are skipped. diff --git a/docs/src/testing.md b/docs/src/testing.md index 62a0b49..9b9262a 100644 --- a/docs/src/testing.md +++ b/docs/src/testing.md @@ -20,10 +20,10 @@ just test-all Tests are co-located with their source modules using `#[cfg(test)]` blocks: -| Module | Tests | -| -------------- | ------------------------------------------------------ | -| `file_data.rs` | `Deref`/`AsRef` impls, empty variant | -| `map.rs` | Successful mapping, empty file rejection, missing file | +| Module | Tests | +| -------------- | ---------------------------------------------------------------------------------------------------------------- | +| `file_data.rs` | `Deref`/`AsRef` impls, empty variant | +| `map.rs` | Successful mapping, empty file rejection, missing file | | `load.rs` | File loading via mmap, stdin handling with byte caps, path resolution (`"-"` routing), empty/missing file errors | ### Clippy in Tests diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..a49c89a --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "mmap-guard-fuzz" +version = "0.0.0" +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = { version = "0.4", features = ["arbitrary-derive"] } +tempfile = "3" + +[dependencies.mmap-guard] +path = ".." +features = ["__fuzz"] + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[[bin]] +name = "fuzz_read_bounded" +path = "fuzz_targets/fuzz_read_bounded.rs" +doc = false + +[[bin]] +name = "fuzz_map_file" +path = "fuzz_targets/fuzz_map_file.rs" +doc = false diff --git a/fuzz/fuzz_targets/fuzz_map_file.rs b/fuzz/fuzz_targets/fuzz_map_file.rs new file mode 100644 index 0000000..2a43497 --- /dev/null +++ b/fuzz/fuzz_targets/fuzz_map_file.rs @@ -0,0 +1,39 @@ +#![no_main] + +use std::io::Write; + +use libfuzzer_sys::fuzz_target; +use mmap_guard::map_file; +use tempfile::NamedTempFile; + +fuzz_target!(|data: &[u8]| { + // Write fuzzer-provided bytes to a temp file, then map it. + let mut tmp = match NamedTempFile::new() { + Ok(f) => f, + // If temp file creation fails, the environment is broken and + // the entire fuzz run is useless — panic to surface the issue. + Err(e) => panic!("temp dir is broken — fuzzing is impossible: {e}"), + }; + + if tmp.write_all(data).is_err() || tmp.flush().is_err() { + return; // I/O failure on temp file — not interesting + } + + match map_file(tmp.path()) { + Ok(mapped) => { + // Round-trip integrity: mapped bytes must equal what we wrote. + assert_eq!(&*mapped, data, "round-trip mismatch"); + } + Err(e) => { + // Empty files cannot be mapped — the only error expected in this + // context (no lock contention on fresh temp files). Any other error + // indicates an environmental issue worth investigating. + assert_eq!( + e.kind(), + std::io::ErrorKind::InvalidInput, + "unexpected error kind: {e}", + ); + assert!(data.is_empty(), "got InvalidInput but data was non-empty"); + } + } +}); diff --git a/fuzz/fuzz_targets/fuzz_read_bounded.rs b/fuzz/fuzz_targets/fuzz_read_bounded.rs new file mode 100644 index 0000000..d0b9666 --- /dev/null +++ b/fuzz/fuzz_targets/fuzz_read_bounded.rs @@ -0,0 +1,58 @@ +#![no_main] + +use std::io::Cursor; + +use libfuzzer_sys::arbitrary::{self, Arbitrary}; +use libfuzzer_sys::fuzz_target; +use mmap_guard::read_bounded; + +/// Structured fuzz input — the fuzzer controls both the data and the cap. +/// `cap_raw` is `u16` to keep the search space small while still covering +/// the interesting boundary conditions (0, 1, exact-fit, overflow). +#[derive(Arbitrary, Debug)] +struct ReadBoundedInput { + cap_raw: Option, + data: Vec, +} + +fuzz_target!(|input: ReadBoundedInput| { + let cap = input.cap_raw.map(usize::from); + let mut cursor = Cursor::new(&input.data); + + match read_bounded(&mut cursor, cap) { + Ok(buf) => { + // Length must not exceed the cap (when set). + if let Some(c) = cap { + assert!(buf.len() <= c, "buf.len() {} exceeded cap {c}", buf.len()); + } + // Without a cap, all data must be returned. + if cap.is_none() { + assert_eq!( + buf.len(), + input.data.len(), + "unlimited read returned fewer bytes than available", + ); + } + // Contents must match the input prefix. + assert_eq!(&buf[..], &input.data[..buf.len()]); + } + Err(e) => { + // The only expected error is overflow (InvalidData). + assert_eq!(e.kind(), std::io::ErrorKind::InvalidData); + // Overflow is impossible without a cap. + assert!( + cap.is_some(), + "got InvalidData with no cap — read_bounded should never overflow without a limit", + ); + // An overflow error should only occur when the input is genuinely + // longer than the cap. + if let Some(c) = cap { + assert!( + input.data.len() > c, + "got InvalidData but data.len() {} <= cap {c}", + input.data.len(), + ); + } + } + } +}); diff --git a/justfile b/justfile index 9104520..6883536 100644 --- a/justfile +++ b/justfile @@ -71,7 +71,7 @@ lint: lint-rust lint-actions lint-docs lint-justfile # Individual lint recipes lint-actions: - @{{ mise_exec }} actionlint .github/workflows/audit.yml .github/workflows/ci.yml .github/workflows/docs.yml .github/workflows/release-plz.yml .github/workflows/scorecard.yml .github/workflows/security.yml + @{{ mise_exec }} actionlint .github/workflows/audit.yml .github/workflows/ci.yml .github/workflows/compat.yml .github/workflows/docs.yml .github/workflows/fuzz.yml .github/workflows/release-plz.yml .github/workflows/scorecard.yml .github/workflows/security.yml lint-docs: @{{ mise_exec }} markdownlint-cli2 docs/**/*.md README.md @@ -184,6 +184,42 @@ coverage-summary: # Full local CI parity check (dist-plan excluded — library crate has no binary targets) ci-check: pre-commit-run fmt-check lint-rust lint-rust-min test-ci build-release audit coverage-check docs-check +# ============================================================================= +# LOCAL CI SIMULATION (act) +# ============================================================================= + +act_flags := "--container-architecture linux/amd64" +# Workflows that only trigger on schedule/PR use workflow_dispatch to run in act +act_dispatch := "workflow_dispatch" + +# Dry-run all CI workflows locally (no containers started) +act-dry-run: + @act {{ act_flags }} -n -W .github/workflows/ci.yml + @act {{ act_flags }} -n -W .github/workflows/audit.yml {{ act_dispatch }} + @act {{ act_flags }} -n -W .github/workflows/compat.yml {{ act_dispatch }} + @act {{ act_flags }} -n -W .github/workflows/fuzz.yml {{ act_dispatch }} + @act {{ act_flags }} -n -W .github/workflows/security.yml {{ act_dispatch }} + +# Dry-run a specific workflow (use workflow_dispatch for schedule-only workflows) +act-dry-run-workflow workflow event=act_dispatch: + @act {{ act_flags }} -n -W .github/workflows/{{ workflow }}.yml {{ event }} + +# Run all CI workflows locally (excludes release-plz, docs publish, scorecard) +act-run: + act {{ act_flags }} -W .github/workflows/ci.yml + act {{ act_flags }} -W .github/workflows/audit.yml {{ act_dispatch }} + act {{ act_flags }} -W .github/workflows/compat.yml {{ act_dispatch }} + act {{ act_flags }} -W .github/workflows/fuzz.yml {{ act_dispatch }} + act {{ act_flags }} -W .github/workflows/security.yml {{ act_dispatch }} + +# Run a specific workflow locally +act-run-workflow workflow event=act_dispatch: + act {{ act_flags }} -W .github/workflows/{{ workflow }}.yml {{ event }} + +# Run a specific job from a workflow locally +act-run-job workflow job event=act_dispatch: + act {{ act_flags }} -j {{ job }} -W .github/workflows/{{ workflow }}.yml {{ event }} + # ============================================================================= # DISTRIBUTION AND PACKAGING # ============================================================================= diff --git a/mise.lock b/mise.lock index d5aee07..d7af104 100644 --- a/mise.lock +++ b/mise.lock @@ -3,60 +3,186 @@ [[tools.actionlint]] version = "1.7.11" backend = "aqua:rhysd/actionlint" -"platforms.linux-arm64" = { checksum = "sha256:21bc0dfb57a913fe175298c2a9e906ee630f747cb66d0a934d0d4b69f4ee1235", url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_linux_arm64.tar.gz"} -"platforms.linux-arm64-musl" = { checksum = "sha256:21bc0dfb57a913fe175298c2a9e906ee630f747cb66d0a934d0d4b69f4ee1235", url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_linux_arm64.tar.gz"} -"platforms.linux-x64" = { checksum = "sha256:900919a84f2229bac68ca9cd4103ea297abc35e9689ebb842c6e34a3d1b01b0a", url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_linux_amd64.tar.gz"} -"platforms.linux-x64-baseline" = { checksum = "sha256:900919a84f2229bac68ca9cd4103ea297abc35e9689ebb842c6e34a3d1b01b0a", url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_linux_amd64.tar.gz"} -"platforms.linux-x64-musl" = { checksum = "sha256:900919a84f2229bac68ca9cd4103ea297abc35e9689ebb842c6e34a3d1b01b0a", url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_linux_amd64.tar.gz"} -"platforms.linux-x64-musl-baseline" = { checksum = "sha256:900919a84f2229bac68ca9cd4103ea297abc35e9689ebb842c6e34a3d1b01b0a", url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_linux_amd64.tar.gz"} -"platforms.macos-arm64" = { checksum = "sha256:a21ba7366d8329e7223faee0ed69eb13da27fe8acabb356bb7eb0b7f1e1cb6d8", url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_darwin_arm64.tar.gz"} -"platforms.macos-x64" = { checksum = "sha256:17ffc17fed8f0258ef6ad4aed932d3272464c7ef7d64e1cb0d65aa97c9752107", url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_darwin_amd64.tar.gz"} -"platforms.macos-x64-baseline" = { checksum = "sha256:17ffc17fed8f0258ef6ad4aed932d3272464c7ef7d64e1cb0d65aa97c9752107", url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_darwin_amd64.tar.gz"} -"platforms.windows-x64" = { checksum = "sha256:5414b7124a91f4b5abee62e5c9d84802237734f8d15b9b7032732a32c3ebffa3", url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_windows_amd64.zip"} -"platforms.windows-x64-baseline" = { checksum = "sha256:5414b7124a91f4b5abee62e5c9d84802237734f8d15b9b7032732a32c3ebffa3", url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_windows_amd64.zip"} + +[tools.actionlint."platforms.linux-arm64"] +checksum = "sha256:21bc0dfb57a913fe175298c2a9e906ee630f747cb66d0a934d0d4b69f4ee1235" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_linux_arm64.tar.gz" + +[tools.actionlint."platforms.linux-arm64-musl"] +checksum = "sha256:21bc0dfb57a913fe175298c2a9e906ee630f747cb66d0a934d0d4b69f4ee1235" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_linux_arm64.tar.gz" + +[tools.actionlint."platforms.linux-x64"] +checksum = "sha256:900919a84f2229bac68ca9cd4103ea297abc35e9689ebb842c6e34a3d1b01b0a" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_linux_amd64.tar.gz" + +[tools.actionlint."platforms.linux-x64-baseline"] +checksum = "sha256:900919a84f2229bac68ca9cd4103ea297abc35e9689ebb842c6e34a3d1b01b0a" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_linux_amd64.tar.gz" + +[tools.actionlint."platforms.linux-x64-musl"] +checksum = "sha256:900919a84f2229bac68ca9cd4103ea297abc35e9689ebb842c6e34a3d1b01b0a" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_linux_amd64.tar.gz" + +[tools.actionlint."platforms.linux-x64-musl-baseline"] +checksum = "sha256:900919a84f2229bac68ca9cd4103ea297abc35e9689ebb842c6e34a3d1b01b0a" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_linux_amd64.tar.gz" + +[tools.actionlint."platforms.macos-arm64"] +checksum = "sha256:a21ba7366d8329e7223faee0ed69eb13da27fe8acabb356bb7eb0b7f1e1cb6d8" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_darwin_arm64.tar.gz" + +[tools.actionlint."platforms.macos-x64"] +checksum = "sha256:17ffc17fed8f0258ef6ad4aed932d3272464c7ef7d64e1cb0d65aa97c9752107" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_darwin_amd64.tar.gz" + +[tools.actionlint."platforms.macos-x64-baseline"] +checksum = "sha256:17ffc17fed8f0258ef6ad4aed932d3272464c7ef7d64e1cb0d65aa97c9752107" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_darwin_amd64.tar.gz" + +[tools.actionlint."platforms.windows-x64"] +checksum = "sha256:5414b7124a91f4b5abee62e5c9d84802237734f8d15b9b7032732a32c3ebffa3" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_windows_amd64.zip" + +[tools.actionlint."platforms.windows-x64-baseline"] +checksum = "sha256:5414b7124a91f4b5abee62e5c9d84802237734f8d15b9b7032732a32c3ebffa3" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.11/actionlint_1.7.11_windows_amd64.zip" [[tools.bun]] version = "1.3.10" backend = "core:bun" -"platforms.linux-arm64" = { checksum = "sha256:fa5ecb25cafa8e8f5c87a0f833719d46dd0af0a86c7837d806531212d55636d3", url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-linux-aarch64.zip"} -"platforms.linux-arm64-musl" = { checksum = "sha256:d2c81365a2e529b78a42330d3a0056e8dbd7896b4a6782c8e392b6532141e34d", url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-linux-aarch64-musl.zip"} -"platforms.linux-x64" = { checksum = "sha256:f57bc0187e39623de716ba3a389fda5486b2d7be7131a980ba54dc7b733d2e08", url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-linux-x64.zip"} -"platforms.linux-x64-baseline" = { checksum = "sha256:41201a8c5ee74a9dcbb1ce25a1104f1f929838b57a845aa78d98379b0ce7cde2", url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-linux-x64-baseline.zip"} -"platforms.linux-x64-musl" = { checksum = "sha256:48a6c32277d343db0148ce066336472ffd380358a4d26bb1329714742492d824", url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-linux-x64-musl.zip"} -"platforms.linux-x64-musl-baseline" = { checksum = "sha256:a7bc4cdea1ef255a83adbf39c7aafcd30e09f2b8f74deec4b10ee318bc024d1f", url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-linux-x64-musl-baseline.zip"} -"platforms.macos-arm64" = { checksum = "sha256:82034e87c9d9b4398ea619aee2eed5d2a68c8157e9a6ae2d1052d84d533ccd8d", url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-darwin-aarch64.zip"} -"platforms.macos-x64" = { checksum = "sha256:c1d90bf6140f20e572c473065dc6b37a4b036349b5e9e4133779cc642ad94323", url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-darwin-x64.zip"} -"platforms.macos-x64-baseline" = { checksum = "sha256:f9686c4e4e760db4cde77a0f1fad05e552648b9c9cbfa4f7fc9a7ec26b9f3267", url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-darwin-x64-baseline.zip"} -"platforms.windows-x64" = { checksum = "sha256:7a77b3e245e2e26965c93089a4a1332e8a326d3364c89fae1d1fd99cdd3cd73d", url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-windows-x64.zip"} -"platforms.windows-x64-baseline" = { checksum = "sha256:715709c69b176e20994533d3292bd0b7c32de9c0c5575b916746ec6b2aa38346", url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-windows-x64-baseline.zip"} + +[tools.bun."platforms.linux-arm64"] +checksum = "sha256:fa5ecb25cafa8e8f5c87a0f833719d46dd0af0a86c7837d806531212d55636d3" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-linux-aarch64.zip" + +[tools.bun."platforms.linux-arm64-musl"] +checksum = "sha256:d2c81365a2e529b78a42330d3a0056e8dbd7896b4a6782c8e392b6532141e34d" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-linux-aarch64-musl.zip" + +[tools.bun."platforms.linux-x64"] +checksum = "sha256:f57bc0187e39623de716ba3a389fda5486b2d7be7131a980ba54dc7b733d2e08" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-linux-x64.zip" + +[tools.bun."platforms.linux-x64-baseline"] +checksum = "sha256:41201a8c5ee74a9dcbb1ce25a1104f1f929838b57a845aa78d98379b0ce7cde2" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-linux-x64-baseline.zip" + +[tools.bun."platforms.linux-x64-musl"] +checksum = "sha256:48a6c32277d343db0148ce066336472ffd380358a4d26bb1329714742492d824" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-linux-x64-musl.zip" + +[tools.bun."platforms.linux-x64-musl-baseline"] +checksum = "sha256:a7bc4cdea1ef255a83adbf39c7aafcd30e09f2b8f74deec4b10ee318bc024d1f" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-linux-x64-musl-baseline.zip" + +[tools.bun."platforms.macos-arm64"] +checksum = "sha256:82034e87c9d9b4398ea619aee2eed5d2a68c8157e9a6ae2d1052d84d533ccd8d" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-darwin-aarch64.zip" + +[tools.bun."platforms.macos-x64"] +checksum = "sha256:c1d90bf6140f20e572c473065dc6b37a4b036349b5e9e4133779cc642ad94323" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-darwin-x64.zip" + +[tools.bun."platforms.macos-x64-baseline"] +checksum = "sha256:f9686c4e4e760db4cde77a0f1fad05e552648b9c9cbfa4f7fc9a7ec26b9f3267" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-darwin-x64-baseline.zip" + +[tools.bun."platforms.windows-x64"] +checksum = "sha256:7a77b3e245e2e26965c93089a4a1332e8a326d3364c89fae1d1fd99cdd3cd73d" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-windows-x64.zip" + +[tools.bun."platforms.windows-x64-baseline"] +checksum = "sha256:715709c69b176e20994533d3292bd0b7c32de9c0c5575b916746ec6b2aa38346" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-windows-x64-baseline.zip" [[tools.cargo-binstall]] -version = "1.17.6" +version = "1.17.7" backend = "aqua:cargo-bins/cargo-binstall" -"platforms.linux-arm64" = { checksum = "sha256:e5f2c4b79b10370dff707b86a14e7a0ad399c5dc5853824e933432910741992c", url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.6/cargo-binstall-aarch64-unknown-linux-musl.tgz"} -"platforms.linux-arm64-musl" = { checksum = "sha256:e5f2c4b79b10370dff707b86a14e7a0ad399c5dc5853824e933432910741992c", url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.6/cargo-binstall-aarch64-unknown-linux-musl.tgz"} -"platforms.linux-x64" = { checksum = "sha256:f926d96e9f0822ded35c4ac2071ce190bd1311565695c49c45e295de0d685aaa", url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.6/cargo-binstall-x86_64-unknown-linux-musl.tgz"} -"platforms.linux-x64-baseline" = { checksum = "sha256:f926d96e9f0822ded35c4ac2071ce190bd1311565695c49c45e295de0d685aaa", url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.6/cargo-binstall-x86_64-unknown-linux-musl.tgz"} -"platforms.linux-x64-musl" = { checksum = "sha256:f926d96e9f0822ded35c4ac2071ce190bd1311565695c49c45e295de0d685aaa", url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.6/cargo-binstall-x86_64-unknown-linux-musl.tgz"} -"platforms.linux-x64-musl-baseline" = { checksum = "sha256:f926d96e9f0822ded35c4ac2071ce190bd1311565695c49c45e295de0d685aaa", url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.6/cargo-binstall-x86_64-unknown-linux-musl.tgz"} -"platforms.macos-arm64" = { checksum = "sha256:101447fa30a723ca8e1a13cec11bb1350b7179331b2aa7054d27bef7a3e19021", url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.6/cargo-binstall-aarch64-apple-darwin.zip"} -"platforms.macos-x64" = { checksum = "sha256:cd07fd79e2848b13b994e3f83fa5377b631625b847f0734219f2706feb518258", url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.6/cargo-binstall-x86_64-apple-darwin.zip"} -"platforms.macos-x64-baseline" = { checksum = "sha256:cd07fd79e2848b13b994e3f83fa5377b631625b847f0734219f2706feb518258", url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.6/cargo-binstall-x86_64-apple-darwin.zip"} -"platforms.windows-x64" = { checksum = "sha256:5fcbddde2d415704d2432bbe606a5767ddaf1ef4ee2c16b7828f8be2ed1e5a5c", url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.6/cargo-binstall-x86_64-pc-windows-msvc.zip"} -"platforms.windows-x64-baseline" = { checksum = "sha256:5fcbddde2d415704d2432bbe606a5767ddaf1ef4ee2c16b7828f8be2ed1e5a5c", url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.6/cargo-binstall-x86_64-pc-windows-msvc.zip"} + +[tools.cargo-binstall."platforms.linux-arm64"] +checksum = "sha256:b0658b0a7f0959bc1dbb4ab665931c31c7dd1109ff01cb8772af17dfdc52a9af" +url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.7/cargo-binstall-aarch64-unknown-linux-musl.tgz" + +[tools.cargo-binstall."platforms.linux-arm64-musl"] +checksum = "sha256:b0658b0a7f0959bc1dbb4ab665931c31c7dd1109ff01cb8772af17dfdc52a9af" +url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.7/cargo-binstall-aarch64-unknown-linux-musl.tgz" + +[tools.cargo-binstall."platforms.linux-x64"] +checksum = "sha256:29b5ecfb6e03c2511a617c77d312b06df0c54717644fbfda3d465ec8240532f0" +url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.7/cargo-binstall-x86_64-unknown-linux-musl.tgz" + +[tools.cargo-binstall."platforms.linux-x64-baseline"] +checksum = "sha256:29b5ecfb6e03c2511a617c77d312b06df0c54717644fbfda3d465ec8240532f0" +url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.7/cargo-binstall-x86_64-unknown-linux-musl.tgz" + +[tools.cargo-binstall."platforms.linux-x64-musl"] +checksum = "sha256:29b5ecfb6e03c2511a617c77d312b06df0c54717644fbfda3d465ec8240532f0" +url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.7/cargo-binstall-x86_64-unknown-linux-musl.tgz" + +[tools.cargo-binstall."platforms.linux-x64-musl-baseline"] +checksum = "sha256:29b5ecfb6e03c2511a617c77d312b06df0c54717644fbfda3d465ec8240532f0" +url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.7/cargo-binstall-x86_64-unknown-linux-musl.tgz" + +[tools.cargo-binstall."platforms.macos-arm64"] +checksum = "sha256:1ad3c0c56fa3970634cce5009ed0ce61b943515f9115f8e480fd0e41d8d89085" +url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.7/cargo-binstall-aarch64-apple-darwin.zip" + +[tools.cargo-binstall."platforms.macos-x64"] +checksum = "sha256:aa7174fb938e668dea4b4c3d22fe6cefed97642cc3a7a419ba96d63d63fd729b" +url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.7/cargo-binstall-x86_64-apple-darwin.zip" + +[tools.cargo-binstall."platforms.macos-x64-baseline"] +checksum = "sha256:aa7174fb938e668dea4b4c3d22fe6cefed97642cc3a7a419ba96d63d63fd729b" +url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.7/cargo-binstall-x86_64-apple-darwin.zip" + +[tools.cargo-binstall."platforms.windows-x64"] +checksum = "sha256:c5cb2444ee04480502a8ac73d96abd9f97af8300ec04ea1c1f2a9e959c02e4d6" +url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.7/cargo-binstall-x86_64-pc-windows-msvc.zip" + +[tools.cargo-binstall."platforms.windows-x64-baseline"] +checksum = "sha256:c5cb2444ee04480502a8ac73d96abd9f97af8300ec04ea1c1f2a9e959c02e4d6" +url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.17.7/cargo-binstall-x86_64-pc-windows-msvc.zip" [[tools.cargo-insta]] version = "1.46.3" backend = "aqua:mitsuhiko/insta" -"platforms.linux-x64" = { checksum = "sha256:c738c47f8d7e834a0277dddb9410a1f7369d37818738fc6a380f22904a83f6e4", url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-unknown-linux-musl.tar.xz"} -"platforms.linux-x64-baseline" = { checksum = "sha256:c738c47f8d7e834a0277dddb9410a1f7369d37818738fc6a380f22904a83f6e4", url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-unknown-linux-musl.tar.xz"} -"platforms.linux-x64-musl" = { checksum = "sha256:c738c47f8d7e834a0277dddb9410a1f7369d37818738fc6a380f22904a83f6e4", url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-unknown-linux-musl.tar.xz"} -"platforms.linux-x64-musl-baseline" = { checksum = "sha256:c738c47f8d7e834a0277dddb9410a1f7369d37818738fc6a380f22904a83f6e4", url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-unknown-linux-musl.tar.xz"} -"platforms.macos-arm64" = { checksum = "sha256:1e620252db7964d876da6b4956872ad84d099ee281753ac7c850ae24413947df", url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-aarch64-apple-darwin.tar.xz"} -"platforms.macos-x64" = { checksum = "sha256:d55ff42a08ad0fc6deed64bb9ab700c069da9c6da40947d9b658cc33fda3dcda", url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-apple-darwin.tar.xz"} -"platforms.macos-x64-baseline" = { checksum = "sha256:d55ff42a08ad0fc6deed64bb9ab700c069da9c6da40947d9b658cc33fda3dcda", url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-apple-darwin.tar.xz"} -"platforms.windows-x64" = { checksum = "sha256:fa0cd6810e393392cf347decacd8a710de9ac95b6747a753f037c46b649209aa", url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-pc-windows-msvc.zip"} -"platforms.windows-x64-baseline" = { checksum = "sha256:fa0cd6810e393392cf347decacd8a710de9ac95b6747a753f037c46b649209aa", url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-pc-windows-msvc.zip"} + +[tools.cargo-insta."platforms.linux-x64"] +checksum = "sha256:c738c47f8d7e834a0277dddb9410a1f7369d37818738fc6a380f22904a83f6e4" +url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-unknown-linux-musl.tar.xz" + +[tools.cargo-insta."platforms.linux-x64-baseline"] +checksum = "sha256:c738c47f8d7e834a0277dddb9410a1f7369d37818738fc6a380f22904a83f6e4" +url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-unknown-linux-musl.tar.xz" + +[tools.cargo-insta."platforms.linux-x64-musl"] +checksum = "sha256:c738c47f8d7e834a0277dddb9410a1f7369d37818738fc6a380f22904a83f6e4" +url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-unknown-linux-musl.tar.xz" + +[tools.cargo-insta."platforms.linux-x64-musl-baseline"] +checksum = "sha256:c738c47f8d7e834a0277dddb9410a1f7369d37818738fc6a380f22904a83f6e4" +url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-unknown-linux-musl.tar.xz" + +[tools.cargo-insta."platforms.macos-arm64"] +checksum = "sha256:1e620252db7964d876da6b4956872ad84d099ee281753ac7c850ae24413947df" +url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-aarch64-apple-darwin.tar.xz" + +[tools.cargo-insta."platforms.macos-x64"] +checksum = "sha256:d55ff42a08ad0fc6deed64bb9ab700c069da9c6da40947d9b658cc33fda3dcda" +url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-apple-darwin.tar.xz" + +[tools.cargo-insta."platforms.macos-x64-baseline"] +checksum = "sha256:d55ff42a08ad0fc6deed64bb9ab700c069da9c6da40947d9b658cc33fda3dcda" +url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-apple-darwin.tar.xz" + +[tools.cargo-insta."platforms.windows-x64"] +checksum = "sha256:fa0cd6810e393392cf347decacd8a710de9ac95b6747a753f037c46b649209aa" +url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-pc-windows-msvc.zip" + +[tools.cargo-insta."platforms.windows-x64-baseline"] +checksum = "sha256:fa0cd6810e393392cf347decacd8a710de9ac95b6747a753f037c46b649209aa" +url = "https://github.com/mitsuhiko/insta/releases/download/1.46.3/cargo-insta-x86_64-pc-windows-msvc.zip" [[tools."cargo:cargo-about"]] version = "0.8.4" @@ -139,36 +265,96 @@ version = "0.15.3" backend = "cargo:mdbook-toc" [[tools."cargo:release-plz"]] -version = "0.3.156" +version = "0.3.157" backend = "cargo:release-plz" [[tools.just]] version = "1.46.0" backend = "aqua:casey/just" -"platforms.linux-arm64" = { checksum = "sha256:b81970c8247fa64cfb30d2a3da0e487e4253f9f2d01865ed5e7d53cdc7b02188", url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-aarch64-unknown-linux-musl.tar.gz"} -"platforms.linux-arm64-musl" = { checksum = "sha256:b81970c8247fa64cfb30d2a3da0e487e4253f9f2d01865ed5e7d53cdc7b02188", url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-aarch64-unknown-linux-musl.tar.gz"} -"platforms.linux-x64" = { checksum = "sha256:79966e6e353f535ee7d1c6221641bcc8e3381c55b0d0a6dc6e54b34f9db36eaa", url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-unknown-linux-musl.tar.gz"} -"platforms.linux-x64-baseline" = { checksum = "sha256:79966e6e353f535ee7d1c6221641bcc8e3381c55b0d0a6dc6e54b34f9db36eaa", url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-unknown-linux-musl.tar.gz"} -"platforms.linux-x64-musl" = { checksum = "sha256:79966e6e353f535ee7d1c6221641bcc8e3381c55b0d0a6dc6e54b34f9db36eaa", url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-unknown-linux-musl.tar.gz"} -"platforms.linux-x64-musl-baseline" = { checksum = "sha256:79966e6e353f535ee7d1c6221641bcc8e3381c55b0d0a6dc6e54b34f9db36eaa", url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-unknown-linux-musl.tar.gz"} -"platforms.macos-arm64" = { checksum = "sha256:438eaf6468a115aa7db93e501cc7e3272f453f6b7083be3863adfab546b23358", url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-aarch64-apple-darwin.tar.gz"} -"platforms.macos-x64" = { checksum = "sha256:ec54dd60ac876261b7318f1852ef9c0319fede1e5a73c14f56d908a8edf595b8", url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-apple-darwin.tar.gz"} -"platforms.macos-x64-baseline" = { checksum = "sha256:ec54dd60ac876261b7318f1852ef9c0319fede1e5a73c14f56d908a8edf595b8", url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-apple-darwin.tar.gz"} -"platforms.windows-x64" = { checksum = "sha256:f0acf3f8ccbcf360b481baae9cae4c921774c89d5d932012481d3e0bda78ab39", url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-pc-windows-msvc.zip"} -"platforms.windows-x64-baseline" = { checksum = "sha256:f0acf3f8ccbcf360b481baae9cae4c921774c89d5d932012481d3e0bda78ab39", url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-pc-windows-msvc.zip"} + +[tools.just."platforms.linux-arm64"] +checksum = "sha256:b81970c8247fa64cfb30d2a3da0e487e4253f9f2d01865ed5e7d53cdc7b02188" +url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-aarch64-unknown-linux-musl.tar.gz" + +[tools.just."platforms.linux-arm64-musl"] +checksum = "sha256:b81970c8247fa64cfb30d2a3da0e487e4253f9f2d01865ed5e7d53cdc7b02188" +url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-aarch64-unknown-linux-musl.tar.gz" + +[tools.just."platforms.linux-x64"] +checksum = "sha256:79966e6e353f535ee7d1c6221641bcc8e3381c55b0d0a6dc6e54b34f9db36eaa" +url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-unknown-linux-musl.tar.gz" + +[tools.just."platforms.linux-x64-baseline"] +checksum = "sha256:79966e6e353f535ee7d1c6221641bcc8e3381c55b0d0a6dc6e54b34f9db36eaa" +url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-unknown-linux-musl.tar.gz" + +[tools.just."platforms.linux-x64-musl"] +checksum = "sha256:79966e6e353f535ee7d1c6221641bcc8e3381c55b0d0a6dc6e54b34f9db36eaa" +url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-unknown-linux-musl.tar.gz" + +[tools.just."platforms.linux-x64-musl-baseline"] +checksum = "sha256:79966e6e353f535ee7d1c6221641bcc8e3381c55b0d0a6dc6e54b34f9db36eaa" +url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-unknown-linux-musl.tar.gz" + +[tools.just."platforms.macos-arm64"] +checksum = "sha256:438eaf6468a115aa7db93e501cc7e3272f453f6b7083be3863adfab546b23358" +url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-aarch64-apple-darwin.tar.gz" + +[tools.just."platforms.macos-x64"] +checksum = "sha256:ec54dd60ac876261b7318f1852ef9c0319fede1e5a73c14f56d908a8edf595b8" +url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-apple-darwin.tar.gz" + +[tools.just."platforms.macos-x64-baseline"] +checksum = "sha256:ec54dd60ac876261b7318f1852ef9c0319fede1e5a73c14f56d908a8edf595b8" +url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-apple-darwin.tar.gz" + +[tools.just."platforms.windows-x64"] +checksum = "sha256:f0acf3f8ccbcf360b481baae9cae4c921774c89d5d932012481d3e0bda78ab39" +url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-pc-windows-msvc.zip" + +[tools.just."platforms.windows-x64-baseline"] +checksum = "sha256:f0acf3f8ccbcf360b481baae9cae4c921774c89d5d932012481d3e0bda78ab39" +url = "https://github.com/casey/just/releases/download/1.46.0/just-1.46.0-x86_64-pc-windows-msvc.zip" [[tools.lychee]] version = "0.23.0" backend = "aqua:lycheeverse/lychee" -"platforms.linux-arm64" = { checksum = "sha256:97eb93b02a7d78a752fc33e5b0983439ccaadbf3db952b68a0a4401acd92e6e0", url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-aarch64-unknown-linux-gnu.tar.gz"} -"platforms.linux-arm64-musl" = { checksum = "sha256:97eb93b02a7d78a752fc33e5b0983439ccaadbf3db952b68a0a4401acd92e6e0", url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-aarch64-unknown-linux-gnu.tar.gz"} -"platforms.linux-x64" = { checksum = "sha256:5538440d2c69a45a0a09983271e5dee0c2fe7137d8035d25b2632e10a66a090a", url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-unknown-linux-musl.tar.gz"} -"platforms.linux-x64-baseline" = { checksum = "sha256:5538440d2c69a45a0a09983271e5dee0c2fe7137d8035d25b2632e10a66a090a", url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-unknown-linux-musl.tar.gz"} -"platforms.linux-x64-musl" = { checksum = "sha256:5538440d2c69a45a0a09983271e5dee0c2fe7137d8035d25b2632e10a66a090a", url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-unknown-linux-musl.tar.gz"} -"platforms.linux-x64-musl-baseline" = { checksum = "sha256:5538440d2c69a45a0a09983271e5dee0c2fe7137d8035d25b2632e10a66a090a", url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-unknown-linux-musl.tar.gz"} -"platforms.macos-arm64" = { checksum = "sha256:4c8034900e11083b68ac6f6582c377ff1f704e268991999e09d717973e493e7f", url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-arm64-macos.dmg"} -"platforms.windows-x64" = { checksum = "sha256:0fda7ff0a60c0250939fc25361c2d4e6e7853c31c996733fdd5a1dd760bcb824", url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-windows.exe"} -"platforms.windows-x64-baseline" = { checksum = "sha256:0fda7ff0a60c0250939fc25361c2d4e6e7853c31c996733fdd5a1dd760bcb824", url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-windows.exe"} + +[tools.lychee."platforms.linux-arm64"] +checksum = "sha256:97eb93b02a7d78a752fc33e5b0983439ccaadbf3db952b68a0a4401acd92e6e0" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-aarch64-unknown-linux-gnu.tar.gz" + +[tools.lychee."platforms.linux-arm64-musl"] +checksum = "sha256:97eb93b02a7d78a752fc33e5b0983439ccaadbf3db952b68a0a4401acd92e6e0" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-aarch64-unknown-linux-gnu.tar.gz" + +[tools.lychee."platforms.linux-x64"] +checksum = "sha256:5538440d2c69a45a0a09983271e5dee0c2fe7137d8035d25b2632e10a66a090a" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-unknown-linux-musl.tar.gz" + +[tools.lychee."platforms.linux-x64-baseline"] +checksum = "sha256:5538440d2c69a45a0a09983271e5dee0c2fe7137d8035d25b2632e10a66a090a" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-unknown-linux-musl.tar.gz" + +[tools.lychee."platforms.linux-x64-musl"] +checksum = "sha256:5538440d2c69a45a0a09983271e5dee0c2fe7137d8035d25b2632e10a66a090a" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-unknown-linux-musl.tar.gz" + +[tools.lychee."platforms.linux-x64-musl-baseline"] +checksum = "sha256:5538440d2c69a45a0a09983271e5dee0c2fe7137d8035d25b2632e10a66a090a" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-unknown-linux-musl.tar.gz" + +[tools.lychee."platforms.macos-arm64"] +checksum = "sha256:4c8034900e11083b68ac6f6582c377ff1f704e268991999e09d717973e493e7f" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-arm64-macos.dmg" + +[tools.lychee."platforms.windows-x64"] +checksum = "sha256:0fda7ff0a60c0250939fc25361c2d4e6e7853c31c996733fdd5a1dd760bcb824" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-windows.exe" + +[tools.lychee."platforms.windows-x64-baseline"] +checksum = "sha256:0fda7ff0a60c0250939fc25361c2d4e6e7853c31c996733fdd5a1dd760bcb824" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-windows.exe" [[tools.markdownlint-cli2]] version = "0.21.0" @@ -192,17 +378,50 @@ backend = "npm:prettier" [[tools.python]] version = "3.14.3" backend = "core:python" -"platforms.linux-arm64" = { checksum = "sha256:be0f4dc2932f762292b27d46ea7d3e8e66ddf3969a5eb0254a229015ed402625", url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz"} -"platforms.linux-arm64-musl" = { checksum = "sha256:be0f4dc2932f762292b27d46ea7d3e8e66ddf3969a5eb0254a229015ed402625", url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz"} -"platforms.linux-x64" = { checksum = "sha256:0a73413f89efd417871876c9accaab28a9d1e3cd6358fbfff171a38ec99302f0", url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz"} -"platforms.linux-x64-baseline" = { checksum = "sha256:0a73413f89efd417871876c9accaab28a9d1e3cd6358fbfff171a38ec99302f0", url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz"} -"platforms.linux-x64-musl" = { checksum = "sha256:0a73413f89efd417871876c9accaab28a9d1e3cd6358fbfff171a38ec99302f0", url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz"} -"platforms.linux-x64-musl-baseline" = { checksum = "sha256:0a73413f89efd417871876c9accaab28a9d1e3cd6358fbfff171a38ec99302f0", url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz"} -"platforms.macos-arm64" = { checksum = "sha256:4703cdf18b26798fde7b49b6b66149674c25f97127be6a10dbcf29309bdcdcdb", url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-aarch64-apple-darwin-install_only_stripped.tar.gz"} -"platforms.macos-x64" = { checksum = "sha256:76f1cc26e3d262eae8ca546a93e8bded10cf0323613f7e246fea2e10a8115eb7", url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-apple-darwin-install_only_stripped.tar.gz"} -"platforms.macos-x64-baseline" = { checksum = "sha256:76f1cc26e3d262eae8ca546a93e8bded10cf0323613f7e246fea2e10a8115eb7", url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-apple-darwin-install_only_stripped.tar.gz"} -"platforms.windows-x64" = { checksum = "sha256:950c5f21a015c1bdd1337f233456df2470fab71e4d794407d27a84cb8b9909a0", url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-pc-windows-msvc-install_only_stripped.tar.gz"} -"platforms.windows-x64-baseline" = { checksum = "sha256:950c5f21a015c1bdd1337f233456df2470fab71e4d794407d27a84cb8b9909a0", url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-pc-windows-msvc-install_only_stripped.tar.gz"} + +[tools.python."platforms.linux-arm64"] +checksum = "sha256:be0f4dc2932f762292b27d46ea7d3e8e66ddf3969a5eb0254a229015ed402625" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz" + +[tools.python."platforms.linux-arm64-musl"] +checksum = "sha256:be0f4dc2932f762292b27d46ea7d3e8e66ddf3969a5eb0254a229015ed402625" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz" + +[tools.python."platforms.linux-x64"] +checksum = "sha256:0a73413f89efd417871876c9accaab28a9d1e3cd6358fbfff171a38ec99302f0" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz" + +[tools.python."platforms.linux-x64-baseline"] +checksum = "sha256:0a73413f89efd417871876c9accaab28a9d1e3cd6358fbfff171a38ec99302f0" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz" + +[tools.python."platforms.linux-x64-musl"] +checksum = "sha256:0a73413f89efd417871876c9accaab28a9d1e3cd6358fbfff171a38ec99302f0" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz" + +[tools.python."platforms.linux-x64-musl-baseline"] +checksum = "sha256:0a73413f89efd417871876c9accaab28a9d1e3cd6358fbfff171a38ec99302f0" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz" + +[tools.python."platforms.macos-arm64"] +checksum = "sha256:4703cdf18b26798fde7b49b6b66149674c25f97127be6a10dbcf29309bdcdcdb" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-aarch64-apple-darwin-install_only_stripped.tar.gz" + +[tools.python."platforms.macos-x64"] +checksum = "sha256:76f1cc26e3d262eae8ca546a93e8bded10cf0323613f7e246fea2e10a8115eb7" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-apple-darwin-install_only_stripped.tar.gz" + +[tools.python."platforms.macos-x64-baseline"] +checksum = "sha256:76f1cc26e3d262eae8ca546a93e8bded10cf0323613f7e246fea2e10a8115eb7" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-apple-darwin-install_only_stripped.tar.gz" + +[tools.python."platforms.windows-x64"] +checksum = "sha256:950c5f21a015c1bdd1337f233456df2470fab71e4d794407d27a84cb8b9909a0" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-pc-windows-msvc-install_only_stripped.tar.gz" + +[tools.python."platforms.windows-x64-baseline"] +checksum = "sha256:950c5f21a015c1bdd1337f233456df2470fab71e4d794407d27a84cb8b9909a0" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3+20260303-x86_64-pc-windows-msvc-install_only_stripped.tar.gz" [[tools.rust]] version = "1.94.0" @@ -211,29 +430,106 @@ backend = "core:rust" [[tools.scorecard]] version = "5.4.0" backend = "aqua:ossf/scorecard" -"platforms.linux-arm64" = { checksum = "sha256:3f8b6354c62ec0287a8e9694481d834e16bff8451cf5b5dca435e8400ce5adaf", url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_linux_arm64.tar.gz"} -"platforms.linux-arm64-musl" = { checksum = "sha256:3f8b6354c62ec0287a8e9694481d834e16bff8451cf5b5dca435e8400ce5adaf", url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_linux_arm64.tar.gz"} -"platforms.linux-x64" = { checksum = "sha256:e5183aeaa5aa548fbb7318a6deb3e1038be0ef9aca24e655422ae88dfbe67502", url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_linux_amd64.tar.gz"} -"platforms.linux-x64-baseline" = { checksum = "sha256:e5183aeaa5aa548fbb7318a6deb3e1038be0ef9aca24e655422ae88dfbe67502", url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_linux_amd64.tar.gz"} -"platforms.linux-x64-musl" = { checksum = "sha256:e5183aeaa5aa548fbb7318a6deb3e1038be0ef9aca24e655422ae88dfbe67502", url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_linux_amd64.tar.gz"} -"platforms.linux-x64-musl-baseline" = { checksum = "sha256:e5183aeaa5aa548fbb7318a6deb3e1038be0ef9aca24e655422ae88dfbe67502", url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_linux_amd64.tar.gz"} -"platforms.macos-arm64" = { checksum = "sha256:2c672695a27d35537dd4054f690f31fa1d6a72b0957598f45181296487f537f4", url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_darwin_arm64.tar.gz"} -"platforms.macos-x64" = { checksum = "sha256:2abfec13b8eecc9b730e3782c9b3a9544d31ae861ce21ea7fe6a369d887d7c89", url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_darwin_amd64.tar.gz"} -"platforms.macos-x64-baseline" = { checksum = "sha256:2abfec13b8eecc9b730e3782c9b3a9544d31ae861ce21ea7fe6a369d887d7c89", url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_darwin_amd64.tar.gz"} -"platforms.windows-x64" = { checksum = "sha256:f7d0ece0dde703e4baa5f96e9b6ed33e6e786138c90db8de2c4943f24015b9ff", url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_windows_amd64.tar.gz"} -"platforms.windows-x64-baseline" = { checksum = "sha256:f7d0ece0dde703e4baa5f96e9b6ed33e6e786138c90db8de2c4943f24015b9ff", url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_windows_amd64.tar.gz"} + +[tools.scorecard."platforms.linux-arm64"] +checksum = "sha256:3f8b6354c62ec0287a8e9694481d834e16bff8451cf5b5dca435e8400ce5adaf" +url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_linux_arm64.tar.gz" +provenance = "slsa" + +[tools.scorecard."platforms.linux-arm64-musl"] +checksum = "sha256:3f8b6354c62ec0287a8e9694481d834e16bff8451cf5b5dca435e8400ce5adaf" +url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_linux_arm64.tar.gz" +provenance = "slsa" + +[tools.scorecard."platforms.linux-x64"] +checksum = "sha256:e5183aeaa5aa548fbb7318a6deb3e1038be0ef9aca24e655422ae88dfbe67502" +url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_linux_amd64.tar.gz" +provenance = "slsa" + +[tools.scorecard."platforms.linux-x64-baseline"] +checksum = "sha256:e5183aeaa5aa548fbb7318a6deb3e1038be0ef9aca24e655422ae88dfbe67502" +url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_linux_amd64.tar.gz" +provenance = "slsa" + +[tools.scorecard."platforms.linux-x64-musl"] +checksum = "sha256:e5183aeaa5aa548fbb7318a6deb3e1038be0ef9aca24e655422ae88dfbe67502" +url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_linux_amd64.tar.gz" +provenance = "slsa" + +[tools.scorecard."platforms.linux-x64-musl-baseline"] +checksum = "sha256:e5183aeaa5aa548fbb7318a6deb3e1038be0ef9aca24e655422ae88dfbe67502" +url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_linux_amd64.tar.gz" +provenance = "slsa" + +[tools.scorecard."platforms.macos-arm64"] +checksum = "sha256:2c672695a27d35537dd4054f690f31fa1d6a72b0957598f45181296487f537f4" +url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_darwin_arm64.tar.gz" +provenance = "slsa" + +[tools.scorecard."platforms.macos-x64"] +checksum = "sha256:2abfec13b8eecc9b730e3782c9b3a9544d31ae861ce21ea7fe6a369d887d7c89" +url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_darwin_amd64.tar.gz" +provenance = "slsa" + +[tools.scorecard."platforms.macos-x64-baseline"] +checksum = "sha256:2abfec13b8eecc9b730e3782c9b3a9544d31ae861ce21ea7fe6a369d887d7c89" +url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_darwin_amd64.tar.gz" +provenance = "slsa" + +[tools.scorecard."platforms.windows-x64"] +checksum = "sha256:f7d0ece0dde703e4baa5f96e9b6ed33e6e786138c90db8de2c4943f24015b9ff" +url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_windows_amd64.tar.gz" +provenance = "slsa" + +[tools.scorecard."platforms.windows-x64-baseline"] +checksum = "sha256:f7d0ece0dde703e4baa5f96e9b6ed33e6e786138c90db8de2c4943f24015b9ff" +url = "https://github.com/ossf/scorecard/releases/download/v5.4.0/scorecard_5.4.0_windows_amd64.tar.gz" +provenance = "slsa" [[tools.shellcheck]] version = "0.11.0" backend = "aqua:koalaman/shellcheck" -"platforms.linux-arm64" = { checksum = "sha256:12b331c1d2db6b9eb13cfca64306b1b157a86eb69db83023e261eaa7e7c14588", url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.aarch64.tar.xz"} -"platforms.linux-arm64-musl" = { checksum = "sha256:12b331c1d2db6b9eb13cfca64306b1b157a86eb69db83023e261eaa7e7c14588", url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.aarch64.tar.xz"} -"platforms.linux-x64" = { checksum = "sha256:8c3be12b05d5c177a04c29e3c78ce89ac86f1595681cab149b65b97c4e227198", url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.x86_64.tar.xz"} -"platforms.linux-x64-baseline" = { checksum = "sha256:8c3be12b05d5c177a04c29e3c78ce89ac86f1595681cab149b65b97c4e227198", url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.x86_64.tar.xz"} -"platforms.linux-x64-musl" = { checksum = "sha256:8c3be12b05d5c177a04c29e3c78ce89ac86f1595681cab149b65b97c4e227198", url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.x86_64.tar.xz"} -"platforms.linux-x64-musl-baseline" = { checksum = "sha256:8c3be12b05d5c177a04c29e3c78ce89ac86f1595681cab149b65b97c4e227198", url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.x86_64.tar.xz"} -"platforms.macos-arm64" = { checksum = "sha256:56affdd8de5527894dca6dc3d7e0a99a873b0f004d7aabc30ae407d3f48b0a79", url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.darwin.aarch64.tar.xz"} -"platforms.macos-x64" = { checksum = "sha256:3c89db4edcab7cf1c27bff178882e0f6f27f7afdf54e859fa041fca10febe4c6", url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.darwin.x86_64.tar.xz"} -"platforms.macos-x64-baseline" = { checksum = "sha256:3c89db4edcab7cf1c27bff178882e0f6f27f7afdf54e859fa041fca10febe4c6", url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.darwin.x86_64.tar.xz"} -"platforms.windows-x64" = { checksum = "sha256:8a4e35ab0b331c85d73567b12f2a444df187f483e5079ceffa6bda1faa2e740e", url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.zip"} -"platforms.windows-x64-baseline" = { checksum = "sha256:8a4e35ab0b331c85d73567b12f2a444df187f483e5079ceffa6bda1faa2e740e", url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.zip"} + +[tools.shellcheck."platforms.linux-arm64"] +checksum = "sha256:12b331c1d2db6b9eb13cfca64306b1b157a86eb69db83023e261eaa7e7c14588" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.aarch64.tar.xz" + +[tools.shellcheck."platforms.linux-arm64-musl"] +checksum = "sha256:12b331c1d2db6b9eb13cfca64306b1b157a86eb69db83023e261eaa7e7c14588" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.aarch64.tar.xz" + +[tools.shellcheck."platforms.linux-x64"] +checksum = "sha256:8c3be12b05d5c177a04c29e3c78ce89ac86f1595681cab149b65b97c4e227198" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.x86_64.tar.xz" + +[tools.shellcheck."platforms.linux-x64-baseline"] +checksum = "sha256:8c3be12b05d5c177a04c29e3c78ce89ac86f1595681cab149b65b97c4e227198" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.x86_64.tar.xz" + +[tools.shellcheck."platforms.linux-x64-musl"] +checksum = "sha256:8c3be12b05d5c177a04c29e3c78ce89ac86f1595681cab149b65b97c4e227198" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.x86_64.tar.xz" + +[tools.shellcheck."platforms.linux-x64-musl-baseline"] +checksum = "sha256:8c3be12b05d5c177a04c29e3c78ce89ac86f1595681cab149b65b97c4e227198" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.x86_64.tar.xz" + +[tools.shellcheck."platforms.macos-arm64"] +checksum = "sha256:56affdd8de5527894dca6dc3d7e0a99a873b0f004d7aabc30ae407d3f48b0a79" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.darwin.aarch64.tar.xz" + +[tools.shellcheck."platforms.macos-x64"] +checksum = "sha256:3c89db4edcab7cf1c27bff178882e0f6f27f7afdf54e859fa041fca10febe4c6" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.darwin.x86_64.tar.xz" + +[tools.shellcheck."platforms.macos-x64-baseline"] +checksum = "sha256:3c89db4edcab7cf1c27bff178882e0f6f27f7afdf54e859fa041fca10febe4c6" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.darwin.x86_64.tar.xz" + +[tools.shellcheck."platforms.windows-x64"] +checksum = "sha256:8a4e35ab0b331c85d73567b12f2a444df187f483e5079ceffa6bda1faa2e740e" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.zip" + +[tools.shellcheck."platforms.windows-x64-baseline"] +checksum = "sha256:8a4e35ab0b331c85d73567b12f2a444df187f483e5079ceffa6bda1faa2e740e" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.zip" diff --git a/mise.toml b/mise.toml index c6809b2..a7d8987 100644 --- a/mise.toml +++ b/mise.toml @@ -31,7 +31,7 @@ markdownlint-cli2 = "0.21.0" "cargo:cargo-machete" = "0.9.1" "cargo:git-cliff" = "2.12.0" scorecard = "5.4.0" -"cargo:release-plz" = "0.3.156" +"cargo:release-plz" = "0.3.157" "pipx:pre-commit" = "latest" "bun" = "latest" shellcheck = "0.11.0" diff --git a/src/lib.rs b/src/lib.rs index 22bfce8..f21be64 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,3 +64,9 @@ mod map; pub use file_data::FileData; pub use load::{load, load_stdin}; pub use map::map_file; + +// Re-export internals for fuzz targets when the `__fuzz` feature is active. +// This is NOT part of the public API — the leading underscores signal that. +#[cfg(feature = "__fuzz")] +#[doc(hidden)] +pub use load::read_bounded; diff --git a/src/load.rs b/src/load.rs index 032ecff..123b0ea 100644 --- a/src/load.rs +++ b/src/load.rs @@ -43,8 +43,10 @@ const CHUNK_SIZE: usize = 8 * 1024; /// When `max_bytes` is `Some(n)`, the function returns an [`io::ErrorKind::InvalidData`] /// error as soon as the accumulated length would exceed `n`. When `None`, reading /// continues until EOF with no limit. -#[allow(clippy::indexing_slicing)] // read_size and n are always <= CHUNK_SIZE -fn read_bounded(reader: &mut R, max_bytes: Option) -> io::Result> { +#[allow(clippy::indexing_slicing)] // read_size <= CHUNK_SIZE by construction; n <= read_size by Read::read() contract +#[allow(unreachable_pub)] // pub visibility used by __fuzz re-export; module is private +#[allow(clippy::missing_errors_doc)] // internal API, only pub for __fuzz re-export +pub fn read_bounded(reader: &mut R, max_bytes: Option) -> io::Result> { let initial_capacity = max_bytes.map_or(CHUNK_SIZE, |cap| cap.min(CHUNK_SIZE)); let mut buf = Vec::with_capacity(initial_capacity); let mut chunk = [0_u8; CHUNK_SIZE]; @@ -171,7 +173,7 @@ pub fn load_stdin(max_bytes: Option) -> io::Result { } #[cfg(test)] -#[allow(clippy::unwrap_used, clippy::expect_used)] +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::indexing_slicing)] mod tests { use std::io::{self, Cursor, Write}; use std::path::Path; @@ -386,4 +388,59 @@ mod tests { assert_eq!(&*data, input); } + + // --- proptest property tests --- + + mod prop { + use std::io::Cursor; + + use proptest::prelude::*; + + use super::*; + + proptest! { + #![proptest_config(ProptestConfig::with_cases(512))] + + /// For any (data, cap) pair, `read_bounded` must either: + /// - return `Ok(buf)` where `buf.len() <= cap` and contents match, or + /// - return `Err(InvalidData)` when `data.len() > cap`. + #[test] + fn prop_read_bounded( + data in proptest::collection::vec(any::(), 0..65_536), + cap in proptest::option::of(0_u16..=u16::MAX), + ) { + let cap_usize = cap.map(usize::from); + let mut cursor = Cursor::new(&data); + + match read_bounded(&mut cursor, cap_usize) { + Ok(buf) => { + if let Some(c) = cap_usize { + prop_assert!(buf.len() <= c, "buf.len() {} > cap {c}", buf.len()); + } else { + prop_assert_eq!( + buf.len(), + data.len(), + "unlimited read returned fewer bytes than available", + ); + } + prop_assert_eq!(&buf[..], &data[..buf.len()]); + } + Err(e) => { + prop_assert_eq!(e.kind(), io::ErrorKind::InvalidData); + prop_assert!( + cap_usize.is_some(), + "got InvalidData with no cap — should be impossible", + ); + if let Some(c) = cap_usize { + prop_assert!( + data.len() > c, + "got InvalidData but data.len() {} <= cap {c}", + data.len(), + ); + } + } + } + } + } + } } diff --git a/tests/prop_map_file.rs b/tests/prop_map_file.rs new file mode 100644 index 0000000..c57e83d --- /dev/null +++ b/tests/prop_map_file.rs @@ -0,0 +1,36 @@ +//! Property tests for `map_file` round-trip integrity. + +#![allow(clippy::unwrap_used, clippy::expect_used)] + +use std::io::Write; + +use proptest::prelude::*; +use tempfile::NamedTempFile; + +use mmap_guard::{FileData, map_file}; + +proptest! { + #![proptest_config(ProptestConfig::with_cases(256))] + + /// Writing arbitrary bytes to a temp file and mapping it back must + /// produce identical contents (round-trip integrity). + #[test] + fn prop_map_file_roundtrip(data in proptest::collection::vec(any::(), 1..65_536)) { + let mut tmp = NamedTempFile::new().expect("failed to create temp file"); + tmp.write_all(&data).expect("failed to write"); + tmp.flush().expect("failed to flush"); + + let mapped = map_file(tmp.path()).expect("map_file failed"); + assert!(matches!(mapped, FileData::Mapped(..)), "expected Mapped variant"); + prop_assert_eq!(&*mapped, &data[..]); + } + +} + +/// Empty files must be rejected with `InvalidInput`. +#[test] +fn map_file_rejects_empty() { + let tmp = NamedTempFile::new().expect("failed to create temp file"); + let err = map_file(tmp.path()).expect_err("expected error for empty file"); + assert_eq!(err.kind(), std::io::ErrorKind::InvalidInput); +}