When shared mounts are passed to Monty.run(...), mount identity is not preserved if caller-provided order differs from Monty’s internal longest-prefix-first ordering. After a successful run, mounts can be written back into the wrong shared slots, causing the caller-visible mount objects to come back with the wrong virtual_path, host_path, and mode. This appears to be a real mount identity corruption bug, not just a display issue.
Monty version: 0.0.16
Python version: 3.11.7
Note: Bug found by ChatGPT while I'm playing with hackmonty. Issue title and body generated by AI, I don't want to throw AI slop somewhere but I tried this by myself and it seemed a bug to me.
Repro
from pathlib import Path
from tempfile import TemporaryDirectory
from pydantic_monty import Monty, MountDir
with TemporaryDirectory() as dir_a, TemporaryDirectory() as dir_ab:
Path(dir_a, "one.txt").write_text("ONE")
Path(dir_ab, "two.txt").write_text("TWO")
mount_a = MountDir("/a", dir_a, mode="read-only")
mount_ab = MountDir("/a/b", dir_ab, mode="read-write")
print("BEFORE mount_a :", mount_a.virtual_path, mount_a.host_path, mount_a.mode)
print("BEFORE mount_ab:", mount_ab.virtual_path, mount_ab.host_path, mount_ab.mode)
Monty("1 + 1").run(mount=[mount_a, mount_ab])
print("AFTER mount_a :", mount_a.virtual_path, mount_a.host_path, mount_a.mode)
print("AFTER mount_ab:", mount_ab.virtual_path, mount_ab.host_path, mount_ab.mode)
Observed raw output
BEFORE mount_a : /a /private/var/folders/9t/dwwzwmw57xg7yyml_2jtb9lc0000gn/T/tmpf9iya794 read-only
BEFORE mount_ab: /a/b /private/var/folders/9t/dwwzwmw57xg7yyml_2jtb9lc0000gn/T/tmpgaa15ift read-write
AFTER mount_a : /a/b /private/var/folders/9t/dwwzwmw57xg7yyml_2jtb9lc0000gn/T/tmpgaa15ift read-write
AFTER mount_ab: /a /private/var/folders/9t/dwwzwmw57xg7yyml_2jtb9lc0000gn/T/tmpf9iya794 read-only
Expected behavior
mount_a should remain bound to /a with its original host directory and read-only mode, and mount_ab should remain bound to /a/b with its original host directory and read-write mode.
Actual behavior
After Monty.run(...), the two mount objects are swapped. mount_a comes back as the /a/b mount, and mount_ab comes back as the /a mount.
Likely cause
The behavior appears to come from a mismatch between:
- the order shared mounts are taken from caller-provided slots,
- the internal reordering done for mount dispatch, and
- the positional write-back when mounts are returned to shared slots.
Impact
At minimum, this causes persistent mount identity corruption across a run. If shared mount objects are reused, later operations may target the wrong mount point, host directory, or mode. Depending on how shared mounts are used, this could also create integrity or privilege-confusion risks.
When shared mounts are passed to
Monty.run(...), mount identity is not preserved if caller-provided order differs from Monty’s internal longest-prefix-first ordering. After a successful run, mounts can be written back into the wrong shared slots, causing the caller-visible mount objects to come back with the wrongvirtual_path,host_path, andmode. This appears to be a real mount identity corruption bug, not just a display issue.Monty version: 0.0.16
Python version: 3.11.7
Repro
Observed raw output
Expected behavior
mount_ashould remain bound to/awith its original host directory andread-onlymode, andmount_abshould remain bound to/a/bwith its original host directory andread-writemode.Actual behavior
After
Monty.run(...), the two mount objects are swapped.mount_acomes back as the/a/bmount, andmount_abcomes back as the/amount.Likely cause
The behavior appears to come from a mismatch between:
Impact
At minimum, this causes persistent mount identity corruption across a run. If shared mount objects are reused, later operations may target the wrong mount point, host directory, or mode. Depending on how shared mounts are used, this could also create integrity or privilege-confusion risks.