mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2026-08-19 01:15:04 -05:00
evaluate_and_patch_config() called keyring.get_password() synchronously at `import config` time to detect a selected-but-unusable OS keyring backend. On Debian 13 (and similar headless/RDP sessions with no live D-Bus/GNOME-Keyring session), that call - and even the keyring import itself - can block forever, freezing the whole desktop app before it ever starts. Revert evaluate_config.py to the pre-9.17 synchronous check (backend name only, no get_password call). Move the usability probe into pgadmin.utils.keyring_probe, run from create_app() in a background daemon thread so it never delays startup, isolated in its own process via subprocess.Popen(sys.executable, '-c', ...) so a hang can actually be killed - a thread-only timeout can't do this, it would leave CPython's per-module import lock held forever and wedge any later `import keyring` in the parent process too. subprocess.Popen (plain fork+exec), not multiprocessing.Process, is required here: create_app() runs at the top level of pgAdmin4.py while it's still being imported, and multiprocessing's spawn start method refuses to start a child before the current process finishes bootstrapping its __main__ module. An earlier version of this fix used multiprocessing and crashed the probe thread with RuntimeError on every single test run, which corrupted the SQLAlchemy/sqlite session for the rest of app init and surfaced as an unrelated-looking "attempt to write a readonly database" error on module_preference inserts. config.USE_OS_SECRET_STORAGE is only ever read from request handlers requiring an authenticated session, never at import time or inside create_app() itself, so the async resolution race is safe in practice. Tests mock subprocess.Popen for the timeout/kill/config-fallback orchestration (deterministic, no real 3s wait or backend dependency), plus one test class that runs the real probe script in a real subprocess against a fake keyring module injected via PYTHONPATH, so the script body itself has real coverage. Verified with the full regression suite (--exclude feature_tests) in both desktop mode (2134 passed, 0 failed) and server mode (2251 passed, 0 failed); remaining skips are pre-existing pgAgent-dependent job tests.