Skip to content

Commit ad5b876

Browse files
Require concrete api-key strip normalization outputs
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent 47ca587 commit ad5b876

File tree

6 files changed

+21
-129
lines changed

6 files changed

+21
-129
lines changed

hyperbrowser/client/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def __init__(
4040
raise HyperbrowserError("api_key must be a string")
4141
try:
4242
normalized_resolved_api_key = resolved_api_key.strip()
43-
if not isinstance(normalized_resolved_api_key, str):
43+
if type(normalized_resolved_api_key) is not str:
4444
raise TypeError("normalized api_key must be a string")
4545
except HyperbrowserError:
4646
raise

hyperbrowser/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def normalize_api_key(
3636
raise HyperbrowserError("api_key must be a string")
3737
try:
3838
normalized_api_key = api_key.strip()
39-
if not isinstance(normalized_api_key, str):
39+
if type(normalized_api_key) is not str:
4040
raise TypeError("normalized api_key must be a string")
4141
except HyperbrowserError:
4242
raise

hyperbrowser/transport/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def _normalize_transport_api_key(api_key: str) -> str:
6969

7070
try:
7171
normalized_api_key = api_key.strip()
72-
if not isinstance(normalized_api_key, str):
72+
if type(normalized_api_key) is not str:
7373
raise TypeError("normalized api_key must be a string")
7474
except HyperbrowserError:
7575
raise

tests/test_client_api_key.py

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,10 @@ def strip(self, chars=None): # type: ignore[override]
240240

241241

242242
@pytest.mark.parametrize("client_class", [Hyperbrowser, AsyncHyperbrowser])
243-
def test_client_wraps_api_key_empty_check_length_failures(client_class):
243+
def test_client_wraps_api_key_string_subclass_strip_results(client_class):
244244
class _BrokenLengthApiKey(str):
245245
class _NormalizedKey(str):
246-
def __len__(self):
247-
raise RuntimeError("api key length exploded")
246+
pass
248247

249248
def strip(self, chars=None): # type: ignore[override]
250249
_ = chars
@@ -253,23 +252,10 @@ def strip(self, chars=None): # type: ignore[override]
253252
with pytest.raises(HyperbrowserError, match="Failed to normalize api_key") as exc_info:
254253
client_class(api_key=_BrokenLengthApiKey("test-key"))
255254

256-
assert isinstance(exc_info.value.original_error, RuntimeError)
255+
assert isinstance(exc_info.value.original_error, TypeError)
257256

258257

259258
@pytest.mark.parametrize("client_class", [Hyperbrowser, AsyncHyperbrowser])
260-
def test_client_preserves_hyperbrowser_api_key_empty_check_length_failures(
261-
client_class,
262-
):
263-
class _BrokenLengthApiKey(str):
264-
class _NormalizedKey(str):
265-
def __len__(self):
266-
raise HyperbrowserError("custom length failure")
267-
268-
def strip(self, chars=None): # type: ignore[override]
269-
_ = chars
270-
return self._NormalizedKey("test-key")
271-
272-
with pytest.raises(HyperbrowserError, match="custom length failure") as exc_info:
273-
client_class(api_key=_BrokenLengthApiKey("test-key"))
274-
275-
assert exc_info.value.original_error is None
259+
def test_client_rejects_blank_api_key_input(client_class):
260+
with pytest.raises(HyperbrowserError, match="api_key must not be empty"):
261+
client_class(api_key=" ")

tests/test_config.py

Lines changed: 6 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -400,11 +400,10 @@ def strip(self, chars=None): # type: ignore[override]
400400
assert isinstance(exc_info.value.original_error, TypeError)
401401

402402

403-
def test_client_config_wraps_api_key_empty_check_length_failures():
403+
def test_client_config_wraps_api_key_string_subclass_strip_results():
404404
class _BrokenApiKey(str):
405405
class _NormalizedKey(str):
406-
def __len__(self):
407-
raise RuntimeError("api key length exploded")
406+
pass
408407

409408
def strip(self, chars=None): # type: ignore[override]
410409
_ = chars
@@ -413,55 +412,12 @@ def strip(self, chars=None): # type: ignore[override]
413412
with pytest.raises(HyperbrowserError, match="Failed to normalize api_key") as exc_info:
414413
ClientConfig(api_key=_BrokenApiKey("test-key"))
415414

416-
assert isinstance(exc_info.value.original_error, RuntimeError)
417-
418-
419-
def test_client_config_preserves_hyperbrowser_api_key_empty_check_length_failures():
420-
class _BrokenApiKey(str):
421-
class _NormalizedKey(str):
422-
def __len__(self):
423-
raise HyperbrowserError("custom length failure")
424-
425-
def strip(self, chars=None): # type: ignore[override]
426-
_ = chars
427-
return self._NormalizedKey("test-key")
428-
429-
with pytest.raises(HyperbrowserError, match="custom length failure") as exc_info:
430-
ClientConfig(api_key=_BrokenApiKey("test-key"))
431-
432-
assert exc_info.value.original_error is None
433-
434-
435-
def test_client_config_wraps_api_key_iteration_runtime_errors():
436-
class _BrokenApiKey(str):
437-
def strip(self, chars=None): # type: ignore[override]
438-
_ = chars
439-
return self
440-
441-
def __iter__(self):
442-
raise RuntimeError("api key iteration exploded")
443-
444-
with pytest.raises(
445-
HyperbrowserError, match="Failed to validate api_key characters"
446-
) as exc_info:
447-
ClientConfig(api_key=_BrokenApiKey("test-key"))
448-
449-
assert isinstance(exc_info.value.original_error, RuntimeError)
450-
451-
452-
def test_client_config_preserves_hyperbrowser_api_key_iteration_errors():
453-
class _BrokenApiKey(str):
454-
def strip(self, chars=None): # type: ignore[override]
455-
_ = chars
456-
return self
415+
assert isinstance(exc_info.value.original_error, TypeError)
457416

458-
def __iter__(self):
459-
raise HyperbrowserError("custom iteration failure")
460417

461-
with pytest.raises(HyperbrowserError, match="custom iteration failure") as exc_info:
462-
ClientConfig(api_key=_BrokenApiKey("test-key"))
463-
464-
assert exc_info.value.original_error is None
418+
def test_client_config_rejects_blank_api_key_values():
419+
with pytest.raises(HyperbrowserError, match="api_key must not be empty"):
420+
ClientConfig(api_key=" ")
465421

466422

467423
def test_client_config_rejects_empty_or_invalid_base_url():

tests/test_transport_api_key.py

Lines changed: 6 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -45,29 +45,10 @@ def strip(self, chars=None): # type: ignore[override]
4545

4646

4747
@pytest.mark.parametrize("transport_class", [SyncTransport, AsyncTransport])
48-
def test_transport_wraps_api_key_character_iteration_failures(transport_class):
49-
class _BrokenIterApiKey(str):
50-
def strip(self, chars=None): # type: ignore[override]
51-
_ = chars
52-
return self
53-
54-
def __iter__(self):
55-
raise RuntimeError("api key iteration exploded")
56-
57-
with pytest.raises(
58-
HyperbrowserError, match="Failed to validate api_key characters"
59-
) as exc_info:
60-
transport_class(api_key=_BrokenIterApiKey("test-key"))
61-
62-
assert isinstance(exc_info.value.original_error, RuntimeError)
63-
64-
65-
@pytest.mark.parametrize("transport_class", [SyncTransport, AsyncTransport])
66-
def test_transport_wraps_api_key_empty_check_length_failures(transport_class):
48+
def test_transport_wraps_api_key_string_subclass_strip_results(transport_class):
6749
class _BrokenLengthApiKey(str):
6850
class _NormalizedKey(str):
69-
def __len__(self):
70-
raise RuntimeError("api key length exploded")
51+
pass
7152

7253
def strip(self, chars=None): # type: ignore[override]
7354
_ = chars
@@ -76,41 +57,10 @@ def strip(self, chars=None): # type: ignore[override]
7657
with pytest.raises(HyperbrowserError, match="Failed to normalize api_key") as exc_info:
7758
transport_class(api_key=_BrokenLengthApiKey("test-key"))
7859

79-
assert isinstance(exc_info.value.original_error, RuntimeError)
80-
81-
82-
@pytest.mark.parametrize("transport_class", [SyncTransport, AsyncTransport])
83-
def test_transport_preserves_hyperbrowser_api_key_empty_check_length_failures(
84-
transport_class,
85-
):
86-
class _BrokenLengthApiKey(str):
87-
class _NormalizedKey(str):
88-
def __len__(self):
89-
raise HyperbrowserError("custom length failure")
90-
91-
def strip(self, chars=None): # type: ignore[override]
92-
_ = chars
93-
return self._NormalizedKey("test-key")
94-
95-
with pytest.raises(HyperbrowserError, match="custom length failure") as exc_info:
96-
transport_class(api_key=_BrokenLengthApiKey("test-key"))
97-
98-
assert exc_info.value.original_error is None
60+
assert isinstance(exc_info.value.original_error, TypeError)
9961

10062

10163
@pytest.mark.parametrize("transport_class", [SyncTransport, AsyncTransport])
102-
def test_transport_preserves_hyperbrowser_api_key_character_iteration_failures(
103-
transport_class,
104-
):
105-
class _BrokenIterApiKey(str):
106-
def strip(self, chars=None): # type: ignore[override]
107-
_ = chars
108-
return self
109-
110-
def __iter__(self):
111-
raise HyperbrowserError("custom iteration failure")
112-
113-
with pytest.raises(HyperbrowserError, match="custom iteration failure") as exc_info:
114-
transport_class(api_key=_BrokenIterApiKey("test-key"))
115-
116-
assert exc_info.value.original_error is None
64+
def test_transport_rejects_blank_normalized_api_keys(transport_class):
65+
with pytest.raises(HyperbrowserError, match="api_key must not be empty"):
66+
transport_class(api_key=" ")

0 commit comments

Comments
 (0)