From a572304286755be2d2b5d600cfcf12acabdc8ba5 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 20:25:08 -0500 Subject: [PATCH 01/29] docs(agents): update AGENTS.md to reflect implemented features and future plans Signed-off-by: UncleSp1d3r --- AGENTS.md | 70 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 7d715bfc..ac0136b8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -64,8 +64,9 @@ Target File → Memory Mapper → File Buffer ```rust // Core data structures in lib.rs pub struct MagicRule { /* ... */ } -pub enum TypeKind { Byte, Short, Long, String, /* ... */ } -pub enum Operator { Equal, NotEqual, Greater, /* ... */ } +pub enum TypeKind { Byte, Short, Long, String } +pub enum Operator { Equal, NotEqual, BitwiseAnd, BitwiseAndMask } +// Additional types and operators are planned for v1.0+ // Parser module structure parser/ @@ -78,7 +79,7 @@ evaluator/ ├── mod.rs // Main evaluation engine ├── offset.rs // Offset resolution (absolute, indirect, relative) ├── types.rs // Type interpretation with endianness -└── operators.rs // Comparison and bitwise operations +└── operators.rs // Equality and bitwise operations ``` ## Code Quality Standards @@ -175,15 +176,25 @@ cargo test --doc # Test documentation examples ## Magic File Compatibility -### Supported Syntax +### Currently Implemented (v0.1.0) - **Offsets**: Absolute, indirect, relative, and from-end specifications -- **Types**: byte, short, long, string, regex with endianness support -- **Operators**: =, !=, >, \<, & (bitwise AND), ^ (XOR) +- **Types**: `byte`, `short`, `long`, `string` with endianness support +- **Operators**: `=` (equal), `!=` (not equal), `&` (bitwise AND with optional mask) - **Nested Rules**: Hierarchical rule evaluation with proper indentation -- **String Matching**: Both exact and regex pattern matching +- **String Matching**: Exact string matching with null-termination -### Binary-Safe Regex Handling +### Planned Features (v1.0+) + +- Comparison operators: `>`, `<`, `>=`, `<=` +- Bitwise XOR operator: `^` +- Regex type: Pattern matching with binary-safe regex support +- Additional types: 64-bit integers, floats, doubles, dates +- Search type: Multi-pattern string searching + +### Future Enhancement: Binary-Safe Regex Handling + +> The following is planned for future releases and is not yet implemented. ```rust // Use regex crate with bytes feature for binary-safe matching @@ -196,6 +207,36 @@ impl BinaryRegex for regex::bytes::Regex { } ``` +## Current Limitations (v0.1.0) + +### Type System + +- No regex/search pattern matching +- No 64-bit integer types (quad, qquad) +- No floating-point types (float, double, befloat, lefloat) +- No date/time types (date, qdate, ldate, qldate) +- String type supports null-terminated strings only (no fixed-length strings) + +### Operators + +- No comparison operators (`>`, `<`, `>=`, `<=`) +- No XOR operator (`^`) +- No negation operator (`~`) +- BitwiseAnd supports mask values but not all libmagic mask syntax + +### Offset Specifications + +- Indirect offsets implemented but may not support all libmagic syntax variations +- No support for complex offset expressions + +### Magic File Syntax + +- Limited support for special directives (only `!:strength` is parsed) +- No support for `!:mime`, `!:ext`, `!:apple` directives in evaluation +- No support for named tests or use/name directives + +See issue #52 for the planned enhancement roadmap. + ## Performance Requirements ### Critical Optimizations @@ -257,6 +298,8 @@ sample.bin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV) ### Adding New Type Support +> **Note:** Currently implemented types are `Byte`, `Short`, `Long`, and `String`. Regex and other advanced types are planned for future releases. + 1. Extend `TypeKind` enum in `src/parser/ast.rs` 2. Add parsing logic in `src/parser/grammar.rs` 3. Implement reading logic in `src/evaluator/types.rs` @@ -265,6 +308,8 @@ sample.bin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV) ### Adding New Operators +> **Note:** Currently implemented operators are `Equal`, `NotEqual`, and `BitwiseAnd` (with `BitwiseAndMask`). Comparison operators (`>`, `<`) and XOR (`^`) are planned for future releases. + 1. Extend `Operator` enum in `src/parser/ast.rs` 2. Add parsing logic in `src/parser/grammar.rs` 3. Implement operator logic in `src/evaluator/operators.rs` @@ -385,10 +430,11 @@ The project includes automated CI checks via `.kiro/hooks/ci-auto-fix.kiro.hook` ### Development Phases -1. **MVP (v0.1)**: Basic parsing and evaluation -2. **Enhanced Features (v0.2)**: Indirect offsets, regex, caching -3. **Performance & Compatibility (v0.3)**: Optimizations, full compatibility -4. **Production Ready (v1.0)**: Stable API, complete documentation +1. **MVP (v0.1.0)** - CURRENT: Basic parsing and evaluation with byte/short/long/string types, equality and bitwise AND operators, built-in rules for 10 common formats +2. **Enhanced Features (v0.2)**: Comparison operators (`>`, `<`), indirect offset improvements, strength-based rule ordering +3. **Advanced Types (v0.3)**: Regex type, 64-bit integers, floating-point types, search patterns +4. **Full Compatibility (v0.4)**: Complete libmagic syntax support, all special directives, named tests +5. **Production Ready (v1.0)**: Stable API, complete documentation, 95%+ compatibility with GNU file ## Best Practices From 11dfbc2ae9a0224670e462631480b3b7c9026879 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 20:35:04 -0500 Subject: [PATCH 02/29] docs(agents): fix inaccurate feature claims in AGENTS.md Address CodeRabbit review feedback and remaining accuracy issues: - Show full enum signatures with associated data (TypeKind, Operator) - Correct offset claims: only absolute/from-end are evaluated, indirect/relative are parsed but stubbed - Mark Aho-Corasick and rule caching as planned, not current - Clarify regex dep is used in tests, not as a magic type - Note aho-corasick is not yet in Cargo.toml Closes #50 Signed-off-by: UncleSp1d3r --- AGENTS.md | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ac0136b8..ce77ff4c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -34,8 +34,8 @@ This document provides comprehensive guidelines for AI assistants working on the - Use memory-mapped I/O (`memmap2`) for efficient file access - Implement zero-copy operations where possible -- Use Aho-Corasick indexing for multi-pattern string searches -- Cache compiled magic rules for performance +- Use Aho-Corasick indexing for multi-pattern string searches (planned) +- Cache compiled magic rules for performance (planned) - Profile with `cargo bench` for performance regressions ### 4. Testing Required @@ -64,9 +64,16 @@ Target File → Memory Mapper → File Buffer ```rust // Core data structures in lib.rs pub struct MagicRule { /* ... */ } -pub enum TypeKind { Byte, Short, Long, String } -pub enum Operator { Equal, NotEqual, BitwiseAnd, BitwiseAndMask } -// Additional types and operators are planned for v1.0+ +pub enum TypeKind { + Byte, + Short { endian: Endianness, signed: bool }, + Long { endian: Endianness, signed: bool }, + String { max_length: Option }, +} +pub enum Operator { + Equal, NotEqual, BitwiseAnd, BitwiseAndMask(u64), +} +// Additional types and operators are planned -- see Current Limitations below // Parser module structure parser/ @@ -178,7 +185,7 @@ cargo test --doc # Test documentation examples ### Currently Implemented (v0.1.0) -- **Offsets**: Absolute, indirect, relative, and from-end specifications +- **Offsets**: Absolute and from-end specifications (indirect and relative are parsed but not yet evaluated) - **Types**: `byte`, `short`, `long`, `string` with endianness support - **Operators**: `=` (equal), `!=` (not equal), `&` (bitwise AND with optional mask) - **Nested Rules**: Hierarchical rule evaluation with proper indentation @@ -226,8 +233,9 @@ impl BinaryRegex for regex::bytes::Regex { ### Offset Specifications -- Indirect offsets implemented but may not support all libmagic syntax variations -- No support for complex offset expressions +- Indirect offsets are parsed into the AST but evaluation is not yet implemented (#37) +- Relative offsets are parsed into the AST but evaluation is not yet implemented (#38) +- Only absolute and from-end offsets are fully functional ### Magic File Syntax @@ -425,8 +433,8 @@ The project includes automated CI checks via `.kiro/hooks/ci-auto-fix.kiro.hook` - `nom`: Parser combinators - `serde`: Serialization - `clap`: CLI argument parsing -- `regex`: Pattern matching -- `aho-corasick`: Multi-pattern search +- `regex`: Pattern matching (used in tests; regex *type* for magic rules is planned) +- `aho-corasick`: Multi-pattern search (planned, not yet added) ### Development Phases From 72c37d0e2536397804868c2df6ac9cadf3f5ba20 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 20:44:59 -0500 Subject: [PATCH 03/29] docs(readme): update README.md with project badges for visibility Signed-off-by: UncleSp1d3r --- README.md | 4 ++++ mise.toml | 1 + 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index 0f385b14..f2f7c13c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # libmagic-rs +[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/EvilBit-Labs/libmagic-rs/badge)](https://scorecard.dev/viewer/?uri=github.com/EvilBit-Labs/libmagic-rs) +[![Crates.io](https://img.shields.io/crates/v/libmagic-rs)](https://crates.io/crates/libmagic-rs) +[![License](https://img.shields.io/crates/l/libmagic-rs)](https://github.com/EvilBit-Labs/libmagic-rs/blob/main/LICENSE) + A pure-Rust implementation of libmagic, the library that powers the `file` command for identifying file types. This project provides a memory-safe, efficient alternative to the C-based libmagic library. > [!NOTE] diff --git a/mise.toml b/mise.toml index e082f365..65016d48 100644 --- a/mise.toml +++ b/mise.toml @@ -28,3 +28,4 @@ lychee = "0.22.0" markdownlint-cli2 = "0.20.0" pre-commit = "latest" "cargo:cargo-machete" = "0.9.1" +scorecard = "5.4.0" From e6a1e1638882593f99f4dbed95020bc44fce35af Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 20:52:19 -0500 Subject: [PATCH 04/29] ci: pin all GitHub Actions to SHA hashes for supply chain security Pin all 63 action references across 10 workflow files to immutable commit SHAs instead of mutable version tags. This prevents supply chain attacks where a compromised tag could point to malicious code. Also adds github-actions ecosystem to dependabot.yml so pinned SHAs are automatically updated when new versions are released. Actions pinned: - actions/checkout v6.0.2 - actions/cache v4.3.0 - actions/upload-artifact v4.6.2, v6.0.0 - actions/download-artifact v7.0.0 - actions/configure-pages v5.0.0 - actions/deploy-pages v4.0.5 - actions/upload-pages-artifact v4.0.0 - actions/attest-build-provenance v3.2.0 - actions-rust-lang/audit v1.2.7 - codecov/codecov-action v5.5.2 - dorny/paths-filter v3.0.2 - github/codeql-action v3.32.3 - jdx/mise-action v3.6.1 - jontze/action-mdbook v4.0.0 - ossf/scorecard-action v2.4.1 (already pinned) - qltysh/qlty-action/coverage v2.2.0 Signed-off-by: UncleSp1d3r --- .github/dependabot.yml | 5 +++ .github/workflows/audit.yml | 4 +-- .github/workflows/benchmarks.yml | 14 ++++----- .github/workflows/ci.yml | 24 +++++++------- .github/workflows/codeql.yml | 10 +++--- .github/workflows/compatibility.yml | 6 ++-- .github/workflows/copilot-setup-steps.yml | 4 +-- .github/workflows/docs.yml | 12 +++---- .github/workflows/release.yml | 38 +++++++++++------------ .github/workflows/scorecard.yml | 2 +- .github/workflows/security.yml | 4 +-- 11 files changed, 64 insertions(+), 59 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 52258611..2e334460 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,6 +5,11 @@ updates: schedule: interval: "weekly" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: weekly + - package-ecosystem: "devcontainers" directory: "/" schedule: diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 52de3267..1d86c9c7 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -22,6 +22,6 @@ jobs: contents: read issues: write steps: - - uses: actions/checkout@v6 - - uses: actions-rust-lang/audit@v1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions-rust-lang/audit@72c09e02f132669d52284a3323acdb503cfc1a24 # v1.2.7 name: Audit Rust Dependencies diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index a40a31f2..d24c49b4 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -25,16 +25,16 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: jdx/mise-action@v3 + - uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1 with: install: true cache: true github_token: ${{ secrets.GITHUB_TOKEN }} - name: Cache cargo registry - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/.cargo/registry @@ -49,7 +49,7 @@ jobs: run: cargo bench --bench parser_bench --bench evaluation_bench --bench io_bench - name: Upload benchmark results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: benchmark-results path: target/criterion/ @@ -62,18 +62,18 @@ jobs: if: github.event_name == 'pull_request' steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 - - uses: jdx/mise-action@v3 + - uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1 with: install: true cache: true github_token: ${{ secrets.GITHUB_TOKEN }} - name: Cache cargo registry - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/.cargo/registry diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33cc867f..5beaf89c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,9 +28,9 @@ jobs: rust: ${{ steps.filter.outputs.rust }} docs: ${{ steps.filter.outputs.docs }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: dorny/paths-filter@v3 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: filter with: filters: | @@ -54,11 +54,11 @@ jobs: needs: changes if: needs.changes.outputs.rust == 'true' steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: dtolnay/rust-toolchain@1.91.0 with: components: llvm-tools, cargo, rustfmt, clippy - - uses: jdx/mise-action@v3 + - uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1 with: install: true cache: true @@ -72,8 +72,8 @@ jobs: needs: changes if: needs.changes.outputs.rust == 'true' steps: - - uses: actions/checkout@v6 - - uses: jdx/mise-action@v3 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1 with: install: true cache: true @@ -106,8 +106,8 @@ jobs: needs: [changes, test] if: needs.changes.outputs.rust == 'true' steps: - - uses: actions/checkout@v6 - - uses: jdx/mise-action@v3 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1 with: install: true cache: true @@ -123,8 +123,8 @@ jobs: needs: [changes, test] if: needs.changes.outputs.rust == 'true' steps: - - uses: actions/checkout@v6 - - uses: jdx/mise-action@v3 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1 with: install: true cache: true @@ -139,13 +139,13 @@ jobs: run: cargo llvm-cov report --lcov --output-path lcov.info - name: Upload to Codecov - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 with: files: lcov.info fail_ci_if_error: false token: ${{ secrets.CODECOV_TOKEN }} slug: EvilBit-Labs/libmagic-rs - - uses: qltysh/qlty-action/coverage@v2 + - uses: qltysh/qlty-action/coverage@a19242102d17e497f437d7466aa01b528537e899 # v2.2.0 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} files: target/lcov.info diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b03e07fc..3dabbf10 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -19,17 +19,17 @@ jobs: name: CodeQL Analyze runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6 - - uses: jdx/mise-action@v3 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1 with: install: true cache: true github_token: ${{ secrets.GITHUB_TOKEN }} - - uses: github/codeql-action/init@v3 + - uses: github/codeql-action/init@f5c2471be782132e47a6e6f9c725e56730d6e9a3 # v3.32.3 with: languages: rust - - uses: github/codeql-action/autobuild@v3 + - uses: github/codeql-action/autobuild@f5c2471be782132e47a6e6f9c725e56730d6e9a3 # v3.32.3 - - uses: github/codeql-action/analyze@v3 + - uses: github/codeql-action/analyze@f5c2471be782132e47a6e6f9c725e56730d6e9a3 # v3.32.3 diff --git a/.github/workflows/compatibility.yml b/.github/workflows/compatibility.yml index 25b94b83..d6cb6613 100644 --- a/.github/workflows/compatibility.yml +++ b/.github/workflows/compatibility.yml @@ -24,9 +24,9 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: jdx/mise-action@v3 + - uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1 with: install: true cache: true @@ -43,7 +43,7 @@ jobs: - name: Upload test results on failure if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: compatibility-test-results-${{ matrix.os }} path: | diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 54d6ca44..75026e9e 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -17,8 +17,8 @@ jobs: contents: read steps: - - uses: actions/checkout@v6 - - uses: jdx/mise-action@v3 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1 with: install: true cache: true diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 52fd09ba..78ca6330 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -24,15 +24,15 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: jdx/mise-action@v3 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1 with: install: true cache: true github_token: ${{ secrets.GITHUB_TOKEN }} - name: Setup mdBook - uses: jontze/action-mdbook@v4 + uses: jontze/action-mdbook@6c0be56d14c4bf16861b00af61f50ff7400ce502 # v4.0.0 with: token: ${{ secrets.GITHUB_TOKEN }} mdbook-version: latest @@ -55,11 +55,11 @@ jobs: - name: Setup Pages if: github.ref == 'refs/heads/main' - uses: actions/configure-pages@v5 + uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 - name: Upload artifact if: github.ref == 'refs/heads/main' - uses: actions/upload-pages-artifact@v4 + uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4.0.0 with: path: docs/book @@ -73,4 +73,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ff82ca31..13194d5a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,7 +56,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false submodules: recursive @@ -66,7 +66,7 @@ jobs: shell: bash run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.30.3/cargo-dist-installer.sh | sh" - name: Cache dist - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: cargo-dist-cache path: ~/.cargo/bin/dist @@ -82,7 +82,7 @@ jobs: cat plan-dist-manifest.json echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT" - name: "Upload dist-manifest.json" - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: artifacts-plan-dist-manifest path: plan-dist-manifest.json @@ -120,7 +120,7 @@ jobs: - name: enable windows longpaths run: | git config --global core.longpaths true - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false submodules: recursive @@ -135,7 +135,7 @@ jobs: run: ${{ matrix.install_dist.run }} # Get the dist-manifest - name: Fetch local artifacts - uses: actions/download-artifact@v7 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: pattern: artifacts-* path: target/distrib/ @@ -151,7 +151,7 @@ jobs: dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json echo "dist ran successfully" - name: Attest - uses: actions/attest-build-provenance@v3 + uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.2.0 with: subject-path: "target/distrib/*${{ join(matrix.targets, ', ') }}*" - id: cargo-dist @@ -168,7 +168,7 @@ jobs: cp dist-manifest.json "$BUILD_MANIFEST_NAME" - name: "Upload artifacts" - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: artifacts-build-local-${{ join(matrix.targets, '_') }} path: | @@ -185,12 +185,12 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false submodules: recursive - name: Install cached dist - uses: actions/download-artifact@v7 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: cargo-dist-cache path: ~/.cargo/bin/ @@ -202,7 +202,7 @@ jobs: shell: bash # Get all the local artifacts for the global tasks to use (for e.g. checksums) - name: Fetch local artifacts - uses: actions/download-artifact@v7 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: pattern: artifacts-* path: target/distrib/ @@ -233,7 +233,7 @@ jobs: find . -name '*.cdx.xml' | tee -a "$GITHUB_OUTPUT" echo "EOF" >> "$GITHUB_OUTPUT" - name: "Upload artifacts" - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: artifacts-build-global path: | @@ -254,19 +254,19 @@ jobs: outputs: val: ${{ steps.host.outputs.manifest }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false submodules: recursive - name: Install cached dist - uses: actions/download-artifact@v7 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: cargo-dist-cache path: ~/.cargo/bin/ - run: chmod +x ~/.cargo/bin/dist # Fetch artifacts from scratch-storage - name: Fetch artifacts - uses: actions/download-artifact@v7 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: pattern: artifacts-* path: target/distrib/ @@ -279,14 +279,14 @@ jobs: cat dist-manifest.json echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" - name: "Upload dist-manifest.json" - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: # Overwrite the previous copy name: artifacts-dist-manifest path: dist-manifest.json # Create a GitHub Release while uploading all files to it - name: "Download GitHub Artifacts" - uses: actions/download-artifact@v7 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: pattern: artifacts-* path: artifacts @@ -319,14 +319,14 @@ jobs: GITHUB_EMAIL: "admin+bot@axo.dev" if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: true repository: "EvilBit-Labs/homebrew-tap" token: ${{ secrets.HOMEBREW_TAP_TOKEN }} # So we have access to the formula - name: Fetch homebrew formulae - uses: actions/download-artifact@v7 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: pattern: artifacts-* path: Formula/ @@ -366,7 +366,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false submodules: recursive diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 819ed501..9994c8fe 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -73,6 +73,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@f5c2471be782132e47a6e6f9c725e56730d6e9a3 # v3.32.3 with: sarif_file: results.sarif diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 6794838f..5d1a36ee 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -24,8 +24,8 @@ jobs: audit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: jdx/mise-action@v3 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1 with: install: true cache: true From 2873df7e6748794a6b5e0b33b31a43cb05c731ba Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 20:58:24 -0500 Subject: [PATCH 05/29] ci: revert SHA pins in release.yml (managed by cargo-dist) release.yml is autogenerated by cargo-dist and would be overwritten on the next `cargo dist init`. Revert to tag references to avoid conflicts with the generated output. Signed-off-by: UncleSp1d3r --- .github/workflows/release.yml | 38 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 13194d5a..ff82ca31 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,7 +56,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@v6 with: persist-credentials: false submodules: recursive @@ -66,7 +66,7 @@ jobs: shell: bash run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.30.3/cargo-dist-installer.sh | sh" - name: Cache dist - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@v6 with: name: cargo-dist-cache path: ~/.cargo/bin/dist @@ -82,7 +82,7 @@ jobs: cat plan-dist-manifest.json echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT" - name: "Upload dist-manifest.json" - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@v6 with: name: artifacts-plan-dist-manifest path: plan-dist-manifest.json @@ -120,7 +120,7 @@ jobs: - name: enable windows longpaths run: | git config --global core.longpaths true - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@v6 with: persist-credentials: false submodules: recursive @@ -135,7 +135,7 @@ jobs: run: ${{ matrix.install_dist.run }} # Get the dist-manifest - name: Fetch local artifacts - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + uses: actions/download-artifact@v7 with: pattern: artifacts-* path: target/distrib/ @@ -151,7 +151,7 @@ jobs: dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json echo "dist ran successfully" - name: Attest - uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.2.0 + uses: actions/attest-build-provenance@v3 with: subject-path: "target/distrib/*${{ join(matrix.targets, ', ') }}*" - id: cargo-dist @@ -168,7 +168,7 @@ jobs: cp dist-manifest.json "$BUILD_MANIFEST_NAME" - name: "Upload artifacts" - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@v6 with: name: artifacts-build-local-${{ join(matrix.targets, '_') }} path: | @@ -185,12 +185,12 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@v6 with: persist-credentials: false submodules: recursive - name: Install cached dist - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + uses: actions/download-artifact@v7 with: name: cargo-dist-cache path: ~/.cargo/bin/ @@ -202,7 +202,7 @@ jobs: shell: bash # Get all the local artifacts for the global tasks to use (for e.g. checksums) - name: Fetch local artifacts - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + uses: actions/download-artifact@v7 with: pattern: artifacts-* path: target/distrib/ @@ -233,7 +233,7 @@ jobs: find . -name '*.cdx.xml' | tee -a "$GITHUB_OUTPUT" echo "EOF" >> "$GITHUB_OUTPUT" - name: "Upload artifacts" - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@v6 with: name: artifacts-build-global path: | @@ -254,19 +254,19 @@ jobs: outputs: val: ${{ steps.host.outputs.manifest }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@v6 with: persist-credentials: false submodules: recursive - name: Install cached dist - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + uses: actions/download-artifact@v7 with: name: cargo-dist-cache path: ~/.cargo/bin/ - run: chmod +x ~/.cargo/bin/dist # Fetch artifacts from scratch-storage - name: Fetch artifacts - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + uses: actions/download-artifact@v7 with: pattern: artifacts-* path: target/distrib/ @@ -279,14 +279,14 @@ jobs: cat dist-manifest.json echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" - name: "Upload dist-manifest.json" - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@v6 with: # Overwrite the previous copy name: artifacts-dist-manifest path: dist-manifest.json # Create a GitHub Release while uploading all files to it - name: "Download GitHub Artifacts" - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + uses: actions/download-artifact@v7 with: pattern: artifacts-* path: artifacts @@ -319,14 +319,14 @@ jobs: GITHUB_EMAIL: "admin+bot@axo.dev" if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@v6 with: persist-credentials: true repository: "EvilBit-Labs/homebrew-tap" token: ${{ secrets.HOMEBREW_TAP_TOKEN }} # So we have access to the formula - name: Fetch homebrew formulae - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + uses: actions/download-artifact@v7 with: pattern: artifacts-* path: Formula/ @@ -366,7 +366,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@v6 with: persist-credentials: false submodules: recursive From 0cfab477f4b4d7cc990fe72ba4598b16b5f2a3d9 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 21:50:04 -0500 Subject: [PATCH 06/29] chore: add git-cliff changelog generation and simplify justfile - Add cliff.toml with conventional commit parsing and PR linking - Add git-cliff 2.12.0 to mise.toml - Add changelog recipes (changelog, changelog-version, changelog-unreleased) - Remove dead code: ensure-dir (unused), rmrf (only goreleaser consumer) - Remove goreleaser section (project uses cargo-dist) - Fix redundant mise_exec self-calls (just invoking itself through mise) Signed-off-by: UncleSp1d3r --- CHANGELOG.md | 53 +++++++++++++++++++++++++++++++ cliff.toml | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++ justfile | 89 +++++++++++++++------------------------------------- mise.toml | 1 + 4 files changed, 166 insertions(+), 63 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 cliff.toml diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..291c7164 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,53 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [unreleased] + +### Features + +- Add development infrastructure, automation hooks, and comprehensive documentation ([#4](https://github.com/EvilBit-Labs/libmagic-rs/pull/4)) + +- Add evaluation engine with offset resolution and CI/CD automation ([#5](https://github.com/EvilBit-Labs/libmagic-rs/pull/5)) + +- Create rmagic cli ([#7](https://github.com/EvilBit-Labs/libmagic-rs/pull/7)) + +- Implement text magic parser (issue #11) ([#16](https://github.com/EvilBit-Labs/libmagic-rs/pull/16)) + +- Parser integration, CI modernization with mise, and Dev Container support ([#26](https://github.com/EvilBit-Labs/libmagic-rs/pull/26)) + +- Cli enhancements multiple files stdin magic discovery ([#27](https://github.com/EvilBit-Labs/libmagic-rs/pull/27)) + +- Built-in rules build time compilation fallback ([#28](https://github.com/EvilBit-Labs/libmagic-rs/pull/28)) + +- Evaluation enhancements with confidence, MIME, tags, metadata ([#29](https://github.com/EvilBit-Labs/libmagic-rs/pull/29)) + +- Strength calculation & documentation improvements ([#21](https://github.com/EvilBit-Labs/libmagic-rs/pull/21)) ([#30](https://github.com/EvilBit-Labs/libmagic-rs/pull/30)) + + +### Documentation + +- **agents**: Update AGENTS.md to reflect implemented features and future plans + +- **agents**: Fix inaccurate feature claims in AGENTS.md + +- **readme**: Update README.md with project badges for visibility + + +### Miscellaneous Tasks + +- **ci**: Add GitHub workflows for auditing, security, and documentation + +- Add Contributor Covenant Code of Conduct ([#2](https://github.com/EvilBit-Labs/libmagic-rs/pull/2)) + +- Pin all GitHub Actions to SHA hashes for supply chain security + +- Revert SHA pins in release.yml (managed by cargo-dist) + + +### Documentation + +- Comprehensive mdbook rewrite, rustdoc fixes, and test stability ([#33](https://github.com/EvilBit-Labs/libmagic-rs/pull/33)) + + + diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 00000000..c4890722 --- /dev/null +++ b/cliff.toml @@ -0,0 +1,86 @@ +# git-cliff ~ configuration file +# https://git-cliff.org/docs/configuration +# +# Lines starting with "#" are comments. +# Configuration options are organized into tables and keys. +# See documentation for more information on available options. + +[changelog] +# template for the changelog header +header = """ +# Changelog\n +All notable changes to this project will be documented in this file.\n +""" +# template for the changelog body +# https://keats.github.io/tera/docs/#introduction +body = """ +{% if version %}\ + ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} +{% else %}\ + ## [unreleased] +{% endif %}\ +{% for group, commits in commits | group_by(attribute="group") %} + ### {{ group | striptags | trim | upper_first }} + {% for commit in commits %} + - {% if commit.scope %}**{{ commit.scope }}**: {% endif %}\ + {% if commit.breaking %}[**breaking**] {% endif %}\ + {{ commit.message | upper_first }} + {% endfor %} +{% endfor %}\n +""" +# template for the changelog footer +footer = """ + +""" +# remove the leading and trailing whitespace +trim = true +# postprocessors +postprocessors = [] +# render body even when there are no releases to process +# render_always = true +# output file path +# output = "CHANGELOG.md" + +[git] +# parse the commits based on https://www.conventionalcommits.org +conventional_commits = true +# filter out the commits that are not conventional +filter_unconventional = true +# process each line of a commit as an individual commit +split_commits = false +# regex for preprocessing the commit messages +commit_preprocessors = [ + # Replace issue/PR numbers with links + { pattern = '\(#([0-9]+)\)', replace = "([#${1}](https://github.com/EvilBit-Labs/libmagic-rs/pull/${1}))" }, + # Check spelling of the commit with https://github.com/crate-ci/typos + # If the spelling is incorrect, it will be automatically fixed. + # { pattern = '.*', replace_command = 'typos --write-changes -' }, +] +# regex for parsing and grouping commits +commit_parsers = [ + { message = "^feat", group = "Features" }, + { message = "^fix\\(security\\)", group = "Security", scope = "security" }, + { message = "^fix", group = "Bug Fixes" }, + { message = "^doc", group = "Documentation" }, + { message = "^perf", group = "Performance" }, + { message = "^refactor", group = "Refactor" }, + { message = "^style", group = "Styling" }, + { message = "^test", group = "Testing" }, + { message = "^chore\\(release\\): prepare for", skip = true }, + { message = "^chore\\(deps.*\\)", skip = true }, + { message = "^chore\\(pr\\)", skip = true }, + { message = "^chore\\(pull\\)", skip = true }, + { message = "^Merge pull request", skip = true }, + { message = "^Merge branch", skip = true }, + { message = "^chore\\(ci\\): update", skip = true }, + { message = "^chore|^ci", group = "Miscellaneous Tasks" }, + { body = ".*security", group = "Security" }, + { body = "BREAKING CHANGE:", group = "Breaking Changes" }, + { message = "^revert", group = "Revert" }, +] +# filter out the commits that are not matched by commit parsers +filter_commits = false +# sort the tags topologically +topo_order = false +# sort the commits inside sections by oldest/newest order +sort_commits = "oldest" diff --git a/justfile b/justfile index ec45e614..a5ca6de2 100644 --- a/justfile +++ b/justfile @@ -8,8 +8,8 @@ set ignore-comments := true # Use mise to manage all dev tools (go, pre-commit, uv, etc.) # See mise.toml for tool versions -mise_exec := "mise exec --" +mise_exec := "mise exec --" root := justfile_dir() # ============================================================================= @@ -19,26 +19,6 @@ root := justfile_dir() default: @just --list -# ============================================================================= -# CROSS-PLATFORM HELPERS (private) -# ============================================================================= - -[private, windows] -ensure-dir dir: - New-Item -ItemType Directory -Force -Path "{{ dir }}" | Out-Null - -[private, unix] -ensure-dir dir: - /bin/mkdir -p "{{ dir }}" - -[private, windows] -rmrf path: - if (Test-Path "{{ path }}") { Remove-Item "{{ path }}" -Recurse -Force } - -[private, unix] -rmrf path: - /bin/rm -rf "{{ path }}" - # ============================================================================= # SETUP AND INITIALIZATION # ============================================================================= @@ -80,11 +60,12 @@ lint-rust-min: # Format justfile fmt-justfile: - @{{ mise_exec }} just --fmt --unstable + @just --fmt --unstable # Lint justfile formatting lint-justfile: - @{{ mise_exec }} just --fmt --check --unstable + @just --fmt --check --unstable + # Main lint recipe - calls all sub-linters lint: lint-rust lint-actions lint-docs lint-justfile @@ -113,7 +94,6 @@ pre-commit-run: format-files +FILES: @{{ mise_exec }} prettier --write --config .prettierrc.json {{ FILES }} - # ============================================================================= # BUILDING AND TESTING # ============================================================================= @@ -179,23 +159,25 @@ deny: # ============================================================================= # Private helper: run cargo llvm-cov with proper setup -[private, unix] +[private] +[unix] _coverage +args: #!/usr/bin/env bash set -euo pipefail rm -rf target/llvm-cov-target RUSTFLAGS="--cfg coverage" {{ mise_exec }} cargo llvm-cov --workspace --lcov --output-path lcov.info {{ args }} -[private, windows] +[private] +[windows] _coverage +args: Remove-Item -Recurse -Force target/llvm-cov-target -ErrorAction SilentlyContinue $env:RUSTFLAGS = "--cfg coverage"; {{ mise_exec }} cargo llvm-cov --workspace --lcov --output-path lcov.info {{ args }} coverage: - @{{ mise_exec }} just _coverage + @just _coverage coverage-check: - @{{ mise_exec }} just _coverage --fail-under-lines 9.7 + @just _coverage --fail-under-lines 9.7 # Generate HTML coverage report for local viewing [unix] @@ -281,7 +263,7 @@ docs-clean: [unix] docs-check: cd docs && {{ mise_exec }} mdbook build - @{{ mise_exec }} just fmt-check + @just fmt-check # Generate and serve documentation [unix] @@ -292,42 +274,23 @@ docs: @echo "mdbook requires a Unix-like environment to serve" # ============================================================================= -# GORELEASER TESTING +# CHANGELOG # ============================================================================= -# Private helper: run goreleaser with macOS SDK env configured (no-op on non-mac) -[private, unix] -_goreleaser +args: - #!/bin/bash - set -euo pipefail - if command -v xcrun >/dev/null 2>&1; then - SDKROOT_PATH=$(xcrun --sdk macosx --show-sdk-path) - export SDKROOT="${SDKROOT_PATH}" - export MACOSX_DEPLOYMENT_TARGET="11.0" - export CARGO_ZIGBUILD_SYSROOT="${SDKROOT_PATH}" - export RUSTFLAGS="${RUSTFLAGS:-} -C link-arg=-Wl,-syslibroot,${SDKROOT_PATH} -C link-arg=-F${SDKROOT_PATH}/System/Library/Frameworks" - fi - goreleaser {{ args }} - -[private, windows] -_goreleaser +args: - @{{ mise_exec }} goreleaser {{ args }} - -goreleaser-check: - @{{ mise_exec }} goreleaser check - -goreleaser-build: - @just _goreleaser build --clean - -goreleaser-snapshot: - @just _goreleaser release --snapshot --clean - -goreleaser-build-target target: - @just _goreleaser build --clean --single-target {{ target }} - -# Clean GoReleaser artifacts -goreleaser-clean: - @just rmrf dist +# Generate changelog +[group('docs')] +changelog: + @{{ mise_exec }} git-cliff --output CHANGELOG.md + +# Generate changelog for a specific version +[group('docs')] +changelog-version version: + @{{ mise_exec }} git-cliff --tag {{ version }} --output CHANGELOG.md + +# Generate changelog for unreleased changes only +[group('docs')] +changelog-unreleased: + @{{ mise_exec }} git-cliff --unreleased --output CHANGELOG.md # ============================================================================= # RELEASE MANAGEMENT diff --git a/mise.toml b/mise.toml index 65016d48..971513e7 100644 --- a/mise.toml +++ b/mise.toml @@ -28,4 +28,5 @@ lychee = "0.22.0" markdownlint-cli2 = "0.20.0" pre-commit = "latest" "cargo:cargo-machete" = "0.9.1" +"cargo:git-cliff" = "2.12.0" scorecard = "5.4.0" From c6c7d082949e8705a831083361c126d03c1500b8 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 21:57:05 -0500 Subject: [PATCH 07/29] docs: improve SECURITY.md with scope, safe harbor, and responsible disclosure - Add in-scope/out-of-scope vulnerability categories - Add safe harbor clause for security researchers - Add responsible disclosure expectations - Link directly to GitHub private vulnerability reporting form - Update supported versions to reflect actual releases (0.1.x) - Remove redundant sections (severity levels, developer best practices) Signed-off-by: UncleSp1d3r --- SECURITY.md | 121 ++++++++++++++++++++++++---------------------------- 1 file changed, 55 insertions(+), 66 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 6b063d95..010f3e15 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,100 +2,89 @@ ## Supported Versions -libmagic-rs is currently in active development as a passion project. Security updates are provided on a best-effort basis for the following versions: +| Version | Supported | +| ------- | ------------------ | +| 0.1.x | :white_check_mark: | +| < 0.1 | :x: | -| Version | Supported | Notes | -| ------- | ------------------ | ------------------------------------ | -| 1.0.x | :white_check_mark: | Production releases (when available) | -| 0.3.x | :white_check_mark: | Pre-release with security fixes | -| 0.2.x | :white_check_mark: | Pre-release with security fixes | -| 0.1.x | :white_check_mark: | MVP releases with security fixes | -| < 0.1 | :x: | Development versions | +Users on unsupported versions should upgrade to the latest release. Please review the [release notes](https://github.com/EvilBit-Labs/libmagic-rs/releases) when upgrading. -## Security Considerations - -### Memory Safety +## Reporting a Vulnerability -- **Pure Rust Implementation**: No unsafe code except in vetted dependencies -- **Bounds Checking**: All buffer access protected by bounds checking -- **Safe File Handling**: Graceful handling of truncated/corrupted files -- **Fuzzing Integration**: Robustness testing with malformed inputs +We take the security of libmagic-rs seriously. If you believe you have found a security vulnerability, please report it to us as described below. -### Input Validation +**Please do not report security vulnerabilities through public GitHub issues.** -- **Magic File Validation**: Syntax validation before parsing -- **File Size Limits**: Protection against resource exhaustion -- **Malformed Input Handling**: Safe processing of corrupted files -- **Timeout Protection**: Configurable timeouts for long-running evaluations +Instead, use one of the following channels: -### Dependencies +1. [GitHub Private Vulnerability Reporting](https://github.com/EvilBit-Labs/libmagic-rs/security/advisories/new) (preferred) +2. Email [security@evilbitlabs.com](mailto:security@evilbitlabs.com) -- **Vetted Dependencies**: Only trusted, well-maintained crates -- **Security Audits**: Regular `cargo audit` checks -- **Minimal Attack Surface**: Minimal external dependencies -- **License Compliance**: All dependencies must have compatible licenses +Please include: -## Reporting a Vulnerability +- Description of the vulnerability +- Steps to reproduce +- Potential impact +- Suggested fix (if any) -### How to Report +### Scope -If you discover a security vulnerability in libmagic-rs, please report it responsibly: +**In scope:** -1. **Email**: Send details to -2. **GitHub Security**: Use GitHub's private vulnerability reporting feature -3. **Do NOT**: Open public issues for security vulnerabilities +- Buffer overflows or out-of-bounds reads in magic file parsing or evaluation +- Denial of service via crafted magic files or input files +- Path traversal in file input handling +- Command injection via CLI arguments +- Unsafe code in dependencies that affects libmagic-rs -### What to Include +**Out of scope:** -- Description of the vulnerability -- Steps to reproduce the issue -- Potential impact assessment -- Suggested fix (if any) -- Your contact information for follow-up +- Vulnerabilities in the original C libmagic implementation +- Issues requiring physical access to the machine running libmagic-rs +- Social engineering attacks -### Response Timeline +### What to Expect **Note**: This is a passion project with volunteer maintainers. Response times are best-effort and may vary based on maintainer availability. -- **Acknowledgment**: Best effort (typically within 1 week) -- **Initial Assessment**: Best effort (typically within 2 weeks) -- **Fix Development**: Best effort (timeline depends on severity and maintainer availability) -- **Public Disclosure**: Coordinated with fix release when possible +- We will acknowledge receipt of your report within **1 week** +- We will provide an initial assessment within **2 weeks** +- We aim to release a fix within **90 days** of confirmed vulnerabilities +- We will coordinate disclosure through a [GitHub Security Advisory](https://github.com/EvilBit-Labs/libmagic-rs/security/advisories) +- We will credit you in the advisory (unless you prefer to remain anonymous) -### Severity Levels +### Responsible Disclosure -- **Critical**: Remote code execution, memory corruption -- **High**: Denial of service, information disclosure -- **Medium**: Limited information disclosure, minor DoS -- **Low**: Minor issues, edge cases +We ask that you: -## Security Best Practices +- Give us reasonable time to respond to issues before any disclosure +- Avoid accessing or modifying other users' data +- Avoid actions that could negatively impact other users -### For Users +## Security Features -- Keep libmagic-rs updated to the latest version -- Validate input files before processing -- Use appropriate file size limits -- Monitor for security advisories +libmagic-rs includes several security-focused features: -### For Developers +- **Pure Rust implementation**: No unsafe code except in vetted dependencies +- **Bounds checking**: All buffer access protected by bounds checking +- **Safe file handling**: Graceful handling of truncated and corrupted files +- **Dependency auditing**: Regular `cargo audit` and `cargo deny` checks +- **Automated dependency updates**: Via Dependabot -- Follow Rust security best practices -- Use `cargo audit` regularly -- Implement proper error handling -- Test with malformed inputs -- Review all unsafe code usage +## Safe Harbor -## Security Acknowledgments +We support safe harbor for security researchers who: -We appreciate responsible disclosure and will acknowledge security researchers who help improve libmagic-rs security. Contributors will be listed in our security acknowledgments (with permission). +- Make a good faith effort to avoid privacy violations, data destruction, and service disruption +- Only interact with accounts you own or with explicit permission of the account holder +- Report vulnerabilities through the channels described above -**Note**: As a passion project, we may not always be able to provide immediate responses or fixes, but we do our best to address security issues when maintainers are available. +We will not pursue legal action against researchers who follow this policy. ## Contact -For security-related questions or concerns: +For general security questions, open a GitHub Issue. For vulnerability reports, use [Private Vulnerability Reporting](https://github.com/EvilBit-Labs/libmagic-rs/security/advisories/new) or email [security@evilbitlabs.com](mailto:security@evilbitlabs.com). + +--- -- **Email**: -- **GitHub**: [Security Advisories](https://github.com/EvilBit-Labs/libmagic-rs/security/advisories) -- **Issues**: Use private vulnerability reporting for security issues +Thank you for helping keep libmagic-rs and its users secure! From df339a23e9515413779c9c758df7f8a8a55b3483 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 21:59:26 -0500 Subject: [PATCH 08/29] docs: add PGP key for encrypted vulnerability reporting Signed-off-by: UncleSp1d3r --- SECURITY.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index 010f3e15..4f950d8b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -18,7 +18,7 @@ We take the security of libmagic-rs seriously. If you believe you have found a s Instead, use one of the following channels: 1. [GitHub Private Vulnerability Reporting](https://github.com/EvilBit-Labs/libmagic-rs/security/advisories/new) (preferred) -2. Email [security@evilbitlabs.com](mailto:security@evilbitlabs.com) +2. Email [security@evilbitlabs.com](mailto:security@evilbitlabs.com) encrypted with our [PGP key](#pgp-key) (verify the full fingerprint below before use) Please include: @@ -81,6 +81,29 @@ We support safe harbor for security researchers who: We will not pursue legal action against researchers who follow this policy. +## PGP Key + +**Fingerprint:** `F839 4B2C F0FE C451 1B11 E721 8F71 D62B F438 2BC0` + +```text +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mDMEaLJmxhYJKwYBBAHaRw8BAQdAaS3KAoo+AgZGR6G6+m0wT2yulC5d6zV9lf2m +TugBT+O0L3N1cHBvcnRAZXZpbGJpdGxhYnMuaW8gPHN1cHBvcnRAZXZpbGJpdGxh +YnMuaW8+iNcEExYKAH8DCwkHRRQAAAAAABwAIHNhbHRAbm90YXRpb25zLm9wZW5w +Z3Bqcy5vcmexd21FpCDfIrO7bf+T6hH/8drbGLWiuEueWvSTyw4T/QMVCggEFgAC +AQIZAQKbAwIeARYhBPg5Syzw/sRRGxHnIY9x1iv0OCvABQJpiUiCBQkIXQE5AAoJ +EI9x1iv0OCvAm2sA/AqFT6XEULJCimXX9Ve6e63RX7y2B+VoBVHt+PDaPBwkAP4j +39xBoLFI6KZJ/A7SOQBkret+VONwPqyW83xfn+E7Arg4BGiyZsYSCisGAQQBl1UB +BQEBB0ArjU33Uj/x1Kc7ldjVIM9UUCWMTwDWgw8lB/mNESb+GgMBCAeIvgQYFgoA +cAWCaLJmxgkQj3HWK/Q4K8BFFAAAAAAAHAAgc2FsdEBub3RhdGlvbnMub3BlbnBn +cGpzLm9yZ4msIB6mugSL+LkdT93+rSeNePtBY4Aj+O6TRFU9aKiQApsMFiEE+DlL +LPD+xFEbEechj3HWK/Q4K8AAALEXAQDqlsBwMP2XXzXDSnNNLg8yh1/zQcxT1zZ1 +Z26lyM7L6QD+Lya5aFe74WE3wTys5ykGuWkHYEgba+AyZNmuPhwMGAc= +=9zSi +-----END PGP PUBLIC KEY BLOCK----- +``` + ## Contact For general security questions, open a GitHub Issue. For vulnerability reports, use [Private Vulnerability Reporting](https://github.com/EvilBit-Labs/libmagic-rs/security/advisories/new) or email [security@evilbitlabs.com](mailto:security@evilbitlabs.com). From 33c644062385761784bbdee3d870a51a8a1ec396 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 22:00:26 -0500 Subject: [PATCH 09/29] docs: use support@evilbitlabs.io for security contact to match PGP key Signed-off-by: UncleSp1d3r --- SECURITY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 4f950d8b..5c5d4196 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -18,7 +18,7 @@ We take the security of libmagic-rs seriously. If you believe you have found a s Instead, use one of the following channels: 1. [GitHub Private Vulnerability Reporting](https://github.com/EvilBit-Labs/libmagic-rs/security/advisories/new) (preferred) -2. Email [security@evilbitlabs.com](mailto:security@evilbitlabs.com) encrypted with our [PGP key](#pgp-key) (verify the full fingerprint below before use) +2. Email [support@evilbitlabs.io](mailto:support@evilbitlabs.io) encrypted with our [PGP key](#pgp-key) (verify the full fingerprint below before use) Please include: @@ -106,7 +106,7 @@ Z26lyM7L6QD+Lya5aFe74WE3wTys5ykGuWkHYEgba+AyZNmuPhwMGAc= ## Contact -For general security questions, open a GitHub Issue. For vulnerability reports, use [Private Vulnerability Reporting](https://github.com/EvilBit-Labs/libmagic-rs/security/advisories/new) or email [security@evilbitlabs.com](mailto:security@evilbitlabs.com). +For general security questions, open a GitHub Issue. For vulnerability reports, use [Private Vulnerability Reporting](https://github.com/EvilBit-Labs/libmagic-rs/security/advisories/new) or email [support@evilbitlabs.io](mailto:support@evilbitlabs.io). --- From 44c13cd5b8fa48c4ae91007021cc2ac1a899bd9d Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 22:56:58 -0500 Subject: [PATCH 10/29] chore: commit Cargo.lock for reproducible binary builds Cargo.lock was gitignored but the project ships a binary (rmagic). Per Rust best practices, lock files should be committed for binaries to ensure reproducible builds across environments. Signed-off-by: UncleSp1d3r --- .gitignore | 5 +- Cargo.lock | 1333 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1335 insertions(+), 3 deletions(-) create mode 100644 Cargo.lock diff --git a/.gitignore b/.gitignore index 8525a105..5fb33c9a 100644 --- a/.gitignore +++ b/.gitignore @@ -53,9 +53,8 @@ debug/ target/ dist/ -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock +# Cargo.lock is committed because this project ships a binary (rmagic) +# https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html # These are backup files generated by rustfmt **/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..2cc7ff1d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1333 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloca" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4" +dependencies = [ + "cc", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.5.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap-stdin" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d80e97074da664d8e2c49e82cba54c40b9cec15c73810d90bf6a78261ab3ccaa" +dependencies = [ + "thiserror", +] + +[[package]] +name = "clap_builder" +version = "4.5.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "console" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "windows-sys 0.59.0", +] + +[[package]] +name = "criterion" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3" +dependencies = [ + "alloca", + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools", + "num-traits", + "oorandom", + "page_size", + "plotters", + "rayon", + "regex", + "serde", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[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.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[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.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "insta" +version = "1.46.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82db8c87c7f1ccecb34ce0c24399b8a73081427f3c7c50a5d597925356115e4" +dependencies = [ + "console", + "once_cell", + "serde", + "similar", + "tempfile", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[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.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "libmagic-rs" +version = "0.1.0" +dependencies = [ + "byteorder", + "cfg-if", + "clap", + "clap-stdin", + "criterion", + "insta", + "memchr", + "memmap2", + "nix", + "nom", + "proptest", + "regex", + "serde", + "serde_json", + "tempfile", + "thiserror", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "memmap2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" +dependencies = [ + "libc", +] + +[[package]] +name = "nix" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225e7cfe711e0ba79a68baeddb2982723e4235247aefce1482f2f16c27865b66" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "page_size" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566cb3fdacef14c0737f9546df7cfeadbfbc9fef10991038bf5015d0c80532" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "rusty-fork" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "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 = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" +dependencies = [ + "fastrand", + "getrandom 0.4.1", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen 0.46.0", +] + +[[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.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +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 = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[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-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" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" From 277ee65701602da73c6ddddc4f24b376f4559cd6 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 22:57:57 -0500 Subject: [PATCH 11/29] chore: commit mise.lock for reproducible dev tool versions Signed-off-by: UncleSp1d3r --- mise.lock | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 mise.lock diff --git a/mise.lock b/mise.lock new file mode 100644 index 00000000..83ae4cb2 --- /dev/null +++ b/mise.lock @@ -0,0 +1,126 @@ +[[tools.actionlint]] +version = "1.7.10" +backend = "aqua:rhysd/actionlint" + +[[tools.cargo-binstall]] +version = "1.17.5" +backend = "aqua:cargo-bins/cargo-binstall" + +[[tools.cargo-insta]] +version = "1.46.1" +backend = "aqua:mitsuhiko/insta" + +[[tools."cargo:cargo-audit"]] +version = "0.22.0" +backend = "cargo:cargo-audit" + +[[tools."cargo:cargo-auditable"]] +version = "0.7.2" +backend = "cargo:cargo-auditable" + +[[tools."cargo:cargo-cyclonedx"]] +version = "0.5.7" +backend = "cargo:cargo-cyclonedx" + +[[tools."cargo:cargo-deny"]] +version = "0.19.0" +backend = "cargo:cargo-deny" + +[[tools."cargo:cargo-dist"]] +version = "0.30.3" +backend = "cargo:cargo-dist" + +[[tools."cargo:cargo-llvm-cov"]] +version = "0.6.24" +backend = "cargo:cargo-llvm-cov" + +[[tools."cargo:cargo-machete"]] +version = "0.9.1" +backend = "cargo:cargo-machete" + +[[tools."cargo:cargo-nextest"]] +version = "0.9.123-b.4" +backend = "cargo:cargo-nextest" + +[[tools."cargo:cargo-outdated"]] +version = "0.17.0" +backend = "cargo:cargo-outdated" + +[[tools."cargo:cargo-release"]] +version = "0.25.22" +backend = "cargo:cargo-release" + +[[tools."cargo:git-cliff"]] +version = "2.12.0" +backend = "cargo:git-cliff" + +[[tools."cargo:mdbook"]] +version = "0.5.2" +backend = "cargo:mdbook" + +[[tools."cargo:mdbook-admonish"]] +version = "1.20.0" +backend = "cargo:mdbook-admonish" + +[[tools."cargo:mdbook-i18n-helpers"]] +version = "0.4.0" +backend = "cargo:mdbook-i18n-helpers" + +[[tools."cargo:mdbook-linkcheck"]] +version = "0.7.7" +backend = "cargo:mdbook-linkcheck" + +[[tools."cargo:mdbook-mermaid"]] +version = "0.17.0" +backend = "cargo:mdbook-mermaid" + +[[tools."cargo:mdbook-open-on-gh"]] +version = "3.0.0" +backend = "cargo:mdbook-open-on-gh" + +[[tools."cargo:mdbook-tabs"]] +version = "0.3.4" +backend = "cargo:mdbook-tabs" + +[[tools."cargo:mdbook-toc"]] +version = "0.15.3" +backend = "cargo:mdbook-toc" + +[[tools.just]] +version = "1.46.0" +backend = "aqua:casey/just" + +[[tools.lychee]] +version = "0.22.0" +backend = "aqua:lycheeverse/lychee" + +[[tools.markdownlint-cli2]] +version = "0.20.0" +backend = "npm:markdownlint-cli2" + +[[tools."pipx:mdformat"]] +version = "0.7.21" +backend = "pipx:mdformat" + +[tools."pipx:mdformat".options] +uvx_args = "--with mdformat-gfm --with mdformat-frontmatter --with mdformat-footnote --with mdformat-simple-breaks --with mdformat-gfm-alerts --with mdformat-toc --with mdformat-wikilink --with mdformat-tables" + +[[tools.pre-commit]] +version = "4.5.1" +backend = "aqua:pre-commit/pre-commit" + +[[tools.prettier]] +version = "3.8.1" +backend = "npm:prettier" + +[[tools.python]] +version = "3.13.11" +backend = "core:python" + +[[tools.rust]] +version = "1.91.0" +backend = "core:rust" + +[[tools.scorecard]] +version = "5.4.0" +backend = "aqua:ossf/scorecard" From 3e075f377039e942da3983447c7a36f748f00bc2 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 23:04:02 -0500 Subject: [PATCH 12/29] docs: add code review requirements to AGENTS.md and CONTRIBUTING.md Document what reviewers check for, aligning with CodeRabbit's custom checks (memory safety, error handling, test coverage, performance, libmagic compatibility). Both human and AI reviewers now have consistent review criteria. Signed-off-by: UncleSp1d3r --- AGENTS.md | 15 +++++++++++++++ CONTRIBUTING.md | 15 ++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index ce77ff4c..df74d8ba 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -417,6 +417,21 @@ The project includes automated CI checks via `.kiro/hooks/ci-auto-fix.kiro.hook` - Security audit must pass - Performance benchmarks must not regress +### Code Review Requirements + +All pull requests require review before merging. Reviews are performed by maintainers and automated tools (CodeRabbit). Reviewers check for: + +- **Correctness**: Does the code do what it claims? Are edge cases handled? +- **Memory safety**: No unsafe code blocks (except vetted dependencies). All buffer access must use bounds checking with `.get()` methods. No raw pointer arithmetic or transmute operations. +- **Error handling**: Proper use of `Result` types, no panics in library code, no `unwrap()` or `expect()` in library code. Use `thiserror` for structured error types. +- **Tests**: New functionality has tests, existing tests still pass, edge cases and error conditions are covered. Property tests with `proptest` for complex data structures. +- **Performance**: No unnecessary allocations in hot paths, no regressions in benchmarks. Memory-mapped I/O used for file access. +- **libmagic compatibility**: Changes maintain compatibility with libmagic behavior and magic file format. Output format matches GNU `file` command expectations. +- **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 must pass before merge. Branch protection enforces these checks on the `main` branch. + ## Project Context ### Current Status diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8f40ed66..4fd948c9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -234,10 +234,23 @@ pub fn parse_rule(input: &str) -> Result { 1. **Update documentation** for any API changes 2. **Add tests** for new functionality -3. **Run the full test suite** locally +3. **Run the full test suite** locally: `just ci-check` 4. **Create a pull request** with a clear description 5. **Address review feedback** promptly +### Code Review Requirements + +All pull requests require review before merging. Reviewers check for: + +- **Correctness**: Does the code do what it claims? Are edge cases handled? +- **Safety**: No unsafe code, proper bounds checking, no panics in library code +- **Tests**: New functionality has tests, existing tests still pass +- **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 +- **Performance**: No unnecessary allocations in hot paths, no regressions in benchmarks + +CI must pass before merge. This includes formatting, linting, tests, security audit, and CodeQL analysis. Branch protection enforces these checks on the `main` branch. + ### PR Description Template ```markdown From 06e06d8b82abd579d488ec169023a29a00f5f18c Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 23:14:27 -0500 Subject: [PATCH 13/29] chore: add SPDX license and copyright headers to all source files Add to all 39 .rs files (src/, tests/, benches/, build.rs): // Copyright (c) 2025-2026 the libmagic-rs contributors // SPDX-License-Identifier: Apache-2.0 Required for OSSF Best Practices gold level criteria: license_per_file and copyright_per_file. Signed-off-by: UncleSp1d3r --- benches/evaluation_bench.rs | 3 +++ benches/io_bench.rs | 3 +++ benches/parser_bench.rs | 3 +++ build.rs | 3 +++ src/build_helpers.rs | 3 +++ src/builtin_rules.rs | 3 +++ src/error.rs | 3 +++ src/evaluator/mod.rs | 3 +++ src/evaluator/offset.rs | 3 +++ src/evaluator/operators.rs | 3 +++ src/evaluator/strength.rs | 3 +++ src/evaluator/types.rs | 3 +++ src/io/mod.rs | 3 +++ src/lib.rs | 3 +++ src/main.rs | 3 +++ src/mime.rs | 3 +++ src/output/json.rs | 3 +++ src/output/mod.rs | 3 +++ src/output/text.rs | 3 +++ src/parser/ast.rs | 3 +++ src/parser/format.rs | 3 +++ src/parser/grammar.rs | 3 +++ src/parser/hierarchy.rs | 3 +++ src/parser/loader.rs | 3 +++ src/parser/mod.rs | 3 +++ src/parser/preprocessing.rs | 3 +++ src/tags.rs | 3 +++ tests/cli_integration_tests.rs | 3 +++ tests/cli_normalization.rs | 3 +++ tests/common/mod.rs | 3 +++ tests/compatibility_tests.rs | 3 +++ tests/directory_loading_tests.rs | 3 +++ tests/evaluator_tests.rs | 3 +++ tests/integration_tests.rs | 3 +++ tests/json_integration_test.rs | 3 +++ tests/mime_tests.rs | 3 +++ tests/parser_integration_tests.rs | 3 +++ tests/property_tests.rs | 3 +++ tests/tags_tests.rs | 3 +++ 39 files changed, 117 insertions(+) diff --git a/benches/evaluation_bench.rs b/benches/evaluation_bench.rs index 6e0e6b58..2dc15543 100644 --- a/benches/evaluation_bench.rs +++ b/benches/evaluation_bench.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Evaluation benchmarks for libmagic-rs //! //! Benchmarks rule evaluation performance against various file types: diff --git a/benches/io_bench.rs b/benches/io_bench.rs index 81f2b9aa..9d61325d 100644 --- a/benches/io_bench.rs +++ b/benches/io_bench.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! I/O benchmarks for libmagic-rs //! //! Benchmarks file I/O operations including: diff --git a/benches/parser_bench.rs b/benches/parser_bench.rs index 3a19359d..b202f0e9 100644 --- a/benches/parser_bench.rs +++ b/benches/parser_bench.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Parser benchmarks for libmagic-rs //! //! Benchmarks magic file parsing performance including: diff --git a/build.rs b/build.rs index b80c0a37..11e91f0b 100644 --- a/build.rs +++ b/build.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + // Stub module to satisfy error.rs dependencies during build #[allow(dead_code)] mod evaluator { diff --git a/src/build_helpers.rs b/src/build_helpers.rs index eadd5074..504e14e3 100644 --- a/src/build_helpers.rs +++ b/src/build_helpers.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + /// Build-time helpers for compiling magic rules. /// /// This module contains functionality used by the build script to parse magic files diff --git a/src/builtin_rules.rs b/src/builtin_rules.rs index 65583538..ad98288b 100644 --- a/src/builtin_rules.rs +++ b/src/builtin_rules.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Built-in magic rules compiled at build time. //! //! This module contains magic rules that are compiled into the library binary diff --git a/src/error.rs b/src/error.rs index 5d1bdee8..c7263e0b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Error types for the libmagic-rs library. //! //! This module defines the error types used throughout the library for diff --git a/src/evaluator/mod.rs b/src/evaluator/mod.rs index 56fd9f67..d74c2c1a 100644 --- a/src/evaluator/mod.rs +++ b/src/evaluator/mod.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Rule evaluation engine //! //! This module contains the core evaluation logic for executing magic rules diff --git a/src/evaluator/offset.rs b/src/evaluator/offset.rs index 30b1f974..7a919029 100644 --- a/src/evaluator/offset.rs +++ b/src/evaluator/offset.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Offset resolution for magic rule evaluation //! //! This module provides functions for resolving different types of offset specifications diff --git a/src/evaluator/operators.rs b/src/evaluator/operators.rs index e307dcc1..acd6e387 100644 --- a/src/evaluator/operators.rs +++ b/src/evaluator/operators.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Operator application for magic rule evaluation //! //! This module provides functions for applying comparison and bitwise operators diff --git a/src/evaluator/strength.rs b/src/evaluator/strength.rs index 9879e0c4..0469eb76 100644 --- a/src/evaluator/strength.rs +++ b/src/evaluator/strength.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Strength calculation for magic rules //! //! This module implements the strength calculation algorithm based on libmagic's diff --git a/src/evaluator/types.rs b/src/evaluator/types.rs index 448e2752..671875f7 100644 --- a/src/evaluator/types.rs +++ b/src/evaluator/types.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Type interpretation for reading and converting bytes from file buffers //! //! This module provides functions for safely reading different data types from byte buffers diff --git a/src/io/mod.rs b/src/io/mod.rs index 52aef5e2..dac0512e 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! I/O utilities module //! //! This module provides efficient file access utilities including memory-mapped diff --git a/src/lib.rs b/src/lib.rs index 5e77f34a..9dc79112 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Rust Libmagic - A pure-Rust implementation of libmagic //! //! This library provides safe, efficient file type identification through magic rule evaluation. diff --git a/src/main.rs b/src/main.rs index ed10a902..05cd86bb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Command-line interface for libmagic-rs //! //! This binary provides a CLI tool for file type identification using magic rules, diff --git a/src/mime.rs b/src/mime.rs index 58f1f77b..70a4e299 100644 --- a/src/mime.rs +++ b/src/mime.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! MIME type mapping for file type detection //! //! This module provides MIME type mapping from file type descriptions diff --git a/src/output/json.rs b/src/output/json.rs index faeb20d9..1976137f 100644 --- a/src/output/json.rs +++ b/src/output/json.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! JSON output formatting for magic rule evaluation results //! //! This module provides JSON-specific data structures and formatting functions diff --git a/src/output/mod.rs b/src/output/mod.rs index 161a0612..abb5392e 100644 --- a/src/output/mod.rs +++ b/src/output/mod.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Output formatting module for magic rule evaluation results //! //! This module provides data structures and functionality for storing and formatting diff --git a/src/output/text.rs b/src/output/text.rs index 1cadd8be..2663ce74 100644 --- a/src/output/text.rs +++ b/src/output/text.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Text output formatting for magic rule evaluation results //! //! This module provides functionality to format evaluation results in a human-readable diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 61c50b58..9036e606 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Abstract Syntax Tree definitions for magic rules //! //! This module contains the core data structures that represent parsed magic rules diff --git a/src/parser/format.rs b/src/parser/format.rs index a813d946..91ceb8f5 100644 --- a/src/parser/format.rs +++ b/src/parser/format.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Format detection for magic files. //! //! Detects whether a path points to a text magic file, a directory of magic files, diff --git a/src/parser/grammar.rs b/src/parser/grammar.rs index 0f701f9a..69c7567c 100644 --- a/src/parser/grammar.rs +++ b/src/parser/grammar.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Grammar parsing for magic files using nom parser combinators //! //! This module implements the parsing logic for magic file syntax, converting diff --git a/src/parser/hierarchy.rs b/src/parser/hierarchy.rs index 4a9496dd..1db5db5b 100644 --- a/src/parser/hierarchy.rs +++ b/src/parser/hierarchy.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Rule hierarchy building for magic file parsing. //! //! Constructs parent-child relationships between magic rules based on diff --git a/src/parser/loader.rs b/src/parser/loader.rs index b9d49ac9..c62f575a 100644 --- a/src/parser/loader.rs +++ b/src/parser/loader.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! File and directory loading for magic files. //! //! Provides functions for loading magic rules from individual files and diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 5ecf3994..fdc9bfc2 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Magic file parser module //! //! This module handles parsing of magic files into an Abstract Syntax Tree (AST) diff --git a/src/parser/preprocessing.rs b/src/parser/preprocessing.rs index 1f9e1004..ef081586 100644 --- a/src/parser/preprocessing.rs +++ b/src/parser/preprocessing.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Line preprocessing for magic file parsing. //! //! Handles comment removal, empty line filtering, line continuations, diff --git a/src/tags.rs b/src/tags.rs index 7af189df..c09d58f9 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Tag extraction for file type classification //! //! This module extracts classification tags from file type descriptions diff --git a/tests/cli_integration_tests.rs b/tests/cli_integration_tests.rs index ee4c7fa6..94058546 100644 --- a/tests/cli_integration_tests.rs +++ b/tests/cli_integration_tests.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! CLI integration tests for libmagic-rs using canonical libmagic test suite //! //! These tests verify the command-line interface functionality by running against diff --git a/tests/cli_normalization.rs b/tests/cli_normalization.rs index 5241dfe0..49ac7732 100644 --- a/tests/cli_normalization.rs +++ b/tests/cli_normalization.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Tests for CLI output normalization functionality //! //! These tests ensure that the cross-platform normalization helpers work correctly diff --git a/tests/common/mod.rs b/tests/common/mod.rs index abcb46d9..071819ee 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Common test utilities for cross-platform compatibility //! //! This module provides helpers for normalizing test outputs to ensure diff --git a/tests/compatibility_tests.rs b/tests/compatibility_tests.rs index 09930dee..a26a0c5e 100644 --- a/tests/compatibility_tests.rs +++ b/tests/compatibility_tests.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Compatibility tests for libmagic-rs //! //! These tests ensure that our implementation produces identical results to the original libmagic. diff --git a/tests/directory_loading_tests.rs b/tests/directory_loading_tests.rs index 2ab5ec95..57afbe7f 100644 --- a/tests/directory_loading_tests.rs +++ b/tests/directory_loading_tests.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Integration tests for directory loading functionality. //! //! These tests validate the `load_magic_directory()` function's behavior diff --git a/tests/evaluator_tests.rs b/tests/evaluator_tests.rs index bba2f187..3e2e2fbb 100644 --- a/tests/evaluator_tests.rs +++ b/tests/evaluator_tests.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Evaluator integration tests //! //! Tests for confidence calculation, rule ordering, and evaluation behavior diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index dd08776b..b318a08a 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! End-to-end integration tests for core flows //! //! Tests the complete workflow: load database, evaluate files/buffers, diff --git a/tests/json_integration_test.rs b/tests/json_integration_test.rs index 2f7d30fc..958a9f6a 100644 --- a/tests/json_integration_test.rs +++ b/tests/json_integration_test.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Integration tests for JSON output functionality //! //! These tests verify that the CLI correctly integrates the JSON output formatter diff --git a/tests/mime_tests.rs b/tests/mime_tests.rs index c917be04..160aaab9 100644 --- a/tests/mime_tests.rs +++ b/tests/mime_tests.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! MIME type mapping integration tests //! //! Tests for MIME type detection through the public API, diff --git a/tests/parser_integration_tests.rs b/tests/parser_integration_tests.rs index caef3686..4bf81f6f 100644 --- a/tests/parser_integration_tests.rs +++ b/tests/parser_integration_tests.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! End-to-end integration tests for magic file parser and database integration. //! //! These tests validate the complete flow from file/directory loading through diff --git a/tests/property_tests.rs b/tests/property_tests.rs index 4e486844..1c0e9819 100644 --- a/tests/property_tests.rs +++ b/tests/property_tests.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Property-based tests for libmagic-rs //! //! Uses proptest to verify properties that should hold for all valid inputs: diff --git a/tests/tags_tests.rs b/tests/tags_tests.rs index 83c7ce51..05e0ac49 100644 --- a/tests/tags_tests.rs +++ b/tests/tags_tests.rs @@ -1,3 +1,6 @@ +// Copyright (c) 2025-2026 the libmagic-rs contributors +// SPDX-License-Identifier: Apache-2.0 + //! Tag extraction integration tests //! //! Tests for keyword extraction, case insensitivity, rule path tags, From 62619a02391cff24a56326b905790c1c843bdea1 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 23:19:53 -0500 Subject: [PATCH 14/29] docs: add quick reference and OSSF quality standards to CLAUDE.md Document operational gotchas (release.yml is cargo-dist managed, lock files committed, mise/just patterns) and OSSF Best Practices standards for PRs, releases, security, and documentation. Signed-off-by: UncleSp1d3r --- CLAUDE.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 43c994c2..53e59841 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1 +1,37 @@ @AGENTS.md + +## Quick Reference + +- `.github/workflows/release.yml` is auto-generated by cargo-dist -- do not modify manually +- All `.rs` files must have copyright and SPDX headers (see any source file for format) +- `Cargo.lock` and `mise.lock` are committed for reproducible builds -- do not gitignore +- In justfile recipes, never wrap `just` in `{{ mise_exec }}` -- it's redundant +- Changelog: `just changelog`, `just changelog-version `, `just changelog-unreleased` +- Security contact: support@evilbitlabs.io (matches PGP key in SECURITY.md) + +## Open Source Quality Standards (OSSF Best Practices) + +This project targets the OSSF Best Practices silver badge. Maintain these standards: + +### Every PR must: +- Pass CI (clippy, fmt, tests, CodeQL, cargo audit) before merge +- Include tests for new functionality -- this is policy, not optional +- Be reviewed (human or CodeRabbit) for correctness, safety, and style +- Not introduce `unsafe` code, `unwrap()`/`expect()` in library code, or panics + +### Every release must: +- Have human-readable release notes via git-cliff (not raw git log) +- Use unique SemVer identifiers (`vX.Y.Z` tags) +- Be built reproducibly (pinned toolchain, committed lock files, cargo-dist) + +### Security: +- Vulnerabilities go through private reporting (GitHub advisories or support@evilbitlabs.io), never public issues +- `cargo audit` and `cargo deny` run daily in CI -- fix findings promptly +- Medium+ severity vulnerabilities must be fixed within 60 days of public disclosure +- `#![forbid(unsafe_code)]` is enforced project-wide -- this is a hardening mechanism, not a suggestion + +### Documentation: +- Public APIs require rustdoc with examples +- CONTRIBUTING.md documents code review criteria and test policy +- SECURITY.md documents vulnerability reporting with scope, safe harbor, and PGP key +- AGENTS.md must accurately reflect implemented features (not aspirational) From 329e9122750af580b5c0cece818b5b755c3d9e1c Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 23:31:23 -0500 Subject: [PATCH 15/29] docs: add DCO requirement to CONTRIBUTING.md Document Developer Certificate of Origin sign-off requirement, enforced by the DCO GitHub App. Add signed-off-by to PR checklist. Complements Apache-2.0 Section 5 contributor licensing. Signed-off-by: UncleSp1d3r --- CONTRIBUTING.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4fd948c9..fd81a2f9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -251,6 +251,24 @@ All pull requests require review before merging. Reviewers check for: CI must pass before merge. This includes formatting, linting, tests, security audit, and CodeQL analysis. Branch protection enforces these checks on the `main` branch. +### Developer Certificate of Origin (DCO) + +This project requires all contributors to sign off on their commits, certifying that they have the right to submit the code under the project's license. This is enforced by the [DCO GitHub App](https://github.com/apps/dco). + +To sign off, add `-s` to your commit command: + +```bash +git commit -s -m "feat: add new feature" +``` + +This adds a `Signed-off-by` line to your commit message: + +```text +Signed-off-by: Your Name +``` + +By signing off, you agree to the [Developer Certificate of Origin](https://developercertificate.org/). + ### PR Description Template ```markdown @@ -269,6 +287,7 @@ How were these changes tested? - [ ] No clippy warnings (`cargo clippy`) - [ ] Code formatted (`cargo fmt`) - [ ] Documentation updated +- [ ] Commits signed off (`git commit -s`) ``` ## Style Guidelines From e5f8447451e77bde6bb85bcc05ff23bb8a9b50b4 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sat, 14 Feb 2026 23:41:22 -0500 Subject: [PATCH 16/29] docs: add project governance model and update development guide Add governance section to CONTRIBUTING.md defining maintainer-driven decision-making, roles, and path to maintainership. Update mdbook development guide with DCO sign-off step and link to CONTRIBUTING.md. Signed-off-by: UncleSp1d3r --- CONTRIBUTING.md | 26 ++++++++++++++++++++++++++ docs/src/development.md | 7 +++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fd81a2f9..cf4a3fc3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,6 +13,7 @@ Thank you for your interest in contributing to libmagic-rs! This document provid - [Documentation](#documentation) - [Submitting Changes](#submitting-changes) - [Style Guidelines](#style-guidelines) +- [Project Governance](#project-governance) ## Code of Conduct @@ -333,6 +334,31 @@ pub enum ParseError { } ``` +## Project Governance + +### Decision-Making + +libmagic-rs uses a **maintainer-driven** governance model. Decisions are made by the project maintainers through consensus on GitHub issues and pull requests. + +### Roles + +| Role | Responsibilities | Current | +|------|-----------------|---------| +| **Maintainer** | Merge PRs, manage releases, set project direction, review security reports | [@unclesp1d3r](https://github.com/unclesp1d3r), [@kmelton](https://github.com/kmelton) | +| **Contributor** | Submit issues, PRs, and participate in discussions | Anyone following this guide | + +### How Decisions Are Made + +- **Bug fixes and minor changes**: Any maintainer can review and merge +- **New features**: Discussed in a GitHub issue before implementation; maintainer approval required +- **Architecture changes**: Require agreement from both maintainers +- **Breaking API changes**: Discussed in a GitHub issue with community input; require agreement from both maintainers +- **Releases**: Prepared by any maintainer, following the [release process](docs/src/release-process.md) + +### Becoming a Maintainer + +As the project grows, active contributors who demonstrate sustained, high-quality contributions and alignment with project goals may be invited to become maintainers. + ## Getting Help - **Issues**: For bug reports and feature requests diff --git a/docs/src/development.md b/docs/src/development.md index ccd17c37..beffe543 100644 --- a/docs/src/development.md +++ b/docs/src/development.md @@ -401,8 +401,11 @@ git commit -m "test(ast): add comprehensive serialization tests" - Reference to related issues - Test coverage information - Breaking change notes (if any) -3. **Address feedback** from code review -4. **Ensure CI passes** all checks +3. **Sign off commits** with `git commit -s` (DCO required) +4. **Address feedback** from code review +5. **Ensure CI passes** all checks + +For full details on code review criteria, DCO requirements, and project governance, see [CONTRIBUTING.md](https://github.com/EvilBit-Labs/libmagic-rs/blob/main/CONTRIBUTING.md). ## Debugging From ac43becf7565259fdcd305c029b297a5bf1f4d5c Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sun, 15 Feb 2026 00:09:37 -0500 Subject: [PATCH 17/29] docs: update roadmap to match milestones and add non-goals Align README roadmap with GitHub milestones (v0.1.0 through v1.0.0), link issues for each planned feature, mark completed MVP items, and add Non-Goals section (required for OSSF Best Practices badge). Signed-off-by: UncleSp1d3r --- README.md | 67 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index f2f7c13c..65e5ddd8 100644 --- a/README.md +++ b/README.md @@ -414,56 +414,63 @@ This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENS ## Roadmap -### Phase 1: MVP (v0.1) - Current Focus +See [GitHub Milestones](https://github.com/EvilBit-Labs/libmagic-rs/milestones) for detailed issue tracking. -**Core Infrastructure (Complete):** +### v0.1.0 - MVP (Current) - [x] Core AST data structures with comprehensive serialization - [x] Magic file parser for text format with hierarchical rules - [x] Rule evaluation engine with confidence scoring - [x] Memory-mapped file I/O with FileBuffer - [x] Text and JSON output formatters -- [x] CLI with `--json` and `--magic-file` flags -- [x] Comprehensive error handling +- [x] CLI with multiple file support, stdin, `--json`, and `--magic-file` +- [x] Built-in fallback rules with build-time compilation +- [x] Strength calculation and `!:strength` parsing +- [x] Comprehensive error handling, rustdoc, and mdbook documentation +- [x] 94%+ test coverage across 1,058+ tests -**In Progress:** +### v0.2.0 - Core Primitives -- [ ] Multiple file support in CLI -- [ ] Stdin input support (`rmagic -`) -- [ ] Built-in fallback rules (`--use-builtin`) -- [ ] Magdir directory loading (load all files from `/usr/share/file/magic/Magdir/`) -- [ ] Strength calculation (libmagic's `!:strength` parsing) -- [ ] Complete rustdoc and mdbook documentation +- [ ] Comparison operators: `>`, `<`, `>=`, `<=` ([#34](https://github.com/EvilBit-Labs/libmagic-rs/issues/34)) +- [ ] Bitwise XOR, NOT, and any-value operators ([#35](https://github.com/EvilBit-Labs/libmagic-rs/issues/35)) +- [ ] Indirect offset resolution ([#37](https://github.com/EvilBit-Labs/libmagic-rs/issues/37)) +- [ ] Relative offset resolution ([#38](https://github.com/EvilBit-Labs/libmagic-rs/issues/38)) +- [ ] Quad (64-bit integer) type ([#36](https://github.com/EvilBit-Labs/libmagic-rs/issues/36)) -**Success Criteria:** +### v0.3.0 - Advanced Features -- 95%+ compatibility with GNU `file` for common types (ELF, PE, ZIP, JPEG, PNG, PDF) -- >85% test coverage +- [ ] Regex and search types ([#39](https://github.com/EvilBit-Labs/libmagic-rs/issues/39)) +- [ ] Float and double types ([#40](https://github.com/EvilBit-Labs/libmagic-rs/issues/40)) +- [ ] Date and timestamp types ([#41](https://github.com/EvilBit-Labs/libmagic-rs/issues/41)) +- [ ] Pascal string type ([#43](https://github.com/EvilBit-Labs/libmagic-rs/issues/43)) +- [ ] Meta-types: default, clear, name, use, indirect ([#42](https://github.com/EvilBit-Labs/libmagic-rs/issues/42)) -### Phase 2: Enhanced Features (v0.2) +### v0.4.0 - API and UX Polish -- [ ] Binary `.mgc` format support (deferred per OpenBSD approach) -- [ ] Indirect offset resolution -- [ ] Regex support with binary-safe matching -- [ ] Compiled rule caching for faster startup -- [ ] Additional operators and type support -- [ ] Aho-Corasick string indexing +- [ ] Builder pattern for `MagicDatabase` ([#45](https://github.com/EvilBit-Labs/libmagic-rs/issues/45)) +- [ ] JSON output metadata ([#46](https://github.com/EvilBit-Labs/libmagic-rs/issues/46)) +- [ ] Parse warnings for skipped rules ([#47](https://github.com/EvilBit-Labs/libmagic-rs/issues/47)) +- [ ] Improved error messages ([#49](https://github.com/EvilBit-Labs/libmagic-rs/issues/49)) +- [ ] Partial results on timeout ([#44](https://github.com/EvilBit-Labs/libmagic-rs/issues/44)) -### Phase 3: Performance & Compatibility (v0.3) - -- [ ] Performance optimizations and benchmarking -- [ ] Full libmagic syntax compatibility -- [ ] PE/Mach-O/ELF format-specific detection -- [ ] Go build info extraction - -### Phase 4: Production Ready (v1.0) +### v1.0.0 - Production Ready +- [ ] 95%+ compatibility with GNU `file` ([#48](https://github.com/EvilBit-Labs/libmagic-rs/issues/48), [#57](https://github.com/EvilBit-Labs/libmagic-rs/issues/57)) - [ ] Stable API with semver guarantees - [ ] Migration guide from C libmagic - [ ] Performance parity validation -- [ ] Fuzzing and security testing - [ ] crates.io publication +### Non-Goals + +The following are explicitly out of scope for this project: + +- **Binary `.mgc` compilation**: We follow the OpenBSD approach of using text magic files directly, not the compiled binary format +- **Drop-in C ABI replacement**: This is a Rust-native library, not a C-compatible shared library with `libmagic.so` ABI +- **MIME database management**: We detect file types via magic rules, not by maintaining a MIME type registry +- **File modification or conversion**: This is a read-only detection tool +- **Network protocol detection**: We identify file contents, not network traffic + ## Support - **Documentation**: [Project Documentation](docs/) From 217e02d21644b7e89db1e358b8ce01c6b193ecc9 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sun, 15 Feb 2026 00:32:34 -0500 Subject: [PATCH 18/29] docs: add release verification guide for signed artifacts Add brief verification instructions to README Security section and a detailed release-verification.md to mdbook covering Sigstore keyless signing, GitHub Attestations, SBOM, and cargo-auditable. Required for OSSF signed_releases criterion. Signed-off-by: UncleSp1d3r --- README.md | 10 +++++ docs/src/SUMMARY.md | 1 + docs/src/release-verification.md | 69 ++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 docs/src/release-verification.md diff --git a/README.md b/README.md index 65e5ddd8..5a6f9df3 100644 --- a/README.md +++ b/README.md @@ -389,6 +389,16 @@ The library provides a migration path from C-based libmagic: - **Safe File Handling**: Graceful handling of truncated/corrupted files - **Fuzzing Integration**: Robustness testing with malformed inputs +### Verifying Releases + +All release artifacts are cryptographically signed via [Sigstore](https://www.sigstore.dev/) using GitHub Attestations. To verify a downloaded artifact: + +```bash +gh attestation verify --repo EvilBit-Labs/libmagic-rs +``` + +See the [release verification guide](https://evilbitlabs.io/libmagic-rs/release-verification.html) for details. + ## Contributing 1. Fork the repository diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 4eb2c71f..6e994a6b 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -46,6 +46,7 @@ - [Chapter 18: Code Style & Standards](./code-style.md) - [Chapter 19: Testing Guidelines](./testing-guidelines.md) - [Chapter 20: Release Process](./release-process.md) +- [Chapter 21: Release Verification](./release-verification.md) --- diff --git a/docs/src/release-verification.md b/docs/src/release-verification.md new file mode 100644 index 00000000..cec6d583 --- /dev/null +++ b/docs/src/release-verification.md @@ -0,0 +1,69 @@ +# Release Verification + +All libmagic-rs release artifacts are cryptographically signed to ensure authenticity and integrity. This guide explains how to verify that a downloaded artifact is genuine. + +## How Releases Are Signed + +libmagic-rs uses [Sigstore](https://www.sigstore.dev/) keyless signing via GitHub Attestations. During the release build: + +1. `cargo-dist` builds release artifacts in GitHub Actions +2. `actions/attest-build-provenance` generates a signed [SLSA provenance](https://slsa.dev/) attestation for each artifact +3. The attestation is stored in GitHub's attestation ledger and Sigstore's transparency log + +**Keyless signing** means there are no long-lived private keys to manage or compromise. Each build receives an ephemeral signing certificate tied to the GitHub Actions workflow identity. + +## Verifying with GitHub CLI + +The simplest way to verify an artifact: + +```bash +# Install GitHub CLI if you haven't already +# https://cli.github.com/ + +# Download a release artifact +gh release download v0.1.0 --repo EvilBit-Labs/libmagic-rs + +# Verify the artifact +gh attestation verify rmagic-x86_64-unknown-linux-gnu.tar.xz \ + --repo EvilBit-Labs/libmagic-rs +``` + +A successful verification looks like: + +```text +Loaded digest sha256:abc123... for file rmagic-x86_64-unknown-linux-gnu.tar.xz +Loaded 1 attestation from GitHub API + +The following attestation matched the digest: + - Predicate type: https://slsa.dev/provenance/v1 + - Signer: https://github.com/EvilBit-Labs/libmagic-rs/.github/workflows/release.yml + - Build trigger: push +``` + +## What Verification Proves + +A successful verification confirms: + +- **Authenticity**: The artifact was built by the official GitHub Actions workflow in the `EvilBit-Labs/libmagic-rs` repository +- **Integrity**: The artifact has not been modified since it was built +- **Provenance**: The build was triggered by a specific commit and tag + +## Additional Integrity Checks + +### SBOM (Software Bill of Materials) + +Each release includes a CycloneDX SBOM generated by `cargo-cyclonedx`, listing all dependencies and their versions. + +### Embedded Dependency Metadata + +Release binaries are built with `cargo-auditable`, which embeds dependency information directly into the binary. You can inspect it with: + +```bash +cargo audit bin rmagic +``` + +This allows post-deployment vulnerability scanning against the RustSec Advisory Database. + +## Homebrew + +Homebrew formula installations from the `EvilBit-Labs/homebrew-tap` tap are verified through Homebrew's standard SHA256 checksum mechanism, which is populated from the GitHub Release artifacts. From 70b6ad5cab54600383fa0da5b589f09c0b807279 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sun, 15 Feb 2026 00:40:01 -0500 Subject: [PATCH 19/29] docs: add security assurance case for OSSF gold criteria Add formal security assurance case covering threat model, trust boundaries, Saltzer/Schroeder secure design principles, CWE/SANS Top 25 countermeasures, OWASP Top 10 applicability, and supply chain security measures. Signed-off-by: UncleSp1d3r --- docs/src/SUMMARY.md | 1 + docs/src/security-assurance.md | 146 +++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 docs/src/security-assurance.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 6e994a6b..ebdaafaa 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -56,3 +56,4 @@ - [Appendix B: Command Reference](./cli-reference.md) - [Appendix C: Magic File Examples](./magic-examples.md) - [Appendix D: Compatibility Matrix](./compatibility.md) +- [Appendix E: Security Assurance Case](./security-assurance.md) diff --git a/docs/src/security-assurance.md b/docs/src/security-assurance.md new file mode 100644 index 00000000..ad1eba90 --- /dev/null +++ b/docs/src/security-assurance.md @@ -0,0 +1,146 @@ +# Security Assurance Case + +This document provides a structured argument that libmagic-rs meets its security requirements. It follows the assurance case model described in [NIST IR 7608](https://csrc.nist.gov/publications/detail/nistir/7608/final). + +## 1. Security Requirements + +libmagic-rs is a file type detection library and CLI tool. Its security requirements are: + +1. **SR-1**: Must not crash, panic, or exhibit undefined behavior when processing any input file +2. **SR-2**: Must not crash, panic, or exhibit undefined behavior when parsing any magic file +3. **SR-3**: Must not read beyond allocated buffer boundaries +4. **SR-4**: Must not allow path traversal via CLI arguments +5. **SR-5**: Must not execute arbitrary code based on file contents or magic rule definitions +6. **SR-6**: Must not consume unbounded resources (memory, CPU) during evaluation +7. **SR-7**: Must not leak sensitive information from one file evaluation to another + +## 2. Threat Model + +### 2.1 Assets + +- **Host system**: The machine running libmagic-rs +- **File contents**: Data being inspected (may be sensitive) +- **Magic rules**: Definitions that drive file type detection + +### 2.2 Threat Actors + +| Actor | Motivation | Capability | +|-------|-----------|------------| +| Malicious file author | Exploit the detection tool to gain code execution or cause DoS | Can craft arbitrary file contents | +| Malicious magic file author | Inject rules that cause crashes, resource exhaustion, or incorrect results | Can craft arbitrary magic rule syntax | +| Supply chain attacker | Compromise a dependency to inject malicious code | Can publish malicious crate versions | + +### 2.3 Attack Vectors + +| ID | Vector | Target SR | +|----|--------|-----------| +| AV-1 | Crafted file triggers buffer over-read | SR-1, SR-3 | +| AV-2 | Crafted file triggers integer overflow in offset calculation | SR-1, SR-3 | +| AV-3 | Deeply nested magic rules cause stack overflow | SR-1, SR-6 | +| AV-4 | Extremely large file causes memory exhaustion | SR-6 | +| AV-5 | Malformed magic file causes parser crash | SR-2 | +| AV-6 | CLI argument with path traversal reads unintended files | SR-4 | +| AV-7 | Compromised dependency introduces unsafe code | SR-5 | + +## 3. Trust Boundaries + +```text ++------------------------------------------------------------------+ +| Untrusted | +| +------------------+ +-------------------+ | +| | Input Files | | Magic Files | | +| | (any content) | | (user or system) | | +| +--------+---------+ +--------+----------+ | +| | | | ++-----------+-----------------------+-------------------------------+ + | | + =========|=======================|============ Trust Boundary ==== + | | ++-----------v-----------------------v-------------------------------+ +| libmagic-rs | +| | +| +----------------+ +----------------+ +--------------+ | +| | Parser | | Evaluator | | Output | | +| | - validates | | - bounds-check | | - formats | | +| | magic syntax | | all access | | results | | +| +----------------+ +----------------+ +--------------+ | +| | +| +----------------+ +----------------+ | +| | I/O Layer | | CLI | | +| | - mmap files | | - clap args | | +| | - size limits | | - validates | | +| +----------------+ +----------------+ | ++------------------------------------------------------------------+ +``` + +All data crossing the trust boundary (file contents, magic file syntax, CLI arguments) is treated as untrusted and validated before use. + +## 4. Secure Design Principles (Saltzer and Schroeder) + +| Principle | How Applied | +|-----------|-------------| +| **Economy of mechanism** | Pure Rust with minimal dependencies. Simple parser-evaluator pipeline. No plugin system, no scripting, no network I/O. | +| **Fail-safe defaults** | `#![forbid(unsafe_code)]` enforced project-wide. Buffer access defaults to bounds-checked `.get()` returning `None` rather than panicking. Invalid magic rules are skipped, not executed. | +| **Complete mediation** | Every buffer access is bounds-checked. Every magic file is validated during parsing. Every CLI argument is validated by `clap`. | +| **Open design** | Fully open source (Apache-2.0). Security does not depend on obscurity. All security mechanisms are publicly documented. | +| **Separation of privilege** | Parser and evaluator are separate modules with distinct responsibilities. Parse errors cannot bypass evaluation safety checks. | +| **Least privilege** | The tool only reads files; it never writes, executes, or modifies them. No network access. No elevated permissions required. | +| **Least common mechanism** | No shared mutable state between file evaluations. Each evaluation operates on its own data. No global caches that could leak information. | +| **Psychological acceptability** | CLI follows GNU `file` conventions. Error messages are descriptive and actionable. Default behavior is safe (built-in rules, no network). | + +## 5. Common Weakness Countermeasures + +### 5.1 CWE/SANS Top 25 + +| CWE | Weakness | Countermeasure | Status | +|-----|----------|---------------|--------| +| CWE-787 | Out-of-bounds write | Rust ownership prevents writes to unowned memory. `#![forbid(unsafe_code)]` eliminates raw pointer writes. | Mitigated | +| CWE-79 | XSS | Not applicable (no web output). | N/A | +| CWE-89 | SQL injection | Not applicable (no database). | N/A | +| CWE-416 | Use after free | Rust ownership/borrowing system prevents use-after-free at compile time. | Mitigated | +| CWE-78 | OS command injection | No shell invocation or command execution. CLI arguments parsed by `clap`, not passed to shell. | Mitigated | +| CWE-20 | Improper input validation | All inputs validated: magic syntax validated by parser, file buffers bounds-checked, CLI args validated by `clap`. | Mitigated | +| CWE-125 | Out-of-bounds read | All buffer access uses `.get()` with bounds checking. Memory-mapped files have known size limits. | Mitigated | +| CWE-22 | Path traversal | CLI accepts file paths as arguments but only performs read-only access. No path construction from file contents. | Mitigated | +| CWE-352 | CSRF | Not applicable (no web interface). | N/A | +| CWE-434 | Unrestricted upload | Not applicable (no file upload). | N/A | +| CWE-476 | NULL pointer dereference | Rust's `Option` type eliminates null pointer dereferences at compile time. | Mitigated | +| CWE-190 | Integer overflow | Rust panics on integer overflow in debug builds. Offset calculations use checked arithmetic. | Mitigated | +| CWE-502 | Deserialization of untrusted data | Magic files are parsed with a strict grammar, not deserialized from arbitrary formats. | Mitigated | +| CWE-400 | Resource exhaustion | Evaluation timeouts prevent unbounded CPU use. Memory-mapped I/O avoids loading entire files into memory. | Mitigated | + +### 5.2 OWASP Top 10 (where applicable) + +Most OWASP Top 10 categories target web applications and are not applicable to a file detection library. The applicable items are: + +| Category | Applicability | Countermeasure | +|----------|--------------|---------------| +| A03: Injection | Partial -- magic file parsing | Strict grammar-based parser rejects invalid syntax | +| A04: Insecure Design | Applicable | Secure design principles applied throughout (see Section 4) | +| A06: Vulnerable Components | Applicable | `cargo audit` daily, `cargo deny`, Dependabot, `cargo-auditable` | +| A09: Security Logging | Partial | Evaluation errors logged; security events reported via GitHub Advisories | + +## 6. Supply Chain Security + +| Measure | Implementation | +|---------|---------------| +| Dependency auditing | `cargo audit` and `cargo deny` run daily in CI | +| Dependency updates | Dependabot configured for automated PRs | +| Pinned toolchain | Rust 1.91.0 via `rust-toolchain.toml` | +| Reproducible builds | `Cargo.lock` and `mise.lock` committed | +| Build provenance | Sigstore attestations via `actions/attest-build-provenance` | +| SBOM generation | `cargo-cyclonedx` produces CycloneDX SBOM per release | +| Binary auditing | `cargo-auditable` embeds dependency metadata in binaries | +| CI integrity | All GitHub Actions pinned to SHA hashes | +| Code review | Required on all PRs; automated by CodeRabbit with security-focused checks | + +## 7. Ongoing Assurance + +This assurance case is maintained as a living document. It is updated when: + +- New features introduce new attack surfaces +- New threat vectors are identified +- Dependencies change significantly +- Security incidents occur + +The project maintains continuous assurance through automated CI checks (clippy, CodeQL, cargo audit, cargo deny) that run on every commit. From 6c4af632816a3fd73eaae3d7ae23fdd20e5234fe Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sun, 15 Feb 2026 00:42:58 -0500 Subject: [PATCH 20/29] docs(readme): add OpenSSF Best Practices badge Signed-off-by: UncleSp1d3r --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5a6f9df3..a24fbd90 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # libmagic-rs +[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/11947/badge)](https://www.bestpractices.dev/projects/11947) [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/EvilBit-Labs/libmagic-rs/badge)](https://scorecard.dev/viewer/?uri=github.com/EvilBit-Labs/libmagic-rs) [![Crates.io](https://img.shields.io/crates/v/libmagic-rs)](https://crates.io/crates/libmagic-rs) [![License](https://img.shields.io/crates/l/libmagic-rs)](https://github.com/EvilBit-Labs/libmagic-rs/blob/main/LICENSE) From 0840a8832b6c0dedcc09ffe7a8766d2ecb743a4b Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sun, 15 Feb 2026 00:46:56 -0500 Subject: [PATCH 21/29] docs: move OSSF standards from CLAUDE.md to AGENTS.md CLAUDE.md should only contain @AGENTS.md reference. Move Quick Reference and OSSF Best Practices sections to AGENTS.md. Add DCO sign-off requirement and security assurance doc references. Signed-off-by: UncleSp1d3r --- AGENTS.md | 39 +++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 36 ------------------------------------ 2 files changed, 39 insertions(+), 36 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index df74d8ba..5812301b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -506,3 +506,42 @@ CI must pass before merge. Branch protection enforces these checks on the `main` - Profile with `cargo bench` for performance analysis This guide ensures consistent, high-quality development practices for the libmagic-rs project while maintaining focus on memory safety, performance, and compatibility. + +## Quick Reference + +- `.github/workflows/release.yml` is auto-generated by cargo-dist -- do not modify manually +- All `.rs` files must have copyright and SPDX headers (see any source file for format) +- `Cargo.lock` and `mise.lock` are committed for reproducible builds -- do not gitignore +- In justfile recipes, never wrap `just` in `{{ mise_exec }}` -- it's redundant +- Changelog: `just changelog`, `just changelog-version `, `just changelog-unreleased` +- Security contact: support@evilbitlabs.io (matches PGP key in SECURITY.md) + +## Open Source Quality Standards (OSSF Best Practices) + +This project has the OSSF Best Practices passing badge. Maintain these standards: + +### Every PR must: +- Sign off commits with `git commit -s` (DCO enforced by GitHub App) +- Pass CI (clippy, fmt, tests, CodeQL, cargo audit) before merge +- Include tests for new functionality -- this is policy, not optional +- Be reviewed (human or CodeRabbit) for correctness, safety, and style +- Not introduce `unsafe` code, `unwrap()`/`expect()` in library code, or panics + +### Every release must: +- Have human-readable release notes via git-cliff (not raw git log) +- Use unique SemVer identifiers (`vX.Y.Z` tags) +- Be built reproducibly (pinned toolchain, committed lock files, cargo-dist) + +### Security: +- Vulnerabilities go through private reporting (GitHub advisories or support@evilbitlabs.io), never public issues +- `cargo audit` and `cargo deny` run daily in CI -- fix findings promptly +- Medium+ severity vulnerabilities must be fixed within 60 days of public disclosure +- `#![forbid(unsafe_code)]` is enforced project-wide -- this is a hardening mechanism, not a suggestion +- `docs/src/security-assurance.md` must be updated when new attack surface is introduced + +### Documentation: +- Public APIs require rustdoc with examples +- CONTRIBUTING.md documents code review criteria, test policy, DCO, and governance +- SECURITY.md documents vulnerability reporting with scope, safe harbor, and PGP key +- AGENTS.md must accurately reflect implemented features (not aspirational) +- `docs/src/release-verification.md` documents artifact signing for users diff --git a/CLAUDE.md b/CLAUDE.md index 53e59841..43c994c2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,37 +1 @@ @AGENTS.md - -## Quick Reference - -- `.github/workflows/release.yml` is auto-generated by cargo-dist -- do not modify manually -- All `.rs` files must have copyright and SPDX headers (see any source file for format) -- `Cargo.lock` and `mise.lock` are committed for reproducible builds -- do not gitignore -- In justfile recipes, never wrap `just` in `{{ mise_exec }}` -- it's redundant -- Changelog: `just changelog`, `just changelog-version `, `just changelog-unreleased` -- Security contact: support@evilbitlabs.io (matches PGP key in SECURITY.md) - -## Open Source Quality Standards (OSSF Best Practices) - -This project targets the OSSF Best Practices silver badge. Maintain these standards: - -### Every PR must: -- Pass CI (clippy, fmt, tests, CodeQL, cargo audit) before merge -- Include tests for new functionality -- this is policy, not optional -- Be reviewed (human or CodeRabbit) for correctness, safety, and style -- Not introduce `unsafe` code, `unwrap()`/`expect()` in library code, or panics - -### Every release must: -- Have human-readable release notes via git-cliff (not raw git log) -- Use unique SemVer identifiers (`vX.Y.Z` tags) -- Be built reproducibly (pinned toolchain, committed lock files, cargo-dist) - -### Security: -- Vulnerabilities go through private reporting (GitHub advisories or support@evilbitlabs.io), never public issues -- `cargo audit` and `cargo deny` run daily in CI -- fix findings promptly -- Medium+ severity vulnerabilities must be fixed within 60 days of public disclosure -- `#![forbid(unsafe_code)]` is enforced project-wide -- this is a hardening mechanism, not a suggestion - -### Documentation: -- Public APIs require rustdoc with examples -- CONTRIBUTING.md documents code review criteria and test policy -- SECURITY.md documents vulnerability reporting with scope, safe harbor, and PGP key -- AGENTS.md must accurately reflect implemented features (not aspirational) From f9068bd2c29761113434438160cb966561090053 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sun, 15 Feb 2026 00:59:21 -0500 Subject: [PATCH 22/29] docs: extract roadmap into ROADMAP.md to keep README concise Move detailed milestone items and linked issues (#34-#63) into a dedicated ROADMAP.md file. Replace the verbose roadmap section in README.md with a compact summary table linking to the full roadmap and GitHub Milestones. Signed-off-by: UncleSp1d3r --- README.md | 65 ++++++++---------------------------------------------- ROADMAP.md | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 56 deletions(-) create mode 100644 ROADMAP.md diff --git a/README.md b/README.md index a24fbd90..1b0e5135 100644 --- a/README.md +++ b/README.md @@ -425,62 +425,15 @@ This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENS ## Roadmap -See [GitHub Milestones](https://github.com/EvilBit-Labs/libmagic-rs/milestones) for detailed issue tracking. - -### v0.1.0 - MVP (Current) - -- [x] Core AST data structures with comprehensive serialization -- [x] Magic file parser for text format with hierarchical rules -- [x] Rule evaluation engine with confidence scoring -- [x] Memory-mapped file I/O with FileBuffer -- [x] Text and JSON output formatters -- [x] CLI with multiple file support, stdin, `--json`, and `--magic-file` -- [x] Built-in fallback rules with build-time compilation -- [x] Strength calculation and `!:strength` parsing -- [x] Comprehensive error handling, rustdoc, and mdbook documentation -- [x] 94%+ test coverage across 1,058+ tests - -### v0.2.0 - Core Primitives - -- [ ] Comparison operators: `>`, `<`, `>=`, `<=` ([#34](https://github.com/EvilBit-Labs/libmagic-rs/issues/34)) -- [ ] Bitwise XOR, NOT, and any-value operators ([#35](https://github.com/EvilBit-Labs/libmagic-rs/issues/35)) -- [ ] Indirect offset resolution ([#37](https://github.com/EvilBit-Labs/libmagic-rs/issues/37)) -- [ ] Relative offset resolution ([#38](https://github.com/EvilBit-Labs/libmagic-rs/issues/38)) -- [ ] Quad (64-bit integer) type ([#36](https://github.com/EvilBit-Labs/libmagic-rs/issues/36)) - -### v0.3.0 - Advanced Features - -- [ ] Regex and search types ([#39](https://github.com/EvilBit-Labs/libmagic-rs/issues/39)) -- [ ] Float and double types ([#40](https://github.com/EvilBit-Labs/libmagic-rs/issues/40)) -- [ ] Date and timestamp types ([#41](https://github.com/EvilBit-Labs/libmagic-rs/issues/41)) -- [ ] Pascal string type ([#43](https://github.com/EvilBit-Labs/libmagic-rs/issues/43)) -- [ ] Meta-types: default, clear, name, use, indirect ([#42](https://github.com/EvilBit-Labs/libmagic-rs/issues/42)) - -### v0.4.0 - API and UX Polish - -- [ ] Builder pattern for `MagicDatabase` ([#45](https://github.com/EvilBit-Labs/libmagic-rs/issues/45)) -- [ ] JSON output metadata ([#46](https://github.com/EvilBit-Labs/libmagic-rs/issues/46)) -- [ ] Parse warnings for skipped rules ([#47](https://github.com/EvilBit-Labs/libmagic-rs/issues/47)) -- [ ] Improved error messages ([#49](https://github.com/EvilBit-Labs/libmagic-rs/issues/49)) -- [ ] Partial results on timeout ([#44](https://github.com/EvilBit-Labs/libmagic-rs/issues/44)) - -### v1.0.0 - Production Ready - -- [ ] 95%+ compatibility with GNU `file` ([#48](https://github.com/EvilBit-Labs/libmagic-rs/issues/48), [#57](https://github.com/EvilBit-Labs/libmagic-rs/issues/57)) -- [ ] Stable API with semver guarantees -- [ ] Migration guide from C libmagic -- [ ] Performance parity validation -- [ ] crates.io publication - -### Non-Goals - -The following are explicitly out of scope for this project: - -- **Binary `.mgc` compilation**: We follow the OpenBSD approach of using text magic files directly, not the compiled binary format -- **Drop-in C ABI replacement**: This is a Rust-native library, not a C-compatible shared library with `libmagic.so` ABI -- **MIME database management**: We detect file types via magic rules, not by maintaining a MIME type registry -- **File modification or conversion**: This is a read-only detection tool -- **Network protocol detection**: We identify file contents, not network traffic +See [ROADMAP.md](ROADMAP.md) for the full roadmap with linked issues, or [GitHub Milestones](https://github.com/EvilBit-Labs/libmagic-rs/milestones) for detailed issue tracking. + +| Milestone | Focus | +|-----------|-------| +| **v0.1.0** (current) | MVP: parser, evaluator, CLI, built-in rules, 94%+ test coverage | +| **v0.2.0** | Comparison operators, bitwise XOR/NOT, indirect/relative offsets, 64-bit integers | +| **v0.3.0** | Regex, float/double, date/timestamp, pascal strings, meta-types | +| **v0.4.0** | Builder API, JSON metadata, parse warnings, improved errors | +| **v1.0.0** | 95%+ GNU `file` compatibility, stable API, crates.io publication | ## Support diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 00000000..d874659e --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,63 @@ +# Roadmap + +See [GitHub Milestones](https://github.com/EvilBit-Labs/libmagic-rs/milestones) for detailed issue tracking. + +## v0.1.0 - MVP (Current) + +- [x] Core AST data structures with comprehensive serialization +- [x] Magic file parser for text format with hierarchical rules +- [x] Rule evaluation engine with confidence scoring +- [x] Memory-mapped file I/O with FileBuffer +- [x] Text and JSON output formatters +- [x] CLI with multiple file support, stdin, `--json`, and `--magic-file` +- [x] Built-in fallback rules with build-time compilation +- [x] Strength calculation and `!:strength` parsing +- [x] Comprehensive error handling, rustdoc, and mdbook documentation +- [x] 94%+ test coverage across 1,058+ tests + +## v0.2.0 - Core Primitives + +- [ ] Split evaluator module into focused submodules ([#59](https://github.com/EvilBit-Labs/libmagic-rs/issues/59)) +- [ ] Disambiguate `MatchResult` types ([#60](https://github.com/EvilBit-Labs/libmagic-rs/issues/60)) +- [ ] Extract CLI tests into integration tests ([#61](https://github.com/EvilBit-Labs/libmagic-rs/issues/61)) +- [ ] Pre-create evaluator submodules for new features ([#62](https://github.com/EvilBit-Labs/libmagic-rs/issues/62)) +- [ ] Comparison operators: `>`, `<`, `>=`, `<=` ([#34](https://github.com/EvilBit-Labs/libmagic-rs/issues/34)) +- [ ] Bitwise XOR, NOT, and any-value operators ([#35](https://github.com/EvilBit-Labs/libmagic-rs/issues/35)) +- [ ] Indirect offset resolution ([#37](https://github.com/EvilBit-Labs/libmagic-rs/issues/37)) +- [ ] Relative offset resolution ([#38](https://github.com/EvilBit-Labs/libmagic-rs/issues/38)) +- [ ] Quad (64-bit integer) type ([#36](https://github.com/EvilBit-Labs/libmagic-rs/issues/36)) + +## v0.3.0 - Advanced Features + +- [ ] Convert `evaluator/types.rs` to directory module ([#63](https://github.com/EvilBit-Labs/libmagic-rs/issues/63)) +- [ ] Regex and search types ([#39](https://github.com/EvilBit-Labs/libmagic-rs/issues/39)) +- [ ] Float and double types ([#40](https://github.com/EvilBit-Labs/libmagic-rs/issues/40)) +- [ ] Date and timestamp types ([#41](https://github.com/EvilBit-Labs/libmagic-rs/issues/41)) +- [ ] Pascal string type ([#43](https://github.com/EvilBit-Labs/libmagic-rs/issues/43)) +- [ ] Meta-types: default, clear, name, use, indirect ([#42](https://github.com/EvilBit-Labs/libmagic-rs/issues/42)) + +## v0.4.0 - API and UX Polish + +- [ ] Builder pattern for `MagicDatabase` ([#45](https://github.com/EvilBit-Labs/libmagic-rs/issues/45)) +- [ ] JSON output metadata ([#46](https://github.com/EvilBit-Labs/libmagic-rs/issues/46)) +- [ ] Parse warnings for skipped rules ([#47](https://github.com/EvilBit-Labs/libmagic-rs/issues/47)) +- [ ] Improved error messages ([#49](https://github.com/EvilBit-Labs/libmagic-rs/issues/49)) +- [ ] Partial results on timeout ([#44](https://github.com/EvilBit-Labs/libmagic-rs/issues/44)) + +## v1.0.0 - Production Ready + +- [ ] 95%+ compatibility with GNU `file` ([#48](https://github.com/EvilBit-Labs/libmagic-rs/issues/48), [#57](https://github.com/EvilBit-Labs/libmagic-rs/issues/57)) +- [ ] Stable API with semver guarantees +- [ ] Migration guide from C libmagic +- [ ] Performance parity validation +- [ ] crates.io publication + +## Non-Goals + +The following are explicitly out of scope for this project: + +- **Binary `.mgc` compilation**: We follow the OpenBSD approach of using text magic files directly, not the compiled binary format +- **Drop-in C ABI replacement**: This is a Rust-native library, not a C-compatible shared library with `libmagic.so` ABI +- **MIME database management**: We detect file types via magic rules, not by maintaining a MIME type registry +- **File modification or conversion**: This is a read-only detection tool +- **Network protocol detection**: We identify file contents, not network traffic From 65cf086cb20b9f04ee824f0b50d23fe5b45f6ffa Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sun, 15 Feb 2026 01:12:49 -0500 Subject: [PATCH 23/29] docs: add project-level Claude Code skills for Rust development Add 5 optimized skills tailored for the libmagic-rs Rust codebase: - tdd-workflow: TDD with cargo test/nextest, llvm-cov, proptest - security-review: memory safety, buffer bounds, unsafe code, supply chain - verification-loop: cargo check/clippy/fmt/test/audit pipeline - strategic-compact: context management for long sessions - api-design: Rust library API patterns, builder, error design, clap CLI Signed-off-by: UncleSp1d3r --- .claude/skills/api-design/SKILL.md | 226 +++++++++++++++++++ .claude/skills/security-review/SKILL.md | 236 ++++++++++++++++++++ .claude/skills/strategic-compact/SKILL.md | 51 +++++ .claude/skills/tdd-workflow/SKILL.md | 257 ++++++++++++++++++++++ .claude/skills/verification-loop/SKILL.md | 110 +++++++++ 5 files changed, 880 insertions(+) create mode 100644 .claude/skills/api-design/SKILL.md create mode 100644 .claude/skills/security-review/SKILL.md create mode 100644 .claude/skills/strategic-compact/SKILL.md create mode 100644 .claude/skills/tdd-workflow/SKILL.md create mode 100644 .claude/skills/verification-loop/SKILL.md diff --git a/.claude/skills/api-design/SKILL.md b/.claude/skills/api-design/SKILL.md new file mode 100644 index 00000000..bc82116b --- /dev/null +++ b/.claude/skills/api-design/SKILL.md @@ -0,0 +1,226 @@ +--- +name: api-design +description: Rust library API design patterns including builder pattern, error handling, trait design, type safety, and CLI design with clap. +--- + +# API Design Patterns (Rust Library & CLI) + +## When to Activate + +- Designing or modifying public library API in `lib.rs` +- Adding new public types, traits, or functions +- Reviewing API ergonomics and consistency +- Designing CLI arguments and output formats +- Planning breaking vs non-breaking changes + +## Library API Design + +### Builder Pattern +```rust +// For types with many optional configuration fields +pub struct EvaluationConfig { + timeout: Duration, + max_rules: usize, + follow_symlinks: bool, +} + +impl EvaluationConfig { + pub fn builder() -> EvaluationConfigBuilder { + EvaluationConfigBuilder::default() + } +} + +pub struct EvaluationConfigBuilder { /* ... */ } + +impl EvaluationConfigBuilder { + pub fn timeout(mut self, timeout: Duration) -> Self { + self.timeout = Some(timeout); + self + } + + pub fn build(self) -> Result { + // Validate configuration + Ok(EvaluationConfig { /* ... */ }) + } +} +``` + +### Error Design + +#### Three-Tier Error Hierarchy +```rust +// Top-level: user-facing errors +pub enum LibmagicError { + Parse(ParseError), + Evaluation(EvaluationError), + Config(ConfigError), + Io(std::io::Error), +} + +// Module-level: specific to subsystem +pub enum ParseError { + InvalidSyntax { line: usize, reason: String }, + IoError(String), +} + +// Always implement std::error::Error + Display +impl std::fmt::Display for LibmagicError { /* ... */ } +impl std::error::Error for LibmagicError { /* ... */ } +``` + +#### Error Guidelines +- Use `thiserror` for deriving Error implementations +- Errors should be actionable (include line numbers, context) +- Never expose internal paths or system details in public errors +- Implement `From` conversions for ergonomic `?` usage + +### Type Safety + +#### Newtype Pattern +```rust +// Wrap primitives to prevent misuse +pub struct Offset(i64); +pub struct Score(u32); +pub struct Level(u32); + +// Prevents accidentally passing a score where an offset is expected +fn evaluate_at(offset: Offset, buffer: &[u8]) -> Result; +``` + +#### Enum-Based Type Discrimination +```rust +// Use enums to make invalid states unrepresentable +pub enum OffsetSpec { + Absolute(i64), + Indirect { base: i64, pointer_type: TypeKind }, + Relative(i64), + FromEnd(i64), +} +// Cannot have both Absolute and Relative -- the type system prevents it +``` + +### Public API Surface + +#### Minimize Exposure +```rust +// Only expose what users need +pub use crate::evaluator::EvaluationResult; +pub use crate::parser::MagicRule; + +// Keep internals private +pub(crate) use crate::evaluator::EvaluationContext; +``` + +#### Document Everything Public +```rust +/// Evaluate magic rules against a file buffer. +/// +/// # Arguments +/// * `rules` - Parsed magic rules to evaluate +/// * `buffer` - File contents to identify +/// +/// # Returns +/// The best matching result, or `None` if no rules match. +/// +/// # Errors +/// Returns `EvaluationError` if evaluation fails due to +/// invalid offsets or corrupted rule definitions. +/// +/// # Examples +/// ``` +/// use libmagic_rs::MagicDatabase; +/// +/// let db = MagicDatabase::default(); +/// let result = db.evaluate_buffer(&[0x7f, 0x45, 0x4c, 0x46])?; +/// ``` +pub fn evaluate_buffer(&self, buffer: &[u8]) -> Result, EvaluationError>; +``` + +### Trait Design +```rust +// Small, focused traits +pub trait SafeBufferAccess { + fn get_byte(&self, offset: usize) -> Option; + fn get_slice(&self, offset: usize, len: usize) -> Option<&[u8]>; + fn len(&self) -> usize; +} + +// Implement for multiple types +impl SafeBufferAccess for FileBuffer { /* ... */ } +impl SafeBufferAccess for &[u8] { /* ... */ } +``` + +## CLI Design (clap) + +### Argument Structure +```rust +#[derive(Parser)] +#[command(name = "rmagic", about = "Identify file types")] +struct Args { + /// Files to identify + #[arg(required = true)] + files: Vec, + + /// Output as JSON + #[arg(long)] + json: bool, + + /// Use custom magic file + #[arg(long, value_name = "FILE")] + magic_file: Option, +} +``` + +### CLI Conventions +- Follow GNU `file` command conventions where possible +- Short flags for common options (`-j` for JSON) +- Long flags for all options (`--json`) +- Positional arguments for files +- `--` to separate flags from file arguments +- Exit code 0 for success, 1 for errors + +### Output Format Consistency +- Text output: `filename: description` (matches GNU `file`) +- JSON output: structured with `filename`, `matches`, `metadata` +- Errors to stderr, results to stdout +- Quiet mode suppresses non-essential output + +## API Evolution + +### Non-Breaking Changes (patch/minor version) +- Adding new enum variants (if `#[non_exhaustive]`) +- Adding new optional fields to builders +- Adding new methods to existing types +- Loosening input constraints + +### Breaking Changes (major version) +- Removing or renaming public types/functions +- Changing function signatures +- Adding required fields to structs +- Tightening input constraints +- Changing error types + +### Defensive Techniques +```rust +// Mark enums as non-exhaustive for future extension +#[non_exhaustive] +pub enum TypeKind { + Byte, + Short { endian: Endianness, signed: bool }, + Long { endian: Endianness, signed: bool }, + String { max_length: Option }, + // Future: Quad, Float, Regex, etc. +} +``` + +## API Review Checklist + +Before exposing new public API: +- [ ] All public items have rustdoc with examples +- [ ] Error types are descriptive and actionable +- [ ] Builder pattern used for types with >3 optional fields +- [ ] Types prevent invalid states at compile time +- [ ] `#[non_exhaustive]` on enums that may grow +- [ ] Consistent naming with existing API surface +- [ ] `From`/`Into` conversions for ergonomic use +- [ ] `Display` and `Debug` implemented for all public types diff --git a/.claude/skills/security-review/SKILL.md b/.claude/skills/security-review/SKILL.md new file mode 100644 index 00000000..643beeb4 --- /dev/null +++ b/.claude/skills/security-review/SKILL.md @@ -0,0 +1,236 @@ +--- +name: security-review +description: Security review for Rust systems code. Covers memory safety, buffer handling, unsafe code, input validation, resource exhaustion, and supply chain security. +--- + +# Security Review (Rust Systems Code) + +## When to Activate + +- Adding new buffer access or offset resolution code +- Handling untrusted input (magic files, target files) +- Adding or reviewing dependencies +- Modifying parser or evaluator logic +- Before releases or PRs with security-sensitive changes + +## Security Checklist + +### 1. Memory Safety + +#### Bounds-Checked Buffer Access +```rust +// WRONG: Direct indexing can panic +let byte = buffer[offset]; + +// CORRECT: Bounds-checked access +let byte = buffer.get(offset).ok_or(MagicError::OutOfBounds)?; + +// CORRECT: Slice with bounds check +let slice = buffer.get(start..end).ok_or(MagicError::OutOfBounds)?; +``` + +#### Safe String Operations +```rust +// WRONG: Direct slicing can panic on non-UTF-8 boundaries +let rest = &input[2..]; + +// CORRECT: Use strip_prefix/strip_suffix +let rest = input.strip_prefix("0x").unwrap_or(input); +``` + +#### Verification Steps +- [ ] All buffer access uses `.get()` with bounds checking +- [ ] No direct indexing (`buffer[i]`) on untrusted data +- [ ] String operations use `strip_prefix`/`strip_suffix` instead of slicing +- [ ] No panicking operations (`.unwrap()`, `.expect()`, `panic!()`) in library code + +### 2. Unsafe Code Policy + +#### Zero Tolerance +```rust +// This is enforced project-wide +#![forbid(unsafe_code)] +``` + +#### Verification Steps +- [ ] `#![forbid(unsafe_code)]` present in `lib.rs` +- [ ] No `unsafe` blocks anywhere in project source +- [ ] Dependencies with `unsafe` are vetted (memmap2, byteorder, nom) +- [ ] `cargo audit` passes with no vulnerabilities + +### 3. Integer Safety + +#### Overflow Protection +```rust +// WRONG: Can overflow silently in release builds +let offset = base + adjustment; + +// CORRECT: Checked arithmetic +let offset = base.checked_add(adjustment) + .ok_or(MagicError::InvalidOffset { offset: format!("{} + {}", base, adjustment) })?; + +// CORRECT: Saturating for non-critical paths +let score = base_score.saturating_add(bonus); +``` + +#### Verification Steps +- [ ] Offset calculations use checked arithmetic +- [ ] No implicit integer truncation (e.g., `u64 as u32`) +- [ ] Cast operations use `TryFrom`/`try_into()` where overflow is possible +- [ ] Clippy pedantic lints catch suspicious casts + +### 4. Input Validation (Magic Files) + +#### Parser Robustness +```rust +// Magic files are untrusted input -- strict validation required +fn parse_magic_line(line: &str) -> Result { + // Validate line structure before parsing + // Return ParseError on invalid syntax, never panic + // Skip unrecognized directives gracefully +} +``` + +#### Verification Steps +- [ ] Parser returns `Err` on invalid syntax, never panics +- [ ] Deeply nested rules have depth limits +- [ ] Unrecognized directives are skipped with warnings +- [ ] Malformed offset/type/operator specifications produce clear errors +- [ ] Property tests fuzz the parser with arbitrary input + +### 5. Input Validation (Target Files) + +#### File Buffer Safety +```rust +// All file access through FileBuffer with bounds checking +let fb = FileBuffer::open(path)?; + +// Size limits prevent resource exhaustion +if fb.len() > MAX_FILE_SIZE { + return Err(MagicError::FileTooLarge); +} + +// Memory-mapped I/O avoids loading entire file +// Bounds checking on every access +let data = fb.get(offset, length)?; +``` + +#### Verification Steps +- [ ] File size limits enforced before processing +- [ ] Memory-mapped I/O used (not reading entire file into memory) +- [ ] All `FileBuffer` access is bounds-checked +- [ ] Truncated/corrupted files handled gracefully +- [ ] Zero-length files handled without errors + +### 6. Resource Exhaustion Prevention + +#### CPU Limits +```rust +// Evaluation timeout prevents infinite loops +let config = EvaluationConfig { + timeout: Duration::from_secs(5), + max_rules: 10_000, + ..Default::default() +}; +``` + +#### Memory Limits +```rust +// Limit collected results to prevent unbounded growth +const MAX_MATCHES: usize = 100; +if matches.len() >= MAX_MATCHES { + break; +} +``` + +#### Verification Steps +- [ ] Evaluation has configurable timeout +- [ ] Maximum rule evaluation count enforced +- [ ] Match results bounded +- [ ] No unbounded recursion in rule evaluation +- [ ] Stack depth limited for nested rules + +### 7. Supply Chain Security + +#### Dependency Audit +```bash +# Check for known vulnerabilities +cargo audit + +# Check license compliance +cargo deny check + +# Review dependency tree +cargo tree --depth 2 +``` + +#### Verification Steps +- [ ] `cargo audit` clean (no known vulnerabilities) +- [ ] `cargo deny` passes (license compliance) +- [ ] Minimal dependency surface +- [ ] `Cargo.lock` committed for reproducible builds +- [ ] All GitHub Actions pinned to SHA hashes +- [ ] Dependabot enabled for automated updates + +### 8. Error Information Leakage + +#### Safe Error Messages +```rust +// WRONG: Exposes internal paths or system info +Err(format!("Failed to read {}: {}", full_path, system_error)) + +// CORRECT: Actionable but not leaking +Err(MagicError::IoError(std::io::Error::new( + std::io::ErrorKind::NotFound, + "magic file not found" +))) +``` + +#### Verification Steps +- [ ] Error messages don't expose absolute file paths to end users +- [ ] System-level errors wrapped before surfacing to CLI +- [ ] Debug output gated behind `RUST_LOG` / verbose flags + +### 9. CLI Argument Safety + +#### Path Handling +```rust +// clap validates arguments before they reach application code +// No shell expansion or command injection possible +#[derive(Parser)] +struct Args { + /// File to identify + file: PathBuf, + + /// Magic file to use + #[arg(long)] + magic_file: Option, +} +``` + +#### Verification Steps +- [ ] CLI arguments parsed by `clap` (no manual parsing) +- [ ] File paths treated as opaque -- no string manipulation +- [ ] No shell invocation or command execution from user input +- [ ] Symlink handling considered for file access + +## Pre-Release Security Checklist + +- [ ] `#![forbid(unsafe_code)]` enforced +- [ ] `cargo clippy -- -D warnings` passes +- [ ] `cargo audit` clean +- [ ] `cargo deny check` passes +- [ ] All buffer access bounds-checked +- [ ] Integer arithmetic overflow-safe +- [ ] Property tests cover parser and evaluator +- [ ] Resource limits configured +- [ ] Error messages reviewed for information leakage +- [ ] Dependencies minimized and pinned +- [ ] Sigstore attestations configured for release artifacts + +## References + +- [Rust Secure Coding Guidelines](https://anssi-fr.github.io/rust-guide/) +- [RustSec Advisory Database](https://rustsec.org/) +- Project [Security Assurance Case](../../docs/src/security-assurance.md) +- Project [SECURITY.md](../../SECURITY.md) diff --git a/.claude/skills/strategic-compact/SKILL.md b/.claude/skills/strategic-compact/SKILL.md new file mode 100644 index 00000000..b98c0684 --- /dev/null +++ b/.claude/skills/strategic-compact/SKILL.md @@ -0,0 +1,51 @@ +--- +name: strategic-compact +description: Suggests manual context compaction at logical intervals to preserve context through task phases rather than arbitrary auto-compaction. +--- + +# Strategic Compact + +Suggests manual `/compact` at strategic points in your workflow rather than relying on arbitrary auto-compaction. + +## When to Activate + +- Running long sessions that approach context limits +- Working on multi-phase tasks (research, plan, implement, test) +- Switching between unrelated tasks within the same session +- After completing a major milestone and starting new work +- When responses slow down or become less coherent + +## Compaction Decision Guide + +| Phase Transition | Compact? | Why | +|-----------------|----------|-----| +| Research / Planning | Yes | Research context is bulky; plan is the distilled output | +| Planning / Implementation | Yes | Plan is in TodoWrite or a file; free up context for code | +| Implementation / Testing | Maybe | Keep if tests reference recent code; compact if switching focus | +| Debugging / Next feature | Yes | Debug traces pollute context for unrelated work | +| Mid-implementation | No | Losing variable names, file paths, and partial state is costly | +| After a failed approach | Yes | Clear the dead-end reasoning before trying a new approach | + +## What Survives Compaction + +| Persists | Lost | +|----------|------| +| CLAUDE.md / AGENTS.md instructions | Intermediate reasoning and analysis | +| TodoWrite task list | File contents you previously read | +| Memory files (`~/.claude/memory/`) | Multi-step conversation context | +| Git state (commits, branches) | Tool call history and counts | +| Files on disk | Nuanced user preferences stated verbally | + +## Best Practices + +1. **Compact after planning** -- Once plan is finalized in TodoWrite, compact to start fresh +2. **Compact after debugging** -- Clear error-resolution context before continuing +3. **Don't compact mid-implementation** -- Preserve context for related changes +4. **Write before compacting** -- Save important context to files or memory before compacting +5. **Use `/compact` with a summary** -- Add a custom message: `/compact Focus on implementing indirect offsets next` + +## Rust-Specific Considerations + +- After reading large source files (evaluator/mod.rs at 2,638 lines), compact before implementation +- After running `cargo test` with verbose output, compact if moving to different module +- After architecture review or exploration, compact before starting refactoring work diff --git a/.claude/skills/tdd-workflow/SKILL.md b/.claude/skills/tdd-workflow/SKILL.md new file mode 100644 index 00000000..46fa04c6 --- /dev/null +++ b/.claude/skills/tdd-workflow/SKILL.md @@ -0,0 +1,257 @@ +--- +name: tdd-workflow +description: Enforces test-driven development for Rust. Write tests first with cargo test/nextest, implement to pass, refactor, verify >85% coverage with cargo llvm-cov. +--- + +# Test-Driven Development Workflow (Rust) + +## When to Activate + +- Writing new features or functionality +- Fixing bugs or issues +- Refactoring existing code +- Adding new magic rule types or operators +- Extending parser, evaluator, or output modules + +## Core Principles + +### 1. Tests BEFORE Code +ALWAYS write tests first, then implement code to make tests pass. + +### 2. Coverage Requirements +- Minimum 85% coverage (project target per AGENTS.md) +- All edge cases covered +- Error scenarios tested +- Boundary conditions verified +- Doc examples verified with `cargo test --doc` + +### 3. Test Types + +#### Unit Tests +- Inline `#[cfg(test)]` modules alongside source +- Individual functions, parsers, evaluators +- Pure logic and data transformations + +#### Integration Tests +- In `tests/` directory with real magic files +- End-to-end rule parsing and evaluation +- CLI argument handling and output formatting + +#### Property Tests +- Use `proptest` for fuzzing magic rule evaluation +- Random input generation for parser robustness +- Boundary value exploration + +#### Benchmarks +- Use `criterion` for performance-critical code +- Evaluator hot paths, parser throughput +- Memory-mapped I/O performance + +## TDD Workflow Steps + +### Step 1: Define the Behavior +``` +Given [a magic rule with specific offset/type/operator], +When [evaluated against a file buffer with known contents], +Then [the evaluator should return the expected match result]. +``` + +### Step 2: Write Failing Tests +```rust +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_new_feature_basic() { + // Arrange + let rule = MagicRule { /* ... */ }; + let buffer = &[0x7f, 0x45, 0x4c, 0x46]; + + // Act + let result = evaluate_rule(&rule, buffer); + + // Assert + assert!(result.is_ok()); + assert_eq!(result.unwrap().description, "ELF"); + } + + #[test] + fn test_new_feature_edge_case() { + // Empty buffer should not panic + let rule = MagicRule { /* ... */ }; + let result = evaluate_rule(&rule, &[]); + assert!(result.is_ok()); + assert!(result.unwrap().is_none()); + } + + #[test] + fn test_new_feature_error_case() { + // Invalid offset should return error, not panic + let rule = MagicRule { offset: OffsetSpec::Absolute(-1), /* ... */ }; + let result = evaluate_rule(&rule, &[0x00]); + assert!(result.is_err()); + } +} +``` + +### Step 3: Run Tests (They Should Fail) +```bash +cargo test test_new_feature -- --nocapture +# Tests should fail -- we haven't implemented yet +``` + +### Step 4: Implement Code +Write minimal code to make tests pass. Follow project patterns: +- Use `.get()` for bounds-checked buffer access +- Return `Result` consistently +- No `unsafe`, no `.unwrap()`, no `panic!` + +### Step 5: Run Tests Again +```bash +cargo nextest run +# All tests should pass +``` + +### Step 6: Refactor +Improve code quality while keeping tests green: +- Remove duplication +- Improve naming +- Extract modules if file exceeds 500 lines +- Ensure clippy compliance + +### Step 7: Verify Coverage +```bash +cargo llvm-cov --html +# Verify 85%+ coverage achieved +# Open target/llvm-cov/html/index.html to inspect +``` + +## Testing Patterns + +### Property-Based Testing +```rust +use proptest::prelude::*; + +proptest! { + #[test] + fn parser_never_panics_on_arbitrary_input(input in ".*") { + // Parser should return Ok or Err, never panic + let _ = parse_magic_line(&input); + } + + #[test] + fn evaluator_handles_any_buffer( + buffer in prop::collection::vec(any::(), 0..1024) + ) { + let rule = create_test_rule(); + let _ = evaluate_rule(&rule, &buffer); + } +} +``` + +### Parameterized Tests +```rust +#[test] +fn test_endianness_variants() { + let cases = vec![ + (Endianness::Big, &[0x00, 0x01u8] as &[u8], 1u64), + (Endianness::Little, &[0x01, 0x00u8] as &[u8], 1u64), + ]; + + for (endian, buffer, expected) in cases { + let result = read_short(buffer, endian); + assert_eq!(result, Ok(expected), "Failed for {:?}", endian); + } +} +``` + +### Test Fixtures +```rust +fn create_elf_header() -> Vec { + vec![0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00] +} + +fn create_test_rule() -> MagicRule { + MagicRule { + offset: OffsetSpec::Absolute(0), + typ: TypeKind::String { max_length: None }, + op: Operator::Equal, + value: Value::String("ELF".to_string()), + message: "ELF file".to_string(), + children: vec![], + level: 0, + } +} +``` + +## Test Organization + +``` +src/ + parser/ + mod.rs # #[cfg(test)] mod tests { ... } + ast.rs # #[cfg(test)] mod tests { ... } + grammar.rs # #[cfg(test)] mod tests { ... } + evaluator/ + mod.rs # #[cfg(test)] mod tests { ... } + types.rs # #[cfg(test)] mod tests { ... } + operators.rs # #[cfg(test)] mod tests { ... } + io/ + mod.rs # #[cfg(test)] mod tests { ... } + output/ + mod.rs # #[cfg(test)] mod tests { ... } +tests/ + compatibility.rs # Integration tests against GNU file + integration.rs # End-to-end rule evaluation +benches/ + evaluation.rs # Performance benchmarks +``` + +## Common Testing Mistakes to Avoid + +### WRONG: Testing internal state +```rust +assert_eq!(parser.line_number, 5); // Implementation detail +``` + +### CORRECT: Test observable behavior +```rust +let rules = parse_magic_file(input)?; +assert_eq!(rules.len(), 5); +assert_eq!(rules[0].message, "ELF"); +``` + +### WRONG: Ignoring error paths +```rust +let result = evaluate_rule(&rule, buffer).unwrap(); // Will panic +``` + +### CORRECT: Test both success and error +```rust +assert!(evaluate_rule(&rule, buffer).is_ok()); +assert!(evaluate_rule(&rule, &[]).is_ok()); // Empty buffer +assert!(evaluate_rule(&bad_rule, buffer).is_err()); // Bad rule +``` + +## Quick Reference + +```bash +# Run all tests +cargo nextest run + +# Run specific module tests +cargo test parser::grammar::tests + +# Run with output visible +cargo test -- --nocapture + +# Run doc tests +cargo test --doc + +# Coverage report +cargo llvm-cov --html + +# Benchmarks +cargo bench +``` diff --git a/.claude/skills/verification-loop/SKILL.md b/.claude/skills/verification-loop/SKILL.md new file mode 100644 index 00000000..57126838 --- /dev/null +++ b/.claude/skills/verification-loop/SKILL.md @@ -0,0 +1,110 @@ +--- +name: verification-loop +description: Comprehensive verification for Rust projects. Runs cargo check, clippy, fmt, tests, coverage, and security audit in sequence. +--- + +# Verification Loop (Rust) + +## When to Use + +- After completing a feature or significant code change +- Before creating a PR +- After refactoring +- When you want to ensure all quality gates pass + +## Verification Phases + +### Phase 1: Build Verification +```bash +cargo check 2>&1 | tail -20 +``` +If build fails, STOP and fix before continuing. + +### Phase 2: Format Check +```bash +cargo fmt -- --check 2>&1 | head -20 +``` +If formatting issues found, run `cargo fmt` to fix. + +### Phase 3: Lint Check +```bash +cargo clippy -- -D warnings 2>&1 | head -30 +``` +All clippy warnings are errors in this project. Fix before continuing. + +### Phase 4: Test Suite +```bash +# Run all tests with nextest +cargo nextest run 2>&1 | tail -50 + +# Also run doc tests (nextest doesn't run these) +cargo test --doc 2>&1 | tail -20 +``` + +Report: +- Total tests: X +- Passed: X +- Failed: X + +### Phase 5: Coverage Check +```bash +cargo llvm-cov --summary-only 2>&1 | tail -10 +``` +Target: 85%+ coverage. If below threshold, identify uncovered code. + +### Phase 6: Security Audit +```bash +cargo audit 2>&1 | tail -20 +``` + +### Phase 7: Diff Review +```bash +git diff --stat +git diff HEAD --name-only +``` + +Review each changed file for: +- Unintended changes +- Missing error handling (`.unwrap()`, direct indexing) +- Files exceeding 500-600 line guideline +- Missing tests for new code paths + +## Output Format + +After running all phases, produce a verification report: + +``` +VERIFICATION REPORT +================== + +Build: [PASS/FAIL] +Format: [PASS/FAIL] +Clippy: [PASS/FAIL] (X warnings) +Tests: [PASS/FAIL] (X/Y passed) +Doc Tests: [PASS/FAIL] +Coverage: [X%] (target: 85%) +Audit: [PASS/FAIL] (X advisories) +Diff: [X files changed] + +Overall: [READY/NOT READY] for PR + +Issues to Fix: +1. ... +2. ... +``` + +## Quick Verification (Pre-commit) + +For fast checks during development: +```bash +just ci-check +``` + +This runs the project's standard CI validation suite. + +## Full CI Verification + +Matches what runs in GitHub Actions: +```bash +cargo fmt -- --check && cargo clippy -- -D warnings && cargo nextest run && cargo test --doc && cargo audit +``` From 1ff3204b3920c9c4afa0a7ea081060967b66803e Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sun, 15 Feb 2026 01:21:12 -0500 Subject: [PATCH 24/29] chore: add Claude Code hook to enforce DCO sign-off on commits PreToolUse hook checks all Bash commands for git commit without -s or --signoff flag and blocks them with exit code 2. Signed-off-by: UncleSp1d3r --- .claude/hooks/enforce-dco-signoff.sh | 17 +++++++++++++++++ .claude/settings.json | 15 +++++++++++++++ 2 files changed, 32 insertions(+) create mode 100755 .claude/hooks/enforce-dco-signoff.sh create mode 100644 .claude/settings.json diff --git a/.claude/hooks/enforce-dco-signoff.sh b/.claude/hooks/enforce-dco-signoff.sh new file mode 100755 index 00000000..50a0ed05 --- /dev/null +++ b/.claude/hooks/enforce-dco-signoff.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Claude Code PreToolUse hook: ensure all git commits include DCO sign-off (-s) + +CMD="${CLAUDE_TOOL_INPUT_command:-}" + +# Only check commands that contain "git commit" +if ! echo "$CMD" | grep -q "git commit"; then + exit 0 +fi + +# Allow if -s or --signoff is present anywhere in the command +if echo "$CMD" | grep -qE -- '(-s\b|--signoff)'; then + exit 0 +fi + +echo "BLOCK: All commits must include DCO sign-off. Add the -s flag to your git commit command." +exit 2 diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 00000000..dbe203ea --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,15 @@ +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": "bash .claude/hooks/enforce-dco-signoff.sh" + } + ] + } + ] + } +} From 82044ef9bc6aa46e814610087a731f7e9ef4f9be Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sun, 15 Feb 2026 01:25:45 -0500 Subject: [PATCH 25/29] chore: add hookify rules for Rust code safety warnings Add 4 hookify rules to warn about common safety issues: - warn-unsafe-code: flags unsafe blocks/fn/impl (project forbids unsafe) - warn-direct-string-slice: flags &str[n..] (use strip_prefix instead) - warn-panic-in-lib: flags unwrap/expect/panic in src/ (use Result) - warn-emoji-in-code: flags emoji in code/docs (with bypass for processing) Signed-off-by: UncleSp1d3r --- .claude/hookify.warn-direct-string-slice.md | 21 +++++++++++++++++ .claude/hookify.warn-emoji-in-code.md | 17 ++++++++++++++ .claude/hookify.warn-panic-in-lib.md | 26 +++++++++++++++++++++ .claude/hookify.warn-unsafe-code.md | 15 ++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 .claude/hookify.warn-direct-string-slice.md create mode 100644 .claude/hookify.warn-emoji-in-code.md create mode 100644 .claude/hookify.warn-panic-in-lib.md create mode 100644 .claude/hookify.warn-unsafe-code.md diff --git a/.claude/hookify.warn-direct-string-slice.md b/.claude/hookify.warn-direct-string-slice.md new file mode 100644 index 00000000..5dd16b93 --- /dev/null +++ b/.claude/hookify.warn-direct-string-slice.md @@ -0,0 +1,21 @@ +--- +name: warn-direct-string-slice +enabled: true +event: file +conditions: + - field: new_text + operator: regex_match + pattern: "&\\w+\\[\\d+\\.\\.\\]|&\\w+\\[\\.\\.\\d+\\]|&\\w+\\[\\d+\\.\\.]" +--- + +**Direct string slicing detected.** + +Use `strip_prefix()` / `strip_suffix()` instead of `&str[n..]` to avoid UTF-8 boundary panics. + +```rust +// Wrong: can panic on non-ASCII +let rest = &input[2..]; + +// Correct: safe +let rest = input.strip_prefix("0x").unwrap_or(input); +``` diff --git a/.claude/hookify.warn-emoji-in-code.md b/.claude/hookify.warn-emoji-in-code.md new file mode 100644 index 00000000..4f3a6c68 --- /dev/null +++ b/.claude/hookify.warn-emoji-in-code.md @@ -0,0 +1,17 @@ +--- +name: warn-emoji-in-code +enabled: true +event: file +conditions: + - field: new_text + operator: regex_match + pattern: "[\U0001F300-\U0001F9FF\u2600-\u26FF\u2700-\u27BF\U0001FA00-\U0001FA6F\U0001FA70-\U0001FAFF]" +--- + +**Emoji detected in code or documentation.** + +Project guidelines prohibit emojis and non-ASCII characters in code, comments, and documentation. + +**Exception:** If this code is specifically handling or processing emoji/non-ASCII characters (e.g., test cases for Unicode handling), this warning can be disregarded. + +If this is not emoji-processing code, remove the emoji and use plain text instead. diff --git a/.claude/hookify.warn-panic-in-lib.md b/.claude/hookify.warn-panic-in-lib.md new file mode 100644 index 00000000..879d5be6 --- /dev/null +++ b/.claude/hookify.warn-panic-in-lib.md @@ -0,0 +1,26 @@ +--- +name: warn-panic-in-lib +enabled: true +event: file +conditions: + - field: file_path + operator: regex_match + pattern: src/.*\.rs$ + - field: new_text + operator: regex_match + pattern: \.unwrap\(\)|\.expect\(|panic!\( +--- + +**Potential panic in library code detected.** + +This project uses `unwrap_used = "deny"` and `panic = "deny"` in clippy config. Use `Result` patterns instead. + +```rust +// Wrong: panics at runtime +let val = something.unwrap(); + +// Correct: propagate error +let val = something.ok_or(MagicError::InvalidValue)?; +``` + +Note: `.unwrap()` is acceptable inside `#[cfg(test)]` modules. diff --git a/.claude/hookify.warn-unsafe-code.md b/.claude/hookify.warn-unsafe-code.md new file mode 100644 index 00000000..249c88cd --- /dev/null +++ b/.claude/hookify.warn-unsafe-code.md @@ -0,0 +1,15 @@ +--- +name: warn-unsafe-code +enabled: true +event: file +conditions: + - field: new_text + operator: regex_match + pattern: unsafe\s*\{|unsafe\s+fn|unsafe\s+impl +--- + +**Unsafe code detected.** + +This project enforces `#![forbid(unsafe_code)]` project-wide. No unsafe blocks, functions, or impls are permitted in project source code. + +If you believe unsafe is absolutely necessary, stop and discuss with the user before proceeding. From a3af8ea0c1bbafcaf2028f738ce00ef2d4657b64 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sun, 15 Feb 2026 01:32:30 -0500 Subject: [PATCH 26/29] fix: address Copilot PR review comments - cliff.toml: fix duplicate Documentation sections (case-insensitive match), separate Breaking Changes into its own group (), compact list formatting in template - justfile: fix coverage-check threshold from 9.7 to 85, add scorecard.yml to lint-actions - AGENTS.md: fix vulnerability timeline to 90 days (match SECURITY.md), fix unsafe_code wording (workspace lints not crate attribute), fix note style consistency, fix string type limitation description - docs/src/security-assurance.md: fix unsafe_code enforcement wording to reference workspace lints in Cargo.toml - mise.toml: align new tool entries with existing formatting - ROADMAP.md: remove specific coverage percentage claim - CHANGELOG.md: regenerated with all fixes applied Signed-off-by: UncleSp1d3r --- AGENTS.md | 8 +++---- CHANGELOG.md | 44 +++++++++++++++++----------------- ROADMAP.md | 2 +- cliff.toml | 28 +++++++++++----------- docs/src/security-assurance.md | 4 ++-- justfile | 4 ++-- mise.toml | 6 ++--- 7 files changed, 48 insertions(+), 48 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 5812301b..9ec3a617 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -201,7 +201,7 @@ cargo test --doc # Test documentation examples ### Future Enhancement: Binary-Safe Regex Handling -> The following is planned for future releases and is not yet implemented. +> **Note:** The following is planned for future releases and is not yet implemented. ```rust // Use regex crate with bytes feature for binary-safe matching @@ -222,7 +222,7 @@ impl BinaryRegex for regex::bytes::Regex { - No 64-bit integer types (quad, qquad) - No floating-point types (float, double, befloat, lefloat) - No date/time types (date, qdate, ldate, qldate) -- String type supports null-terminated strings only (no fixed-length strings) +- String evaluation reads until first NUL or end-of-buffer by default; `max_length: Some(_)` is supported internally but no dedicated fixed-length string parser syntax exists yet ### Operators @@ -535,8 +535,8 @@ This project has the OSSF Best Practices passing badge. Maintain these standards ### Security: - Vulnerabilities go through private reporting (GitHub advisories or support@evilbitlabs.io), never public issues - `cargo audit` and `cargo deny` run daily in CI -- fix findings promptly -- Medium+ severity vulnerabilities must be fixed within 60 days of public disclosure -- `#![forbid(unsafe_code)]` is enforced project-wide -- this is a hardening mechanism, not a suggestion +- Medium+ severity vulnerabilities: we aim to release a fix within 90 days of confirmation (see SECURITY.md for canonical policy) +- `unsafe_code = "forbid"` is enforced project-wide via workspace lints in `Cargo.toml` -- this is a hardening mechanism, not a suggestion - `docs/src/security-assurance.md` must be updated when new attack surface is introduced ### Documentation: diff --git a/CHANGELOG.md b/CHANGELOG.md index 291c7164..e0657783 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,52 +2,52 @@ All notable changes to this project will be documented in this file. + ## [unreleased] ### Features - Add development infrastructure, automation hooks, and comprehensive documentation ([#4](https://github.com/EvilBit-Labs/libmagic-rs/pull/4)) - - Add evaluation engine with offset resolution and CI/CD automation ([#5](https://github.com/EvilBit-Labs/libmagic-rs/pull/5)) - - Create rmagic cli ([#7](https://github.com/EvilBit-Labs/libmagic-rs/pull/7)) - - Implement text magic parser (issue #11) ([#16](https://github.com/EvilBit-Labs/libmagic-rs/pull/16)) - - Parser integration, CI modernization with mise, and Dev Container support ([#26](https://github.com/EvilBit-Labs/libmagic-rs/pull/26)) - - Cli enhancements multiple files stdin magic discovery ([#27](https://github.com/EvilBit-Labs/libmagic-rs/pull/27)) - - Built-in rules build time compilation fallback ([#28](https://github.com/EvilBit-Labs/libmagic-rs/pull/28)) - - Evaluation enhancements with confidence, MIME, tags, metadata ([#29](https://github.com/EvilBit-Labs/libmagic-rs/pull/29)) - - Strength calculation & documentation improvements ([#21](https://github.com/EvilBit-Labs/libmagic-rs/pull/21)) ([#30](https://github.com/EvilBit-Labs/libmagic-rs/pull/30)) - ### Documentation +- Comprehensive mdbook rewrite, rustdoc fixes, and test stability ([#33](https://github.com/EvilBit-Labs/libmagic-rs/pull/33)) - **agents**: Update AGENTS.md to reflect implemented features and future plans - - **agents**: Fix inaccurate feature claims in AGENTS.md - - **readme**: Update README.md with project badges for visibility - +- Improve SECURITY.md with scope, safe harbor, and responsible disclosure +- Add PGP key for encrypted vulnerability reporting +- Use support@evilbitlabs.io for security contact to match PGP key +- Add code review requirements to AGENTS.md and CONTRIBUTING.md +- Add quick reference and OSSF quality standards to CLAUDE.md +- Add DCO requirement to CONTRIBUTING.md +- Add project governance model and update development guide +- Update roadmap to match milestones and add non-goals +- Add release verification guide for signed artifacts +- Add security assurance case for OSSF gold criteria +- **readme**: Add OpenSSF Best Practices badge +- Move OSSF standards from CLAUDE.md to AGENTS.md +- Extract roadmap into ROADMAP.md to keep README concise +- Add project-level Claude Code skills for Rust development ### Miscellaneous Tasks - **ci**: Add GitHub workflows for auditing, security, and documentation - - Add Contributor Covenant Code of Conduct ([#2](https://github.com/EvilBit-Labs/libmagic-rs/pull/2)) - - Pin all GitHub Actions to SHA hashes for supply chain security - - Revert SHA pins in release.yml (managed by cargo-dist) - - -### Documentation - -- Comprehensive mdbook rewrite, rustdoc fixes, and test stability ([#33](https://github.com/EvilBit-Labs/libmagic-rs/pull/33)) - - +- Add git-cliff changelog generation and simplify justfile +- Commit Cargo.lock for reproducible binary builds +- Commit mise.lock for reproducible dev tool versions +- Add SPDX license and copyright headers to all source files +- Add Claude Code hook to enforce DCO sign-off on commits +- Add hookify rules for Rust code safety warnings diff --git a/ROADMAP.md b/ROADMAP.md index d874659e..a6e0ceee 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -13,7 +13,7 @@ See [GitHub Milestones](https://github.com/EvilBit-Labs/libmagic-rs/milestones) - [x] Built-in fallback rules with build-time compilation - [x] Strength calculation and `!:strength` parsing - [x] Comprehensive error handling, rustdoc, and mdbook documentation -- [x] 94%+ test coverage across 1,058+ tests +- [x] High test coverage across 1,058+ tests ## v0.2.0 - Core Primitives diff --git a/cliff.toml b/cliff.toml index c4890722..49bd31b0 100644 --- a/cliff.toml +++ b/cliff.toml @@ -14,19 +14,19 @@ All notable changes to this project will be documented in this file.\n # template for the changelog body # https://keats.github.io/tera/docs/#introduction body = """ -{% if version %}\ - ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} -{% else %}\ - ## [unreleased] -{% endif %}\ +{%- if version %} +## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} +{%- else %} +## [unreleased] +{%- endif %} {% for group, commits in commits | group_by(attribute="group") %} - ### {{ group | striptags | trim | upper_first }} - {% for commit in commits %} - - {% if commit.scope %}**{{ commit.scope }}**: {% endif %}\ - {% if commit.breaking %}[**breaking**] {% endif %}\ - {{ commit.message | upper_first }} - {% endfor %} -{% endfor %}\n +### {{ group | striptags | trim | upper_first }} +{% for commit in commits %} +- {% if commit.scope %}**{{ commit.scope }}**: {% endif -%} +{% if commit.breaking %}[**breaking**] {% endif -%} +{{ commit.message | upper_first }} +{%- endfor %} +{% endfor %} """ # template for the changelog footer footer = """ @@ -61,7 +61,7 @@ commit_parsers = [ { message = "^feat", group = "Features" }, { message = "^fix\\(security\\)", group = "Security", scope = "security" }, { message = "^fix", group = "Bug Fixes" }, - { message = "^doc", group = "Documentation" }, + { message = "^[Dd]oc", group = "Documentation" }, { message = "^perf", group = "Performance" }, { message = "^refactor", group = "Refactor" }, { message = "^style", group = "Styling" }, @@ -75,7 +75,7 @@ commit_parsers = [ { message = "^chore\\(ci\\): update", skip = true }, { message = "^chore|^ci", group = "Miscellaneous Tasks" }, { body = ".*security", group = "Security" }, - { body = "BREAKING CHANGE:", group = "Breaking Changes" }, + { body = "BREAKING CHANGE:", group = "Breaking Changes" }, { message = "^revert", group = "Revert" }, ] # filter out the commits that are not matched by commit parsers diff --git a/docs/src/security-assurance.md b/docs/src/security-assurance.md index ad1eba90..af0ebfd2 100644 --- a/docs/src/security-assurance.md +++ b/docs/src/security-assurance.md @@ -80,7 +80,7 @@ All data crossing the trust boundary (file contents, magic file syntax, CLI argu | Principle | How Applied | |-----------|-------------| | **Economy of mechanism** | Pure Rust with minimal dependencies. Simple parser-evaluator pipeline. No plugin system, no scripting, no network I/O. | -| **Fail-safe defaults** | `#![forbid(unsafe_code)]` enforced project-wide. Buffer access defaults to bounds-checked `.get()` returning `None` rather than panicking. Invalid magic rules are skipped, not executed. | +| **Fail-safe defaults** | Workspace lint `unsafe_code = "forbid"` enforced project-wide via `Cargo.toml`. Buffer access defaults to bounds-checked `.get()` returning `None` rather than panicking. Invalid magic rules are skipped, not executed. | | **Complete mediation** | Every buffer access is bounds-checked. Every magic file is validated during parsing. Every CLI argument is validated by `clap`. | | **Open design** | Fully open source (Apache-2.0). Security does not depend on obscurity. All security mechanisms are publicly documented. | | **Separation of privilege** | Parser and evaluator are separate modules with distinct responsibilities. Parse errors cannot bypass evaluation safety checks. | @@ -94,7 +94,7 @@ All data crossing the trust boundary (file contents, magic file syntax, CLI argu | CWE | Weakness | Countermeasure | Status | |-----|----------|---------------|--------| -| CWE-787 | Out-of-bounds write | Rust ownership prevents writes to unowned memory. `#![forbid(unsafe_code)]` eliminates raw pointer writes. | Mitigated | +| CWE-787 | Out-of-bounds write | Rust ownership prevents writes to unowned memory. Workspace-level lints in `Cargo.toml` forbid unsafe code and eliminate raw pointer writes. | Mitigated | | CWE-79 | XSS | Not applicable (no web output). | N/A | | CWE-89 | SQL injection | Not applicable (no database). | N/A | | CWE-416 | Use after free | Rust ownership/borrowing system prevents use-after-free at compile time. | Mitigated | diff --git a/justfile b/justfile index a5ca6de2..0cb179e9 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/benchmarks.yml .github/workflows/ci.yml .github/workflows/codeql.yml .github/workflows/compatibility.yml .github/workflows/copilot-setup-steps.yml .github/workflows/docs.yml .github/workflows/release.yml .github/workflows/security.yml + @{{ mise_exec }} actionlint .github/workflows/audit.yml .github/workflows/benchmarks.yml .github/workflows/ci.yml .github/workflows/codeql.yml .github/workflows/compatibility.yml .github/workflows/copilot-setup-steps.yml .github/workflows/docs.yml .github/workflows/release.yml .github/workflows/scorecard.yml .github/workflows/security.yml lint-docs: @{{ mise_exec }} markdownlint-cli2 docs/**/*.md README.md @@ -177,7 +177,7 @@ coverage: @just _coverage coverage-check: - @just _coverage --fail-under-lines 9.7 + @just _coverage --fail-under-lines 85 # Generate HTML coverage report for local viewing [unix] diff --git a/mise.toml b/mise.toml index 971513e7..603a0db1 100644 --- a/mise.toml +++ b/mise.toml @@ -27,6 +27,6 @@ actionlint = "1.7.10" lychee = "0.22.0" markdownlint-cli2 = "0.20.0" pre-commit = "latest" -"cargo:cargo-machete" = "0.9.1" -"cargo:git-cliff" = "2.12.0" -scorecard = "5.4.0" +"cargo:cargo-machete" = "0.9.1" +"cargo:git-cliff" = "2.12.0" +scorecard = "5.4.0" From ec9c740b91f619a0eb21c4cb6d05ef0e43df1fcf Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sun, 15 Feb 2026 01:40:24 -0500 Subject: [PATCH 27/29] fix: use portable grep pattern in DCO sign-off hook Replace \b word boundary (GNU-only) with POSIX-safe space/line anchors for cross-platform compatibility on macOS BSD grep. Signed-off-by: UncleSp1d3r --- .claude/hooks/enforce-dco-signoff.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.claude/hooks/enforce-dco-signoff.sh b/.claude/hooks/enforce-dco-signoff.sh index 50a0ed05..3b97a2bc 100755 --- a/.claude/hooks/enforce-dco-signoff.sh +++ b/.claude/hooks/enforce-dco-signoff.sh @@ -9,7 +9,7 @@ if ! echo "$CMD" | grep -q "git commit"; then fi # Allow if -s or --signoff is present anywhere in the command -if echo "$CMD" | grep -qE -- '(-s\b|--signoff)'; then +if echo "$CMD" | grep -qE -- '(^| )-s( |$)|(^| )--signoff( |$)'; then exit 0 fi From b5fbfb7bb478bb16c0a7e04c0740cdb0282a126d Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sun, 15 Feb 2026 01:42:27 -0500 Subject: [PATCH 28/29] docs: expand Cargo.lock rationale in .gitignore Explain why Cargo.lock is committed despite the project including a library: binary reproducibility, cargo-auditable, and no impact on downstream library consumers since cargo publish ignores it. Signed-off-by: UncleSp1d3r --- .gitignore | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 5fb33c9a..44a115df 100644 --- a/.gitignore +++ b/.gitignore @@ -53,8 +53,12 @@ debug/ target/ dist/ -# Cargo.lock is committed because this project ships a binary (rmagic) -# https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +# Cargo.lock is committed intentionally. Although this project includes a +# library (src/lib.rs), it also ships a binary (rmagic). Committing the lock +# file ensures reproducible binary builds and auditable dependencies (via +# cargo-auditable). Library consumers are unaffected because cargo publish +# ignores Cargo.lock when resolving transitive dependencies. +# See: https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html # These are backup files generated by rustfmt **/*.rs.bk From fc8686234c29d187d44ab9c6f691b019e3522991 Mon Sep 17 00:00:00 2001 From: UncleSp1d3r Date: Sun, 15 Feb 2026 01:46:41 -0500 Subject: [PATCH 29/29] fix: address additional Copilot review comments - ci.yml: pin dtolnay/rust-toolchain to SHA, fix Qlty coverage path from target/lcov.info to lcov.info to match report output - docs.yml: build mdBook before copying rustdoc into book/api/ to prevent mdBook from overwriting the API docs directory - enforce-dco-signoff.sh: match "git commit" as distinct subcommand to avoid false positives on git commit-tree etc. Signed-off-by: UncleSp1d3r --- .claude/hooks/enforce-dco-signoff.sh | 4 ++-- .github/workflows/ci.yml | 4 ++-- .github/workflows/docs.yml | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.claude/hooks/enforce-dco-signoff.sh b/.claude/hooks/enforce-dco-signoff.sh index 3b97a2bc..2d0f8270 100755 --- a/.claude/hooks/enforce-dco-signoff.sh +++ b/.claude/hooks/enforce-dco-signoff.sh @@ -3,8 +3,8 @@ CMD="${CLAUDE_TOOL_INPUT_command:-}" -# Only check commands that contain "git commit" -if ! echo "$CMD" | grep -q "git commit"; then +# Only check commands that contain "git commit" as a distinct subcommand +if ! echo "$CMD" | grep -qE '(^|[;&|] *)git commit( |$)'; then exit 0 fi diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5beaf89c..bc1edd3c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: if: needs.changes.outputs.rust == 'true' steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: dtolnay/rust-toolchain@1.91.0 + - uses: dtolnay/rust-toolchain@0dd4a6d07aedb0ef7f65e79f3e229a6c102ae2e0 # 1.91.0 with: components: llvm-tools, cargo, rustfmt, clippy - uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1 @@ -148,4 +148,4 @@ jobs: - uses: qltysh/qlty-action/coverage@a19242102d17e497f437d7466aa01b528537e899 # v2.2.0 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} - files: target/lcov.info + files: lcov.info diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 78ca6330..5c51a1ec 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -42,17 +42,17 @@ jobs: - name: Install mdbook plugins run: cargo binstall mdbook-tabs mdbook-i18n-helpers mdbook-alerts mdbook-yml-header mdbook-image-size --no-confirm - - name: Build rustdoc - run: | - cargo doc --no-deps --document-private-items --target-dir target - mkdir -p docs/book/api - cp -r target/doc/* docs/book/api/ - - name: Build mdBook run: | cd docs mdbook build + - name: Build rustdoc and copy into book + run: | + cargo doc --no-deps --document-private-items --target-dir target + mkdir -p docs/book/api + cp -r target/doc/* docs/book/api/ + - name: Setup Pages if: github.ref == 'refs/heads/main' uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0