Skip to content

Commit 47ca587

Browse files
Harden extension/session key display normalization
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent 32fbe0d commit 47ca587

File tree

3 files changed

+26
-5
lines changed

3 files changed

+26
-5
lines changed

hyperbrowser/client/managers/extension_utils.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,24 @@ def _get_type_name(value: Any) -> str:
1515

1616
def _safe_stringify_key(value: object) -> str:
1717
try:
18-
return str(value)
18+
normalized_key = str(value)
19+
if type(normalized_key) is not str:
20+
raise TypeError("normalized key must be a string")
21+
return normalized_key
1922
except Exception:
2023
return f"<unprintable {_get_type_name(value)}>"
2124

2225

2326
def _format_key_display(value: object) -> str:
2427
try:
2528
normalized_key = _safe_stringify_key(value)
26-
if not isinstance(normalized_key, str):
29+
if type(normalized_key) is not str:
2730
raise TypeError("normalized key display must be a string")
2831
normalized_key = "".join(
2932
"?" if ord(character) < 32 or ord(character) == 127 else character
3033
for character in normalized_key
3134
).strip()
32-
if not isinstance(normalized_key, str):
35+
if type(normalized_key) is not str:
3336
raise TypeError("normalized key display must be a string")
3437
except Exception:
3538
return "<unreadable key>"

hyperbrowser/client/managers/session_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def _format_recording_key_display(key: str) -> str:
1616
"?" if ord(character) < 32 or ord(character) == 127 else character
1717
for character in key
1818
).strip()
19-
if not isinstance(normalized_key, str):
19+
if type(normalized_key) is not str:
2020
raise TypeError("normalized recording key display must be a string")
2121
except Exception:
2222
return "<unreadable key>"

tests/test_extension_utils.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,24 @@ def __str__(self) -> str:
178178
parse_extension_list_response_data({_BrokenStringKey(): "value"})
179179

180180

181+
def test_parse_extension_list_response_data_missing_key_handles_string_subclass_str_results():
182+
class _StringSubclassKey:
183+
class _RenderedKey(str):
184+
pass
185+
186+
def __str__(self) -> str:
187+
return self._RenderedKey("subclass-key")
188+
189+
with pytest.raises(
190+
HyperbrowserError,
191+
match=(
192+
"Expected 'extensions' key in response but got "
193+
"\\[<unprintable _StringSubclassKey>\\] keys"
194+
),
195+
):
196+
parse_extension_list_response_data({_StringSubclassKey(): "value"})
197+
198+
181199
def test_parse_extension_list_response_data_missing_key_handles_unreadable_keys():
182200
class _BrokenKeysMapping(dict):
183201
def keys(self):
@@ -371,7 +389,7 @@ def __getitem__(self, key: str) -> object:
371389

372390
with pytest.raises(
373391
HyperbrowserError,
374-
match="Failed to read extension object value for key '<unreadable key>' at index 0",
392+
match="Failed to read extension object value for key '<unprintable _BrokenKey>' at index 0",
375393
) as exc_info:
376394
parse_extension_list_response_data(
377395
{"extensions": [_BrokenValueLookupMapping()]}

0 commit comments

Comments
 (0)