Skip to content

feat(evaluator): add debug-level tracing for skipped rules#184

Merged
unclesp1d3r merged 11 commits into
mainfrom
172-evaluator-add-debug-level-tracing-for-skipped-rules
Mar 25, 2026
Merged

feat(evaluator): add debug-level tracing for skipped rules#184
unclesp1d3r merged 11 commits into
mainfrom
172-evaluator-add-debug-level-tracing-for-skipped-rules

Conversation

@unclesp1d3r
Copy link
Copy Markdown
Member

@unclesp1d3r unclesp1d3r commented Mar 25, 2026

Summary

Add the log crate as the project's first logging facade, emit log::debug! when the evaluator skips rules due to expected errors, and convert library-side eprintln! calls to structured log macros. Also switches Mergify to merge-queue style.

Impact: 6 relevant files changed (+29, -20 in src/), low risk
Closes: #172

What Changed

Source Changes

File Change
Cargo.toml Add log = "0.4" to [dependencies] and [build-dependencies]
src/evaluator/engine/mod.rs Bind errors with e @ at 2 skip points, emit debug!, remove TODO
src/parser/loader.rs eprintln! -> log::warn!, remove #[allow(clippy::print_stderr)] attrs, update rustdoc
src/output/mod.rs eprintln! -> log::warn!, remove #[cfg(debug_assertions)] gate

CI/Config Changes

File Change
.mergify.yml Switch to merge queue: autoqueue bots, @mergifyio queue for human PRs

Why These Changes

When evaluate_rules skips a rule due to BufferOverrun, InvalidOffset, TypeReadError, or IoError, there was no diagnostic output. Users could not distinguish "rule didn't match the file" from "rule failed internally." A TODO comment at engine/mod.rs:201 explicitly requested this.

Additionally, two library modules used raw eprintln! for warnings -- library code should use the log facade so consumers control output.

Technical Details

  • log over tracing: Unanimous decision across 5 review agents. log has zero transitive deps, suits this synchronous library, and maximizes consumer compatibility. Migration to tracing later is mechanical if needed.
  • e @ binding: Stable since Rust 1.68, follows GOTCHAS.md S9.1. Parentheses required around nested OR alternatives.
  • log in [build-dependencies]: Required because build.rs compiles the entire parser module via #[path = "src/parser/mod.rs"], which includes mod loader;.
  • #[cfg(debug_assertions)] removal: Intentional. Confidence validation is a single integer comparison (~1ns). log::warn! is zero-cost without a backend. The gate was a workaround for lacking a logging framework.
  • "Warning:" prefix dropped: Log level already conveys severity.

How Has This Been Tested?

  • cargo fmt --check -- clean
  • cargo clippy -- -D warnings -- zero warnings
  • cargo nextest run -- 1085 passed, 0 failed, 5 skipped
  • cargo test --doc -- 163 passed, 0 failed
  • Pre-commit hooks pass on all commits
  • CI passes on GitHub
  • Manual: RUST_LOG=debug cargo run -- --use-builtin <file> shows skip messages (requires consumer to add log backend)

Performance Impact

Per performance review analysis:

  • log::debug! with no backend: ~0.3ns per call (single atomic load, relaxed ordering)
  • 1,000 rules evaluated: +0.3us total overhead (well below I/O noise floor)
  • Confidence validation: ~1-2ns (single cmp + predicted branch)
  • Compile time: +0.1-0.3s clean build (log is ~1,200 lines, zero deps)
  • Binary size: <1KB increase

Breaking Changes

None. The log facade emits nothing without a registered backend. All existing behavior is preserved.

Review Checklist

  • Uses Display {} not Debug {:?} (satisfies use_debug = "warn" clippy lint)
  • Dependencies alphabetically ordered in Cargo.toml
  • No unwrap()/expect() in library code
  • SPDX/copyright headers preserved (existing files only)
  • Stale #[allow] attributes and TODO comments removed
  • Rustdoc updated to reflect log::warn! instead of eprintln!
  • Child skip arm comment accurately reflects defensive/unreachable nature

unclesp1d3r and others added 3 commits March 24, 2026 20:48
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Add the `log` crate as the project's logging facade and emit
`log::debug!` when evaluate_rules skips a rule due to expected
evaluation errors (BufferOverrun, InvalidOffset, TypeReadError,
IoError). This lets users distinguish "rule didn't match" from
"rule failed internally" by enabling RUST_LOG=debug.

Also converts library-side eprintln! calls to log macros:
- parser/loader.rs: parse failure warnings -> log::warn!
- output/mod.rs: confidence validation -> log::warn!
  (removed #[cfg(debug_assertions)] gate -- zero-cost with no backend)

Binary-side eprintln! in main.rs stays as-is (user-facing CLI output).

Closes #172

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Adopt the queue-based Mergify style from stringy/opnDossier:
- dosubot: autoqueue, quality check only
- dependabot: autoqueue, full CI required
- release-plz: autoqueue, DCO only (exempt from full CI)
- Human PRs: manually enqueued via @Mergifyio queue command
- Add conventional commit enforcement (skip for bots)
- Raise outdated PR limit from 3 to 10 commits behind

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
@unclesp1d3r unclesp1d3r linked an issue Mar 25, 2026 that may be closed by this pull request
4 tasks
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Mar 25, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 25, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c86462f8-bfdd-4362-af0d-a616cc1c4fd5

📥 Commits

Reviewing files that changed from the base of the PR and between 7ec4646 and 345f42d.

⛔ Files ignored due to path filters (1)
  • .github/workflows/release.yml is excluded by !.github/workflows/release.yml and included by .github/**
📒 Files selected for processing (14)
  • .github/workflows/benchmarks.yml
  • .github/workflows/ci.yml
  • .github/workflows/compatibility.yml
  • .github/workflows/copilot-setup-steps.yml
  • .github/workflows/docs.yml
  • .github/workflows/release-plz.yml
  • .github/workflows/scorecard.yml
  • .mergify.yml
  • dist-workspace.toml
  • docs/src/development.md
  • docs/src/getting-started.md
  • docs/src/troubleshooting.md
  • src/evaluator/engine/mod.rs
  • src/parser/loader.rs

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.


📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added configurable logging support via RUST_LOG environment variable for debugging rule evaluation and file type detection issues.
  • Bug Fixes

    • Improved confidence validation to work consistently across all build modes, not just debug builds.
  • Documentation

    • Minimum Rust version requirement updated to 1.91+ (2024 edition).
    • Added comprehensive troubleshooting guide with debug logging examples and rule evaluation diagnostics.

Walkthrough

Adds structured logging (replacing stderr prints with log calls), narrows some evaluator error matching to propagate unexpected errors, introduces an .mcp.json MCP server config and tessl.json vendored dependency, updates CI/workflow action pins, and overhauls Mergify queue/pull rules.

Changes

Cohort / File(s) Summary
Configuration files
\.mcp.json, tessl.json, dist-workspace.toml
Add an MCP server config (tessl), add a vendored dependency config (stringy / actionbook/rust-skills), and pin two GitHub Action commits in dist workspace.
Mergify rules
.mergify.yml
Replace per-bot pull_request_rules merges with queue_rules, add auto-queue behaviors for dosubot, dependabot, release-plz, require conventional-commit titles for non-bot PRs, and increase #commits-behind threshold from 3 to 10.
CI / Workflows
.github/workflows/... (benchmarks.yml, ci.yml, compatibility.yml, copilot-setup-steps.yml, docs.yml, release-plz.yml, scorecard.yml)
Bump pinned action commits/versions (notably jdx/mise-action across workflows, codecov and ossf/scorecard-action updates) and fix YAML indentation in some workflow files.
Rust manifest
Cargo.toml
Add log = "0.4" to [dependencies] and [build-dependencies].
Evaluator engine
src/evaluator/engine/mod.rs
Import log::debug; emit debug logs when skipping rules due to expected evaluation errors; restrict caught TypeReadError variants to BufferOverrun and InvalidPStringLength, letting other variants propagate.
Output validation
src/output/mod.rs
Import log::warn; replace debug-only stderr warning with warn! and remove #[cfg(debug_assertions)] so confidence validation runs in all builds.
Parser loader
src/parser/loader.rs
Replace eprintln! per-file parse warnings with log::warn!; remove Clippy suppression for stderr printing.
Documentation
docs/src/... (development.md, getting-started.md, troubleshooting.md)
Update docs to describe logging conventions, add troubleshooting for enabling debug logging, bump Rust toolchain requirement to 1.91+, and show examples referencing new debug output behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Suggested labels

evaluator

🎉 Logs now whisper when rules retreat,
Buffer overruns no longer beat —
Mergify queues hum, workflows align,
Debug traces show each skip, in time. 🛠️

🚥 Pre-merge checks | ✅ 8 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Libmagic-Compatibility-Check ⚠️ Warning PR adds logging to magic rule evaluation but fails to fix critical error handling bug where TypeReadError::UnsupportedType is silently skipped instead of propagated per libmagic semantics. Narrow TypeReadError pattern match to explicitly list only BufferOverrun and InvalidPStringLength variants for graceful skip; let UnsupportedType fall through to propagation arm at lines 205-207 and 247-252.
Test-Coverage-Check ⚠️ Warning PR adds debug logging for skipped rule evaluations but lacks tests verifying log output or error handling for BufferOverrun, InvalidOffset, TypeReadError, and IoError cases. Add unit tests to verify log::debug! emissions for each error variant when rules are skipped, plus tests for logging changes in output/mod.rs and parser/loader.rs.
✅ Passed checks (8 passed)
Check name Status Explanation
Title check ✅ Passed The PR title follows Conventional Commits specification with type 'feat', scope 'evaluator', and a clear descriptive message about adding debug-level tracing for skipped rules.
Linked Issues check ✅ Passed All primary objectives from issue #172 are met: debug-level logging is added when rules are skipped [src/evaluator/engine/mod.rs], rule messages and errors are included in traces, output is debug-level only, and both top-level and child evaluation errors are covered.
Out of Scope Changes check ✅ Passed All changes are within scope of issue #172 objectives: logging infrastructure (Cargo.toml, .mcp.json, tessl.json), evaluator tracing (src/evaluator/engine/mod.rs), library-side logging conversions (parser/loader.rs, output/mod.rs), and Mergify workflow updates are supporting or related changes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 85.00%.
Memory-Safety-Check ✅ Passed The pull request introduces no unsafe code blocks and maintains memory safety standards through the safe log crate and workspace-enforced forbid directive.
Performance-Regression-Check ✅ Passed Logging additions use zero-cost abstractions with debug calls only in error paths and warn calls in non-hot paths, introducing no performance regressions.
Error-Handling-Check ✅ Passed The PR maintains proper error handling with Result types for all public library APIs and no panics. Only logging integrations via log crate were added without violating error handling principles.
Description check ✅ Passed The PR description directly addresses the changeset: adds log crate as logging facade, emits debug-level logs for skipped rules, converts library eprintln! calls to structured logging, and updates Mergify configuration.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 172-evaluator-add-debug-level-tracing-for-skipped-rules

Comment @coderabbitai help to get the list of available commands and usage tips.

@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented Mar 25, 2026

Merge Protections

Your pull request matches the following merge protections and will not be merged until they are valid.

🟢 📃 Configuration Change Requirements

Wonderful, this rule succeeded.

Mergify configuration change

  • check-success = Configuration changed

🟢 CI must pass

Wonderful, this rule succeeded.

All CI checks must pass. Release-plz PRs are exempt because they only bump versions and changelogs (code was already tested on main), and GITHUB_TOKEN-triggered force-pushes suppress CI.

  • check-success = coverage
  • check-success = quality
  • check-success = test
  • check-success = test-cross-platform (macos-latest, macOS)
  • check-success = test-cross-platform (ubuntu-22.04, Linux)
  • check-success = test-cross-platform (ubuntu-latest, Linux)
  • check-success = test-cross-platform (windows-latest, Windows)

🟢 Do not merge outdated PRs

Wonderful, this rule succeeded.

Make sure PRs are within 10 commits of the base branch before merging

  • #commits-behind <= 3

@dosubot dosubot Bot added evaluator Rule evaluation engine and logic rust Rust language features and idioms labels Mar 25, 2026
@dosubot
Copy link
Copy Markdown
Contributor

dosubot Bot commented Mar 25, 2026

Related Documentation

3 document(s) may need updating based on files changed in this PR:

libMagic-rs

development /libmagic-rs/blob/main/docs/src/development.md
View Suggested Changes
@@ -411,27 +411,47 @@
 
 ### Logging
 
-Use the `log` crate for debugging:
+The project uses `log = "0.4"` as its logging facade. Logging is used throughout the codebase to provide diagnostic information during development and troubleshooting.
+
+**Logging Conventions:**
+
+- `log::debug!()` for diagnostic information (such as skipped rule evaluations in `src/evaluator/engine/mod.rs`)
+- `log::warn!()` for warnings (parse failures in `src/parser/loader.rs`, confidence validation issues in `src/output/mod.rs`)
+
+Example usage:
 
 ```rust
-use log::{debug, error, info, warn};
-
-pub fn parse_rule(input: &str) -> Result<MagicRule> {
-    debug!("Parsing rule: {}", input);
-
-    let result = do_parsing(input)?;
-
-    info!("Successfully parsed rule: {}", result.message);
-    Ok(result)
+use log::{debug, warn};
+
+pub fn evaluate_rules(rules: &[MagicRule], buffer: &[u8]) -> Result<Vec<RuleMatch>> {
+    for rule in rules {
+        match evaluate_single_rule(rule, buffer) {
+            Ok(data) => { /* ... */ }
+            Err(e) => {
+                // Expected evaluation errors -- skip gracefully
+                debug!("Skipping rule '{}': {}", rule.message, e);
+                continue;
+            }
+        }
+    }
+    // ...
 }
 ```
 
-Run with logging:
-
-```bash
+Enable logging during development:
+
+```bash
+# See debug output during testing
 RUST_LOG=debug cargo test
-RUST_LOG=libmagic_rs=trace cargo run
-```
+
+# See debug output when running the CLI
+RUST_LOG=debug cargo run -- --use-builtin file.bin
+
+# Filter to specific module
+RUST_LOG=libmagic_rs::evaluator=debug cargo run
+```
+
+Debug-level logging is particularly useful for understanding rule evaluation behavior in `src/evaluator/engine/mod.rs`, where it shows which rules are skipped due to buffer overruns, invalid offsets, or type read errors.
 
 ### Debugging Tests
 

✅ Accepted

getting-started /libmagic-rs/blob/main/docs/src/getting-started.md
View Suggested Changes
@@ -64,6 +64,20 @@
 # Help and options
 ./target/release/rmagic --help
 ```
+
+### Troubleshooting Detection Issues
+
+Enable debug logging to see when rules are skipped due to evaluation errors (buffer overruns, invalid offsets, type read failures) versus simply not matching:
+
+```bash
+# CLI: Enable debug logs for a single invocation
+RUST_LOG=debug cargo run -- --use-builtin example.bin
+
+# Or with the compiled binary
+RUST_LOG=debug ./target/release/rmagic --use-builtin example.bin
+```
+
+Debug output shows which rules the evaluator skips and why, helping diagnose unexpected file detection behavior.
 
 ### Library Usage
 

✅ Accepted

troubleshooting /libmagic-rs/blob/main/docs/src/troubleshooting.md
View Suggested Changes
@@ -237,6 +237,27 @@
 RUST_LOG=debug cargo run -- example.bin
 RUST_LOG=libmagic_rs=trace cargo test
 ```
+
+### Diagnosing Rule Evaluation Issues
+
+**Problem**: File types are not detected correctly, or you want to understand why certain rules match or fail
+
+**Solution**: Enable debug logging to see detailed information about rule evaluation
+
+```bash
+# CLI tool with builtin rules
+RUST_LOG=debug rmagic --use-builtin example.bin
+
+# CLI tool with custom magic file
+RUST_LOG=debug rmagic --magic custom.magic example.bin
+```
+
+Debug logging shows which rules are skipped during evaluation and why. This helps distinguish between:
+
+- **Rule didn't match**: Normal behavior where the rule's test condition evaluated to false
+- **Rule failed internally**: Evaluation errors like `BufferOverrun`, `InvalidOffset`, `TypeReadError`, or `IoError` that cause the rule to be skipped
+
+For library usage, initialize a logger that respects the `RUST_LOG` environment variable (such as `env_logger`), then run your program with `RUST_LOG=debug` to see the same diagnostic information.
 
 ### Use Debug Output
 

✅ Accepted

Note: You must be authenticated to accept/decline updates.

How did I do? Any feedback?

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 25, 2026

Codecov Report

❌ Patch coverage is 50.00000% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/evaluator/engine/mod.rs 50.00% 2 Missing ⚠️
src/output/mod.rs 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot added parser Magic file parsing components and grammar output Result formatting and output generation and removed evaluator Rule evaluation engine and logic rust Rust language features and idioms labels Mar 25, 2026
unclesp1d3r and others added 2 commits March 24, 2026 23:57
…lows

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…r docs

Address code review findings:
- Reword child rule skip comment to accurately reflect that the arm is
  defensive/unreachable under current implementation
- Update loader.rs rustdoc from "logged to stderr" to "logged at warn
  level" to match the eprintln! -> log::warn! conversion

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Cargo.toml (1)

153-162: ⚠️ Potential issue | 🟠 Major

Initialize a logger backend in the CLI binary.

The log facade alone produces no output. The binary's main() function must initialize a logger (e.g., env_logger::init()) before processing files; otherwise, the active debug!() and warn!() calls throughout the library code will remain silent, and RUST_LOG=debug will have no effect. A common approach for CLI tools:

fn main() {
    env_logger::builder()
        .filter_level(log::LevelFilter::Warn)
        .parse_default_env()
        .init();
    
    let args = Args::parse();
    // ... rest of main
}

Add env_logger to [dependencies] in Cargo.toml and call its initializer near the start of main().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Cargo.toml` around lines 153 - 162, The CLI currently depends on the `log`
facade but never initializes a logger backend, so debug!/warn! calls remain
silent; add `env_logger = "0.10"` (or appropriate version) to `[dependencies]`
in Cargo.toml and initialize it at the start of the binary's main() (e.g., call
env_logger::builder().parse_default_env().init() or env_logger::init()) before
parsing Args::parse() or doing any processing so RUST_LOG takes effect; update
the binary's main() function (the main() that calls Args::parse()) to perform
this initialization.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.mergify.yml:
- Around line 34-39: The queue rule currently identifies release-plz PRs only by
the head branch pattern (head ~= ^release-plz-) which is attacker-controllable;
update the queue_conditions for that rule to include an author check such as
author = release-plz[bot] (or alternatively require a maintainer-applied label)
so that only PRs created by the trusted bot match the queue; i.e., modify the
queue_conditions block (where queue_conditions and head ~= ^release-plz- are
defined) to add author = release-plz[bot] alongside the existing conditions.
- Around line 44-49: The default Mergify queue defined by queue_conditions is
missing the "label != do-not-merge" guard; update the queue_conditions block in
.mergify.yml to include the same label check used by other queues (i.e., add
"label != do-not-merge") so manually enqueued PRs respect the do-not-merge
label, ensuring consistency with dosubot, dependabot, and release-plz queues.
- Around line 1-12: The dosubot queue rule currently only requires the `quality`
check (see queue_rules -> name: dosubot and merge_conditions -> check-success =
quality); update its merge_conditions to require the repository's full CI check
instead of (or in addition to) `quality`—for example replace or add
`check-success = full-ci` (or the exact full CI check name used in this repo) so
dosubot merges only after the full CI passes.

In `@src/evaluator/engine/mod.rs`:
- Around line 194-199: The pattern matching on LibmagicError currently treats
all crate::error::EvaluationError::TypeReadError(_) as skippable; change it to
only match the data-dependent TypeReadError variants (e.g., those indicating
transient/data issues such as TypeReadError::OutOfBounds or
TypeReadError::Truncated — but exclude TypeReadError::UnsupportedType) so that
UnsupportedType still propagates; apply the same narrowing to the child-rule arm
that matches LibmagicError there (the second arm currently handling child-rule
errors) so both places mirror the same selective TypeReadError variant list.

---

Outside diff comments:
In `@Cargo.toml`:
- Around line 153-162: The CLI currently depends on the `log` facade but never
initializes a logger backend, so debug!/warn! calls remain silent; add
`env_logger = "0.10"` (or appropriate version) to `[dependencies]` in Cargo.toml
and initialize it at the start of the binary's main() (e.g., call
env_logger::builder().parse_default_env().init() or env_logger::init()) before
parsing Args::parse() or doing any processing so RUST_LOG takes effect; update
the binary's main() function (the main() that calls Args::parse()) to perform
this initialization.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 55691d9d-0c1f-47de-a870-a7072f4c675f

📥 Commits

Reviewing files that changed from the base of the PR and between 88a6a58 and 7ec4646.

⛔ Files ignored due to path filters (3)
  • .codex/config.toml is excluded by none and included by none
  • .gemini/settings.json is excluded by none and included by none
  • Cargo.lock is excluded by !**/*.lock and included by none
📒 Files selected for processing (7)
  • .mcp.json
  • .mergify.yml
  • Cargo.toml
  • src/evaluator/engine/mod.rs
  • src/output/mod.rs
  • src/parser/loader.rs
  • tessl.json

Comment thread .mergify.yml
Comment thread .mergify.yml
Comment thread .mergify.yml
Comment thread src/evaluator/engine/mod.rs
@unclesp1d3r unclesp1d3r self-assigned this Mar 25, 2026
…efault queue

Address CodeRabbit review findings:
- Add `author = release-plz[bot]` to release-plz queue to prevent
  fork-based branch name spoofing
- Add `label != do-not-merge` to default queue for consistency with
  all other queue rules

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
coderabbitai[bot]
coderabbitai Bot previously approved these changes Mar 25, 2026
Replace the TypeReadError(_) wildcard in both rule-skip match arms with
explicit data-dependent variants (BufferOverrun, InvalidPStringLength).
This ensures TypeReadError::UnsupportedType propagates as an error
instead of being silently skipped, surfacing evaluator capability gaps.

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Mar 25, 2026
dosubot Bot and others added 3 commits March 25, 2026 04:13
The codeql-action version comment was corrupted with concatenated
version strings (v4.32.6.4.32.62.4.32.6). The SHA is correct for
v4.32.6 -- only the comment needed fixing.

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
@unclesp1d3r
Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 25, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@unclesp1d3r unclesp1d3r merged commit db661cb into main Mar 25, 2026
29 of 30 checks passed
@unclesp1d3r unclesp1d3r deleted the 172-evaluator-add-debug-level-tracing-for-skipped-rules branch March 25, 2026 04:30
@coderabbitai coderabbitai Bot added evaluator Rule evaluation engine and logic and removed parser Magic file parsing components and grammar output Result formatting and output generation labels Mar 25, 2026
@github-actions github-actions Bot mentioned this pull request Apr 25, 2026
unclesp1d3r pushed a commit that referenced this pull request Apr 25, 2026
## 🤖 New release

* `libmagic-rs`: 0.5.0 -> 0.6.0 (⚠ API breaking changes)

### ⚠ `libmagic-rs` breaking changes

```text
--- failure constructible_struct_adds_field: externally-constructible struct adds field ---

Description:
A pub struct constructible with a struct literal has a new pub field. Existing struct literals must be updated to include the new field.
        ref: https://doc.rust-lang.org/reference/expressions/struct-expr.html
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/constructible_struct_adds_field.ron

Failed in:
  field MagicRule.value_transform in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:1189
  field MagicRule.value_transform in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:1189
  field MagicRule.value_transform in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:1189

--- failure copy_impl_added: type now implements Copy ---

Description:
A public type now implements Copy, causing non-move closures to capture it by reference instead of moving it.
        ref: rust-lang/rust#100905
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/copy_impl_added.ron

Failed in:
  libmagic_rs::mime::MimeMapper in /tmp/.tmpwFvgw1/libmagic-rs/src/mime.rs:98

--- failure enum_marked_non_exhaustive: enum marked #[non_exhaustive] ---

Description:
A public enum has been marked #[non_exhaustive]. Pattern-matching on it outside of its crate must now include a wildcard pattern like `_`, or it will fail to compile.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#attr-adding-non-exhaustive
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/enum_marked_non_exhaustive.ron

Failed in:
  enum OffsetSpec in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:198
  enum OffsetSpec in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:198
  enum OffsetSpec in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:198
  enum LibmagicError in /tmp/.tmpwFvgw1/libmagic-rs/src/error.rs:15
  enum LibmagicError in /tmp/.tmpwFvgw1/libmagic-rs/src/error.rs:15
  enum IoError in /tmp/.tmpwFvgw1/libmagic-rs/src/io/mod.rs:26
  enum Operator in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:838
  enum Operator in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:838
  enum Operator in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:838
  enum TypeReadError in /tmp/.tmpwFvgw1/libmagic-rs/src/evaluator/types/mod.rs:56
  enum ParseError in /tmp/.tmpwFvgw1/libmagic-rs/src/error.rs:74
  enum ParseError in /tmp/.tmpwFvgw1/libmagic-rs/src/error.rs:74
  enum Value in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:965
  enum Value in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:965
  enum Value in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:965
  enum TypeKind in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:398
  enum TypeKind in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:398
  enum TypeKind in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:398
  enum EvaluationError in /tmp/.tmpwFvgw1/libmagic-rs/src/error.rs:148
  enum EvaluationError in /tmp/.tmpwFvgw1/libmagic-rs/src/error.rs:148

--- failure enum_struct_variant_field_added: pub enum struct variant field added ---

Description:
An enum's exhaustive struct variant has a new field, which has to be included when constructing or matching on this variant.
        ref: https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/enum_struct_variant_field_added.ron

Failed in:
  field base_relative of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:251
  field adjustment_op of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:266
  field result_relative of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:272
  field base_relative of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:251
  field adjustment_op of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:266
  field result_relative of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:272
  field base_relative of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:251
  field adjustment_op of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:266
  field result_relative of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:272

--- failure function_missing: pub fn removed or renamed ---

Description:
A publicly-visible function cannot be imported by its prior path. A `pub use` may have been removed, or the function itself may have been renamed or removed entirely.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/function_missing.ron

Failed in:
  function libmagic_rs::parser::grammar::is_empty_line, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:1025
  function libmagic_rs::parser::grammar::parse_strength_directive, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:846
  function libmagic_rs::parser::grammar::parse_type_and_operator, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:683
  function libmagic_rs::parser::grammar::parse_offset, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:179
  function libmagic_rs::parser::parse_offset, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:179
  function libmagic_rs::parser::grammar::parse_comment, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:1004
  function libmagic_rs::parser::grammar::parse_message, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:810
  function libmagic_rs::parser::grammar::parse_value, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:633
  function libmagic_rs::parser::grammar::parse_number, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:133
  function libmagic_rs::parser::parse_number, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:133
  function libmagic_rs::parser::grammar::has_continuation, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:1060
  function libmagic_rs::parser::grammar::parse_magic_rule, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:946
  function libmagic_rs::parser::grammar::parse_rule_offset, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:779
  function libmagic_rs::parser::grammar::is_comment_line, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:1042
  function libmagic_rs::parser::grammar::is_strength_directive, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:902
  function libmagic_rs::parser::grammar::parse_type, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:749
  function libmagic_rs::parser::grammar::parse_operator, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:227

--- failure function_parameter_count_changed: pub fn parameter count changed ---

Description:
A publicly-visible function now takes a different number of parameters.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#fn-change-arity
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/function_parameter_count_changed.ron

Failed in:
  libmagic_rs::evaluator::evaluate_single_rule now takes 3 parameters instead of 2, in /tmp/.tmpwFvgw1/libmagic-rs/src/evaluator/engine/mod.rs:196

--- failure inherent_method_missing: pub method removed or renamed ---

Description:
A publicly-visible method or associated fn is no longer available under its prior name. It may have been renamed or removed entirely.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/inherent_method_missing.ron

Failed in:
  FileBuffer::create_symlink, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/io/mod.rs:326
  EvaluationContext::increment_recursion_depth, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/evaluator/mod.rs:114
  EvaluationContext::decrement_recursion_depth, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/evaluator/mod.rs:130
  EvaluationContext::increment_recursion_depth, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/evaluator/mod.rs:114
  EvaluationContext::decrement_recursion_depth, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/evaluator/mod.rs:130

--- failure module_missing: pub module removed or renamed ---

Description:
A publicly-visible module cannot be imported by its prior path. A `pub use` may have been removed, or the module may have been renamed, removed, or made non-public.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/module_missing.ron

Failed in:
  mod libmagic_rs::parser::grammar, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:4

--- failure struct_marked_non_exhaustive: struct marked #[non_exhaustive] ---

Description:
A public struct has been marked #[non_exhaustive], which will prevent it from being constructed using a struct literal outside of its crate. It previously had no private fields, so a struct literal could be used to construct it outside its crate.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#attr-adding-non-exhaustive
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/struct_marked_non_exhaustive.ron

Failed in:
  struct EvaluationConfig in /tmp/.tmpwFvgw1/libmagic-rs/src/config.rs:42
```

<details><summary><i><b>Changelog</b></i></summary><p>

<blockquote>

## [0.6.0] - 2026-04-25

### Features

- **parser**: Add Date and QDate types with serialization support
([#165](#165))
- **parser**: Implement pstring (Pascal string) type
([#170](#170))
- **parser**: Implement pstring multi-byte length prefix variants (/B,
/H, /h, /L, /l, /J)
([#183](#183))
- **evaluator**: Add debug-level tracing for skipped rules
([#184](#184))
- **evaluator**: Implement indirect offset resolution
([#37](#37))
([#199](#199))
- **evaluator**: Implement relative offset resolution
([#38](#38))
([#211](#211))
- **deps**: Add new skills to actionbook/rust-skills and
trailofbits/skills
- **evaluator**: Regex and search types (closes #39)
([#214](#214))
- Implement libmagic meta-type directives and format substitution
([#42](#42))
([#230](#230))

### Bug Fixes

- **regex**: PR #214 follow-up review findings
([#215](#215))
- Load and correctly evaluate /usr/share/file/magic/filesystems and
adjacent magic files
([#233](#233))

### Documentation

- **gotchas**: Clarify requirements for adding TypeKind variants

### Miscellaneous Tasks

- Rename .coderabbitai.yaml to .coderabbit.yaml
- **Mergify**: Configuration update
([#173](#173))
- Update .gitignore to exclude local AI assistant files
- **mergify**: Upgrade configuration to current format
([#205](#205))
- Resolve all pending TODO items
([#212](#212))
- **mergify**: Upgrade configuration to current format
([#231](#231))
<!-- generated by git-cliff -->

### Security

- **io**: Close TOCTOU race in `FileBuffer::new` metadata validation
(CWE-367). `validate_file_metadata` now uses `File::metadata()` on the
open descriptor instead of re-canonicalizing the path, so an attacker
cannot swap the path between `open_file` and validation. Error paths now
report the caller-supplied path rather than the canonicalized variant.
- **cli**: Remove relative-path fallbacks from `default_magic_file_path`
(CWE-426). `./missing.magic`, `./third_party/magic.mgc`, and the
`CI`/`GITHUB_ACTIONS` env-var branch no longer resolve against the
process cwd. CI pipelines must pass `--magic <path>` explicitly.
- **evaluator**: `build_regex` now bounds `size_limit` and
`dfa_size_limit` to 1 MiB (`REGEX_COMPILE_SIZE_LIMIT`) to reject
compile-time DoS patterns (CWE-1333) from adversarial magic files.

### Features

- **parser**: Implement meta-type directives: `name`/`use` subroutines,
`default`/`clear` per-level fallback, and `indirect` re-evaluation.
`parse_text_magic_file` now returns `ParsedMagic { rules, name_table }`
(breaking change from `Vec<MagicRule>`). Named subroutines are hoisted
into `NameTable` at load time and dispatched via `RuleEnvironment` in
the evaluator. Recursion is bounded by
`EvaluationConfig::max_recursion_depth`. Resolves
[#42](#42).
- **evaluator**: Thread-local regex compile cache eliminates the
double-compile paid by every successful regex match.
`regex_bytes_consumed` now reuses the compiled `Regex` from `read_regex`
instead of recompiling the pattern to derive the anchor advance. The
cache is reset at the start of every `evaluate_rules_with_config` call,
bounding memory to one evaluation.
- **config**: `EvaluationConfig` is now `#[non_exhaustive]`; new
builder-style setters (`with_max_recursion_depth`,
`with_max_string_length`, `with_stop_at_first_match`, `with_mime_types`,
`with_timeout_ms`) let external crates construct configurations without
struct literals.
- **parser**: `MagicRule::new()` smart constructor with
`::with_children()`, `::with_strength_modifier()`, `::with_level()`
builder methods and a `::validate()` method enforcing structural
invariants (non-empty message, `level <= MAX_LEVEL`, children nested
strictly deeper than parent). New `MagicRuleValidationError` error type.
- **parser**: `RegexFlags::with_case_insensitive()` and
`::with_start_offset()` builder methods.

### Refactor

- **engine**: Extract `evaluate_pattern_rule()` and
`evaluate_value_rule()` helpers from
`evaluate_single_rule_with_anchor`'s 90-line body. Dispatch is now a
two-arm type-category split; each helper has focused rustdoc on
semantics and invariants.
- **types**: Replace the `_ =>` catch-all in
`bytes_consumed_with_pattern` with an explicit listing of the
fixed-width `TypeKind` variants. Adding a new variable-width variant
without updating this match is now a compile error instead of a silent
relative-offset anchor corruption in release builds.
- **parser**: Split the 185-line `type_keyword_to_kind` match into
per-family helpers (`byte_family`, `short_family`, `long_family`,
`quad_family`, `float_family`, `double_family`, `date_family`,
`qdate_family`, `string_family`). Drops the
`#[allow(clippy::too_many_lines)]` attribute.
- **main**: `main()` returns `std::process::ExitCode` instead of calling
`process::exit`, so destructors run on the happy path. Ctrl-C
`AtomicBool` flag uses `Ordering::Relaxed` instead of `SeqCst`.
- **grammar**: `parse_strength_directive` uses nom 8's `preceded` +
`Parser::map` instead of the legacy `map(pair(char(...), parse_number),
|(_, n)| ...)` pattern.
- **output**: Add `#[serde(skip_serializing_if = "Option::is_none",
default)]` to public `Option<T>` fields so JSON output no longer emits
`"field": null` for unset optional values.

### Documentation

- **lib**: Add `# Security` sections to
`MagicDatabase::with_builtin_rules`, `::with_builtin_rules_and_config`,
`::load_from_file`, and `::load_from_file_with_config` warning about the
unbounded default timeout and recommending
`EvaluationConfig::performance()` for untrusted input.
- **lib**: Document `MagicDatabase: Send + Sync` for parallel scanning.
- **README**: Update `TypeKind` enum example to match the current AST,
add `regex` and `search/N` to the supported types table, add pre-1.0 API
stability warning, correct the roadmap to mark v0.2-v0.4 as shipped.
- **AGENTS.md**: Relabel "Currently Implemented (v0.1.0)" and "Current
Limitations (v0.1.0)" to v0.5.0 and rewrite the Development Phases
section to reflect actual shipped scope.

### Testing

- Security regression tests for S-H1 (planted-magic-file in cwd), S-H2
(TOCTOU path-swap contract), S-M2 (pathological regex bounded runtime),
S-L2 (codegen message escape round-trip), and GOTCHAS S13.1
(`EvaluationConfig::default()` unbounded timeout invariant).
- Backspace message concatenation regression tests for first-match,
consecutive, and empty-rest edge cases.
- `MagicRule::validate()` tests covering empty message, child level
invariant, and max-depth rejection.
- `RegexCache` population/clear/reuse tests.

### Breaking Changes

- **parser**: `parse_text_magic_file` return type changed from
`Result<Vec<MagicRule>, ParseError>` to `Result<ParsedMagic,
ParseError>`. Callers must destructure `ParsedMagic { rules, name_table
}`. Low-level callers that only need the rule list can use
`parsed.rules`. `load_magic_file` and `load_magic_directory` return the
same new type.
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

evaluator Rule evaluation engine and logic size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Evaluator: add debug-level tracing for skipped rules

1 participant