77
88class TestHiddenAPIKeyInput :
99 """Tests that API key input is hidden from terminal/logs."""
10-
10+
1111 def test_uses_getpass_not_input (self ):
1212 """Verify that getpass.getpass is used instead of input()."""
1313 with patch ('getpass.getpass' , return_value = 'hidden_key' ) as mock_getpass :
1414 key = prompt_for_api_key ('groq' , 'https://example.com' , interactive = True )
15-
15+
1616 # Verify getpass was called
1717 mock_getpass .assert_called_once ()
1818 assert key == 'hidden_key'
19-
19+
2020 def test_getpass_masks_input (self ):
2121 """Verify getpass hides input from terminal."""
2222 # getpass.getpass() does not echo input to terminal
2323 # This is verified by the fact that getpass module is imported
2424 # and used instead of builtins.input
2525 with patch ('getpass.getpass' , return_value = 'secret_api_key' ) as mock_getpass :
2626 key = prompt_for_api_key ('openai' , 'https://openai.com' , interactive = True )
27-
27+
2828 # The getpass function is called with appropriate prompt
2929 call_args = mock_getpass .call_args [0 ][0 ]
3030 assert 'OPENAI' in call_args .upper ()
3131 assert key == 'secret_api_key'
32-
32+
3333 def test_hidden_input_with_skip (self ):
3434 """Hidden input should work with skip_if_missing."""
3535 with patch ('getpass.getpass' , return_value = '' ) as mock_getpass :
3636 key = prompt_for_api_key (
37- 'anthropic' ,
37+ 'anthropic' ,
3838 'https://console.anthropic.com/keys' ,
3939 interactive = True ,
4040 skip_if_missing = True
4141 )
42-
42+
4343 mock_getpass .assert_called_once ()
4444 assert key is None
45-
45+
4646 def test_hidden_input_required_empty_raises (self ):
4747 """Empty hidden input should raise when key is required."""
4848 with patch ('getpass.getpass' , return_value = '' ) as mock_getpass :
@@ -53,28 +53,28 @@ def test_hidden_input_required_empty_raises(self):
5353 interactive = True ,
5454 skip_if_missing = False
5555 )
56-
56+
5757 mock_getpass .assert_called_once ()
58-
58+
5959 def test_hidden_input_strips_whitespace (self ):
6060 """Hidden input should have whitespace stripped."""
61- with patch ('getpass.getpass' , return_value = ' api_key_with_spaces ' ) as mock_getpass :
61+ with patch ('getpass.getpass' , return_value = ' api_key_with_spaces ' ):
6262 key = prompt_for_api_key ('groq' , 'https://console.groq.com/keys' , interactive = True )
63-
63+
6464 # Whitespace should be stripped
6565 assert key == 'api_key_with_spaces'
6666 assert not key .startswith (' ' )
6767 assert not key .endswith (' ' )
68-
68+
6969 def test_hidden_input_non_interactive_no_getpass (self ):
7070 """Non-interactive mode should not call getpass."""
7171 with patch ('getpass.getpass' ) as mock_getpass :
7272 with pytest .raises (ValueError ):
7373 prompt_for_api_key ('groq' , 'https://console.groq.com/keys' , interactive = False )
74-
74+
7575 # getpass should not be called in non-interactive mode
7676 mock_getpass .assert_not_called ()
77-
77+
7878 def test_hidden_input_eof_error (self ):
7979 """Handle EOF when getpass is used."""
8080 with patch ('getpass.getpass' , side_effect = EOFError ):
@@ -84,7 +84,7 @@ def test_hidden_input_eof_error(self):
8484 'https://aistudio.google.com/app/apikey' ,
8585 interactive = True
8686 )
87-
87+
8888 def test_hidden_input_os_error (self ):
8989 """Handle OSError when getpass is used."""
9090 with patch ('getpass.getpass' , side_effect = OSError ):
@@ -94,23 +94,23 @@ def test_hidden_input_os_error(self):
9494 'https://portal.azure.com' ,
9595 interactive = True
9696 )
97-
97+
9898 def test_hidden_input_multiple_calls (self ):
9999 """Multiple hidden inputs should each use getpass."""
100100 with patch ('getpass.getpass' , side_effect = ['key1' , 'key2' , 'key3' ]):
101101 key1 = prompt_for_api_key ('groq' , 'https://example.com' , interactive = True )
102102 key2 = prompt_for_api_key ('openai' , 'https://example.com' , interactive = True )
103103 key3 = prompt_for_api_key ('anthropic' , 'https://example.com' , interactive = True )
104-
104+
105105 assert key1 == 'key1'
106106 assert key2 == 'key2'
107107 assert key3 == 'key3'
108-
108+
109109 def test_hidden_input_with_special_characters (self ):
110110 """Hidden input should handle special characters in API keys."""
111111 special_key = 'sk-key_with-special.chars+/=abc123'
112-
112+
113113 with patch ('getpass.getpass' , return_value = special_key ):
114114 key = prompt_for_api_key ('openai' , 'https://platform.openai.com/api-keys' , interactive = True )
115-
115+
116116 assert key == special_key
0 commit comments