@@ -260,11 +260,14 @@ def fake_get_password(domain: str, identifier: str) -> str:
260260 return 'from-keyring'
261261
262262 monkeypatch .setattr (client_connection .keyring , 'get_password' , fake_get_password )
263+ writes : list [tuple [str , str , str ]] = []
264+ monkeypatch .setattr (client_connection , 'set_keyring_password' , lambda * args : writes .append (args ))
263265
264266 client .connect (user = 'alice' , host = 'db' , port = 3307 , use_keyring = True )
265267
266268 assert FakeSQLExecute .calls [- 1 ]['password' ] == 'from-keyring'
267269 assert get_password_calls == [('mycli.net' , 'alice@db:3307:' )]
270+ assert writes == []
268271
269272
270273def test_connect_uses_mylogin_password_before_keyring (monkeypatch : pytest .MonkeyPatch ) -> None :
@@ -275,7 +278,7 @@ def test_connect_uses_mylogin_password_before_keyring(monkeypatch: pytest.Monkey
275278 'get_password' ,
276279 lambda domain , identifier : get_password_calls .append ((domain , identifier )) or 'from-mylogin' , # type: ignore[func-returns-value]
277280 )
278- monkeypatch .setattr (client_connection . keyring , 'set_password ' , lambda * _args : None )
281+ monkeypatch .setattr (client_connection , 'set_keyring_password ' , lambda * _args : None )
279282
280283 client .connect (user = 'alice' , host = 'db' , port = 3307 , use_keyring = True )
281284
@@ -293,7 +296,7 @@ def test_connect_resolves_supplied_candidates_after_connection_details(monkeypat
293296 'get_password' ,
294297 lambda domain , identifier : keyring_calls .append ((domain , identifier )) or 'from-dsn' , # type: ignore[func-returns-value]
295298 )
296- monkeypatch .setattr (client_connection . keyring , 'set_password ' , lambda * _args : None )
299+ monkeypatch .setattr (client_connection , 'set_keyring_password ' , lambda * _args : None )
297300
298301 client .connect (user = 'alice' , host = 'db' , port = 3307 , password_candidates = candidates , use_keyring = True )
299302
@@ -326,8 +329,8 @@ def test_connect_saves_selected_password_to_keyring(monkeypatch: pytest.MonkeyPa
326329 secho_calls : list [tuple [str , dict [str , Any ]]] = []
327330 monkeypatch .setattr (client_connection .keyring , 'get_password' , lambda * _args : 'old-secret' )
328331 monkeypatch .setattr (
329- client_connection . keyring ,
330- 'set_password ' ,
332+ client_connection ,
333+ 'set_keyring_password ' ,
331334 lambda domain , identifier , password : set_password_calls .append ((domain , identifier , password )),
332335 )
333336 monkeypatch .setattr (client_connection .click , 'secho' , lambda message , ** kwargs : secho_calls .append ((message , kwargs )))
@@ -348,14 +351,54 @@ def test_connect_reports_keyring_save_error(monkeypatch: pytest.MonkeyPatch) ->
348351 def fail_set_password (* _args : Any ) -> None :
349352 raise RuntimeError ('locked' )
350353
351- monkeypatch .setattr (client_connection . keyring , 'set_password ' , fail_set_password )
354+ monkeypatch .setattr (client_connection , 'set_keyring_password ' , fail_set_password )
352355 monkeypatch .setattr (client_connection .click , 'secho' , lambda message , ** kwargs : secho_calls .append ((message , kwargs )))
353356
354357 client .connect (user = 'alice' , host = 'db' , port = 3307 , password_candidates = candidates , use_keyring = True )
355358
356359 assert secho_calls == [('Password not saved to the system keyring: locked' , {'err' : True , 'fg' : 'red' })]
357360
358361
362+ def test_connect_saves_fallback_password_when_keyring_is_empty (monkeypatch : pytest .MonkeyPatch ) -> None :
363+ client = DummyClient ()
364+ FakeSQLExecute .effects = [op_error (1045 ), None ]
365+ writes : list [tuple [str , str , str ]] = []
366+ monkeypatch .setattr (client_connection .keyring , 'get_password' , lambda * _args : None )
367+ monkeypatch .setattr (client_connection .click , 'prompt' , lambda * _args , ** _kwargs : 'new-secret' )
368+ monkeypatch .setattr (client_connection , 'set_keyring_password' , lambda * args : writes .append (args ))
369+
370+ client .connect (user = 'alice' , host = 'db' , port = 3307 , use_keyring = True )
371+
372+ assert writes == [('mycli.net' , 'alice@db:3307:' , 'new-secret' )]
373+
374+
375+ def test_connect_does_not_rewrite_rejected_keyring_password (monkeypatch : pytest .MonkeyPatch ) -> None :
376+ client = DummyClient ()
377+ FakeSQLExecute .effects = [op_error (1045 )]
378+ writes : list [tuple [str , str , str ]] = []
379+ monkeypatch .setattr (client_connection .keyring , 'get_password' , lambda * _args : 'old-secret' )
380+ monkeypatch .setattr (client_connection , 'set_keyring_password' , lambda * args : writes .append (args ))
381+
382+ with pytest .raises (SystemExit ):
383+ client .connect (user = 'alice' , host = 'db' , port = 3307 , use_keyring = True )
384+
385+ assert writes == []
386+
387+
388+ @pytest .mark .parametrize ('reset' , [False , True ])
389+ def test_connect_only_rewrites_unchanged_password_for_reset (monkeypatch : pytest .MonkeyPatch , reset : bool ) -> None :
390+ client = DummyClient ()
391+ candidates = PasswordCandidates ()
392+ candidates .add_value ('literal' , 'secret' )
393+ writes : list [tuple [str , str , str ]] = []
394+ monkeypatch .setattr (client_connection .keyring , 'get_password' , lambda * _args : 'secret' )
395+ monkeypatch .setattr (client_connection , 'set_keyring_password' , lambda * args : writes .append (args ))
396+
397+ client .connect (user = 'alice' , host = 'db' , port = 3307 , password_candidates = candidates , use_keyring = True , reset_keyring = reset )
398+
399+ assert writes == ([('mycli.net' , 'alice@db:3307:' , 'secret' )] if reset else [])
400+
401+
359402def test_connect_uses_ssh_jump_with_remote_socket (monkeypatch : pytest .MonkeyPatch ) -> None :
360403 tunnel_calls : list [dict [str , Any ]] = []
361404
@@ -485,8 +528,8 @@ def close(self) -> None:
485528 lambda domain , identifier : keyring_calls .append (('get' , domain , identifier )),
486529 )
487530 monkeypatch .setattr (
488- client_connection . keyring ,
489- 'set_password ' ,
531+ client_connection ,
532+ 'set_keyring_password ' ,
490533 lambda domain , identifier , password : keyring_calls .append (('set' , domain , identifier , password )),
491534 )
492535 password_candidates = PasswordCandidates ()
0 commit comments