|
6 | 6 | import threading |
7 | 7 | import time |
8 | 8 | import types |
| 9 | +import warnings |
9 | 10 |
|
10 | 11 | import pytest |
11 | 12 |
|
@@ -471,3 +472,57 @@ def delete_password(self, service: str, key: str) -> None: |
471 | 472 | assert reloaded._KEYRING_AVAILABLE is True |
472 | 473 | finally: |
473 | 474 | importlib.reload(original_module) |
| 475 | + |
| 476 | + |
| 477 | +@pytest.mark.parametrize( |
| 478 | + ("keyring_available", "keyring_backend", "store_key", "allow_insecure", "os_name", "expected"), |
| 479 | + [ |
| 480 | + (True, object(), "", "", "posix", "keyring"), |
| 481 | + (False, None, "my-secret-passphrase", "", "posix", "encrypted-fallback"), |
| 482 | + (False, None, "", "1", "posix", "plaintext-fallback"), |
| 483 | + (False, None, "", "1", "nt", "unavailable"), |
| 484 | + (False, None, "", "", "posix", "unavailable"), |
| 485 | + ], |
| 486 | +) |
| 487 | +def test_keyring_store_mode_detection( |
| 488 | + monkeypatch, |
| 489 | + keyring_available: bool, |
| 490 | + keyring_backend: object | None, |
| 491 | + store_key: str, |
| 492 | + allow_insecure: str, |
| 493 | + os_name: str, |
| 494 | + expected: str, |
| 495 | +) -> None: |
| 496 | + monkeypatch.setattr(keyring_store, "_KEYRING_AVAILABLE", keyring_available) |
| 497 | + monkeypatch.setattr(keyring_store, "_keyring", keyring_backend) |
| 498 | + monkeypatch.setattr(keyring_store.os, "name", os_name, raising=False) |
| 499 | + |
| 500 | + if store_key: |
| 501 | + monkeypatch.setenv(keyring_store._TOKEN_STORE_KEY_ENV, store_key) |
| 502 | + else: |
| 503 | + monkeypatch.delenv(keyring_store._TOKEN_STORE_KEY_ENV, raising=False) |
| 504 | + |
| 505 | + if allow_insecure: |
| 506 | + monkeypatch.setenv(keyring_store._ALLOW_INSECURE_FALLBACK_ENV, allow_insecure) |
| 507 | + else: |
| 508 | + monkeypatch.delenv(keyring_store._ALLOW_INSECURE_FALLBACK_ENV, raising=False) |
| 509 | + |
| 510 | + assert keyring_store.get_token_store_mode() == expected |
| 511 | + |
| 512 | + |
| 513 | +def test_keyring_store_plaintext_fallback_warns_once_on_use(monkeypatch, tmp_path) -> None: |
| 514 | + monkeypatch.setattr(keyring_store, "_KEYRING_AVAILABLE", False) |
| 515 | + monkeypatch.setattr(keyring_store, "_keyring", None) |
| 516 | + monkeypatch.setattr(keyring_store, "cache_dir", lambda: tmp_path) |
| 517 | + monkeypatch.setattr(keyring_store.os, "name", "posix", raising=False) |
| 518 | + monkeypatch.setenv(keyring_store._ALLOW_INSECURE_FALLBACK_ENV, "1") |
| 519 | + monkeypatch.delenv(keyring_store._TOKEN_STORE_KEY_ENV, raising=False) |
| 520 | + monkeypatch.setattr(keyring_store, "_PLAINTEXT_WARNING_EMITTED", False) |
| 521 | + |
| 522 | + with pytest.warns(UserWarning, match="plaintext token fallback"): |
| 523 | + keyring_store.save_tokens("demo", "acc", "ref") |
| 524 | + |
| 525 | + with warnings.catch_warnings(record=True) as recorded: |
| 526 | + warnings.simplefilter("always") |
| 527 | + keyring_store.get_tokens("demo") |
| 528 | + assert len(recorded) == 0 |
0 commit comments