Repository navigation
Fix destination directory/filename split in file copier - #143
Merged
Merged
Conversation
winrm-filecopier.py split the destination by taking ntpath.basename() and then calling str.replace(filename, '') on the whole path. replace() removes every occurrence of the filename, not just the last component, so the remote directory was corrupted whenever the filename also appeared earlier in the path: C:\Users\admin\Desktop\a -> directory C:\Users\dmin\Desktop\ C:\deploy\app\app -> directory C:\deploy\\ The file was then written into a wrong, newly created folder. A destination ending in a separator (a directory) produced an empty filename, so the upload targeted the directory path itself and failed instead of using the source file's name. The fallback branch using check_is_file/get_file could never run, because basename() never returns None and its result is always a substring of the path. Move the split into common.split_destination(), which uses ntpath.split (accepts both \ and /), strips only the last component, and falls back to the source basename when the destination ends in a separator. The directory keeps its trailing separator, so ordinary paths such as C:\Windows\TEMP\123-dispatch.ps1 produce exactly the same remote_path and filename as before. Add unit tests for the helper.
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
The focused fix preserves existing upload formatting, covers the reported regressions, and has no identified blocking issues.
No open issues 🎉
What changed in this PR
Fixes #142 by correcting destination splitting in the WinRM file copier without changing normal script-dispatch path formatting.
Changes:
- Preserves parent directories when the filename also appears earlier in the path.
- Uses the source filename for destinations ending in a separator.
- Adds eight regression tests.
| File | Description |
|---|---|
| tests/test_common.py | Tests destination splitting and separator handling. |
| contents/winrm-filecopier.py | Replaces filename replacement logic with the shared helper. |
| contents/common.py | Adds Windows-aware destination splitting. |
Review effort: Balanced
fdevans
approved these changes
Oct 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Change
common.split_destination(destination, source), which splits the destination withntpath.split(accepts both\and/), strips only the last path component, and falls back to the source file's basename when the destination ends in a separator.winrm-filecopier.pyin place of thebasename+str.replacelogic (and the unreachableelsebranch).tests/test_common.pywith unit tests for the helper.Why
str.replace(filename, '')removed every occurrence of the filename from the path, so destinations likeC:\Users\admin\Desktop\aorC:\deploy\app\appwere uploaded into a wrong, newly created folder. A destination ending in\gave an empty filename and the upload failed instead of using the source name.The returned directory keeps its trailing separator, so ordinary paths such as
C:\Windows\TEMP\123-dispatch.ps1produce exactly the sameremote_pathand filename as before, and the format stays compatible withwinrm_upload().check_is_file/get_fileincommon.pyare no longer called; I left them in place rather than remove public helpers in a bug fix.Verification
python3 -m unittest discover -s tests: all pass, including 8 new tests covering a normal dispatch path, a filename that also appears in a parent directory, a single-character filename, trailing\and/, forward and mixed separators, and a file in the drive root.End-to-end on Rundeck: I also ran this on a local Rundeck 6.4.0-SNAPSHOT server with the plugin built from
mainand from this branch, against a local stub WinRM endpoint (plain HTTP, basic auth, implements the WS-Man shell calls and emulates the handful of commands the plugin sends). It is not a real Windows host.C:\Users\admin\Desktop\a:mainwrites the file toC:\Users\dmin\Desktop\a; this branch writes it toC:\Users\admin\Desktop\a.C:\WINDOWS\TEMP\...-dispatch-script.tmp.bat, still work.Fixes #142