Preserve macOS Keychain access choices - #1633
MelvinCERBA wants to merge 4 commits into
Conversation
dbcli#1631 fixes a real bug we share: ConfigObj strips everything after a # in a service-file password. dbcli#1633 applies too: we rewrite the keyring password on every successful connection, including one just read from it.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
UsmanGhias
left a comment
There was a problem hiding this comment.
Hi Melvin, thanks for putting this together! This is a fantastic security improvement that prevents python from unnecessarily pre-authorizing keychain credentials on macOS, protecting users from unintended background access.
Technically, I really like how cleanly you separated the macOS specific logic into macos_keychain.py while keeping the fallback path intact for other platforms. One minor thing to double check is the ctypes memory management and error handling across different macOS versions, but the unit tests look quite thorough and cover the core code paths well.
Overall, this is very neat work. Happy to see this land once CI passes.
Best,
Usman
Description
On macOS, Keychain trusts the executable that creates a credential by default. Because pgcli runs through Python, saving a password pre-authorizes Python to read it without confirmation. Rewriting an existing credential also resets access choices such as Allow Once.
This is a problem because, for example, you typically don't want your coding agent to be able to access DBs you store the credentials for in Keychain without your manual approval.
This PR preserves the user's Keychain access choices:
Implementation-wise, pgcli preserves keyring's normal backend selection, including chained backends. For native macOS Keychain, it reuses
keyring.backends.macOS.api: existing items are updated with onlykSecValueData, preserving their access controls, while new items receive aSecAccesscreated from an empty trusted-application list. The few Security.framework calls not exposed by keyring are bound throughctypes.The implementation supports keyring 23.1 through 25.x. Regression tests cover native backend detection, chained and custom backends, ACL-preserving updates, and creation with no trusted applications.
Checklist
changelog.rst.AUTHORSfile (or it's already there).pip install pre-commit && pre-commit install).