From 705f1259305e9d7cbaffbb23dde0d3984520b61a Mon Sep 17 00:00:00 2001 From: Kundan Sable Date: Wed, 22 Jul 2026 15:20:00 +0530 Subject: [PATCH] fix: detect a selected-but-unusable OS keyring and fall back gracefully MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit evaluate_and_patch_config() only disabled USE_OS_SECRET_STORAGE when keyring.get_keyring().name == 'fail Keyring'. On Debian 13 over RDP, a real backend (e.g. SecretService) is selected because no D-Bus/GNOME Keyring session is running, so the name check passes even though every actual keyring call fails — leaving the crypt key unset and every operation raising a bare CryptKeyMissing. Probe the selected backend with a harmless read of a never-existing entry after selection. A healthy backend returns None without prompting; an unusable one raises, and we disable USE_OS_SECRET_STORAGE so the app falls back to the master-password / in-app crypt key mechanism instead of failing outright. Fixes #10107 --- web/pgadmin/evaluate_config.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/web/pgadmin/evaluate_config.py b/web/pgadmin/evaluate_config.py index 644e02bca06..a6c797a636d 100644 --- a/web/pgadmin/evaluate_config.py +++ b/web/pgadmin/evaluate_config.py @@ -138,8 +138,26 @@ def evaluate_and_patch_config(config: dict) -> dict: config.setdefault('KEYRING_NAME', '') else: k_name = keyring.get_keyring().name - # Setup USE_OS_SECRET_STORAGE false as no keyring backend available - if k_name == 'fail Keyring': + # A keyring backend may be selected (e.g. SecretService on Linux) + # yet be completely unusable at runtime - for example in a headless + # or RDP session where there is no running D-Bus / GNOME Keyring. + # In that case every keyring call raises and the crypt key is never + # set, surfacing as a bare CryptKeyMissing on every operation. + # Probe the backend with a harmless read of an entry that never + # exists; if the backend is healthy this returns None without + # prompting, and if it is unusable it raises. When it is not usable, + # disable OS secret storage so pgAdmin falls back to the + # master-password / in-app crypt key mechanism. + keyring_usable = k_name != 'fail Keyring' + if keyring_usable: + try: + keyring.get_password( + 'pgAdmin4', 'entry_to_check_keyring_access') + except Exception: + keyring_usable = False + + if not keyring_usable: + # Setup USE_OS_SECRET_STORAGE false as no usable keyring backend config['USE_OS_SECRET_STORAGE'] = False config['KEYRING_NAME'] = '' else: