Skip to content

CLI: skip delete_adhoc_servers() in CLI mode (fixes setup.py user-management regression)#10008

Closed
asheshv wants to merge 1 commit into
pgadmin-org:masterfrom
asheshv:fix/setup-py-cli-adhoc-skip
Closed

CLI: skip delete_adhoc_servers() in CLI mode (fixes setup.py user-management regression)#10008
asheshv wants to merge 1 commit into
pgadmin-org:masterfrom
asheshv:fix/setup-py-cli-adhoc-skip

Conversation

@asheshv

@asheshv asheshv commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Closes #9987.

Problem

setup.py update-user (and other CLI user-management commands) crash with:

AttributeError: 'PgAdmin' object has no attribute 'login_manager'

…blocking all CLI automation: config scripts, Kubernetes operators, password rotations.

Root cause

PR #9830 ("enforce data isolation and harden shared servers in server mode") added a per-user scoping check to delete_adhoc_servers() that touches current_user.is_authenticated.

Call sequence on the CLI path:

  1. setup.py:432 calls ManageRoles.get_role(...) inside app.test_request_context() (so SQLAlchemy session works)
  2. setup.py:154 invokes create_app('-cli')
  3. pgadmin/__init__.py:498 calls delete_adhoc_servers()
  4. delete_adhoc_servers() reads current_user.is_authenticated
  5. → Flask-Login's LocalProxy calls current_app.login_manager._load_user()
  6. boom: login_manager is installed at create_app:546 (Flask-Security init_app), AFTER line 498

In normal web startup the call at line 498 also runs with no login_manager yet — but has_request_context() returns False there, so the has_user guard short-circuits before the current_user access. CLI is different because setup.py deliberately opens a test_request_context for SQLAlchemy.

Fix

Wrap the cleanup call in if not cli_mode: — the same pattern already used elsewhere in create_app for paths init, etc. Adhoc servers are a UI/tool concept (Schema Diff workspaces, Query Tool ad-hoc connections, PSQL connections) — they have no meaning in a CLI session that only wants to read/write one user row.

Skipping the cleanup in CLI mode is semantically correct, not just a workaround.

End-user effect

Reporter's command now succeeds:

$ python3 setup.py update-user rhino@example.com --password abc123 --role Administrator
           User Details
+---------------------------------+
| Field       | Value             |
|-------------+-------------------|
| Username    | rhino@example.com |
| Email       | rhino@example.com |
| auth_source | internal          |
| role        | Administrator     |
| active      | True              |
+---------------------------------+

(matching the v9.13 baseline they cited).

Behaviour matrix

Mode delete_adhoc_servers() runs? Why
Desktop/Server (web) Yes — at startup as before cli_mode == False
CLI (setup.py *) No cli_mode == True; no UI ever creates adhoc servers in CLI sessions, nothing to clean up
Per-tool exit cleanup (delete_adhoc_servers(sid=...)) Unchanged Called from a real request context in the running web app

Notes

  • No new dependencies, no migration, 1 file / +9/-1.
  • No login_manager defensive coupling added — the root cause is "this function shouldn't run in CLI mode in the first place", so the fix is at the call site, not inside the function. Future callers from a real request context get the full per-user scoping as PR fix: enforce data isolation and harden shared servers in server mode #9830 intended.

Test plan

  • pycodestyle clean.
  • Manual: python3 setup.py update-user <email> --password <pw> --role Administrator against a freshly-installed pgAdmin → succeeds without traceback.
  • Manual: python3 setup.py add-user <email> ... → succeeds.
  • Manual: start pgAdmin in desktop/server mode → adhoc servers from a previous run are still cleaned up at startup (regression guard for the web-mode path).
  • Manual: open a Schema Diff workspace against ad-hoc connection params; close it; restart pgAdmin → adhoc server is gone (per-tool cleanup still works).

Summary by CodeRabbit

  • Bug Fixes
    • Resolved an issue where temporary server cleanup was incorrectly executed during CLI operations, preventing initialization failures in command-line mode.
Closes pgadmin-org#9987.

PR pgadmin-org#9830 ("enforce data isolation and harden shared servers in
server mode") added a per-user scoping check to
`delete_adhoc_servers()` that touches `current_user.is_authenticated`.

In normal web startup the call at `create_app:498` runs without a
request context, so the `has_request_context()` short-circuit kicks
in and `current_user` is never dereferenced. But `setup.py` CLI
commands (`update-user`, `add-user`, etc.) wrap their work in
`app.test_request_context()` so SQLAlchemy session operations work
— which flips `has_request_context()` to True and forces the
`current_user` proxy to call `current_app.login_manager._load_user()`.

`login_manager` is installed by Flask-Security at
`create_app:546`, AFTER the line-498 cleanup call — so in CLI mode
the proxy raises:

  AttributeError: 'PgAdmin' object has no attribute 'login_manager'

…blocking all CLI user-management automation (configuration scripts,
Kubernetes operators, password rotations).

Fix: gate the `delete_adhoc_servers()` call with the existing
`if not cli_mode:` pattern used elsewhere in create_app (paths
init, etc.). Adhoc servers are a UI/tool concept (Schema Diff
workspaces, Query Tool ad-hoc connections); they have no meaning
in a CLI session that only wants to update one user row, so
skipping the cleanup is semantically correct, not just a workaround.

Behaviour in web/server mode is unchanged.
@coderabbitai

coderabbitai Bot commented Jun 6, 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: c4db8374-b19a-45c5-8f4b-6de5cc69a3b6

📥 Commits

Reviewing files that changed from the base of the PR and between 1487059 and b1d63d6.

📒 Files selected for processing (1)
  • web/pgadmin/__init__.py

Walkthrough

create_app() now skips adhoc server deletion during CLI mode. The cleanup call is guarded by if not cli_mode: to prevent Flask-Security initialization errors when setup.py user-management commands execute the app factory without a web request context.

Changes

CLI Mode Adhoc Server Cleanup

Layer / File(s) Summary
Adhoc server cleanup guard
web/pgadmin/__init__.py
The delete_adhoc_servers() call is wrapped in a if not cli_mode: conditional guard with comments explaining that cleanup is skipped in CLI mode to avoid accessing uninitialized Flask-Security components that would otherwise cause AttributeError when user-management commands run.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 accurately summarizes the main change: skipping delete_adhoc_servers() in CLI mode to fix a setup.py user-management regression.
Linked Issues check ✅ Passed The PR addresses all key objectives from #9987: prevents AttributeError crashes in CLI user-management commands, ensures they complete successfully, implements a minimal change by gating delete_adhoc_servers with if not cli_mode:, and preserves server-mode behavior.
Out of Scope Changes check ✅ Passed The change is narrowly scoped to the linked issue: only one file modified (+9/-1) with a conditional guard on delete_adhoc_servers for CLI mode, no unrelated changes 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.

@hiteshjambhale

Copy link
Copy Markdown
Contributor

Reviewed and tested. Looks good to me.

@dpage

dpage commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Merged to master as 879ae40 (squashed, preserving @asheshv as author), with a Bug fixes release-notes entry for #9987.

I smoke-tested the fix end-to-end against a throwaway desktop-mode SQLite DB: with the guard reverted, setup.py update-user <email> --password ... --role Administrator reproduces the exact AttributeError: 'PgAdmin' object has no attribute 'login_manager'; with the fix in place the same command succeeds and prints the User Details table. The web-mode startup path (create_app() without -cli) still runs delete_adhoc_servers() cleanly.

The squash rewrites the SHA so GitHub won't auto-close this — closing manually. Thanks @asheshv, and @hiteshjambhale for the review!

@dpage dpage closed this Jun 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants