Skip to content

Commit 8073e94

Browse files
Sanitize upload path display in file input errors
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent 7f8d16b commit 8073e94

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

hyperbrowser/client/managers/session_upload_utils.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@
88

99
from ..file_utils import ensure_existing_file_path, open_binary_file
1010

11+
_MAX_FILE_PATH_DISPLAY_LENGTH = 200
12+
13+
14+
def _format_upload_path_for_error(raw_file_path: object) -> str:
15+
if not is_plain_string(raw_file_path):
16+
return "<provided path>"
17+
try:
18+
normalized_path = "".join(
19+
"?" if ord(character) < 32 or ord(character) == 127 else character
20+
for character in raw_file_path
21+
)
22+
except Exception:
23+
return "<provided path>"
24+
if not is_plain_string(normalized_path):
25+
return "<provided path>"
26+
if len(normalized_path) <= _MAX_FILE_PATH_DISPLAY_LENGTH:
27+
return normalized_path
28+
return f"{normalized_path[:_MAX_FILE_PATH_DISPLAY_LENGTH]}..."
29+
1130

1231
def normalize_upload_file_input(
1332
file_input: Union[str, PathLike[str], IO],
@@ -22,10 +41,11 @@ def normalize_upload_file_input(
2241
"file_input path is invalid",
2342
original_error=exc,
2443
) from exc
44+
file_path_display = _format_upload_path_for_error(raw_file_path)
2545
file_path = ensure_existing_file_path(
2646
raw_file_path,
27-
missing_file_message=f"Upload file not found at path: {raw_file_path}",
28-
not_file_message=f"Upload file path must point to a file: {raw_file_path}",
47+
missing_file_message=f"Upload file not found at path: {file_path_display}",
48+
not_file_message=f"Upload file path must point to a file: {file_path_display}",
2949
)
3050
return file_path, None
3151

tests/test_session_upload_utils.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,34 @@ def __str__(self) -> str:
7171
assert exc_info.value.original_error is None
7272

7373

74+
def test_normalize_upload_file_input_survives_string_subclass_fspath_in_error_messages():
75+
class _PathString(str):
76+
def __str__(self) -> str: # type: ignore[override]
77+
raise RuntimeError("broken stringify")
78+
79+
class _PathLike(PathLike[str]):
80+
def __fspath__(self) -> str:
81+
return _PathString("/tmp/nonexistent-subclass-path-for-upload-utils-test")
82+
83+
with pytest.raises(
84+
HyperbrowserError,
85+
match="file_path must resolve to a string path",
86+
) as exc_info:
87+
normalize_upload_file_input(_PathLike())
88+
89+
assert exc_info.value.original_error is None
90+
91+
92+
def test_normalize_upload_file_input_rejects_control_character_paths_before_message_validation():
93+
with pytest.raises(
94+
HyperbrowserError,
95+
match="file_path must not contain control characters",
96+
) as exc_info:
97+
normalize_upload_file_input("bad\tpath.txt")
98+
99+
assert exc_info.value.original_error is None
100+
101+
74102
def test_normalize_upload_file_input_returns_open_file_like_object():
75103
file_obj = io.BytesIO(b"content")
76104

0 commit comments

Comments
 (0)