google styled doc
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
"""
|
||||
Credential persistence interfaces and implementations for Mail Intake.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
This package defines the abstractions and concrete implementations used
|
||||
to persist authentication credentials across Mail Intake components.
|
||||
|
||||
@@ -16,6 +20,16 @@ The package provides:
|
||||
|
||||
Credential lifecycle management, interpretation, and security policy
|
||||
decisions remain the responsibility of authentication providers.
|
||||
|
||||
---
|
||||
|
||||
## Public API
|
||||
|
||||
CredentialStore
|
||||
PickleCredentialStore
|
||||
RedisCredentialStore
|
||||
|
||||
---
|
||||
"""
|
||||
|
||||
from mail_intake.credentials.store import CredentialStore
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
"""
|
||||
Local filesystem–based credential persistence for Mail Intake.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
This module provides a file-backed implementation of the
|
||||
``CredentialStore`` abstraction using Python's ``pickle`` module.
|
||||
|
||||
@@ -29,13 +33,16 @@ class PickleCredentialStore(CredentialStore[T]):
|
||||
filesystem. It is a simple implementation intended primarily for
|
||||
development, testing, and single-process execution contexts.
|
||||
|
||||
This implementation:
|
||||
- Stores credentials on the local filesystem
|
||||
- Uses pickle for serialization and deserialization
|
||||
- Does not provide encryption, locking, or concurrency guarantees
|
||||
Notes:
|
||||
**Guarantees:**
|
||||
|
||||
Credential lifecycle management, validation, and refresh logic are
|
||||
explicitly out of scope for this class.
|
||||
- Stores credentials on the local filesystem
|
||||
- Uses pickle for serialization and deserialization
|
||||
- Does not provide encryption, locking, or concurrency guarantees
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- Credential lifecycle management, validation, and refresh logic are explicitly out of scope for this class
|
||||
"""
|
||||
|
||||
def __init__(self, path: str):
|
||||
@@ -43,7 +50,7 @@ class PickleCredentialStore(CredentialStore[T]):
|
||||
Initialize a pickle-backed credential store.
|
||||
|
||||
Args:
|
||||
path:
|
||||
path (str):
|
||||
Filesystem path where credentials will be stored.
|
||||
The file will be created or overwritten as needed.
|
||||
"""
|
||||
@@ -53,15 +60,16 @@ class PickleCredentialStore(CredentialStore[T]):
|
||||
"""
|
||||
Load credentials from the local filesystem.
|
||||
|
||||
If the credential file does not exist or cannot be successfully
|
||||
deserialized, this method returns ``None``.
|
||||
|
||||
The store does not attempt to validate or interpret the returned
|
||||
credentials.
|
||||
|
||||
Returns:
|
||||
An instance of type ``T`` if credentials are present and
|
||||
successfully deserialized; otherwise ``None``.
|
||||
Optional[T]:
|
||||
An instance of type ``T`` if credentials are present and
|
||||
successfully deserialized; otherwise ``None``.
|
||||
|
||||
Notes:
|
||||
**Guarantees:**
|
||||
|
||||
- If the credential file does not exist or cannot be successfully deserialized, this method returns ``None``
|
||||
- The store does not attempt to validate or interpret the returned credentials
|
||||
"""
|
||||
try:
|
||||
with open(self.path, "rb") as fh:
|
||||
@@ -73,12 +81,14 @@ class PickleCredentialStore(CredentialStore[T]):
|
||||
"""
|
||||
Persist credentials to the local filesystem.
|
||||
|
||||
Any previously stored credentials at the configured path are
|
||||
overwritten.
|
||||
|
||||
Args:
|
||||
credentials:
|
||||
credentials (T):
|
||||
The credential object to persist.
|
||||
|
||||
Notes:
|
||||
**Responsibilities:**
|
||||
|
||||
- Any previously stored credentials at the configured path are overwritten
|
||||
"""
|
||||
with open(self.path, "wb") as fh:
|
||||
pickle.dump(credentials, fh)
|
||||
@@ -87,8 +97,10 @@ class PickleCredentialStore(CredentialStore[T]):
|
||||
"""
|
||||
Remove persisted credentials from the local filesystem.
|
||||
|
||||
This method deletes the credential file if it exists and should
|
||||
be treated as an idempotent operation.
|
||||
Notes:
|
||||
**Lifecycle:**
|
||||
|
||||
- This method deletes the credential file if it exists and should be treated as an idempotent operation
|
||||
"""
|
||||
import os
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
"""
|
||||
Redis-backed credential persistence for Mail Intake.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
This module provides a Redis-based implementation of the
|
||||
``CredentialStore`` abstraction, enabling credential persistence
|
||||
across distributed and horizontally scaled deployments.
|
||||
@@ -37,14 +41,16 @@ class RedisCredentialStore(CredentialStore[T]):
|
||||
distributed and horizontally scaled deployments where credentials
|
||||
must be shared across multiple processes or nodes.
|
||||
|
||||
The store is intentionally generic and delegates all serialization
|
||||
concerns to caller-provided functions. This avoids unsafe mechanisms
|
||||
such as pickle and allows credential formats to be explicitly
|
||||
controlled and audited.
|
||||
Notes:
|
||||
**Responsibilities:**
|
||||
|
||||
This class is responsible only for persistence and retrieval.
|
||||
It does not interpret, validate, refresh, or otherwise manage
|
||||
the lifecycle of the credentials being stored.
|
||||
- This class is responsible only for persistence and retrieval
|
||||
- It does not interpret, validate, refresh, or otherwise manage the lifecycle of the credentials being stored
|
||||
|
||||
**Guarantees:**
|
||||
|
||||
- The store is intentionally generic and delegates all serialization concerns to caller-provided functions
|
||||
- This avoids unsafe mechanisms such as pickle and allows credential formats to be explicitly controlled and audited
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -59,31 +65,20 @@ class RedisCredentialStore(CredentialStore[T]):
|
||||
Initialize a Redis-backed credential store.
|
||||
|
||||
Args:
|
||||
redis_client:
|
||||
An initialized Redis client instance (for example,
|
||||
``redis.Redis`` or a compatible interface) used to
|
||||
communicate with the Redis server.
|
||||
redis_client (Any):
|
||||
An initialized Redis client instance (for example, ``redis.Redis`` or a compatible interface) used to communicate with the Redis server.
|
||||
|
||||
key:
|
||||
The Redis key under which credentials are stored.
|
||||
Callers are responsible for applying appropriate
|
||||
namespacing to avoid collisions.
|
||||
key (str):
|
||||
The Redis key under which credentials are stored. Callers are responsible for applying appropriate namespacing to avoid collisions.
|
||||
|
||||
serialize:
|
||||
A callable that converts a credential object of type
|
||||
``T`` into a ``bytes`` representation suitable for
|
||||
storage in Redis.
|
||||
serialize (Callable[[T], bytes]):
|
||||
A callable that converts a credential object of type ``T`` into a ``bytes`` representation suitable for storage in Redis.
|
||||
|
||||
deserialize:
|
||||
A callable that converts a ``bytes`` payload retrieved
|
||||
from Redis back into a credential object of type ``T``.
|
||||
deserialize (Callable[[bytes], T]):
|
||||
A callable that converts a ``bytes`` payload retrieved from Redis back into a credential object of type ``T``.
|
||||
|
||||
ttl_seconds:
|
||||
Optional time-to-live (TTL) for the stored credentials,
|
||||
expressed in seconds. When provided, Redis will
|
||||
automatically expire the stored credentials after the
|
||||
specified duration. If ``None``, credentials are stored
|
||||
without an expiration.
|
||||
ttl_seconds (Optional[int]):
|
||||
Optional time-to-live (TTL) for the stored credentials, expressed in seconds. When provided, Redis will automatically expire the stored credentials after the specified duration. If ``None``, credentials are stored without an expiration.
|
||||
"""
|
||||
self.redis = redis_client
|
||||
self.key = key
|
||||
@@ -95,16 +90,16 @@ class RedisCredentialStore(CredentialStore[T]):
|
||||
"""
|
||||
Load credentials from Redis.
|
||||
|
||||
If no value exists for the configured key, or if the stored
|
||||
payload cannot be successfully deserialized, this method
|
||||
returns ``None``.
|
||||
|
||||
The store does not attempt to validate the returned credentials
|
||||
or determine whether they are expired or otherwise usable.
|
||||
|
||||
Returns:
|
||||
An instance of type ``T`` if credentials are present and
|
||||
successfully deserialized; otherwise ``None``.
|
||||
Optional[T]:
|
||||
An instance of type ``T`` if credentials are present and
|
||||
successfully deserialized; otherwise ``None``.
|
||||
|
||||
Notes:
|
||||
**Guarantees:**
|
||||
|
||||
- If no value exists for the configured key, or if the stored payload cannot be successfully deserialized, this method returns ``None``
|
||||
- The store does not attempt to validate the returned credentials or determine whether they are expired or otherwise usable
|
||||
"""
|
||||
raw = self.redis.get(self.key)
|
||||
if not raw:
|
||||
@@ -118,13 +113,15 @@ class RedisCredentialStore(CredentialStore[T]):
|
||||
"""
|
||||
Persist credentials to Redis.
|
||||
|
||||
Any previously stored credentials under the same key are
|
||||
overwritten. If a TTL is configured, the credentials will
|
||||
expire automatically after the specified duration.
|
||||
|
||||
Args:
|
||||
credentials:
|
||||
credentials (T):
|
||||
The credential object to persist.
|
||||
|
||||
Notes:
|
||||
**Responsibilities:**
|
||||
|
||||
- Any previously stored credentials under the same key are overwritten
|
||||
- If a TTL is configured, the credentials will expire automatically after the specified duration
|
||||
"""
|
||||
payload = self.serialize(credentials)
|
||||
if self.ttl_seconds:
|
||||
@@ -136,7 +133,10 @@ class RedisCredentialStore(CredentialStore[T]):
|
||||
"""
|
||||
Remove stored credentials from Redis.
|
||||
|
||||
This operation deletes the configured Redis key if it exists.
|
||||
Implementations should treat this method as idempotent.
|
||||
Notes:
|
||||
**Lifecycle:**
|
||||
|
||||
- This operation deletes the configured Redis key if it exists
|
||||
- Implementations should treat this method as idempotent
|
||||
"""
|
||||
self.redis.delete(self.key)
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
"""
|
||||
Credential persistence abstractions for Mail Intake.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
This module defines the generic persistence contract used to store and
|
||||
retrieve authentication credentials across Mail Intake components.
|
||||
|
||||
@@ -29,16 +33,18 @@ class CredentialStore(ABC, Generic[T]):
|
||||
Abstract base class defining a generic persistence interface for
|
||||
authentication credentials.
|
||||
|
||||
This interface separates *credential lifecycle management* from
|
||||
*credential storage mechanics*. Implementations are responsible
|
||||
only for persistence concerns, while authentication providers
|
||||
retain full control over credential creation, validation, refresh,
|
||||
and revocation logic.
|
||||
Notes:
|
||||
**Responsibilities:**
|
||||
|
||||
The store is intentionally agnostic to:
|
||||
- The concrete credential type being stored
|
||||
- The serialization format used to persist credentials
|
||||
- The underlying storage backend or durability guarantees
|
||||
- Provide persistent storage separating life-cycle management from storage mechanics
|
||||
- Keep implementation focused only on persistence
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- The store is intentionally agnostic to:
|
||||
- The concrete credential type being stored
|
||||
- The serialization format used to persist credentials
|
||||
- The underlying storage backend or durability guarantees
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
@@ -46,16 +52,16 @@ class CredentialStore(ABC, Generic[T]):
|
||||
"""
|
||||
Load previously persisted credentials.
|
||||
|
||||
Implementations should return ``None`` when no credentials are
|
||||
present or when stored credentials cannot be successfully
|
||||
decoded or deserialized.
|
||||
|
||||
The store must not attempt to validate, refresh, or otherwise
|
||||
interpret the returned credentials.
|
||||
|
||||
Returns:
|
||||
An instance of type ``T`` if credentials are available and
|
||||
loadable; otherwise ``None``.
|
||||
Optional[T]:
|
||||
An instance of type ``T`` if credentials are available and
|
||||
loadable; otherwise ``None``.
|
||||
|
||||
Notes:
|
||||
**Guarantees:**
|
||||
|
||||
- Implementations should return ``None`` when no credentials are present or when stored credentials cannot be successfully decoded or deserialized
|
||||
- The store must not attempt to validate, refresh, or otherwise interpret the returned credentials
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
@@ -63,18 +69,20 @@ class CredentialStore(ABC, Generic[T]):
|
||||
"""
|
||||
Persist credentials to the underlying storage backend.
|
||||
|
||||
This method is invoked when credentials are newly obtained or
|
||||
have been refreshed and are known to be valid at the time of
|
||||
persistence.
|
||||
|
||||
Implementations are responsible for:
|
||||
- Ensuring durability appropriate to the deployment context
|
||||
- Applying encryption or access controls where required
|
||||
- Overwriting any previously stored credentials
|
||||
|
||||
Args:
|
||||
credentials:
|
||||
credentials (T):
|
||||
The credential object to persist.
|
||||
|
||||
Notes:
|
||||
**Lifecycle:**
|
||||
|
||||
- This method is invoked when credentials are newly obtained or have been refreshed and are known to be valid at the time of persistence
|
||||
|
||||
**Responsibilities:**
|
||||
|
||||
- Ensuring durability appropriate to the deployment context
|
||||
- Applying encryption or access controls where required
|
||||
- Overwriting any previously stored credentials
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
@@ -82,9 +90,13 @@ class CredentialStore(ABC, Generic[T]):
|
||||
"""
|
||||
Remove any persisted credentials from the store.
|
||||
|
||||
This method is called when credentials are known to be invalid,
|
||||
revoked, corrupted, or otherwise unusable, and must ensure that
|
||||
no stale authentication material remains accessible.
|
||||
Notes:
|
||||
**Lifecycle:**
|
||||
|
||||
Implementations should treat this operation as idempotent.
|
||||
- This method is called when credentials are known to be invalid, revoked, corrupted, or otherwise unusable
|
||||
- Must ensure that no stale authentication material remains accessible
|
||||
|
||||
**Guarantees:**
|
||||
|
||||
- Implementations should treat this operation as idempotent
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user