-
Notifications
You must be signed in to change notification settings - Fork 805
Ensure saved shared server passwords are re-encrypted on password change.#9258 #9475
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
WalkthroughThe Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~15–25 minutes
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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/browser/server_groups/servers/utils.py (1)
475-499: Consider extracting shared re-encryption logic to reduce duplication.The password and tunnel password re-encryption logic (lines 480-495) is nearly identical to the Server handling code (lines 455-470). Consider extracting this into a helper function to improve maintainability.
🔎 Suggested refactoring approach:
Create a helper function to handle the tunnel password re-encryption:
def _reencrpyt_tunnel_password(server, manager, old_key, new_key): """Re-encrypt tunnel password for a server or shared server.""" if server.tunnel_password is not None: tunnel_password = decrypt(server.tunnel_password, old_key) if isinstance(tunnel_password, bytes): tunnel_password = tunnel_password.decode() tunnel_password = encrypt(tunnel_password, new_key) setattr(server, 'tunnel_password', tunnel_password) manager.tunnel_password = tunnel_password elif manager.tunnel_password is not None: tunnel_password = decrypt(manager.tunnel_password, old_key) if isinstance(tunnel_password, bytes): tunnel_password = tunnel_password.decode() tunnel_password = encrypt(tunnel_password, new_key) manager.tunnel_password = tunnel_passwordThen use it for both Server and SharedServer:
for server in Server.query.filter_by(user_id=user_id).all(): manager = driver.connection_manager(server.id) _password_check(server, manager, old_key, new_key) - - if server.tunnel_password is not None: - tunnel_password = decrypt(server.tunnel_password, old_key) - if isinstance(tunnel_password, bytes): - tunnel_password = tunnel_password.decode() - - tunnel_password = encrypt(tunnel_password, new_key) - setattr(server, 'tunnel_password', tunnel_password) - manager.tunnel_password = tunnel_password - elif manager.tunnel_password is not None: - tunnel_password = decrypt(manager.tunnel_password, old_key) - - if isinstance(tunnel_password, bytes): - tunnel_password = tunnel_password.decode() - - tunnel_password = encrypt(tunnel_password, new_key) - manager.tunnel_password = tunnel_password + _reencrpyt_tunnel_password(server, manager, old_key, new_key) db.session.commit() manager.update_session() # Ensure saved shared server passwords are re-encrypted. for server in SharedServer.query.filter_by(user_id=user_id).all(): manager = driver.connection_manager(server.id) _password_check(server, manager, old_key, new_key) - - if server.tunnel_password is not None: - tunnel_password = decrypt(server.tunnel_password, old_key) - if isinstance(tunnel_password, bytes): - tunnel_password = tunnel_password.decode() - - tunnel_password = encrypt(tunnel_password, new_key) - setattr(server, 'tunnel_password', tunnel_password) - manager.tunnel_password = tunnel_password - elif manager.tunnel_password is not None: - tunnel_password = decrypt(manager.tunnel_password, old_key) - - if isinstance(tunnel_password, bytes): - tunnel_password = tunnel_password.decode() - - tunnel_password = encrypt(tunnel_password, new_key) - manager.tunnel_password = tunnel_password + _reencrpyt_tunnel_password(server, manager, old_key, new_key) db.session.commit() manager.update_session()
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
web/pgadmin/browser/server_groups/servers/utils.py(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
web/pgadmin/browser/server_groups/servers/utils.py (2)
web/pgadmin/model/__init__.py (2)
Server(188-275)SharedServer(425-500)web/pgadmin/utils/crypto.py (2)
decrypt(47-61)encrypt(25-44)
🪛 Ruff (0.14.8)
web/pgadmin/browser/server_groups/servers/utils.py
486-486: Do not call setattr with a constant attribute value. It is not any safer than normal property access.
Replace setattr with assignment
(B010)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: run-feature-tests-pg (16)
- GitHub Check: run-feature-tests-pg (17)
- GitHub Check: run-feature-tests-pg (14)
- GitHub Check: run-feature-tests-pg (13)
- GitHub Check: run-feature-tests-pg (18)
- GitHub Check: run-feature-tests-pg (15)
🔇 Additional comments (1)
web/pgadmin/browser/server_groups/servers/utils.py (1)
22-22: LGTM!The import of
SharedServeris necessary and correct for the new functionality.
|
|
||
| # Ensure saved shared server passwords are re-encrypted. | ||
| for server in SharedServer.query.filter_by(user_id=user_id).all(): | ||
| manager = driver.connection_manager(server.id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, let's find and examine the utils.py file and the context around line 477
cat -n web/pgadmin/browser/server_groups/servers/utils.py | sed -n '470,500p'Repository: pgadmin-org/pgadmin4
Length of output: 1471
🏁 Script executed:
# Find SharedServer model definition
find . -type f -name "*.py" | xargs grep -l "class SharedServer" 2>/dev/null | head -5Repository: pgadmin-org/pgadmin4
Length of output: 167
🏁 Script executed:
# Examine SharedServer model definition
grep -A 30 "class SharedServer" web/pgadmin/model/__init__.pyRepository: pgadmin-org/pgadmin4
Length of output: 967
🏁 Script executed:
# Search for connection_manager method definition
grep -r "def connection_manager" --include="*.py" web/pgadmin/ | head -5Repository: pgadmin-org/pgadmin4
Length of output: 153
🏁 Script executed:
# Examine connection_manager method
grep -A 20 "def connection_manager" web/pgadmin/utils/driver/psycopg3/__init__.pyRepository: pgadmin-org/pgadmin4
Length of output: 716
🏁 Script executed:
# Search for how connection_manager is called elsewhere
grep -B3 "connection_manager" web/pgadmin/browser/server_groups/servers/utils.py | head -30Repository: pgadmin-org/pgadmin4
Length of output: 927
🏁 Script executed:
# Let's verify by checking if there are any other places where connection_manager
# is called with a SharedServer and see if there's a pattern
grep -r "SharedServer" web/pgadmin/browser/server_groups/servers/utils.py -A 5 -B 5 | grep -A 2 -B 2 "connection_manager"Repository: pgadmin-org/pgadmin4
Length of output: 310
Use server.osid instead of server.id for SharedServer connection manager lookup.
The connection_manager method expects the actual PostgreSQL server ID from the Server table. For SharedServer entries, this is stored in the osid foreign key field, not the id field (which is SharedServer's primary key). Using server.id will cause connection manager lookup failures or incorrect behavior.
- manager = driver.connection_manager(server.id)
+ manager = driver.connection_manager(server.osid)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| manager = driver.connection_manager(server.id) | |
| manager = driver.connection_manager(server.osid) |
🤖 Prompt for AI Agents
In web/pgadmin/browser/server_groups/servers/utils.py around line 477, the call
uses server.id to look up the connection manager but SharedServer entries store
the actual PostgreSQL server id in server.osid; update the lookup to use
server.osid for SharedServer entries (or when server.osid is present and not
None) and fall back to server.id otherwise so the connection_manager call
receives the correct underlying server id.
Summary by CodeRabbit
Release Notes
✏️ Tip: You can customize this high-level summary in your review settings.