Shxiao fa89a12526
fix(sandbox): mask output tails into POSIX-style virtual paths (#5247)
* fix(sandbox): mask output tails into POSIX-style virtual paths

The output maskers slice the matched path tail from the original
output. With separator-agnostic matching, a Windows-spelled nested
tail kept its backslashes and was spliced into the POSIX-style virtual
path, so glob results and masked read output showed mixed paths like
/mnt/user-data/workspace/pkg\util.py or
/mnt/skills/integrations/lark-cli\lark-doc\SKILL.md. Virtual paths are
always POSIX-style, so normalize nested tails to forward slashes the
same way depth-1 tails already end up. Depth-1 tails and the callable
replacer (LocalSandbox._reverse_resolve_path) were unaffected.

Pin the nested-tail contract in test_sandbox_path_patterns; the
previously failing glob-tool and skills-masking regressions now pass
on Windows hosts.

* refactor(sandbox): share the mask tail-splicing rule; guard it on Linux CI

Review follow-up for #5247:

- hoist the tail-splicing rule (slice off the base, strip leading
  separators, normalize the rest to "/") into
  path_patterns.normalize_mask_tail and import it at both call sites,
  so the two maskers can only drift in their matching logic, not in
  the splice;
- add test_mask_local_paths_normalizes_windows_spelled_skill_tails,
  which spells the skills host root and the output with Windows-style
  strings so the nested tail keeps backslashes on every platform.
  Reverting the mask_local_paths_in_output-side normalization now goes
  red on Linux CI too, not only on Windows hosts.
2026-09-09 10:09:28 +08:00
..