gh-149835: Resolve symlinks in shutil._destinsrc#3
Conversation
shutil.move's cross-device fallback uses _destinsrc(src, dst) to refuse moving a directory into itself (which would make copytree recurse infinitely). The guard normalised paths with os.path.abspath, which collapses '.' and '..' but does not resolve symlinks, so a symlink component anywhere in dst could make a destination that physically lives inside src look like it is outside in string space, silently bypassing the guard. Switch to os.path.realpath so the comparison is performed on the resolved, canonical paths. Add a regression test that builds the symlink layout described in the issue and asserts _destinsrc reports containment correctly.
|
PR Author Agent⚡ on behalf of @ding-alex 👋 I'm driving this PR from here to merge. Here's what I'll do:
I'll post updates here as the PR progresses. Feel free to leave a comment anytime! |
|
PR Risk Analysis 🛡️ · Human Input Needed — needs input on Correctness & Logic, Risk, Tests, APIs & Schemas. DetailsInput Needed
Memory (seen 2× — 2 pr-outcome; last PR #2; permanent): Prefer a full review instead?👉 Start General Review 👍 / 👎 Was this risk analysis helpful? React to this comment with your feedback. |
|
PR Author Agent⚡ on behalf of @ding-alex ✅ Ready for review. Gate status:
@ding-alex — this PR lives in your personal fork, so there are no code-owner auto-requests. Could you say who should review? Recent authors of the touched files ( Edited: removed @-mentions of recent-author suggestions that were unintentionally pinging maintainers on a fork PR. Apologies. |
|
@ding-alex I guess you meant to open this upstream? Please have you agent not ping people on your fork. |
|
PR Author Agent⚡ on behalf of @ding-alex Apologies for the unwanted ping — you're right, this PR was intentionally opened in the fork (not upstream), and I shouldn't have @-mentioned upstream maintainers as reviewer suggestions when none of you can be assigned here anyway. I've edited the previous comment to remove the mentions and will not ping non-collaborators on fork PRs again. |
|
That doesn’t look like a human (it seems to be „on behalf of” one) :-/ |
|
PR Author Agent⚡ on behalf of @ding-alex Correct — I'm an automated agent acting for the PR author, not a human. Sorry for the noise on this fork PR; I won't ping non-collaborators here again. The author has been notified to decide whether to keep this on the fork or forward upstream. |
Fixes python#149835.
shutil.move, in the cross-device fallback path, uses_destinsrc(src, dst)to refuse moving a directory into itself (which would makecopytreerecurse infinitely). The guard normalises the two paths withos.path.abspathand then does a string-prefix check.abspathonly collapses./..components — it does not resolve symlinks — so a symlink component anywhere indstcan make a destination that is physically insidesrclook like it is outside in string space, and the guard silently passes.This change uses
os.path.realpathfor bothsrcanddstso the comparison is performed on the resolved, canonical paths.A regression test (
TestMove.test_destinsrc_symlink_bypass) is added that constructs the symlink layout described in the issue and asserts that_destinsrccorrectly reports containment.Author: @ding-alex
Pull Request opened by Augment Code | View session