-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
fix(keyring): make keyring unlock thread safe #10062
base: main
Are you sure you want to change the base?
Conversation
Reviewer's Guide by SourceryThis pull request makes the keyring unlock thread-safe to avoid multiple credential store unlock requests when using a ThreadPoolExecutor. It introduces a pre-flight check to ensure keyring unlocks only once, improves logging, and implements thread-safe caching for PasswordManager properties. Sequence diagram for thread-safe keyring unlock processsequenceDiagram
participant App as Poetry Application
participant PM as PasswordManager
participant PK as PoetryKeyring
participant K as Keyring System
App->>PM: Check keyring availability
activate PM
PM->>PK: is_available()
activate PK
PK->>K: Check backend validity
PK->>K: Test keyring unlock (get_password)
K-->>PK: Return unlock status
PK-->>PM: Return availability status
deactivate PK
PM-->>App: Return keyring status
deactivate PM
Note over App,K: Only one unlock attempt is made
Note over App,K: due to thread-safe caching
Class diagram for thread-safe keyring implementationclassDiagram
class PasswordManager {
-Config _config
+use_keyring: bool
+keyring: PoetryKeyring
}
class PoetryKeyring {
-str _namespace
+get_password(name: str, username: str)
+set_password(name: str, username: str, password: str)
+delete_password(name: str, username: str)
+get_entry_name(name: str)
+is_available(): bool
}
class AtomicCachedProperty {
-BoundedSemaphore _semaphore
-dict[object, Lock] _locks
+__get__(instance, owner)
}
note for AtomicCachedProperty "New thread-safe property decorator"
PasswordManager --> PoetryKeyring
PasswordManager ..> AtomicCachedProperty : uses
State diagram for keyring availability checkstateDiagram-v2
[*] --> CheckingAvailability
CheckingAvailability --> ImportCheck
ImportCheck --> BackendCheck: Import successful
ImportCheck --> Unavailable: Import failed
BackendCheck --> UnlockCheck: Valid backend found
BackendCheck --> Unavailable: No valid backend
UnlockCheck --> Available: Unlock successful
UnlockCheck --> Unavailable: Unlock failed
Available --> [*]
Unavailable --> [*]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
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.
Hey @abn - I've reviewed your changes and they look great!
Here's what I looked at during the review
- 🟡 General issues: 1 issue found
- 🟢 Security: all looks good
- 🟢 Testing: all looks good
- 🟢 Complexity: all looks good
- 🟢 Documentation: all looks good
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
2e469bf
to
23bbc46
Compare
This change implements a new decorator ``@atomic_cached_property` that extends `@functools.cached_property` to allow for a thread-safe atomic cached property. This also allows cached properties to function consistently across Python versions as the undocumented thread safety lock implemented in the stdlib prior to 3.12 was erroneous and has been removed since 3.12. Reference: https://docs.python.org/3/library/functools.html#functools.cached_property
When using `poetry install`, Poetry executor prefers to execute operations using a `concurrent.futures.ThreadPoolExecutor`. This can lead to multiple credential store unlock requests to be dispatched simultaneously. If the credential store is locked, and a user either intentionally or unintentionally dismisses the prompt to provide the store password; or the dbus messages fail to launch the prompter the Poetry user can experience, what can appear as a "hang". This in fact can be several threads competing with each other waiting for a dbus event indefinitely; this is a consequence of how Poetry uses keyring. This change introduces the following: - pre-flight check for installer commands that ensures keyring unlocks only once for the duration of the command - improved logging of keyring unlock event and/or failure - thread safe caching of `PasswordManager.<use_keyring|keyring>` This change does not address the following: - handling cases where dbus message fails or prompter is blocked - authentication of a locked keyring in a non-tty session
23bbc46
to
fbeb719
Compare
Updated the implementation to only unlock for installer commands. |
When using
poetry install
, Poetry executor prefers to execute operations using aconcurrent.futures.ThreadPoolExecutor
. This can lead to multiple credential store unlock requests to be dispatched simultaneously.If the credential store is locked, and a user either intentionally or unintentionally dismisses the prompt to provide the store password; or the dbus messages fail to launch the prompter the Poetry user can experience, what can appear as a "hang". This in fact can be several threads competing with each other waiting for a dbus event indefinitely; this is a consequence of how Poetry uses keyring.
This change introduces the following:
PasswordManager.<use_keyring|keyring>
@atomic_cached_property
decoratorThis change does not address the following:
I am also open to consider an alternative for
@atomic_cached_property
as I am not so comfortable having to implement something like this unless we really need it.Resolves: #8623
Summary by Sourcery
Make keyring unlock thread-safe and improve logging.
Bug Fixes:
Enhancements:
PasswordManager
properties.Tests: