Skip to content

merge queue: checking main (2b49294), #387, #390 and #388 together - #397

Closed
mergify[bot] wants to merge 25 commits into
mainfrom
mergify/merge-queue/149ee7daa3
Closed

merge queue: checking main (2b49294), #387, #390 and #388 together#397
mergify[bot] wants to merge 25 commits into
mainfrom
mergify/merge-queue/149ee7daa3

Conversation

@mergify

@mergify mergify Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

✨ Merge queue reset: an external action moved the base branch head to bd7d97c. The pull request #388 has been requeued. ✨

Branch main (2b49294), #387, #390 and #388 are queued together for merge.

This pull request has been created by Mergify to speculatively check the mergeability of #388.
You don't need to do anything. Mergify will close this pull request automatically when it is complete.

Required conditions of queue rule dependabot for merge:

Required conditions to stay in the queue:

---
checking_base_sha: fc2a4a8fc023f53f43e6607e9d517de6b5f5e59e
previous_check_retries: []
previous_failed_batches: []
pull_requests:
  - number: 388
    scopes: []
scopes: []
...

dependabot Bot and others added 25 commits July 20, 2026 03:34
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 7.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Commits](actions/checkout@v6.0.2...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [release-plz/action](https://github.com/release-plz/action) from 0.5.130 to 0.5.131.
- [Release notes](https://github.com/release-plz/action/releases)
- [Commits](release-plz/action@e879257...2eb1d8b)

---
updated-dependencies:
- dependency-name: release-plz/action
  dependency-version: 0.5.131
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) from 4.37.0 to 4.37.1.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@99df26d...7188fc3)

---
updated-dependencies:
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.37.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
…373)

## Problem

`just lint-rust` (`cargo clippy --workspace --all-targets --all-features
-- -D warnings`) fails on `main`:

```
error: multiple versions for dependency `bitflags`: 1.3.2, 2.13.1
  = note: `-D clippy::multiple-crate-versions` implied by `-D warnings`
```

This reproduces locally and blocks all open PRs (they inherit the break
from `main`).

## Root cause

`6047619` bumped `jiff 0.2.27 -> 0.2.32`. jiff enters the graph **only**
through `env_logger`'s default `humantime` feature (`humantime =
["dep:jiff"]`), which env_logger uses to render log timestamps. jiff
0.2.32 newly pulls `defmt -> bitflags 1.3.2`, colliding with the
`bitflags 2.x` used everywhere else. The dup is present in the
**default** build graph (not just `--all-features`).

## Fix

We only call `env_logger::init()` (`src/main.rs:242`) and never render
log timestamps, so `humantime` is dead weight. Disable env_logger's
default features and keep `auto-color` + `regex` (RUST_LOG filtering):

```toml
env_logger = { version = "0.11", default-features = false, features = ["auto-color", "regex"] }
```

This removes `jiff`/`defmt`/`bitflags 1.3.2` from every build config at
the source -- **no clippy `allow`, no transitive-version pin**, so the
strict deny-all lint policy stays intact.

## Verification

- `cargo clippy --all-features -D warnings` -- pass
- `cargo clippy --no-default-features -D warnings` -- pass
- `cargo build --release --all-features` -- pass
- `rmagic --version` runs with `RUST_LOG=debug` logging intact (color +
filtering)
- `Cargo.lock` pruned of `jiff`, `jiff-static`, `defmt`, `defmt-macros`,
`defmt-parser`, `bitflags 1.3.2`

## Note (separate, pre-existing)

`just ci-check` also fails at `dist-plan` with `dist 0.32.0 vs
cargo-dist-version = 0.31.0 in Cargo.toml` -- a mismatch introduced by
`83b3ec3` bumping the mise `cargo-dist` tool without updating
`Cargo.toml`. Unrelated to this change; tracked separately.

## Test plan

- [x] clippy (all-features + no-default-features)
- [x] release build
- [x] CLI smoke test with logging
- [ ] CI green on this branch

---------

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
)

This pull request primarily makes two changes: it fixes the enforcement
of workspace lints by moving the `[lints] workspace = true` section in
`Cargo.toml` to the correct location, and it cleans up the formatting of
`CHANGELOG.md` by ensuring a consistent separation between sections.
Additionally, it removes the file exclusion list from `.mdformat.toml`.

The most important changes are:

**Lint enforcement:**
* Moves `[lints] workspace = true` to the correct position in
`Cargo.toml` to ensure workspace-wide linting is actually enforced.
Previously, this section was misplaced and thus inert.
[[1]](diffhunk://#diff-2e9d962a08321605940b5a657135052fbcef87b5e360662bb527c96d9a615542L35-L39)
[[2]](diffhunk://#diff-2e9d962a08321605940b5a657135052fbcef87b5e360662bb527c96d9a615542R220-R224)

**Changelog formatting:**
* Adds consistent blank lines and generated-by comments between sections
in `CHANGELOG.md`, improving readability and ensuring automated
changelog tools work as intended.
[[1]](diffhunk://#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edL5)
[[2]](diffhunk://#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edR16)
[[3]](diffhunk://#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edR28)
[[4]](diffhunk://#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edR40)
[[5]](diffhunk://#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edR56)
[[6]](diffhunk://#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edR69)
[[7]](diffhunk://#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edR103)
[[8]](diffhunk://#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edL147-R176)
[[9]](diffhunk://#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edR188-R212)
[[10]](diffhunk://#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edR230)
[[11]](diffhunk://#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edR245-R253)
[[12]](diffhunk://#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edR281)

**Formatting configuration:**
* Removes the exclusion list from `.mdformat.toml`, likely to simplify
or update markdown formatting rules.

---------

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…om system magic DB (#376)

> **PR at a glance** — 62 commits · 86 files (+8,202 / −1,157) ·
substantive review surface **39 files** (+5,363 / −484 across
`src`/`tests`/`docs`) · **Risk: Medium** · **1607 tests + 184 doctests
green**, clippy/fmt clean (all + no-default features) · **0 differential
regressions** vs GNU `file` (file-5.41)
>
> Most of the raw file count is pre-existing CI/chore baseline this
branch stacks on (see **Stacking** below). The real review surface is
the ~39 source/test/doc files. Best read **commit-by-commit** — each fix
is one logically-scoped, GOTCHAS-referenced commit, and the correctness
fixes were each proven by a monotonic before/after differential against
the real `file` binary.

---

## Summary

Loading the macOS-shipped magic DB fatally aborted analysis of **every**
target:

```
$ rmagic --magic-file /usr/share/file/magic/ ./Cargo.toml
Evaluation error: Type reading error: Unsupported type: regex without string pattern
```

`assembler` sorts early and its top-level `regex` rules (e.g. `0 regex
\^[\040\t]{0,50}\\.asciiz`) run for every file, so one per-rule read
error propagated to the top and aborted the whole DB. This PR fixes both
the fatal abort (**floor**) and makes the affected `regex` rules resolve
**correctly** to match GNU `file` semantics (**target**).

Plan:
`docs/plans/2026-07-17-001-fix-system-magic-regex-graceful-plan.md`
(gitignored; local).

## What changed (the 8 regex-fix commits in this PR)

The substantive change is the 8 commits from `a1897d1` onward
(`fix(evaluator)…` through `test: serialize…`). Earlier CI/chore commits
in the range are pre-existing baseline that this branch stacks on (see
**Stacking** below).

1. **Parser getstr fidelity** (`src/parser/grammar/getstr/`) — `regex`
patterns are now resolved to a `Value::String` using GNU `file`'s
`apprentice.c::getstr` escape table (`\t`→tab, octal `\040`→space,
`\xNN`→byte, `\\`→`\`, unknown-escape drops the backslash so `\^`→`^`).
Escape-produced bytes `>= 0x80` are re-encoded as regex-native `\xHH` in
the pattern text (a raw high byte can't go into a UTF-8 `String`, and
`parse_text_magic_file` is fail-fast — GOTCHAS S3.11). The escape table
was **derived from upstream source, not inferred**; `\d`/`\s`/`\w`
demote to literals, matching libmagic.
2. **Evaluator `Value::Bytes` backstop** (`src/evaluator/types/mod.rs`)
— both `Regex` read arms (and `bytes_consumed_with_pattern`) now accept
`Value::Bytes`, mirroring `Search`, removing the long-standing
Regex/Search asymmetry (GOTCHAS S2.4). Lossy UTF-8 decode emits a
`warn!` on real substitution.
3. **Narrow graceful skip** (`src/evaluator/engine/mod.rs`) — the
pattern-missing `UnsupportedType` condition is now caught-and-skipped at
all three engine catch sites; genuine capability gaps and the regex
compile-size DoS guard **still propagate** (`debug!` for
missing-pattern, `warn!` for compile-size). Pinned by a narrowness
negative test (R3).
4. **`regex::bytes` unicode fix** (`src/evaluator/types/regex.rs`) —
`build_regex` now sets `.unicode(false)` so `\xHH` high-byte escapes
match the **raw byte**, not the UTF-8 encoding of the codepoint. This
was a genuine, independently-discovered correctness bug that would have
silently broken the `>= 0x80` contract; proven non-vacuous by revert and
pinned with a regression test.
5. **`parse_hex_bytes` truncation fix** (`src/parser/grammar/value.rs`)
— bareword hex-lookalike tokens (`4a[42`) previously truncated to
`[0x4a]` and leaked the remainder; now require a token boundary.

## Testing (accuracy-first)

Correct output is the product, so the suite proves correctness, not just
non-crash:

- **Content-fidelity table** asserting exact resolved regex text for
every escape class (incl. the `>= 0x80` → `\xHH` path).
- **Positive AND negative fixtures for all 7 affected `assembler` regex
rules**, plus quantifier-boundary and escaped-dot-not-wildcard proofs.
- **Gated system-DB load test** + **differential parity against GNU
`file`** (`tests/system_magic_dir.rs`) — both gates run when
`/usr/share/file/magic/` and the `file` binary are present; parity held
on this host against `file-5.41`.
- All three engine catch sites tested independently; property-based
fuzzing (proptest) caught the `bytes_consumed` third-site bug now
closed.

Verification: `cargo clippy --all-features` and `--no-default-features`
clean (`-D warnings`); `cargo fmt --check` clean; full suite **1541
passed / 0 failed / 6 skipped**, deterministic over repeated runs;
doctests 182/0; floor repro exits 0.

A new `.config/nextest.toml` serializes the process-spawning integration
tests (the planted-magic CLI security tests + the new
differential-parity suite) into a single-threaded group, removing a rare
load-dependent spawn/cwd flake while keeping the ~1500 unit tests fully
parallel.

## Post-review hardening (multi-agent review outcome)

A four-agent review (general code, test coverage, silent-failure,
comment accuracy) verified the fix empirically — **no Critical or
Important findings**; all four confirmed full-suite green, live
differential parity, and the getstr table matching upstream
`apprentice.c` source byte-for-byte. The converged actionable gaps were
then **closed in-branch** (16 new tests, 1525 → **1541**):

- Test for the getstr empty-resolve `Err` path (the fatal-abort class
this fix targets); documented that a lone trailing backslash is instead
*recovered* as `Value::Bytes` by the `parse_value` fallback.
- Content-fidelity rows for the 5 previously-untested named control
escapes (`\a \f \n \r \v`).
- Extracted the 3 "missing pattern operand" messages into shared
`const`s (drift-proof) + engine-level graceful-skip proofs for `search`
and flagged-`string` (not just `regex`) at all three catch sites.
- U7 behavioral round-trip (corrected hex-lookalike literal actually
matches a buffer).
- 3-site parity for the compile-failure `warn!` skip path.
- Log-capture tests (`testing_logger` dev-dep, BSD-3, deny/audit clean)
pinning the `debug!`/`warn!` contracts — including the CWE-1333
compile-size signal.
- Removed a dead condition in the getstr resolver; doc polish in GOTCHAS
§2.12.

## Known caveat — pre-existing, NOT introduced by this PR (needs a
decision)

At the **default** CLI config, `stop_at_first_match: true` (GOTCHAS
S13.2) lets an earlier message-less top-level rule shadow more specific
matches, so `rmagic --magic-file /usr/share/file/magic/ <asm-file>` now
completes (no fatal error) but can emit a **blank** description where
GNU `file` prints "assembler source text, ASCII text". This reproduces
for plain ASCII with no assembler content, so it is a general
pre-existing evaluator-default behavior, **not** caused by this diff —
the differential-parity test confirms rule-level correctness by using
`with_stop_at_first_match(false)`.

This is a strict improvement over the prior behavior (fatal error on
every file → completes), never a regression. But it means the CLI's
real-world output for an assembly file still isn't fully at GNU-`file`
parity. Two adjacent gaps: (a) the `stop_at_first_match` + empty-message
shadowing, and (b) `rmagic` returns empty where `file` falls back to
"ASCII text" (missing text/data fallback). Both are crate-wide
evaluation-semantics concerns deliberately out of scope for this regex
fix and would each warrant their own plan; flagged here for a conscious
decision rather than a silent tracking issue.

## Stacking

Stacks on the CI-fix commits and PR #373
(`fix/drop-env_logger-humantime-bitflags-dup`). Base should be
reconciled (rebase onto `main`) once #373 and the CI baseline land. The
8 regex commits are the reviewable unit.

## CI Status — failing on pre-existing toolchain-setup breakage, NOT
this code

The CI checks (`test`, `quality`, `audit`, `Compare Benchmarks`,
Compatibility Tests, `copilot-setup-steps`) fail **inside the
`jdx/mise-action` setup step, before any code compiles**, with:

- `cargo-binstall failed` → `Failed to install tools: cargo:cargo-audit,
cargo:mdbook-i18n-helpers, cargo:mdbook-linkcheck`
- `error: could not read component file:
…/manifest-rust-std-x86_64-unknown-linux-gnu: No such file or directory`
- `mise cache not found` / corrupted `cargo-binstall … bin_paths` cache
file

This is the pre-existing "#373 CI failing again" toolchain/mise-action
breakage this branch stacks on — the runners cannot set up the Rust
toolchain or install dev tools, so every Rust job fails identically at
the environment step. **No change to this diff can fix it**, and it is
out of scope for the regex fix. It needs the separate CI investigation
the plan already carved out.

**Local verification (authoritative for this code)** all passes: `cargo
clippy --all-features` and `--no-default-features` (`-D warnings`)
clean; `cargo fmt --check` clean; `cargo nextest run --all-features` →
**1541 passed / 0 failed / 6 skipped** (deterministic over repeated
runs); doctests **182 passed / 0 failed**; floor repro exits 0; live
differential parity against `file-5.41` passes. **DCO passes** in CI
(all commits sign-off'd). Re-run CI after the toolchain/mise-action
issue (and #373) is resolved.

🤖 Prepared for maintainer review — **not merged** (maintainer controls
all merges).



---

## Additional fixes landed in this PR (beyond the original
regex-graceful scope)

Once the DB loaded and evaluated end-to-end, follow-on issues surfaced;
per the "don't leave residuals / accuracy-first" direction they were
fixed in-band rather than deferred:

6. **`stop_at_first_match` message-less shadowing + text/data fallback**
(`4c55a34`, `src/evaluator/engine/mod.rs`, `src/output/ascmagic.rs`,
`src/lib.rs`) — a message-less top-level gating rule that matched under
the default config (`stop_at_first_match: true`) halted evaluation
before a later, more specific rule, producing a **blank** description.
The stop gate is now conditioned on a match (or descendant) carrying
usable text (`has_message_bearing_match`), and a GNU `file`-style
text/data classifier (`classify_fallback`: `empty`/`ASCII text`/`UTF-8
Unicode text`/`data`) ensures a readable file never yields blank output.
(GOTCHAS S13.2, S13.3)
7. **Bare `&MASK` semantics** (`f8d1e56`,
`src/evaluator/operators/bitwise.rs`) — `apply_bitwise_and` implemented
magic(5)'s bare `&` as `(v & l) != 0` ("any bit"); real libmagic
`magiccheck()` is `(v & l) == l` ("all bits"). Verified by A/B against
the real `file` binary (a ~17-bit AIX-core mask was spuriously matching
nearly any binary blob). Strictly stricter — single-bit flag masks (the
vast majority) are provably unaffected.
8. **Host-adaptive system-DB tests + portable end-to-end guards**
(`d85aecf`, `tests/system_magic_dir.rs`) — the assembler tests hardcoded
that `/usr/share/file/magic/` contains the source rules. That holds on
macOS but **not** on Ubuntu/Debian, which ship only the compiled
`magic.mgc` and leave that dir empty — so `file --magic-file` and rmagic
both correctly report `ASCII text`. Tests now assert **parity with real
`file` on the same `--magic-file` DB** (absolute assembler expectation
gated on the host DB actually carrying the rule), plus two
**host-independent** temp-magic-file guards that exercise the
S13.2/S13.3 fixes on every CI platform. Verified locally on macOS and in
a Debian container reproducing the empty-dir Ubuntu condition. Also
fixed a filename-contamination bug (`file` stdout includes the path, so
a bare `"assembler"` substring matched the filename `assembler.s`).

### CI infrastructure fixes

- **Toolchain conflict** (`a5a3959`, `2a52af7`) — resolved a mise/rustup
rust-toolchain conflict that was failing all CI jobs; scoped per-job
`install_args`.
- **Cross-platform exec auto-install** (`f8fabf4`) —
`test-cross-platform` (gated on `test`, long red) ran for the first time
and hit `mise.toml`'s `exec_auto_install = true`, which made `mise x`
install the entire dev toolset before running; several `cargo:` tools
have no macOS/Windows prebuilt (compile fallback disabled), so it
fatally failed there. Set `MISE_EXEC_AUTO_INSTALL=false` scoped to that
job so `mise x` uses only `rust cargo:cargo-nextest`.

Learnings captured in
`docs/solutions/integration-issues/loading-real-system-magic-db-getstr-rawbyte-graceful-skip-2026-07-17.md`.

**CI status:** all required checks green (quality, test,
test-cross-platform ×4, coverage) plus all Compatibility Tests
(macOS/Ubuntu/Windows).


---

## Further correctness fixes from the rmagic-vs-`file` differential loop

After the DB loaded cleanly, a systematic differential against real GNU
`file -b` (system magic DB, file-5.41) surfaced more genuine
wrong/blank/misleading output. Each was fixed with a regression test
verified against real `file` and a monotonic before/after differential
(improvements, 0 regressions). GOTCHAS references are authoritative.

- **Line-tolerant runtime loading** (`d063be9`) — an unparseable rule
now skips itself + its deeper-indented subtree with a `warn!` instead of
dropping the whole file. Recovered ~21 real system files
(gzip/jpeg/pdf/linux/windows had been lost over a single unsupported
rule). Build-time codegen stays strict. (GOTCHAS S3.11)
- **Multi-fragment descriptions** (`6bb3fd2`) — `stop_at_first_match` no
longer truncates child/continuation siblings; strength sort is
top-level-only. gzip now renders its full `..., from Unix, original size
...` chain in file order. (GOTCHAS S13.4)
- **XML/plist detection** (`4779d0b`, `00b28e4`, `900b901`) — magic(5)
`\ ` is a literal space, and an unknown escape drops the backslash (`\<`
→ `<`, `\^` → `^`) across all three bareword paths, matching
`apprentice.c::getstr`. `0 string \<?xml\ version=` now matches → `XML
document text`. (GOTCHAS S2.12, S3.12)
- **String ordering full-field render + `%.Ns` precision** (`f876aa0`) —
an ordering-op `string` compares the `pattern.len()` prefix but renders
the full field; `%.3s` truncation implemented. `XML 1.0 document text`
(was `XML 1`). (GOTCHAS S14.3)
- **String barewords never parse as numbers** (`32045a3`) — `0 string
>0` compares the literal byte `'0'`, not `Uint(0)`; restored the
pervasive `>0 ... %s` idiom (name/face/palette/version). (GOTCHAS S3.6)
- **Non-UTF-8 bareword → `Value::Bytes`** (`e293698`) — high-byte
signatures (OS/2 INF `HSP\x01\x9b\x00`) no longer lossy-corrupt to a
mismatching `String`. (GOTCHAS S6.7)
- **`offset == EOF` permitted** (`9b0a480`) — truncated LUKS headers
render their empty `string x` children (`LUKS ... [,`) matching `file`.
(GOTCHAS S15.1)
- **Message-bearing `clear`** (`98b4718`, `3eea76b`) — `>>&0 clear x
program text` emits its fragment (`c program text`, was `c`). (GOTCHAS
S13.6)
- **`use` name-line message** (`f3c4e5a`) — a subroutine's `name`-line
description is emitted at the use site with no separator (Mach-O `[`,
matlab4, algol_68). (GOTCHAS S14.4)
- **Bare `search` (no `/N`)** (`3c1b250`) — accepted as scan-to-EOF
(`range: Option<NonZeroUsize>`); recovers PDF page count, VCF/SAM/ICC,
sfnt name tables. (GOTCHAS S2.13)
- **`use \^name` endian-flip** (`aeda456`, closes the value-read half of
#236) — flips LE↔BE for endian-bearing reads inside a `\^` subroutine
(mirrors libmagic `cvt_flip`), toggling + propagating into nested `use`.
Byte-for-byte BE-TIFF parity + single-arch Mach-O dylib fix; 798-file
differential = 40 improvements, 0 regressions. (GOTCHAS S16)
- **rustdoc intra-doc link fix** (`d4f598f`) — unblocks the `docs.yml`
build job.

## Follow-on issues (deferred work, concretely tracked)

Work surfaced but intentionally **not** in this PR, each filed as a
tracked issue:

- **#377** — compiled-in structural detectors (JSON/CSV/TAR/CDF + `#!`
shebang interpreter scripts) needing native Rust ports.
- **#378** — Mach-O universal per-arch inner classification + indirect
base-offset (the `[ x86_64]` bracket detail); also owns the `\^`
**indirect-offset** flip remainder of #236.
- **#379** — strength-formula divergence from libmagic scale (numerics
underweighted vs search/regex); includes the dtrace `c program text`
over-match example.
- **#380** — `%f`/`%e`/`%g`/`%F` float format specifiers in
`format_magic_message`.
- **#381** — sfnt/TrueType name-table string rendering divergence
(nested indirect offset + `lestring16`).
- **#382** — append ascmagic text-class to matched magic descriptions
(`, ASCII text` combined classification).
- **#383** — CLI broken-symlink reporting + symlink follow policy
(`-L`/`-h`) for `file` parity.
- **#384** — parser support for constructs the tolerant loader currently
skips (`guid` [67 rules], `ubeqdate`, `der`, indirect-offset variants).

#236 carries a comment documenting the done (value-read) / deferred
(indirect-offset → #378) split.


---

## Risk assessment

**Overall: Medium** — a large diff touching parser/evaluator core, but
every behavior change is bounded by a regression test and a monotonic
differential against real GNU `file` (0 regressions across the branch).

| Factor | Level | Basis / mitigation |
|--------|-------|--------------------|
| **Size** | High | 86 files / ~9.3k lines — but dominated by stacked
CI/chore baseline; substantive surface is ~39 files. Mitigated by
one-fix-per-commit grouping and GOTCHAS cross-refs. |
| **Complexity** | Medium-High | Changes land in the nom parser and the
evaluation engine (offsets, pattern types, meta-types, endian-flip).
Mitigated by extensive GOTCHAS documentation (S2–S16) and differential
parity tests. |
| **Memory safety** | Low | Pure Rust, **no new `unsafe`** (the single
vetted memmap2 exception is unchanged); bounds-checked `.get()` access;
`checked_add` on offsets; no `unwrap`/`expect`/`panic!` in library code.
|
| **libmagic/GNU `file` compatibility** | Low | Each of the ~15
correctness fixes was A/B-verified against `file-5.41` and shipped with
a monotonic before/after differential (improvements + **0
regressions**). Accepted edge cases are documented (e.g. the single
`magic.mgc` VCF case in GOTCHAS S2.13). |
| **Test coverage** | Low | Suite grew to **1607 nextest + 184
doctests**; each fix has positive + negative + (where applicable)
differential coverage; gated system-DB parity tests run when
`/usr/share/file/magic` + `file` are present. `codecov/patch` gate
passing. |
| **Security** | Low-Medium | This branch is also the v0.5.x hardening
line: regex compile-size DoS guard (CWE-1333), an 8192-byte regex scan
cap, a log-flood guard on untrusted pattern bytes, and the narrow
allowlisted graceful-skip contract (GOTCHAS S2.1). No secrets, no new
external input surface. |

## Review checklist

**General**
- [x] One logical change per commit; conventional-commit messages; DCO
sign-off + GPG on every commit
- [x] No debug/`println!` left in library code; no sensitive data
exposed

**Memory safety & error handling (Rust / this project)**
- [x] No new `unsafe` blocks (workspace `unsafe_code = "deny"` intact)
- [x] No `unwrap()`/`expect()`/`panic!` in library code (tests exempt)
- [x] Buffer access bounds-checked (`.get()`); offset math uses
`checked_*`
- [x] Errors propagate via `Result`/`thiserror`; the only silencing is
the documented narrow graceful-skip (GOTCHAS S2.1)

**Quality gates**
- [x] `cargo clippy -D warnings` clean — `--all-features` **and**
`--no-default-features`
- [x] `cargo fmt --check` clean
- [x] `cargo nextest run --all-features` — 1607 passed / 6 skipped
- [x] `cargo test --doc` — 184 passed
- [x] `cargo doc --document-private-items` builds (no broken intra-doc
links)

**libmagic compatibility & docs**
- [x] Behavior changes validated by differential vs GNU `file`
(monotonic, 0 regressions)
- [x] GOTCHAS.md updated for every non-obvious behavior; AGENTS.md kept
accurate (not aspirational)
- [x] Public-API docs carry rustdoc examples

**Reviewer verification suggestions**
- [ ] Spot-check the graceful-skip narrowness negative test
(`test_evaluate_rules_propagates_non_pattern_missing_unsupported_type`)
— confirms genuine capability gaps still abort
- [ ] Confirm the `\^` endian-flip TIFF oracle
(`tests/endian_flip_use_tests.rs`) matches your reading of libmagic
`cvt_flip`
- [ ] If you have a non-macOS host, confirm the gated system-DB tests
skip cleanly (they assert parity only when the DB + `file` are present)

## Reviewability notes

- **Splitting was considered and is impractical now**: the 62 commits
are a stacked, interdependent line (the graceful-load floor →
correctness fixes each build on the loaded DB). The commit-by-commit
view plus GOTCHAS cross-references is the intended review path;
splitting mid-line would break the differential-verified progression.
- **CI/chore baseline** (mise-action bumps, cargo-dist, lint enablement)
is separated out in the **Stacking** note above and is not part of the
substantive review surface.
- Two review-feedback rounds (multi-agent local review +
CodeRabbit/Copilot) are already resolved in-branch; deferred follow-ups
are tracked in #391 (maintainability refactors) and #392 (cargo-dist
release.yml pinning).

---------

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Co-authored-by: dosubot[bot] <131922026+dosubot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
## 🤖 New release

* `libmagic-rs`: 0.10.0 -> 0.11.0 (⚠ API breaking changes)

### ⚠ `libmagic-rs` breaking changes

```text
--- failure enum_tuple_variant_changed_kind: An enum tuple variant changed kind ---

Description:
A public enum's exhaustive tuple variant has changed to a different kind of enum variant, breaking possible instantiations and patterns.
        ref: https://doc.rust-lang.org/reference/items/enumerations.html
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.48.0/src/lints/enum_tuple_variant_changed_kind.ron

Failed in:
  variant MetaType::Use in /tmp/.tmp6SdjRa/libmagic-rs/src/parser/ast.rs:370
```

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

<blockquote>

## [0.11.0] - 2026-07-20

### Bug Fixes

- **deps**: Drop env_logger humantime feature to remove bitflags dup
([#373](#373))
- **evaluator,parser**: Gracefully and correctly handle regex rules from
system magic DB
([#376](#376))

### Miscellaneous Tasks

- Regenerate mise.lock so rust@latest resolves under --locked
([#342](#342))
- **settings**: Add cargo settings for binstall_only option
<!-- generated by git-cliff -->
</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>
…t access (#371)

## Summary

Follow-up to #370 addressing its two review comments, which merged
before the fixes could land.

1. **attest-build-provenance v4.1.0 -> v4.1.1** (Copilot review on
#370). The `[dist.github-action-commits]` pin in `dist-workspace.toml`
is the source of truth for the SHA `dist generate` writes into
`release.yml`. The pin sat at v4.1.0 (`a2bbfa25`) while the pre-#370
workflow already ran v4.1.1 (`0f67c3f`, latest), so #370's regeneration
silently *downgraded* it — and that shipped in v0.10.0. This bumps the
pin to v4.1.1 and regenerates, restoring the latest release. Verified
`dist generate` is a no-op afterward (config and workflow agree).

2. **Bounds-checked test assertion** (CodeRabbit review on #370).
`rule_path[0]` -> `rule_path.first().map(String::as_str)` in
`test_complex_evaluation_result`, per the project's memory-safety
guideline (all buffer access via bounds-checked methods). Behavior
unchanged; `assert_eq!` diagnostic retained.

## Test plan

- [x] `cargo clippy --all-targets -- -D warnings` clean
- [x] `cargo nextest run test_complex_evaluation_result` passes
- [x] `dist generate` produces zero drift (workflow matches the bumped
pin)
- [ ] CI green

## Note

The recurring dependabot-vs-dist drift on `actions/checkout` (bumps
`release.yml` to v7.0.0, dist wants the pinned v6.0.2) is still open —
worth ignoring `actions/checkout` in the github-actions Dependabot
ecosystem so it stops re-breaking the plan check.

---------

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@mergify

mergify Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Merge queue reset: an external action moved the base branch head to bd7d97c

@mergify mergify Bot closed this Jul 21, 2026
@mergify
mergify Bot deleted the mergify/merge-queue/149ee7daa3 branch July 21, 2026 03:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant