Skip to content

test(adapters): collapse the sanitize_path suite, and fix the bypass it found - #13

Merged
hsusul merged 1 commit into
mainfrom
test/sanitize-path-property
Aug 22, 2026
Merged

test(adapters): collapse the sanitize_path suite, and fix the bypass it found#13
hsusul merged 1 commit into
mainfrom
test/sanitize-path-property

Conversation

@hsusul

@hsusul hsusul commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Stacked on #9, #10, #12 — merge those first.

Problem

Two hand-written assertion lists covered one 25-line pure function with 88 assert_eq! lines. 69 of them arrived one per commit — 12% of this repository's entire history is single-assert commits against sanitize_path. That history is unreviewable, and enumerating slash/dot permutations by hand only ever tests inputs someone thought of.

Change

sanitize_path_table — all 87 unique cases preserved verbatim as data, grouped by what each demonstrates. I extracted them mechanically rather than by hand, with a parser that correctly handles Rust raw strings ending in a backslash (r"src\app\"), and cross-checked the extracted count against the assert_eq! count in each block so nothing was silently dropped. Adding a case is now a row, not a commit.

sanitize_path_invariants — six properties that must hold for all input: no .. segment survives, no empty or . segments, never absolute, no control or zero-width characters, no drive prefix, and idempotence.

The property test found a real bug

Not a test problem — a genuine bypass in sanitize_path:

sanitize_path("A\x7f:")                    ->  "A:"              (expected "")
sanitize_path("C\u{200b}:/Users/dev/x.rs") ->  "C:/Users/dev/x.rs"

The drive-letter check tested the raw segment, before control and zero-width characters were filtered out. Slipping any such character between the letter and the colon made the segment longer than 2 bytes, so the length check missed it — then the character was stripped a moment later and the drive prefix survived into the output.

Windows drive-prefix neutralization is a stated boundary-hardening control, so this was a real hole in it, not a theoretical one. Fixed by filtering first and testing the filtered segment. Four regression cases are in the table alongside the property that caught it.

This is the argument for the change in one example: 88 hand-written cases never found it; the property found it on the first run.

Dependency

proptest as a dev-dependency only, default-features = false — drops the fork/timeout machinery and its rusty-fork + wait-timeout deps, keeping the graph small for the egress audit. egress-check.sh still passes.

Verification

Gate Result
cargo fmt --all -- --check pass
cargo clippy … -D warnings pass
cargo test --locked -p lore-core -p lore-ipc --all-targets 346 pass, 4 ignored
cargo test -p lore-core --test no_network_in_archive pass
./scripts/egress-check.sh pass
./scripts/toolchain-pin-check.sh pass
sanitize_path_invariants × 5 runs stable over fresh case sets each run

…it found

Two hand-written assertion lists (`sanitize_strips_traversal` and
`sanitize_path_neutralizes_traversal_and_drive_letters`) had grown to 88
assert_eq! lines covering one 25-line pure function. 69 of those arrived one
per commit — 12% of the repository's history is single-assert commits against
sanitize_path, which is unreviewable and still only ever tests inputs someone
thought of.

Replaced with:
  - `sanitize_path_table`: all 87 unique cases preserved verbatim as data,
    grouped by what they demonstrate. Extracted mechanically (with a parser
    that handles Rust raw strings ending in a backslash, e.g. r"src\app\")
    and cross-checked against the assert_eq! count in each block, so no case
    was dropped in translation. Adding a case is now a row, not a commit.
  - `sanitize_path_invariants`: six properties that must hold for ALL input —
    no `..` segment survives, no empty/`.` segments, never absolute, no
    control or zero-width characters, no drive prefix, and idempotence.

The property test immediately found a real bypass in sanitize_path itself:

  sanitize_path("A\x7f:")  ->  "A:"     (expected "")

The drive-letter check ran against the RAW segment, before control and
zero-width characters were filtered. Putting any such character between the
letter and the colon made the segment longer than 2 bytes, so the check missed
it; the character was then stripped and the drive prefix survived into the
output. "C\u{200b}:/Users/dev/x.rs" leaked through the same way.

Fixed by filtering first and testing the filtered segment. Windows drive
prefix neutralization is a stated boundary-hardening control, so this closes a
real hole in it rather than a theoretical one. Four regression cases added to
the table alongside the property.

proptest is a dev-dependency only, with default-features off (no fork/timeout
machinery) to keep the dependency graph small for the egress audit.

Verified: fmt, clippy, cargo test --locked --all-targets (346 pass / 4
ignored), no_network_in_archive, egress-check.sh, toolchain-pin-check.sh.
The property test was run 5 times over fresh case sets to confirm stability.
@hsusul
hsusul force-pushed the test/sanitize-path-property branch from 0776864 to 4afd3fd Compare August 22, 2026 22:10
@hsusul
hsusul merged commit f1f703d into main Aug 22, 2026
4 checks passed
@hsusul
hsusul deleted the test/sanitize-path-property branch August 22, 2026 22:18
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