heist/tool/path.py: clean_path() broken
clean_path() does not work when the cwd includes a symlink.
(Ok, granted, this is quite a non-standard situation for a Linux user. :-) In FreeBSD jails /home is a symlink pointing to /usr/home.
Setup:
- heist was installed via
pip install heist-salt - heist is available via
$PATH - On the remote host,
/var/tmp/heistdoes not exist / has been removed. - Work as
salt-masterin/home/salt-master, while/homeis a symlink to/usr/home.
% heist --version
heist 7.0.2
% heist --log-level debug --aritfact-version 3006.7 salt.minion
[...]
[ERROR ] Could not add aliases to PATH
[ERROR ] Could not deploy the alias files from the path /home/salt-master/.heist/artifacts/onedir/linux/scripts/minion to the target
[ERROR ] Creating and deploying the aliases failed. Will continue deploying
[ERROR ] The path /home/salt-master/.heist/artifacts/onedir/linux/salt-3006.7-onedir-linux-x86_64.tar.xz is not in the correct directory
[INFO ] [conn=0, chan=0] Starting SFTP put of /home/salt-master/.heist/artifacts/onedir/linux/salt-3006.7-onedir-linux-x86_64.tar.xz,/home/salt-master/.heist/artifacts/onedir/linux/node3.sz9i.net/root_dir,/home/salt-master/.heist/artifacts/onedir/linux/node3.sz9i.net/code_checksum to /var/tmp/heist_root/9276
[DEBUG ] return value: {'result': 'Error', 'comment': "OS error: [Errno 2] No such file or directory: b'/home/salt-master/.heist/artifacts/onedir/linux/node3.sz9i.net/code_checksum'", 'retvalue': 1}
result: Error
comment: OS error: [Errno 2] No such file or directory: b'/home/salt-master/.heist/artifacts/onedir/linux/node3.sz9i.net/code_checksum'
retvalue: 1
[ERROR ] Could not add aliases to PATH
[ERROR ] Could not deploy the alias files from the path /home/salt-master/.heist/artifacts/onedir/linux/scripts/minion to the target
[ERROR ] Creating and deploying the aliases failed. Will continue deploying
[ERROR ] The path /home/salt-master/.heist/artifacts/onedir/linux/salt-3006.7-onedir-linux-x86_64.tar.xz is not in the correct directory
After some debugging with pdb, it seems the core issue lies here: https://gitlab.com/saltstack/pop/heist/-/blob/df8331e543ee098dd2874958af5c2e2804924da2/heist/tool/path.py#L93
78 def clean_path(hub, root, path, subdir=False):
79 """
80 Return a clean path that has been validated.
81 Using os.path here instead of pathlib, because
82 the api's functionalities are not entirely the
83 same yet.
84 """
# import pdb; pdb.set_trace()
# root is '/home/salt-master/.heist/artifacts/onedir/linux'
# path is '/home/salt-master/.heist/artifacts/onedir/linux/host.example.test/code_checksum'
85 real_root = _realpath(root) # real_root is '/usr/home/salt-master/.heist/artifacts/onedir/linux'
86 path = os.path.expandvars(path) # path is (still) '/home/salt-master/.heist/artifacts/onedir/linux/host.example.test/code_checksum'
87 if not os.path.isabs(real_root): # os.path.isabs(real_root) => True
88 return ""
89 if not os.path.isabs(path): # os.path.isabs(path) => True
90 path = os.path.join(root, path)
91 path = os.path.normpath(path) # path is (still) '/home/salt-master/.heist/artifacts/onedir/linux/host.example.test/code_checksum'
92 real_path = _realpath(path) # real_path is '/usr/home/salt-master/.heist/artifacts/onedir/linux/host.example.test/code_checksum'
93 if path.startswith(real_root): # path.startswith(real_root) => False
# real_path.startswith(real_root) => True
# So, should `path` be changed to `real_path` here?
94 return os.path.join(root, path)
95 if subdir:
96 if real_path.startswith(real_root):
97 return real_path
98 else:
# os.path.dirname(real_path) is '/usr/home/salt-master/.heist/artifacts/onedir/linux/host.example.test'
# os.path.normpath(real_root) is '/usr/home/salt-master/.heist/artifacts/onedir/linux'
99 if os.path.dirname(real_path) == os.path.normpath(real_root):
100 return real_path
101 return ""
I propose this change: !153
I tested this on FreeBSD 14 and this patch brings me past OS error: [Errno 2] No such file or directory: b'/home/salt-master/.heist/artifacts/onedir/linux/node3.sz9i.net/code_checksum'. :-)
I found a related issue in the method which calls clean_path(): heist-salt!93
Edited by Alex W.