Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/47707.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Include the offending path in the "A valid directory was not specified" error raised by file.readdir and file.rmdir
4 changes: 2 additions & 2 deletions salt/modules/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -4192,7 +4192,7 @@ def readdir(path):
raise SaltInvocationError("Dir path must be absolute.")

if not os.path.isdir(path):
raise SaltInvocationError("A valid directory was not specified.")
raise SaltInvocationError(f"A valid directory was not specified: {path}")

dirents = [".", ".."]
dirents.extend(os.listdir(path))
Expand Down Expand Up @@ -4342,7 +4342,7 @@ def rmdir(path, recurse=False, verbose=False, older_than=None):
raise SaltInvocationError("File path must be absolute.")

if not os.path.isdir(path):
raise SaltInvocationError("A valid directory was not specified.")
raise SaltInvocationError(f"A valid directory was not specified: {path}")

if older_than:
now = time.time()
Expand Down
48 changes: 48 additions & 0 deletions tests/pytests/unit/modules/file/test_file_rmdir.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,54 @@ def test_file_rmdir_not_found_exception():
filemod.rmdir("/tmp/not_there")


def test_file_rmdir_not_found_exception_includes_path():
with pytest.raises(SaltInvocationError, match="/tmp/not_there"):
filemod.rmdir("/tmp/not_there")


def test_file_readdir_not_found_exception_includes_path():
with pytest.raises(SaltInvocationError, match="/tmp/not_there"):
filemod.readdir("/tmp/not_there")


def test_file_rmdir_not_found_includes_path_with_state_args_47707():
# The file.rmdir state (salt/states/file.py) calls this as
# rmdir(name, recurse=recurse, verbose=True, older_than=older_than).
# verbose=True is the decisive flag: with it, removal failures are
# normally collected into the returned dict's "errors" list instead of
# raised, but an invalid directory must still raise, and the message
# must include the offending path.
with pytest.raises(SaltInvocationError, match="/tmp/not_there"):
filemod.rmdir("/tmp/not_there", recurse=True, verbose=True, older_than=None)


def test_file_rmdir_relative_path_error_unchanged_47707():
"""
Guard against overcorrection: a relative path must still fail the
absolute-path check, not the valid-directory check changed for #47707.
"""
with pytest.raises(SaltInvocationError, match="must be absolute"):
filemod.rmdir("not_absolute")


def test_file_readdir_relative_path_error_unchanged_47707():
"""
Guard against overcorrection: a relative path must still fail readdir's
absolute-path check, not the valid-directory check changed for #47707.
"""
with pytest.raises(SaltInvocationError, match="must be absolute"):
filemod.readdir("not_absolute")


def test_file_readdir_valid_directory_47707(tmp_path):
"""
Guard against overcorrection: readdir on an existing directory must
still return the directory listing without raising.
"""
(tmp_path / "afile").write_text("data")
assert filemod.readdir(str(tmp_path)) == [".", "..", "afile"]


def test_file_rmdir_success_return():
with patch("os.rmdir", MagicMock(return_value=True)), patch(
"os.path.isdir", MagicMock(return_value=True)
Expand Down
Loading