Skip to content

Fix Query Tool password re-prompt loop for unsaved passwords (#9091)#10073

Merged
asheshv merged 3 commits into
pgadmin-org:masterfrom
dpage:fix-9091-qt-password-prompt-loop
Jun 12, 2026
Merged

Fix Query Tool password re-prompt loop for unsaved passwords (#9091)#10073
asheshv merged 3 commits into
pgadmin-org:masterfrom
dpage:fix-9091-qt-password-prompt-loop

Conversation

@dpage

@dpage dpage commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes an infinite password-prompt loop in the Query Tool (and other tools that open their own connections) for servers whose password was not saved — most visibly reported with long, short-lived cloud auth tokens used as the password (AWS RDS IAM, Azure Entra).

Root cause

When a tool such as the Query Tool opens a connection for a server whose password is not saved, it relies on the password cached on the ServerManager. If that cached password is unavailable, the tool returns 428 and the UI prompts for the password. The entered password is POSTed to the sqleditor.connect_server endpoint.

connect_server short-circuits with "Server connected" whenever the server's primary connection is already established — and in doing so silently discards the password the user just entered. The tool's own connection therefore still has no password and re-prompts immediately, producing an infinite loop in which the re-entered password appears to be rejected.

Fix

In that short-circuit path, cache the entered password on the ServerManager (encrypted) so the tool's connection can reuse it. The password overwrites any previously cached value, so a regenerated short-lived token takes effect immediately rather than the loop retrying a stale/expired one.

The change is confined to the connect_server endpoint via a small helper; it is a no-op when no password is supplied or the encryption key is unavailable.

Test plan

  • New unit test test_cache_manager_password.py (5 scenarios): password supplied is encrypted and cached; an existing cached password is overwritten; no-ops when the password is absent, empty, or the crypt key is missing. The cached value is verified to decrypt back to the original token intact.
  • Existing test_new_connection_dialog still passes.
  • pycodestyle clean.

Note for reviewers

Several reporters (and maintainers) could not reproduce the original symptom in every environment, and a length/content correlation in the thread remains unexplained. This change definitively breaks the prompt loop and makes a correctly re-entered password take effect, matching the primary reported symptom. I've asked the reporters on the issue for their server mode / worker count / workspace-restore details in case a complementary fix (more reliable manager.password persistence) is also warranted.

Closes #9091

Summary by CodeRabbit

  • Bug Fixes

    • Query Tool no longer repeatedly prompts for the password when the primary connection is already established; the entered password is now cached so subsequent tool actions reuse it.
  • Tests

    • Added regression tests covering password caching, overwrite, no-op cases (missing/empty password, missing encryption key, malformed request).
  • Documentation

    • Added release-note entry for this fix (v9.16).

…n-org#9091)

When a tool (Query Tool, View/Edit Data, etc.) opens a connection for a
server whose password was not saved, it relies on the password cached on
the server manager. If that cached password is unavailable, the tool
prompts for it. The entered password was POSTed to the connect_server
endpoint, which short-circuited with "Server connected" whenever the
server's primary connection was already established -- silently discarding
the entered password. The tool's own connection therefore still had no
password and re-prompted immediately, producing an infinite prompt loop
in which the re-entered password appeared to be rejected.

Cache the entered password on the server manager (encrypted) in that
short-circuit path so the tool's connection can reuse it. The password
overwrites any cached value, so a regenerated short-lived cloud auth
token (AWS RDS IAM / Azure Entra) takes effect immediately.
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 650eb435-cf64-4a2f-894a-3c4242afa58b

📥 Commits

Reviewing files that changed from the base of the PR and between 66223ca and a5c89e8.

📒 Files selected for processing (3)
  • docs/en_US/release_notes_9_16.rst
  • web/pgadmin/tools/sqleditor/__init__.py
  • web/pgadmin/tools/sqleditor/utils/tests/test_cache_manager_password.py
✅ Files skipped from review due to trivial changes (1)
  • docs/en_US/release_notes_9_16.rst
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/pgadmin/tools/sqleditor/init.py

Walkthrough

This pull request extracts the password from Query Tool requests and, when the server's primary connection is already established and a crypt key is available, encrypts and stores the password on the server manager to avoid repeated password prompts; includes tests and a release-note entry.

Changes

Password Caching for Query Tool

Layer / File(s) Summary
Password caching helper function and imports
web/pgadmin/tools/sqleditor/__init__.py
Added imports for encrypt and get_crypt_key; implemented _cache_manager_password_from_request(manager) to read password from request form or JSON, handle missing/empty values and missing crypt key, encrypt and store the password via manager._update_password(...), and call manager.update_session(); exceptions are logged and swallowed.
Integration into connect_server
web/pgadmin/tools/sqleditor/__init__.py
When the server connection is already established in connect_server, invoke _cache_manager_password_from_request(manager) so the entered password is persisted for subsequent tool connections.
Regression test for password caching
web/pgadmin/tools/sqleditor/utils/tests/test_cache_manager_password.py
CacheManagerPasswordTest adds scenarios validating encrypted caching when a crypt key and password are present (and that decrypting the stored value matches the original), and no-op behavior when password is missing/empty, crypt key is absent, or request JSON is malformed.
Release notes documentation
docs/en_US/release_notes_9_16.rst
Add v9.16 bug-fix bullet for Issue #9091 describing the Query Tool password re-prompt fix and password-caching behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately describes the main change: fixing a password re-prompt loop issue in Query Tool for unsaved passwords, directly addressing the bug reported in issue #9091.
Linked Issues check ✅ Passed The PR successfully addresses all coding objectives from issue #9091: caching entered passwords on the server manager when the primary connection exists, implementing encryption for cached credentials, and preventing re-prompts for subsequent tool-initiated connections.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the fix: release notes entry, sqleditor connection handler with password caching logic, and comprehensive regression tests. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
web/pgadmin/tools/sqleditor/utils/tests/test_cache_manager_password.py (1)

37-64: ⚡ Quick win

Consider adding a JSON data scenario for complete coverage.

The stack context indicates that _cache_manager_password_from_request should extract passwords from "request form or JSON," but all current scenarios only test the form data path. Consider adding a scenario that supplies the password via request.data (JSON) instead of request.form to ensure both extraction paths are covered.

📝 Suggested JSON scenario
+        ('When a password is supplied via JSON it is encrypted and cached', dict(
+            form_data={},
+            json_data={'password': LONG_TOKEN},
+            crypt_key_present=True,
+            expect_cached=True,
+        )),

Then update line 77 to:

-        mock_request.data = None
+        mock_request.data = getattr(self, 'json_data', {})

Note: The RUF012 warning about mutable class attributes is a false positive. The scenarios pattern is an established convention in pgAdmin's BaseTestGenerator-based tests, where each test run receives independent scenario instances.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/pgadmin/tools/sqleditor/utils/tests/test_cache_manager_password.py`
around lines 37 - 64, Add a test scenario that covers JSON payload extraction by
supplying the password in request.data instead of request.form: update the
scenarios list (alongside the existing form-based cases) to include a case where
form_data={} (or omitted) and json_data={'password': LONG_TOKEN}, with
crypt_key_present=True and expect_cached=True so
_cache_manager_password_from_request is exercised for the JSON path; ensure any
existing_password/expect_cached variants you need are mirrored if you want
overwrite behavior tested.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/pgadmin/tools/sqleditor/__init__.py`:
- Around line 2708-2739: The function _cache_manager_password_from_request
currently calls json.loads(request.data) outside the try/except, which can raise
JSONDecodeError and crash the endpoint; move the JSON parsing into the existing
try/except (or add a small try/except around json.loads) so that invalid JSON is
treated as a no-op and the function returns silently; ensure you catch
json.JSONDecodeError (or Exception) and return early, keeping
manager._update_password(encrypt(...)) and manager.update_session inside the try
block so they only run with valid parsed data.

---

Nitpick comments:
In `@web/pgadmin/tools/sqleditor/utils/tests/test_cache_manager_password.py`:
- Around line 37-64: Add a test scenario that covers JSON payload extraction by
supplying the password in request.data instead of request.form: update the
scenarios list (alongside the existing form-based cases) to include a case where
form_data={} (or omitted) and json_data={'password': LONG_TOKEN}, with
crypt_key_present=True and expect_cached=True so
_cache_manager_password_from_request is exercised for the JSON path; ensure any
existing_password/expect_cached variants you need are mirrored if you want
overwrite behavior tested.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 18d32ae9-cbc2-4d7f-bc6e-5304c382f603

📥 Commits

Reviewing files that changed from the base of the PR and between 04fa05c and 66223ca.

📒 Files selected for processing (3)
  • docs/en_US/release_notes_9_16.rst
  • web/pgadmin/tools/sqleditor/__init__.py
  • web/pgadmin/tools/sqleditor/utils/tests/test_cache_manager_password.py

Comment thread web/pgadmin/tools/sqleditor/__init__.py
Move request-body JSON parsing inside the try/except so malformed request
data is treated as a silent no-op (logged and swallowed) rather than
propagating a JSONDecodeError and turning the connect_server endpoint's
'Server connected' response into a 500. Add a regression test scenario for
the malformed-JSON case.

Addresses CodeRabbit review feedback on pgadmin-org#10073.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes an infinite password re-prompt loop affecting Query Tool (and other tool-specific connections) when a server password is not saved, by caching the user-entered password on the ServerManager even when the primary connection is already established.

Changes:

  • Cache the password from the connect_server request on the ServerManager (encrypted) in the “already connected” short-circuit path.
  • Add unit tests covering caching, overwriting, and no-op scenarios (including malformed JSON handling).
  • Document the fix in the v9.16 release notes.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
web/pgadmin/tools/sqleditor/init.py Add helper to cache request password (encrypted) when connect_server short-circuits as already connected.
web/pgadmin/tools/sqleditor/utils/tests/test_cache_manager_password.py Add regression tests for password caching behavior across multiple scenarios.
docs/en_US/release_notes_9_16.rst Add release note entry for Issue #9091.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread web/pgadmin/tools/sqleditor/__init__.py
@asheshv asheshv merged commit 255550e into pgadmin-org:master Jun 12, 2026
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Very long password not working in Query Tool in v9.6 and newer

3 participants