fix(file-tools): normalize separators for POSIX sensitive-path denylist on Windows - #78653
fix(file-tools): normalize separators for POSIX sensitive-path denylist on Windows#78653andrexibiza wants to merge 2 commits into
Conversation
…st on Windows On Windows hosts the sensitive-path write guard compared ntpath-normalized backslash forms against POSIX denylist prefixes (/etc/, /boot/, ...), failing open for system targets; native Windows local also casefolds so Git Bash-equivalent spellings (/Etc/hosts) cannot bypass. Regression tests cover backslash rewriting, case variants, and safe-path behavior. Fixes NousResearch#76246 Note: open PR NousResearch#76247 covers the same normalization; if both land, the later merge drops the duplicate hunks. Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
|
Status check from the worktree-honesty class review — this PR is yours and stays yours; coordination only. Findings: (1) CI is RED on the current head (runs 30930891109 + 30931082237 both failed; job detail not exposed via API) — needs a green run before it can merge. (2) Dedup flag: open PR #76247 covers the same separator/casefold normalization — verify overlap before both merge. (3) It composes with #78806 (different hunks of _check_sensitive_path; small trivially-resolvable conflict at the hermes-config block boundary expected). (4) It fixes sibling issue #76246, NOT the #78565 cluster — fine, but the body should say so. Want me to run the failing CI jobs locally and post the root cause? Credit: the Windows separator normalization approach here is the right fix for #76246 — the class review confirms it. |
monerostar
left a comment
There was a problem hiding this comment.
Native Win11 verification (monerostar)
Host: Windows 11 build 26200, sys.platform=win32, Python 3.11.15 (Hermes venv). PR head 2d33a223.
Bug reproduces on current main (fail-open)
Swapped in upstream/main tools/file_tools.py on this host. _check_sensitive_path ALLOWs every POSIX denylist target because os.path.normpath rewrites them to backslash form that no longer matches /-prefixed denylist entries:
| input | os.path.normpath |
main |
|---|---|---|
/etc/hosts |
\etc\hosts |
ALLOW |
\etc\hosts |
\etc\hosts |
ALLOW |
/Etc/hosts |
\Etc\hosts |
ALLOW |
/Etc./hosts |
\Etc.\hosts |
ALLOW |
/var/run/docker.sock |
\var\run\docker.sock |
ALLOW |
\boot\grub\grub.cfg |
\boot\grub\grub.cfg |
ALLOW |
%TEMP%\hermes-safe-write.txt |
(native temp) | ALLOW (expected) |
So the write guard is currently a no-op for these spellings on native Windows local.
PR head closes the hole
Same cases under this branch (TERMINAL_ENV=local, casefold_local=True):
| input | PR head |
|---|---|
/etc/hosts, \etc\hosts |
BLOCK |
/Etc/hosts, /Etc./hosts, /ETC/HOSTS |
BLOCK (casefold + trailing-dot strip) |
/var/run/docker.sock, \var\run\docker.sock |
BLOCK |
/boot/grub/grub.cfg, \boot\grub\grub.cfg |
BLOCK |
/tmp/safe_file.txt |
ALLOW |
%TEMP%\hermes-safe-write.txt |
ALLOW |
Helper sanity: \etc\hosts → posix /etc/hosts; /Etc./hosts → casefold /etc/hosts.
Tests
pytest tests/tools/test_file_write_safety.py tests/tools/test_file_tools.py \
-k "sensitive or Sensitive or hosts or boot or private" -o addopts=
→ 14 passed, 62 deselected
Broader file-tool run: 73 passed, 3 failed — all pre-existing Windows suite noise unrelated to this diff (0o600 mode bits; mock expects /tmp/... vs actual \tmp\...).
Notes for maintainers
- Sibling: open #76247 covers the same fail-open class and ships
tests/tools/test_file_write_safety.pycoverage. This PR is a smaller standalone production-only hunk (+63/−9, 1 file). Prefer merging one; the later should drop duplicate logic. Live evidence here supports the behavior, not a preference between the two. - Commit message claims “Regression tests cover …”; this branch does not add tests (only
tools/file_tools.py). Either pull the #76247 tests forward or drop that claim. - CI on this PR currently only shows skipped label-rerun jobs — no full required check rollup visible from here. Worth a push/re-run so “All required checks pass” lights up.
- Could not leave a formal Approve (fork collaborator scope) — evidence comment only.
Verdict: fix is real and high-confidence on native Win11; good candidate once CI is green and the #76247 overlap is resolved.
Add TestCheckSensitivePathWindowsHostSemantics from PR NousResearch#76247 (fangliquanflq) to this branch so the claimed regression coverage actually exists here: backslash normalization, Win32 casefold, trailing-dot/space aliases, and Hermes-config identity checks for write_file and patch on native Windows local. Co-authored-by: fangliquanflq <fangliquan@qq.com>
|
Fixed in 40efdc9. Thanks for the native Win11 verification, monerostar — that evidence table is exactly what this class of bug needs. Addressed points:
Local validation (Windows, git-bash, via
Local native-Win11 evidence for the casefold path (matching your table): |
|
suggesting changes
Security evidence:
Review setup: I reviewed a run-owned local rebase or patch replay against current GitHub Not checked:
Signed: GPT-5.6-luna-max in Codex |
Related #76246 #76247 #78565 #78658 #78806
Note
Topology adjudicated on 2026-08-19: closed as a duplicate of #76247 after exact file-level comparison. Both PRs change the same two files and their complete patches are byte-for-byte identical. #76247 is the older implementation and owns the full review/fix history; this branch's test-import commit preserves @fangliquanflq credit with
Co-authored-by. The surviving path is #76247.This work fixes #76246 only. #78565 is a separate git-worktree
.gitmanaged-state corruption class and remains open. Its current class-closing implementation is open PR #78806; closed PR #78652 is the unmerged pointer-file foundation subsumed into that branch. This PR is not part of #78565.Summary
On Windows hosts, the file-tool sensitive-path write guard fails open for POSIX system
targets (
/etc/...,/boot/...,/var/run/docker.sock):ntpath/Pathrewritingproduces backslash forms that no longer match the
/-prefixed denylist, while the shelllayer can later restore the POSIX path and attempt the write. Native Windows local
backends are also case-insensitive and ignore trailing dots/spaces in ordinary path
components, so Git Bash-equivalent spellings (
/Etc/hosts,/Etc./hosts) bypass theguard.
Fix
tools/file_tools.py—_check_sensitive_pathcompares denylist entries againstslash-normalized forms (
_posix_form_for_sensitive_check); on native Windows localbackends the comparison additionally strips Win32 trailing spaces/dots and casefolds
(
_casefold_sensitive_posix_paths), matching the sink's actual resolution semantics.Container and remote POSIX backends stay case-sensitive. Hermes
config.yamlidentitychecks use the same canonicalization so mixed-case and trailing-dot spellings cannot
bypass the approval-configuration guard.
Verification
The promised tests are present on this branch in
tests/tools/test_file_write_safety.py. They cover:write_fileand V4A patch refusal before file operations are acquired;Current head:
40efdc90061d7abb3c030cd9327178cf9a6ced6b.2d33a223: the current-mainbypass reproduced; protected aliases blocked on the branch; focused run 14 passed,
62 deselected; broader file-tool run 73 passed with three documented pre-existing
Windows harness failures.
3e0d31c40ff0523214d8a7f820b3a91f17c551f7also has successful CI run 30874010869.
Links